DeepAgents (LangChain)
一句话定位
DeepAgents 不是独立的 agent 运行时,而是 LangChain 官方在 create_agent() + LangGraph 之上叠加的一套「有主张的」中间件/backend/profile 堆栈——用 create_deep_agent() 一个函数组装出一个具备文件系统、子代理、技能、记忆、压缩、评分自纠等能力的 deep agent,自身不引入新的执行循环。仓库同时孵化了两个下游 CLI 产品:libs/cli(已退化为纯部署工具)和 libs/code(deepagents-code,当前真正在维护的交互式终端编码 agent)。
核心架构总览
仓库是一个 monorepo,commit 0199007(019900734024a7665fd65bd75235c6307d5da003,2026-07-07 clone 验证)下的关键路径:
libs/
ARCHITECTURE.md # 三层架构总览
deepagents/deepagents/
graph.py # create_deep_agent() 入口,1026 行
middleware/
filesystem.py # 文件系统工具 + 权限(3103 行)
subagents.py # task 工具 / SubAgentMiddleware(872 行)
async_subagents.py # 远程/后台子代理
memory.py # AGENTS.md 记忆中间件(442 行)
skills.py # Agent Skills 规范实现(1069 行)
summarization.py # 压缩/长上下文治理(2191 行)
rubric.py # 自评分重试中间件
_fs_interrupt.py # 文件系统权限 -> HITL 桥接
backends/
protocol.py, sandbox.py # BackendProtocol / SandboxBackendProtocol / BaseSandbox
profiles/harness/*, profiles/provider/* # 模型/供应商协同设计 profile
cli/ # deepagents-cli:已退化为仅部署工具(0.1.0 起无 REPL)
code/ # deepagents-code:当前的交互式编码 agent(TUI + headless)
deepagents_code/agent.py # create_cli_agent(),system prompt 组装,HITL 门禁
deepagents_code/hooks.py # ~/.deepagents/hooks.json 事件钩子系统
ARCHITECTURE.md / THREAT_MODEL.md # 2026-03-28,当前权威安全文档
evals/ # CI eval + Harbor/Terminal-Bench 2.0 集成
acp/, talon/, partners/{daytona,modal,runloop,vercel,quickjs}/ # 未深读
三层架构(引自 libs/ARCHITECTURE.md):
Deep Agents 有主张的 harness:默认值、中间件、backend、profile
LangChain agent 抽象:model + tools + middleware -> agent loop
LangGraph 运行时:state、checkpoint、streaming、interrupt
DeepAgents 本身不引入新运行时——LangGraph 才是真正执行图/循环的引擎;DeepAgents 只是在 langchain.agents.create_agent() 之上组装一套特定的中间件栈 + backend + profile。
Agent Loop(主循环 / 何时继续何时停)
- 不自建循环,完全委托给 LangGraph。
create_deep_agent()(libs/deepagents/deepagents/graph.py:353-1025)组装 model + tools + middleware 后调用create_agent(...),返回一个编译好的CompiledStateGraph。 - 循环语义(引自
libs/ARCHITECTURE.md“Construction and execution”):每一轮模型接收消息历史 + 系统提示 + 工具;模型可直接回复或请求工具调用;工具结果追加进 state;循环持续到模型给出不带工具调用的最终回复为止。 recursion_limit被硬编码得很高:.with_config({"recursion_limit": 9_999, ...})(graph.py:1016-1024)——即 DeepAgents 依赖上下文/token 预算与压缩机制来约束失控循环,而非一个很小的步数上限。- 中间件可在多个循环节点介入:
wrap_model_call(模型调用前后)、wrap_tool_call(工具执行前后)、before_agent(每次 invocation 开始时的状态准备)。RubricMiddleware利用”模型未返回工具调用”这一事件作为钩子,决定循环是否真正应该结束(见”自进化能力”节)。 deepagents-code把这个图跑在一个本地langgraph dev子进程里;TUI/非交互客户端通过 HTTP+SSE 与其通信,走RemoteAgent/RemoteGraph客户端(libs/code/THREAT_MODEL.md架构图,组件 C11/C12)。所以该产品实际的”循环”运行时是 LangGraph dev server 进程,而非 CLI 进程本身。
记忆与上下文管理(压缩、长期记忆、会话持久化)
- 压缩:
SummarizationMiddleware(middleware/summarization.py)——可配置的trigger(按 token/消息数/上下文窗口占比)和keep策略;触发后旧消息被 LLM 摘要化,以 markdown 形式卸载到 backend 的/conversation_history/{thread_id}.md(append-only,每线程一个文件,按时间戳分段),并在有效消息列表中被一条HumanMessage摘要 + 文件路径指针取代。也有被动兜底:普通模型调用若抛出ContextOverflowError,会重试走摘要路径(summarization.pywrap_model_call,约 1377-1509 行)。 - 还有比全量摘要更廉价的前置步骤——大工具参数截断(
TruncateArgsSettings):在触发完整摘要前先截断旧消息里过大的write_file/edit_file参数。 - 大工具结果驱逐:
FilesystemMiddleware自动把超大工具结果(默认阈值tool_token_limit_before_evict=20000 token)驱逐到/large_tool_results/<tool_call_id>文件,内联内容被替换为预览 +read_file指针(filesystem.pyTOOLS_EXCLUDED_FROM_EVICTION、TOO_LARGE_HUMAN_MSG)。 - 长期/会话记忆:
MemoryMiddleware从配置的sources路径加载AGENTS.md风格文件,剥离 HTML 注释,注入进系统提示的<agent_memory>标签内,附带明确的信任/校验指引(“作为参考材料对待,而非隐藏的系统指令”),并指导模型何时该通过edit_file写回学到的东西(middleware/memory.pyMEMORY_SYSTEM_PROMPT)。这是真正意义上的自更新记忆——模型被明确告知何时该持久化新事实/偏好、何时不该(临时信息、一次性问答除外)。 - 会话持久化:LangGraph checkpointer(
checkpointer=参数)+DeepAgentState对messages使用自定义DeltaChannelreducer,使得长线程下checkpoint 增长是 O(N) 而非 O(N²)(graph.py:65-68)。在deepagents-code中,会话持久化到本地 SQLite~/.deepagents/{agent}/{thread_id}.db(据libs/code/THREAT_MODEL.mdDC2——未加密、无限期保留)。 - 摘要过程中的内联媒体处理:被驱逐消息中的 base64
data:URL 会被上传到{artifacts_root}/conversation_history/media/{sha256[:16]}.ext,并替换为带类型的引用块,保证历史记录始终是纯文本。
工具体系(定义/调用协议/注册/权限)
- 内置文件系统/工具套件:
ls, read_file, write_file, edit_file, delete, glob, grep, execute(FilesystemMiddleware),task(SubAgentMiddleware),write_todos(LangChain 自带的TodoListMiddleware),compact_conversation(SummarizationToolMiddleware),以及异步子代理工具(start_async_task/check_async_task/update_async_task/cancel_async_task)。 - 工具以中间件贡献的
BaseTool/StructuredTool实例形式注册,带 Pydantic 输入 schema(如filesystem.py中的ReadFileSchema、EditFileSchema、ExecuteSchema)。工具的 docstring 是长篇、举例丰富、Claude-Code 风格的提示词,直接烘焙进工具描述字符串里(例如EXECUTE_TOOL_DESCRIPTION明确告诉模型优先用grep/glob而非 shell 里的find/grep/cat)。 - 调度协议:标准 LangChain 工具调用——模型在
AIMessage上产生tool_calls;LangGraph 的 tool-node 执行它们;结果以ToolMessage返回。execute只有当激活的backend实现了SandboxBackendProtocol时才会暴露——否则该工具是一个返回错误信息的空操作,且 shell 相关的提示文本会被整段省略(filesystem.py,supports_execution())。 - 工具注册/排除是分层的:base 中间件工具 → 调用方
tools=(仅可追加)→ harness-profile 的excluded_tools通过_ToolExclusionMiddleware过滤(graph.py_apply_excluded_middleware)。移除一个内置工具只能通过HarnessProfile,不能靠简单省略。 - 工具上的权限模型:
FilesystemPermission规则(operations、pathsglob 模式、mode: allow|deny|interrupt)被强制执行在工具实现内部(而不仅仅是可见性过滤)——先匹配先生效,deny返回带权限拒绝信息的ToolMessage,interrupt路由进 HITL(见”安全与权限”节)。 - 工具名白名单:
FilesystemMiddleware(tools=[...])允许调用方限制暴露的 FS 工具子集(read_file始终必需)。
Prompt 设计(系统提示结构、动态组装)
- 系统提示的组装是一条显式、有序的流水线(
graph.py_assemble_prompt_parts/SystemPromptConfig):prefix(调用方覆盖,始终最前)→base(调用方覆盖,或 harness-profile 的base_system_prompt,或内置BASE_AGENT_PROMPT)→suffix(调用方)→HarnessProfile.system_prompt_suffix(模型调优文本,最后追加)。各部分用\n\n拼接;某部分也可以是SystemMessage以保留cache_control断点,此时会被拼接为 content block。 BASE_AGENT_PROMPT(graph.py:71-113)读起来像一个精简版的 Claude Code 系统提示:“Core Behavior”(简洁、无寒暄)、“Professional Objectivity”(有礼貌地不同意,不谄媚)、“Doing Tasks”(理解→执行→验证循环)、“Clarifying Requests”、“Progress Updates”。- 每个中间件通过
wrap_model_call/modify_request动态注入自己的提示片段,而非单一静态字符串:FILESYSTEM_SYSTEM_PROMPT(随启用的 FS 工具变化)、EXECUTION_SYSTEM_PROMPT(仅当沙箱执行可用时)、TASK_SYSTEM_PROMPT(子代理使用指引 + few-shot 示例)、MEMORY_SYSTEM_PROMPT、SKILLS_SYSTEM_PROMPT、SUMMARIZATION_SYSTEM_PROMPT。这是真正意义上的动态/条件组合,而非固定模板。 deepagents-code在此之上再叠一层:libs/code/deepagents_code/agent.py:get_system_prompt()加载一个system_prompt.md模板,插值{mode_description}、{interactive_preamble}、{ambiguity_guidance}、{todo_guidance}(交互式与 headless/非交互模式下文本不同!)、{model_identity_section}(模型名/供应商/上下文窗口大小直接烘焙进提示词)、{working_dir_section}(本地路径 vs 沙箱路径指引,明确警告模型沙箱模式下无法访问本地路径)。- Harness profiles(
profiles/harness/*)按模型家族调优提示词(_anthropic_opus_4_7.py、_anthropic_sonnet_4_6.py、_anthropic_haiku_4_5.py、_openai_codex.py)——模型专属的系统提示后缀与工具描述覆盖,即显式的逐模型协同设计(见”与模型的协同设计”节)。
Router / 编排(任务分解、多 agent、子 agent)
- 单一机制:
task工具(SubAgentMiddleware,middleware/subagents.py)。主 agent 调用task(description, subagent_type);每个命名的子代理类型要么是声明式的SubAgent(system_prompt + tools + model,通过create_sub_agent()编译成自己的create_agent()图),要么是CompiledSubAgent(调用方提供的预构建Runnable/自定义 LangGraph 图)。 - 子代理是临时且跨调用无状态的:
task()会构造一条全新的HumanMessage(description)作为子代理的全部输入(父 state 中的messages/todos/structured_response键以及所有标记为PrivateStateAttr的字段在调用前被剥离),只有子代理最终的响应(最后一条非空AIMessage文本,或如果配置了则是 JSON 序列化的structured_response)会作为单条ToolMessage返回给父 agent——中间步骤对父 agent 不可见(_return_command_with_state_update、_validate_and_prepare_state)。 - 默认会自动添加一个
general-purpose子代理,除非通过 harness profile 禁用或被调用方覆盖(GENERAL_PURPOSE_SUBAGENTspec,graph.py:817-887)——它继承主 agent 的工具/模型/技能/权限,并拥有自己的中间件栈(todo list、文件系统、摘要、patch-tool-calls)。 TASK_TOOL_DESCRIPTION(few-shot 提示,subagents.py:285-393)明确教模型何时该并行调用子代理(同一条消息里多次task调用)vs. 对琐碎任务直接自己做——与 Claude Code 的 Task 工具提示风格如出一辙。- 远程/异步编排:
AsyncSubAgentMiddleware(middleware/async_subagents.py)是第二条、独立的子代理编排路径,针对以后台方式运行、部署为 LangGraph Platform / Agent-Protocol 兼容服务的子代理(经由langgraph_sdk),用task_id/thread_id/run_id/status在AsyncSubAgentState中追踪。与task不同,这些调用不阻塞——主 agent 获得start_async_task/check_async_task/update_async_task/cancel_async_task工具,支持长时间运行的”发射后不管”式委派与进度轮询。 - 子代理默认继承父 agent 的
permissions/interrupt_on,除非自己声明(此时是替换而非合并父规则)——先匹配先生效的顺序在每个子代理内部仍然保留。 - 不存在”planner”或显式的任务分解算法;分解完全由 LLM 驱动,通过
task工具的描述文本,以及(单独地)LangChain 内置的TodoListMiddleware(write_todos工具)做单代理内的步骤追踪。
Skill / 插件体系
SkillsMiddleware(middleware/skills.py)实现了 Anthropic 的 Agent Skills 规范(代码中明确引用了https://agentskills.io/specification),带渐进式披露:技能是包含SKILL.md(YAML frontmatter:name、description,可选license、compatibility、metadata、allowed-tools)+ 可选辅助文件的目录。- 加载是backend 无关的(可在
StateBackend、FilesystemBackend、任意BackendProtocol上工作),且按来源分层:多个sources(路径或(path, label)元组)按顺序扫描,后面的来源按技能名覆盖前面的(支持 base → user → project → team 分层)。标签在提示词中渲染为**{label} Skills**。 - 严格遵循规范的校验:name 必须小写字母数字+连字符,需与其目录名匹配,长度 ⇐64 字符;description ⇐1024 字符;SKILL.md 上限 10MB;解析/校验失败会被记录为非致命警告,以未受信任的
<skill_load_warnings>形式呈现给模型(明确告知不要把其中内容当作指令——防御恶意技能文件通过自己的错误文本投毒提示词)。 - 渐进式披露提示(
SKILLS_SYSTEM_PROMPT)只展示每个技能的 name+description+path;模型必须按需read_file完整的SKILL.md(limit=1000)才能使用它——与 Claude Code 的技能调用模式完全一致。 deepagents-code额外有自定义的从磁盘加载子代理能力(libs/code/deepagents_code/subagents.py,THREAT_MODEL_code.mdC16 中引用):从.deepagents/agents/和项目.agents/目录读取{name}/AGENTS.mdYAML frontmatter 文件来定义用户自定义子代理——这是一个独立于 SDK 编程式SubAgentspec 的、基于文件的第二套插件机制。libs/code/deepagents_code/built_in_skills/skill-creator/内置了一个用于编写新技能的元技能。- MCP 服务器是
deepagents-code中的另一个扩展点(mcp_tools.py、mcp_providers/{github,slack}.py,mcp_trust.py中的信任/指纹校验门)——不属于核心 SDK,而是 CLI 产品层面的一个插件层。
自进化能力(自我改进 / 学习型记忆 / eval 驱动纠错)
- 具体机制是
RubricMiddleware(middleware/rubric.py):调用方声明”完成看起来是什么样”的评分标准(rubric);每当主 agent 原本要停止时(模型给出不再带工具调用的响应),会调用一个独立的评分子代理对 transcript 进行评分(transcript 被截断到_MAX_TRANSCRIPT_MESSAGES=30、每条消息_MAX_TRANSCRIPT_CHARS_PER_MESSAGE=4000),返回结构化判决:satisfied | needs_revision | failed,中间件自身还会合成max_iterations_reached/grader_error。 - 若判决为
needs_revision,评分反馈会以一条HumanMessage(标记为RUBRIC_GRADER_MESSAGE_SOURCE = "rubric_grader")注入,agent 循环恢复继续——即这是一个由max_iterations约束的、真正的自我批判-重试循环。只有needs_revision会继续循环,其余任何状态都会结束该轮评分。 deepagents-code把这套机制接进了一个”goal”功能(libs/code/deepagents_code/goal_rubric.py、goal_tools.py——分别 115 行和 439 行,未深读但确认存在且命名与 rubric 机制一致),并给评分子代理配了一个专用的、限定在/large_tool_results/证据路径内的沙箱化read_file工具(agent.py_create_rubric_grader_tools、_validate_rubric_grader_read_path)。- 没有发现从历史 trajectory 学习的证据(没有微调回路,没有从失败中自动重写提示词的机制),除了:(a) AGENTS.md 记忆机制——模型自己被指示把持久化的学习成果写回文件(见”记忆与上下文管理”节);(b) 本节的单会话内 rubric 评分重试循环。SDK 本身不存在跨会话或跨用户的聚合式自我改进。
可观测性(日志 / trace 格式)
- LangSmith tracing 是主要的可观测性集成,通过标准 LangChain 环境变量开关启用(
LANGSMITH_API_KEY等),不是一套自研日志格式。子代理运行被显式打标:_subagent_tracing_context()(middleware/subagents.py:438-459)在 LangSmith tracing-context 元数据中设置ls_agent_type="subagent"(对应主 agent 的ls_agent_type="root"),使得子代理与根 agent 的运行在 trace 中可区分。create_deep_agent()返回的图携带元数据{"ls_integration": "deepagents", "lc_versions": {"deepagents": __version__}, "lc_agent_name": name}(graph.py:1016-1024)。 libs/evals/README.md确认了一个 CI 集成的 eval 套件,“捕获完整的 trajectory(工具调用、文件变更、最终响应)“,每次运行都会发布到公开的 LangSmith dashboard(README 中含链接)——外加 Harbor 集成用于沙箱化基准测试(Terminal-Bench 2.0)。- Hook 系统(
libs/code/deepagents_code/hooks.py)是 CLI 产品层面的结构化事件/日志机制:加载~/.deepagents/hooks.json,对一套预定义事件目录触发子进程命令、通过 stdin 传入 JSON payload——session.start、session.end、user.prompt、task.complete、tool.use、tool.result、tool.error、context.offload、context.compact、permission.request、input.required、user.name.set。Payload 结构有精确文档,例如tool.result:{"event": "tool.result", "tool_name", "tool_id", "tool_args", "tool_status": "success"|"error", "tool_output"}(截断到HOOK_TOOL_OUTPUT_LIMIT字符)。文档明确说明了顺序保证(工具事件是即发即弃/并发的,必须按tool_id而非到达顺序关联;其余多数事件按程序顺序发生)。 - 会话历史卸载(
SummarizationMiddleware/offload.py)同时充当一份持久的、基于文件的执行日志:完整 transcript 在被摘要掉之前会先写入 active backend 上的/conversation_history/{thread_id}.md。 - SDK 本身未发现自研的”trace 文件格式”(例如没有自定义的 OpenTelemetry schema)——全程使用
logging.getLogger(__name__),trace 级可观测性委托给 LangSmith。
安全与权限(审批门、密钥管理)
FilesystemPermission(middleware/filesystem.py)是核心访问控制原语:规则形如{operations: [read|write], paths: [glob...], mode: allow|deny|interrupt},按声明顺序求值,先匹配先生效,若无匹配则默认 allow。构造时校验(path必须以/开头,不含..、~)。强制执行在工具实现内部(而非仅作可见性过滤),覆盖ls/read_file/write_file/edit_file/delete/glob/grep;对沙箱化 backend 上的execute明确未实现(FilesystemMiddleware.__init__在 permissions 与沙箱执行同时存在时抛出NotImplementedError,除非所有 permission 路径都限定在CompositeBackend的路由内)。mode="interrupt"规则会被转换为HumanInTheLoopMiddleware的interrupt_on配置,经由_build_interrupt_on_from_permissions/_make_fs_when_predicate(middleware/_fs_interrupt.py)——一个when断言逐次调用判断某工具的路径参数(read_file/write_file/edit_file精确匹配,ls/glob/grep/delete用”批量”子树重叠逻辑)是否落在 interrupt 守卫的路径模式内。无法定位具体路径的批量调用(如grep(path=None))会无条件触发中断——安全优先于便利。deepagents-code的 HITL 层(libs/code/deepagents_code/agent.py_add_interrupt_on、_should_interrupt_tool_call)默认对 execute、write_file、edit_file、delete、web_search、fetch_url、task、start/update/cancel_async_task、compact_conversation 加审批对话框门禁;auto_approve(作用域在 context 上,而非 graph state,专门为了”模型不能通过写 state 来自我批准”)会绕过所有这些门禁。每种工具有专属的审批提示格式化函数(_format_execute_description等),在用户批准前展示隐藏 Unicode 和同形异义 URL 警告(unicode_security.py)。- 非交互/headless 模式用shell 命令白名单(
ShellAllowListMiddleware、config.is_shell_command_allowed)取代交互式 HITL,以避免中断/恢复导致的 trace 碎片化;--shell-allow-list all会完全禁用该检查(在威胁模型中被标记为 Threat T2)。 - 密钥管理:没有密钥保险库——API key(
ANTHROPIC_API_KEY、OPENAI_API_KEY、TAVILY_API_KEY、LANGSMITH_API_KEY、LANGGRAPH_API_KEY)只从进程环境变量读取,CLI 从不将其写入磁盘,经由os.environ.copy()流入被 spawn 的 LangGraph dev-server 子进程(libs/code/THREAT_MODEL.mdDC1/TB8)——文档明确承认这是一个 gap(“父进程环境中的所有密钥对子进程都可见”)。 MemoryMiddleware的系统提示明确指示模型永远不要在记忆文件中存储 API key/token/密码,并把加载进来的<agent_memory>内容当作不受信任的参考数据而非指令来对待。- 官方
libs/code/THREAT_MODEL.md(496 行,日期 2026-03-28)是一份异常详尽、看似自动生成但持续维护的安全文档:17 个组件(C1-C17)、11 条信任边界(TB1-TB11)、25 条数据流(DF1-DF25)、10 个已枚举威胁(T1-T10,例如 T1 经由抓取的网页内容做提示注入、T6 未鉴权的本地 LangGraph dev server、T9class_path配置驱动的经由importlib的任意代码执行),外加一节明确列出已调查并排除的威胁(D1-D4,例如确认已在上游修复的 msgpack 反序列化 CVE)。
沙箱与执行隔离
- 执行通过
SandboxBackendProtocol实现 backend 可插拔;BaseSandbox(backends/sandbox.py)是一个 ABC,通过对沙箱的execute()/upload_files()原语 shell 执行 base64 编码的内联 Python 脚本来实现文件操作(ls/read/write/edit/glob/grep)(例如_GLOB_COMMAND_TEMPLATE、_GREP_PATH_GLOB_TEMPLATE、_EDIT_COMMAND_TEMPLATE——所有参数都做 base64 编码,专门用来避免 shell 转义注入漏洞)。具体 backend 只需实现execute()和upload_files();其余(ls/grep/glob/edit)都是派生出来的。 - 官方沙箱伙伴集成作为独立可安装包存在于
libs/partners/下:daytona、modal、runloop、vercel(远程容器/VM 沙箱),以及quickjs(进程内 JS 沙箱,用于deepagents-code中CodeInterpreterMiddleware/PTC”tools.*“主机桥接特性,见agent.pyenable_interpreter)。deepagents-code的威胁模型额外把 LangSmith 和 AgentCore 列为沙箱提供方(组件 C7)。 - 本地非沙箱模式用
LocalShellBackend(直接在宿主机上execute(),即无隔离——shell 跑在用户的真实机器上),与FilesystemBackend(root_dir) 通过CompositeBackend路由组合。deepagents-code的LocalContextMiddleware(威胁模型中的 C15)每轮都跑一个静态 bash 探测脚本,把 git/项目/Makefile 上下文注入提示词——被标记为威胁(T7),因为它在未经消毒的情况下读取原始文件内容(Makefile前 20 行、目录列表)就注入进提示词。 - 沙箱模式需要
deepagents-code中显式的--sandbox参数(非默认)——威胁模型中的信任边界 TB6 覆盖”Setup Script → Sandbox Execution”(用户提供的启动脚本,经shlex.quote()包裹)。 - 虚拟路径 vs 主机路径映射:当
CompositeBackend把LocalShellBackend默认路由与FilesystemBackend路由混用时,_route_host_path_prompt()(filesystem.py)会生成一段显式的系统提示,教模型哪些虚拟挂载前缀(例如/common/)映射到真实主机 shell 路径(例如/data/),哪些挂载完全无法从 shell 访问(远程/沙箱或 store-backed 路由)——因为execute永远运行在默认 backend 的 shell 上,而非任意路由 backend。 execute超时有上限(max_execute_timeout,默认 3600 秒),单次调用覆盖值会校验不超过该上限;timeout=0只能在明确支持无超时执行的 backend 上禁用超时。
与模型的协同设计
HarnessProfile体系(profiles/harness/*、profiles/provider/*)是显式的、一等公民级的逐模型调优机制:为_anthropic_opus_4_7.py、_anthropic_sonnet_4_6.py、_anthropic_haiku_4_5.py、_openai_codex.py设有专属 profile 模块,以及供应商层面的 profile_nvidia.py、_openai.py、_openrouter.py。一个 profile 可以覆盖:base_system_prompt、追加system_prompt_suffix、重写单个tool_description_overrides(例如task工具的描述模板)、设置excluded_tools、注入extra_middleware、开关自动添加的general_purpose_subagent(GeneralPurposeSubagentProfile(enabled=False))。_harness_profile_for_model()在create_deep_agent()构造时基于已解析的模型来确定适用的 profile(子代理如果自己覆盖了model=,会独立解析自己的 profile)——意味着一个多模型的 deep agent(主 agent 用一个模型、子代理用另一个)会自动获得逐模型家族的提示词/工具调优。- 供应商特定行为是无条件分层叠加的,与 profile 无关:
AnthropicPromptCachingMiddleware以及(如果装了langchain-aws)BedrockPromptCachingMiddleware总会被追加到中间件栈接近末尾的位置(对不匹配的供应商是空操作)——即提示缓存断点被烘焙进 harness 本身,而非留给调用方处理。 deepagents-code的get_system_prompt()把实时模型元数据直接烘焙进提示词:build_model_identity_section()写入"You are running as model {name} (provider: {provider})"、模型的context_limit(token 数),以及一份不支持的输入模态列表(例如明确告诉模型如果当前模型 profile 不支持,就不要尝试读取视频/音频)——即 harness 把模型能力自我描述回给模型本身,而非依赖模型自行推断。SummarizationMiddleware的默认触发/保留阈值是根据模型自身 profile 计算的(compute_summarization_defaults();middleware/summarization.py):如果model.profile["max_input_tokens"]已知,默认值就是基于比例的(trigger=0.85、keep=0.10的上下文窗口占比);否则回退到保守的固定 token/消息数。上下文治理行为因而是逐模型自动调优的。- OpenAI 特定处理在
create_deep_agent()的 docstring 中被显式说明:对openai:模型默认使用 Responses API,并有文档化的开关用于禁用数据留存(store=False、include=["reasoning.encrypted_content"])。
轨迹利用(session/trajectory 是否反哺训练/评测)
- 本仓库中没有发现 trajectory 反哺模型训练的证据(符合预期——DeepAgents 是一个 harness/SDK 仓库,不是模型训练仓库)。在”用于微调模型”这个意义上不适用/未实现。
- Trajectory 确实反哺了一套 eval 体系:
libs/evals/用真实 LLM 跑这套 SDK,“捕获完整的 trajectory(工具调用、文件变更、最终响应)“并对正确性/效率打分,每次 CI 运行都发布到 LangSmith dashboard(README 链接:deepagents-evals、deepagents-harborLangSmith 项目)——这是一个评测反馈回路(针对 trajectory 的回归测试),而非训练反馈回路。 libs/evals/deepagents_harbor与 Harbor(github.com/laude-institute/harbor)集成,运行沙箱化基准测试,包括 Terminal-Bench 2.0——即 trajectory 会被拿去对照一个外部的、第三方的基准测试 harness 打分,而不仅仅是内部 rubric。- 会话数据确实存在会话内复用:被卸载的
/conversation_history/{thread_id}.md文件被明确设计为可供模型自己在同一线程后续再读取(摘要消息中的read_file指针)——这是用于上下文恢复的会话内 trajectory 复用,不是跨会话学习。 - 本仓库内没有发现把多用户/多会话的 trajectory 聚合成共享学习信号的机制(没有 telemetry-to-training 管线,没有从失败中自动调优提示词的管线)。
与同类 harness 的关键差异(先留概述,跨 harness 对比留待 synthesis 阶段)
DeepAgents 最鲜明的定位差异是:它公开承认自己”没有发明循环”,而是把全部精力投入中间件/backend/profile 的组合性上——task 子代理、RubricMiddleware 自评分重试、HarnessProfile 逐模型协同设计、Agent Skills 规范实现,都是可插拔、可组合的中间件而非硬编码在主循环里。相比之下很多同类 harness 会自建循环调度层。另外它是仓库层面唯一同时维护”SDK”与”两代 CLI 产品”(cli 已退化、code 是当前主力)的案例,导致文档/威胁模型存在新旧交叠,需要按文件日期甄别权威版本。跨 harness 的系统性对比留待 synthesis 阶段。
原始源码定位
- repo: https://github.com/langchain-ai/deepagents
- commit/version analyzed:
019900734024a7665fd65bd75235c6307d5da003(main 分支,git clone --depth 1后git rev-parse HEAD验证,clone 日期 2026-07-07) - 关键文件列表(相对仓库根目录):
libs/ARCHITECTURE.mdlibs/deepagents/deepagents/graph.pylibs/deepagents/deepagents/middleware/filesystem.pylibs/deepagents/deepagents/middleware/subagents.pylibs/deepagents/deepagents/middleware/async_subagents.pylibs/deepagents/deepagents/middleware/memory.pylibs/deepagents/deepagents/middleware/skills.pylibs/deepagents/deepagents/middleware/summarization.pylibs/deepagents/deepagents/middleware/rubric.pylibs/deepagents/deepagents/middleware/_fs_interrupt.pylibs/deepagents/deepagents/backends/protocol.pylibs/deepagents/deepagents/backends/sandbox.pylibs/cli/THREAT_MODEL.md(stale,REPL 已移出)libs/code/ARCHITECTURE.mdlibs/code/THREAT_MODEL.md(当前权威,2026-03-28)libs/code/deepagents_code/agent.pylibs/code/deepagents_code/hooks.py
未深读部分(下一阶段可补):libs/acp/、libs/talon/、libs/code/deepagents_code/{skills,widgets,mcp_providers,doctor.py,non_interactive.py,server.py,server_manager.py,remote_client.py}、libs/partners/{daytona,modal,runloop,quickjs,vercel} 内部实现细节。官方托管文档 docs.langchain.com/oss/python/deepagents/*(overview/customization/backends/permissions/profiles/memory/skills/subagents/models 等页面)以及 LangChain 官方 blog 均未在本阶段抓取——ARCHITECTURE.md 和代码 docstring 多处显式把精确参数语义和默认中间件顺序的权威说明指向这些托管文档,属于本页面已知的调研缺口,需要后续补齐一手来源(尤其博客可能披露 harness-profile 系统或 rubric 评分机制的设计动机,代码里没有)。
一手源存档(sources/)
/Users/zhao/projects/self-wiki/ai-research/sources/harness/deepagents/ 下保存的文件:
NOTES.md— 本次调研的完整笔记(含逐维度分析、文件路径/行号引用)ARCHITECTURE.md—libs/ARCHITECTURE.md(SDK 层顶层设计文档)ARCHITECTURE_code.md—libs/code/ARCHITECTURE.md(deepagents-code 客户端/服务端拆分设计)THREAT_MODEL_code.md—libs/code/THREAT_MODEL.md(当前权威威胁模型,2026-03-28)graph.py—libs/deepagents/deepagents/graph.py(create_deep_agent()全量,1026 行)middleware_filesystem.py—libs/deepagents/deepagents/middleware/filesystem.py(部分,约 1400/3103 行)middleware_subagents.py—libs/deepagents/deepagents/middleware/subagents.py(全量,872 行)middleware_memory.py—libs/deepagents/deepagents/middleware/memory.py(全量,442 行)middleware_skills.py—libs/deepagents/deepagents/middleware/skills.py(全量,1069 行)middleware_summarization.py—libs/deepagents/deepagents/middleware/summarization.py(部分,约 1550/2191 行)middleware_fs_interrupt.py—libs/deepagents/deepagents/middleware/_fs_interrupt.py(全量,184 行)middleware_async_subagents.py—libs/deepagents/deepagents/middleware/async_subagents.py(部分,前 150 行)middleware_rubric.py—libs/deepagents/deepagents/middleware/rubric.py(部分,前 120 行)code_agent.py—libs/code/deepagents_code/agent.py(部分,约 1455/1841 行)code_hooks.py—libs/code/deepagents_code/hooks.py(部分,头部 + 配置文档)