Managed Deep Agents Beta:一种基于目录的 LangChain Agent 部署方式
LangChain的托管深度智能体功能可将项目文件夹转换为托管型智能体。各类文件的功能、mda部署的运作方式,以及值得了解的测试版缺陷。
来源: LangChain Just Shipped Managed Deep Agents — And Your Agent Is Now a Directory
那些在 LangGraph 上进行开发的团队不断遇到同样的限制。LangGraph 只是一个运行时环境、一种低级基础组件,却有很多人将其当作应用框架来使用。Deep Agents 就是 LangChain 的解决方案:它将规划功能、虚拟文件系统、子代理以及上下文压缩整合到一个框架中,这样人们就无需重新构建这些基础架构。
这确实有所帮助,但随后又出现了新的限制。这类框架的作用范围仅限于进程边界之内。一旦代理需要在重启后继续运行、在人类确认工具调用后重新启动、在周一到周五的早上8点自动执行任务、回复 Slack 中的提及,或是保留当前线程之外的任何记忆,团队就又得重新编写基础设施代码。这就涉及到检查点机制、定时任务、签名验证、线程所有权以及密钥路由等功能。
任何将智能体部署到云容器中的人都知道这会带来多大的失衡。以基于MCP的ECS Fargate文档智能体为例:需要IAM策略、包含私有子网的VPC、存储在S3中的Terraform状态文件以及DynamoDB锁表,同时任务定义在有人发现容器端口不匹配之前会一直失败健康检查。智能体本身的逻辑实现可能需要几天时间,而周围的基础设施则要耗费数周。
Managed Deep Agents正是LangChain针对这一问题的解决方案。它于2026年8月7日进入公开测试阶段。在阅读了21页的文档后,最令人惊讶的并非大家常提到的单命令部署功能,而是智能体不再是一个Python对象,而变成了一个目录。
该产品的实际形态
“managed”这个词含义模糊,因此明确的定义很有帮助。在终端中以mda形式调用的Managed Deep Agents实际上是一个Python软件包。它接收一个项目文件夹,将其编译成托管在LangGraph上的应用程序,然后将该应用程序发送到LangSmith的Agent Server。Deep Agents本身的实现保持不变,由LangSmith负责其运行,包括处理数据持久化、线程管理、沙箱的生命周期、技能加载以及内存管理等功能。
整个工作流程仅需四条命令即可完成:
uv tool install managed-deepagents
mda init research-assistant
cd research-assistant
uv sync
mda dev . # run locally in LangSmith Studio
mda deploy . # deploy to LangSmith
公告开头提到了这一点,而且表述准确,但却低估了更低层级上的实际设计考量。
功能由 ls 控制
mda init 会构建一个项目结构,而文档则将此结构视为全部功能范围:
my-agent/
├── agent.py # required — the model and core config
├── instructions.md # system prompt, synced to Context Hub
├── skills/
│ └── research/
│ └── SKILL.md # task-specific playbooks
├── tools/ # your LangChain tools
├── middleware/ # logic around model and tool calls
├── connectors/
│ └── mcp.py # remote MCP servers
├── channels/
│ └── slack.py # Slack, GitHub, other entry points
├── schedules/
│ └── daily_digest.py # managed cron jobs
├── sandbox/
│ └── __init__.py # isolated filesystem and shell
├── identity.py # auth and thread scoping
├── memory.py # durable cross-thread memory
├── pyproject.toml
├── .env
└── evals/ # Harbor tasks
只有 agent.py 是必选的。其他所有文件都是可选的,关键在于:文件是否存在决定了某项功能是否启用。
删除 sandbox/ 目录,沙箱功能就会消失。在目录根目录下放置 memory.py,持久内存功能就会启用。添加 schedules/daily_digest.py,下次部署时会自动创建一个 LangSmith 定时任务;删除该文件,定时任务也会随之被移除。
任何写过 Terraform 的人都能认出这种结构。它其实是用 Python 语法实现的声明式基础设施——你只需描述期望的状态,mda deploy 便会让实际状态与之保持一致。
只有了解了各文件的内容后,这种结构才能被理解,下面将逐一介绍它们。
agent.py,唯一的必选文件
from managed_deepagents import define_deep_agent
from middleware.audit import log_tool_calls
from tools.search import internet_search
agent = define_deep_agent(
name="research-assistant",
model="openai:gpt-5.5",
tools=[internet_search],
middleware=[log_tool_calls],
interrupt_on={"internet_search": True},
)
name是必需的参数,它既作为LangGraph助手的ID,也作为部署的默认名称。除此之外,define_deep_agent还接受tools、middleware、subagents、permissions、interrupt_on(用于人工干预审批)以及response_format(结构化输出)这些参数。
看看还缺少什么:没有系统提示词,没有内存配置,没有沙箱环境,也没有调度功能。这些都需要通过文件来设置,即便你想通过代码进行配置也做不到。
内置的服务器端搜索工具不需要提供者密钥,不过不同的提供者要求的工具字典格式各异,这很容易出错。
tools=[{"type": "web_search"}] # OpenAI
tools=[{"google_search": {}}] # Google
tools=[{"type": "web_search_20260209", "name": "web_search"}] # Anthropic
当追踪记录中从未出现搜索相关内容时,几乎总是这种不匹配导致的。
instructions.md 和 skills/
同步到云端的上下文信息保存在这里。instructions 文件的内容可能为:
# Research assistant
You are a careful research assistant. Use internet search to find sources,
keep notes, and return concise answers with citations.
它将成为系统提示语,被插入到每次运行中。各技能的表现各不相同。每个技能都位于独立的目录中,并包含前置信息:
---
name: research
description: Gather and synthesize context before answering complex questions.
---
# Research
Use this skill when a task needs more than a direct answer.
1. Identify what information is missing.
2. Use `query_db` to look up relevant records.
3. Summarize findings before responding to the user.
当代理启动时,它只能看到每项技能的名称和描述。只有当有匹配的任务出现时,它才会读取完整的 SKILL.md 文件,相关的辅助文件则会按需加载。这正是开源工具中所采用的渐进式披露机制。
一个实用的运营细节是:在部署时,instructions.md 文件以及整个 skills/ 目录结构都会被上传到 LangSmith Context Hub。之后无需再次部署即可通过用户界面对这些内容进行修改,因此编辑提示词不再需要重新构建系统。那些曾为修正系统提示词中的拼写错误而等待 CI 流水线完成的人就能理解这一优势。
memory.py:持久化内存,可选功能
from managed_deepagents import define_memory
memory = define_memory(scope="agent")
只需这两行代码,没有它们的话,智能体就完全没有任何持久记忆。对于那些认为记忆是默认具备功能的人而言,这可能会让他们感到惊讶。
启用该功能后,会在 /memories/agent/ 路径下创建一个 Context Hub 树结构。该树结构中的 AGENTS.md 文件属于热记忆,每次运行时都会被加载到上下文中。其余内容则为冷记忆,智能体仅在需要时才会读取。读写操作通过常规的 read_file、edit_file 和 write_file 函数实现,而写入 /memories/ 下的其他路径等位置的数据并不具备持久性。由此会产生一个设计上的后果,具体内容将在后文阐述。
sandbox/ 及其快照功能
from managed_deepagents import define_sandbox
sandbox = define_sandbox(
idle_ttl_seconds=600,
default_timeout=600,
docker_image="python:3.12-slim",
)
每条持久线程都有独立的沙箱环境,由 LangSmith Sandboxes 提供支持。可选的 sandbox/setup.sh 文件会在 bash -e 环境下执行一次,其执行结果会被保存为快照,新线程只需克隆该快照即可,无需重复进行设置操作:
#!/usr/bin/env bash
set -euo pipefail
apt-get update && apt-get install -y jq
mkdir -p /workspace
有两个需要注意的陷阱。在setup.sh执行期间可以获取.env中的值,这有助于克隆私有仓库,但负责克隆快照的线程却无法获取这些值。此外,任何在磁盘上留下的设置内容都会被包含在每个线程的镜像中,因此无法将机密信息存储在那里。
schedules/: 带有编译时规则的cron
from managed_deepagents import define_schedule
schedule = define_schedule(
cron="0 8 * * 1-5",
timezone="America/Los_Angeles",
prompt="Review durable memory for reusable research rules. List open questions for today.",
)
每个调度规则对应一个文件,文件名即为该调度规则的名称。必须指定 prompt 或 input 中的其中一个。仅支持五字段的 cron 表达式,因此基于秒数的表达式会导致编译失败。若未指定时区,则默认使用 UTC。
最可能引发问题的限制是:调度规则声明会在编译时被提取出来,且必须能够被静态序列化。不允许使用环境变量、函数调用、**kwargs 或计算得到的值,字面量和顶层常量则是允许的。任何动态内容都应放在 agent、tools 或 middleware 中。
通常每次运行都会创建一个临时线程,任务完成后该线程会被删除。而对于需要保持状态的计划任务,则应使用 thread={"mode": "persistent", "id": "nightly-memory"}。
channels/ 和 connectors/
通道用于接收启动任务的消息,而连接器则为代理提供工具。两者均为单个文件:
# channels/slack.py
from managed_deepagents import channels
channel = channels.slack(
auto_reply=True,
mention_behavior="strip",
conversation={"app_mention": "thread", "direct_message": "conversation"},
)
# connectors/mcp.py
from managed_deepagents import connectors
connector = connectors.mcp(
mcp_servers={
"langchainDocs": {
"transport": "http",
"url": "https://docs.langchain.com/mcp",
"include_tools": ["search_docs_by_lang_chain"],
},
},
)
路由规则遵循文件名。channels/slack.py将其 Events 接口暴露在 /channels/slack/events 地址下,而 MCP 工具默认会以服务器名称作为前缀,因此该连接器会显示为 langchainDocs__search_docs_by_lang_chain。Stdio MCP 服务器不可用,仅支持 Streamable HTTP 和传统的 SSE 协议。
identity.py:谁可以调用该智能体
from managed_deepagents import auth, define_identity
identity = define_identity(auth=auth.langsmith_api_key())
mda init 生成的便是这种安全的默认设置。调用方会在 x-api-key 标头中传入 LangSmith 工作区密钥。由此即可确定是否允许某人调用该智能体,但所有调用者都将使用相同的线程。若需实现用户级隐私保护,则需改用 Supabase:
identity = define_identity(auth=auth.supabase(project_ref="your-project-ref"))
客户端随后会发送 Authorization: Bearer ,MDA会将该JWT与项目对应的JWKS端点进行比对。文档中有一项迁移警告:将此功能添加到现有部署中不会将所有者元数据回填到已存在的线程中。
mda deploy的功能
文档列出了十一个有序步骤,其中重要的包括:
- 检查项目并加载
agent.py。 - 按固定顺序查找LangSmith密钥(
LANGGRAPH_HOST_API_KEY、LANGSMITH_API_KEY、LANGCHAIN_API_KEY),并在shell环境之前读取.env文件。 - 收集所有未被预留的
.env值,并将其作为托管部署的机密信息一并发送。
instructions.md 文件及 skills/ 文件夹上传至 Context Hub。.mda/build 格式并上传压缩包,其大小不得超过 200 MB。DEPLOYED。schedules/ 目录重新构建定时任务列表。第七步正是将此过程与 Terraform 进行比较而不再只是比喻的时候——这实际上属于偏差修正操作,其行为方式与 terraform apply 相同。
与 Terraform 一样,这里也存在一个可以悄悄跳过该步骤的标志。添加 --no-wait 后,CLI 会立即启动远程构建,并在状态变为 DEPLOYED 之前就退出,这意味着运行过程根本不会进入调度协调步骤。新的定时任务不会被创建,而被删除的定时任务仍会执行,同时部署操作会报告成功。每当调度发生变化时,应运行不带 --no-wait 参数的 mda deploy . 命令。在团队操作手册中加入相关说明是一种简单的保障措施。
它在 LangChain 架构中的位置
现在该架构共有四层,但人们往往容易将它们混为一谈。
LangChain 提供了基础构建模块:模型、工具和提示词,它是整个架构的基石。
LangGraph 是运行时层,负责实现持久化、有状态且呈图结构的执行功能(包括数据持久化、流式处理和中断处理),可以将其视为引擎。
Deep Agents作为上层框架,集成了规划器、文件系统、子代理、上下文压缩功能以及预设的默认设置。
Managed Deep Agents则是为该框架提供的托管运行时环境。它其实就是LangSmith客户已在生产环境中使用的Agent Server,只是为Deep Agents项目做了更为规范化的封装。
用汽车作类比:LangGraph提供引擎和变速箱,Deep Agents提供整车,而Managed Deep Agents则同时提供整车、维修厂以及负责更换机油的人员。代价则是无法自行打开引擎盖。这是个公平的交换,相关文档也明确说明了这一点。对于那些需要自定义路径、在图结构之外编写应用代码或直接控制数据持久化功能的人,文档建议直接使用LangSmith Deployment。
共享内存范围
测试版仅提供单一内存作用域 agent:所有能够访问该部署的调用者共享同一套读写结构。
相关文档对后续内容表述得极为直白:内存由所有调用者共享,且每个调用者都能对其产生影响。因此只需存储所有人都可以读取和修改的信息,并将现有内存视为不可信的输入,绝不能借此授予权限、更改工具权限或绕过审批流程。
这其实是一种安全策略的体现。AGENTS.md会在每次运行时被加载到系统上下文中,所以调用者A在周二写入的内容会在周三永久出现在调用者B的上下文中。对于单团队内部工具来说这没问题,但对于多租户系统而言,这就相当于一个带有持久化功能的指令注入通道。
对于那些重视评估与可观测性的人来说,更糟糕的是这种故障不会在评估结果中体现出来。Harbor任务会在运行后对工作区状态进行评分,但它们无法模拟一周前就向热内存写入数据的恶意行为。
文档中的建议很对:当调用方之间不应相互影响时,应避免使用共享内存。在实现按用户划分内存范围的功能之前,这确实限制了可构建系统的功能。
仍在变化的功能界面
在复制任何代码之前,这里有一个实际警告:相关发布帖子的日期是8月7日,而文档却在不断更新。大约三周内就有四个公共API发生了变化,任何根据公告中的示例进行开发的人都会遇到这四个变化。
- 内存:公告称每次部署都从代理级内存开始,而文档则说明持久内存是可选功能,默认处于关闭状态。
- 沙箱:公告中使用了
define_sandbox(provider="langsmith", scope="thread"),并暗示存在共享的agent级别;参考页面列出了idle_ttl_seconds和default_timeout,并指出一个沙箱始终对应一个线程。 - 身份认证:公告提到需要在
identity.py中配置 OIDC 提供商,但身份认证相关页面仅涉及 LangSmith API 密钥和 Supabase。 - Slack:公告中使用了
channels.slack(on=[...]),而 Slack 使用指南中没有on参数,而是将事件订阅信息放在 Slack 应用清单中。
文档本身也并非始终一致。有的页面将命令命名为 mda channel init slack,而另一页面则写为 mda channel add slack .;mda deploy . 的 --configure-slack 参数在 Slack 指南中有说明,但却未出现在 CLI 参考表中。
这并不意味着该产品质量差,只是说明这仍是一个声明式工具的测试版,其界面设计本就不该由用户去猜测。当文档与表格内容不一致时,应以 mda --help 的输出为准。
适用场景与不适用场景
在以下情况下,Managed Deep Agents 非常有用:
- 你已经在 Deep Agents 平台之上进行开发,且基础设施成为瓶颈
- 代理需要持久线程、定时任务或 Slack 接口
- 提示词和技能无需重新部署即可编辑
在以下情况下,可选择直接使用 LangSmith Deployment,或自行托管开源工具:
- 您的后端需要调用该代理。目前测试版以命令行界面为主,API仍在开发中;根据文档说明,要通过程序方式恢复中断的运行,必须联系 LangChain 的支持人员,这会完全阻碍该用例的使用。
- 需要防止不同调用方访问彼此的内存。
- 需要自定义路由或对数据持久化进行手动控制。
- 数据必须存储在美国境外。
- Slack 在多个副本上运行。目前事件去重仅在进程内部实现,因此从 Slack 重新发起请求可能会触发代理两次;若通道中的工具存在副作用,则这些工具必须具备幂等性。
试用体验
安装并搭建框架:
uv tool install managed-deepagents
mda init test-agent && cd test-agent
然后将密钥放入 .env 文件中:
LANGSMITH_API_KEY=<your-key>
OPENAI_API_KEY=<your-key>
在编写任何内容之前,先对生成的框架运行 ls 命令。花五分钟查看目录结构,就能比阅读官方说明更深入地了解产品的模型架构。
接着,执行 uv sync && mda dev . 命令即可构建项目,同时创建一个用于替代 Context Hub 的本地系统(涵盖指令、技能和记忆功能),并在浏览器标签页中启动 LangSmith Studio。该工具不支持项目文件的实时热加载,因此修改后需要停止当前操作并重新运行。官方的快速入门指南位于 LangSmith 的 Python 文档中“Managed Deep Agents”部分。
那些已经在使用 Deep Agents 并自行搭建部署环境的团队,大概一个下午就能完成设置。目录模型是个不错的设计,一旦了解到测试版存在的缺陷,也可以找到相应的解决方法。
相关阅读
- 为何长时序智能体需要控制框架:深度智能体如何管理状态与上下文 —— 深入探讨深度智能体:上下文失效问题、四大核心要素、中间件、控制框架配置、文件系统后端、独立子智能体,以及边缘情况故障与解决方案。
- 在LangGraph中构建规划智能体:规划、执行、重新规划与报告 —— 专为金融研究设计的四节点LangGraph规划智能体:结构化规划方案、支持命名空间识别的工具注册表、重新规划限制,以及带追踪的示例运行过程。