ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Deep Agents 中间件栈深度解析:create_deep_agent 的装配流程与定制边界

Deep Agents 中间件栈深度解析:create_deep_agent 的装配流程与定制边界 Deep Agents 中间件栈深度解析create_deep_agent 的装配流程与定制边界【免费下载链接】deepagentsThe batteries-included agent harness.项目地址: https://gitcode.com/GitHub_Trending/de/deepagentscreate_deep_agent()是 Deep Agentslibs/deepagents面向开发者的核心装配入口它负责解析模型与HarnessProfile、按固定顺序组装有序的AgentMiddleware栈再把最终主栈交给 LangChain 的create_agent()运行。本文以openwiki/architecture/middleware-stack.md为骨架结合 graph.py、_excluded_middleware.py、middleware 目录 与相关单元测试逐层拆解主代理与子代理的中间件装配顺序、profile 排除与调用方替换规则、工具可见性与授权边界以及声明式/编译式/异步三类子代理各自的构建与继承边界帮助你掌握如何在不破坏内置脚手架的前提下安全地定制代理行为。一、定位create_deep_agent 是装配器不是独立运行时Deep Agents 不是一个全新的 Agent 运行时。它位于 LangChain 与 LangGraph 之上是一个开箱即用的 opinionated harness见 ARCHITECTURE.md 三层架构。create_deep_agent()的职责可以概括为六步装配对应 graph.py 中 create_deep_agent 的实现解析请求的模型支持provider:model字符串或直接传入BaseChatModel实例并解析适用的 provider / harness profile解析 backend文件、内存、技能与execute行为落盘位置组装主代理的中间件栈构建默认的 general-purpose 子代理与调用方传入的子代理拼接系统提示词调用方指令 基础 prompt profile 的 suffix调用 LangChaincreate_agent(...)产出可运行的 agent 图。最终透传给create_agent()的选项包括system_prompt、tools、middleware、response_format、context_schema、checkpointer、store、debug、name、cache以及state_schema——模型/工具循环本身由 LangChain 拥有。组装完成后create_deep_agent还会为返回的图设置recursion_limit: 9_999并附加 Deep Agents 相关的 tracing metadata。运行时边界模型如何被调用、状态如何流转详见 SDK 构造与执行。DeepAgentState是图状态的基础它继承 LangChain 的AgentState并把messages字段换成DeltaChannel_messages_delta_reducer使 checkpoint 增长从 O(N²) 降为 O(N)见 graph.py DeepAgentState 定义。二、中间件 vs 普通工具请求时扩展边界的本质区别中间件是请求时request-time的扩展边界。一个实现了wrap_model_call()的中间件会在每次 LLM 请求发出之前被调用因此它可以改变即将发给模型的有效系统提示词、历史消息、工具列表甚至写入跨轮的类型化状态通过state_schema贡献状态字段。LangChain 允许中间件在模型调用前、模型调用周围、工具执行周围以及状态准备阶段介入ARCHITECTURE.md 中的说明。与之相对tools里传的普通可调用对象只有模型主动选中它之后才会执行。它没有机会为任何一次模型请求做准备工作——无法改写工具清单也无法注入提示词。因此判断标准很清晰需要每次请求生效的行为提示词/工具注入、请求改写、跨轮状态、权限检查、压缩→ 用中间件只需要一个自包含操作模型决定调用时执行一次→ 用普通工具。具体到 Deep Agents中间件栈承担了向最终系统提示词注入 filesystem / memory / skills / subagent / human-in-the-loop 指令、在请求发出前增删工具、随上下文增长压缩与卸载历史、把类型化值写入图状态、以及在内置文件工具执行前实施文件系统权限。完整的中间件清单见 middleware catalog。三、主代理装配流程与栈顺序主代理中间件栈的成员资格是条件性的skills、子代理形态、memory、文件系统权限、interrupt 配置、profile extras、已安装的 provider 集成以及 profile 排除项都会影响最终结果。下图为经过源码验证的装配流程与仅有的几个调用方定制决策点可选条目在条件不满足时缺席核心带core band顺序核心带按以下顺序装配对应 graph.py 主栈构建段SkillsMiddleware——仅当传入skills时FilesystemMiddleware——提供内置文件工具并实施permissionsSubAgentMiddleware——仅当存在同步内联子代理时通常是因为自动添加了 general-purpose 子代理Deep Agents 的 summarization 中间件实现类为_DeepAgentsSummarizationMiddleware公开名为SummarizationMiddlewarePatchToolCallsMiddlewareAsyncSubAgentMiddleware——仅当存在远端 async specs 时。尾部带tail band顺序核心带之后追加graph.py 尾部段HarnessProfile.extra_middleware的实例化结果provider 提示词缓存中间件AnthropicPromptCachingMiddleware总是安装对不支持的模型 no-opBedrock 与 Fireworks 变体仅在对应集成包langchain-aws/langchain-fireworks可导入时才追加同样对不支持的模型忽略见 _prompt_caching.pyMemoryMiddleware——仅当传入memory时它带有cache_control断点但只在请求模型为 Anthropic 时生效因此可以无条件安全启用HumanInTheLoopMiddleware——仅当解析后的 interrupt 映射非空时。缓存中间件刻意放在 memory 之前profile extras 先于缓存运行而 memory 对系统提示词的修改发生在 Anthropic 缓存前缀之后避免 memory 更新使缓存前缀失效graph.py 注释。第一遍 profile 排除在尾部组装完成后运行随后调用方middleware被合并第二遍排除再次运行最后仅当 profile 声明了excluded_tools时才追加_ToolExclusionMiddleware。它必须位于栈尾这样它看到的是接近最终的请求——工具生产中间件与调用方模型包装器都已运行完毕被排除的工具名不可能被某个调用方包装器重新注入。装配器还会把显式的state_schema与中间件贡献的 schema 合并通过private_state_field_names()推导私有状态字段名PrivateStateAttr注解见 _state.py并把这些字段赋值给SubAgentMiddleware——这决定了普通同步委派在穿越状态边界时能携带什么。四、上下文管理summarization 中间件的实际职责默认的 summarization 组件远不止是加一段提示词。它在 summarization.py 中实现工作分三步见wrap_model_callL1345-L1484截断旧的大工具参数当 token 达到较低阈值时仅对 keep 窗口之前的消息中AIMessage.tool_calls的args进行缩短——典型对象是write_file的内容、edit_file的补丁、冗长的execute输出。实现上只针对write_file/edit_file两个工具名L1033截断后保留前 20 个字符并追加后缀按阈值压缩历史TriggerClause支持tokens、messages、fraction三种触发条件可 AND 组合keep策略决定保留多少最近上下文ContextOverflowError 兜底重试若阈值未触发但模型调用抛出了ContextOverflowError立即走压缩路径用summary_message 保留的近期消息重试模型调用并通过_clip_overflow_tail把过大的保留尾部 batch 卸载到 per-TM 文件。被逐出的历史会卸载offload到配置的 backend存为/conversation_history/{session_id}.md按 session id 追加 section同时把_summarization_event含cutoff_index、summary_message、file_path作为私有状态写入SummarizationState_summarization_session_id按图调用隔离历史文件。内联的data:媒体块base64 或 percent-encoded如内联 SVG会被解码、按内容 hash 去重后上传到{artifacts_root}/conversation_history/media/{sha256[:16]}.{ext}消息改写为可寻址的image url... /引用上传或解码失败的块会被替换为image errorfailed_to_offload /占位符并计入警告——卸载失败时日志会明确警告更早的消息不可恢复。压缩提示词DEEPAGENTS_DEFAULT_SUMMARY_PROMPT专门附加了媒体引用标签的说明确保总结模型保留这些路径引用。默认阈值是模型感知的compute_summarization_defaults()在模型 profile 提供max_input_tokens时使用(fraction, 0.85)触发 /(fraction, 0.10)保留无 profile 时退化为更保守的(tokens, 170000)触发 /(messages, 6)保留。上下文管理的完整说明见 context management。五、调用方中间件合并与 profile 排除规则按 name 合并而非盲目追加调用方中间件通过_apply_custom_middleware()graph.py按.name合并调用方条目的名字若仍存在于基础栈中 →原位替换保留其原有位置新名字 → 插入到最后一个幸存的 core 成员之后即位于 profile extras、提示词缓存、memory 与 approval 中间件之前第一遍排除发生在合并之前第二遍排除用于移除试图重新引入被排除名字或精确类的条目。这给了调用方一种受控的替换内置行为手段。例如调用方可以传入同名的FilesystemMiddleware但使用更窄的tools[...]从而彻底移除某个文件系统工具——仅靠tools是做不到的tools只做加法。同时使用新名字的自定义中间件不会仅仅因为装在了主代理上就被复制进 general-purpose 子代理。excluded_middleware 的校验与约束HarnessProfile可以通过excluded_middleware从栈中减去条目但受安全性与覆盖率检查约束全部实现见 _excluded_middleware.py受保护脚手架FilesystemMiddleware与SubAgentMiddleware是被保护的脚手架_REQUIRED_MIDDLEWAREgraph.py。按类或按名字排除它们都会抛ValueError而不是静默破坏内置的文件/权限行为或同步task处理器类条目用精确type而非isinstance排除基类不会移除调用方的子类实例字符串条目精确匹配AgentMiddleware.name——因此SummarizationMiddleware这个公共别名可以精准命中__name__不同的实现类_DeepAgentsSummarizationMiddleware见 summarization.py 的 name 属性名字歧义一个字符串排除若在一个栈里匹配到多个不同的类属于歧义配置抛ValueError提示改用类形式排除覆盖率校验每个被允许的条目必须在某处命中。装配完成后若有条目未命中任何中间件抛ValueError——这能捕获拼写错误和过期 profile。对主 profile 而言匹配集合跨主代理栈 自动添加的 general-purpose 栈累积两套栈都过滤完成后再做一次覆盖率检查——因此一条排除合法地只命中其中一个栈也是允许的。声明式子代理若解析到另一个 profile则自己完成独立的校验、过滤与覆盖率检查。工具可见性不是授权excluded_tools会追加最终的_ToolExclusionMiddleware_tool_exclusion.py它在wrap_model_call里从模型请求中移除指定名字的工具同时在wrap_tool_call边界上拒绝执行被排除的名字返回Error: {name} is not available.的ToolMessagestatus 为error。这保持了对外宣传的工具与实际可执行的工具一致——但文档与代码注释都明确这不是安全边界。文件系统权限则由FilesystemMiddleware在其内置工具被调用时强制实施而不是由 backend 强制。因此直接使用 backend 会绕过中间件层的权限规则见 graph.py 中 permissions 参数的说明。权限规则与审批行为的完整讨论见 permissions and human-in-the-loop。六、三条独立的子代理路径子代理形态在装配期即已确定graph.py 子代理分拣段spec 含graph_id→AsyncSubAgent交给AsyncSubAgentMiddlewarespec 含runnable→CompiledSubAgent否则 → 声明式SubAgent。三种形态有着不同的构造与继承边界。声明式子代理declarative每个声明式 spec解析自己的模型与 harness profile并构建独立栈FilesystemMiddleware summarization PatchToolCallsMiddlewareisolated-spec 的 skills 或 fork 继承父级 skillsprofile extras提示词缓存围绕 spec 中间件的两遍排除覆盖率校验最终工具过滤。fork 在配置了 memory 时还会镜像顶层 memory。继承规则很明确SubAgent TypedDict 定义spec 只有在省略某个字段时才继承顶层 tools、permissions 和interrupt_onspec 自带的 permissions整体替换而非扩展父级规则。这些值解析完成后若 interrupt 映射非空则在编译声明式图时追加HumanInTheLoopMiddleware。父级的state_schema会传给这次编译而调用方提供的已编译 runnable 与远端图则各自拥有自己的 schema 与审批配置。上下文模式默认isolated子代理收到一个包含委派任务的HumanMessage而不是父级对话handoff作为isolated的遗留别名被接受见_validate_subagent_modesubagents.py实验性fork子代理收到父级有效压缩历史加上任务 preamble_FORK_TASK_PREAMBLE防止子代理把父级委托消息误当成新请求并用可选的子代理 addendum 重建父级提示词。声明式 fork不能定义独立 skills会抛ValueError它保留合格的私有状态通道而 fork 的 compiled runnable 因 schema 不透明会被剥离私有键fork 子代理调用task会被拒绝返回_FORK_RECURSION_REFUSAL防止递归委派——_ForkTaskToolMiddleware通过_deepagents_forked_context私有状态标记在调用期拦截而非删掉工具见 subagents.py。详见 subagents and skills。general-purpose、compiled 与 async 代理general-purpose 自动添加除非当前 profile 禁用它general_purpose_subagentGeneralPurposeSubagentProfile(enabledFalse)或者某个内联同步 spec 已经占用了general-purpose这个名字harness 会自动添加它graph.py。它的栈包含 filesystem、summarization、patching、可选 skills、profile extras、缓存、排除 pass 与最终工具过滤。它只继承覆盖其原有默认槽位的调用方中间件——而不是任意的主代理专属中间件_gp_inheritable仅保留 name 命中原 GP 栈槽位的条目CompiledSubAgent 原样使用不继承父级 state schema 或顶层审批规则且必须返回含messages键的状态_return_command_with_state_update会校验。完成时父级读取返回状态若structured_response非NoneJSON 序列化后作为ToolMessage内容返回否则取最后一条非空AIMessage文本Anthropic 偶尔会在成功的最后工具调用后输出空end_turn消息因此回退逻辑会跳过空文本。合格的非私有状态更新会被合并回父级AsyncSubAgent 后台任务通过 Agent ProtocolLangGraph SDK作为远端后台任务运行兼容 LangGraph Platform / LangSmith Deployment 与自托管服务器。AsyncSubAgentMiddlewareasync_subagents.py暴露五个工具——start_async_task、check_async_task、update_async_task、cancel_async_task、list_async_tasks——并在中间件状态async_tasks字典带_tasks_reducer中返回与追踪 task ID不阻塞父级task调用图 schema 与审批行为属于远端图。认证由 SDK 通过LANGGRAPH_API_KEY/LANGSMITH_API_KEY/LANGCHAIN_API_KEY自动处理自托管可经headers传入自定义鉴权省略url时使用进程内 ASGI 传输仅限ainvoke异步入口。七、安全变更与聚焦测试顺序变更会改变模型看到的内容和可执行的工具。请测试装配后的完整栈而不仅是中间件构造函数本身test_subagent_middleware_init.py 就是一个围绕SubAgentMiddleware初始化的样例验证默认system_prompt为空、工具仅task一个、构造注解可运行时解析。原文档给出的测试聚焦点替换 vs 插入同名中间件原位替换、新名中间件插入 core 之后两遍排除合并前第一遍、合并后第二遍最终请求/工具调用过滤_ToolExclusionMiddleware的请求侧过滤与工具调用侧拒绝受保护脚手架与歧义名失败排除FilesystemMiddleware/SubAgentMiddleware抛ValueError、字符串排除命中多类抛ValueError跨主代理与 general-purpose 的覆盖率profile 级排除允许只命中其中一个栈声明式 / compiled / async / isolated / fork 各自路径尤其私有状态处理、fork 的 prompt/history 构造、递归委派拒绝、结构化响应回退。仓库的单元测试套件覆盖了中间件提供的文件系统与task工具图级测试则覆盖 profile 排除行为与子代理栈装配。改造中间件栈时以这些测试矩阵为回归基准可以显著降低模型侧行为漂移与工具静默消失的风险。八、定制决策速查目标手段边界每次模型请求前改写 prompt / 工具 / 历史自定义中间件wrap_model_call放在middleware中按 name 与内置槽位合并替换某个内置行为如收窄文件工具同名中间件替换保留原位置tools无法移除内置工具彻底拿掉内置工具同名FilesystemMiddleware 更窄tools不破坏脚手架不能排除类本身按 profile 排除中间件HarnessProfile.excluded_middleware类条目精确 type、字符串精确 name受保护脚手架/歧义/未命中均抛ValueError不让模型看到某些工具HarnessProfile.excluded_tools只是可见性过滤非安全边界文件访问控制permissions规则仅作用于FilesystemMiddleware内置工具直接使用 backend 会绕过长对话压缩内置 summarization阈值可配大参数截断 → 阈值压缩 → 溢出重试历史 offload 到 backend委派子代理SubAgentisolated/fork、CompiledSubAgent、AsyncSubAgent各自拥有独立栈、schema 与审批边界这套核心脚手架 调用方插入 profile 排除 尾部行为的装配模型是 Deep Agents 既能开箱即用、又能精确定制的根本原因脚手架保证能力下限排除与替换规则保证定制不越界三态子代理保证隔离边界清晰。如需继续深入可依次阅读 middleware catalog、context management、subagents and skills 与 permissions and human-in-the-loop。【免费下载链接】deepagentsThe batteries-included agent harness.项目地址: https://gitcode.com/GitHub_Trending/de/deepagents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表