前言上篇文章对基于 DeepAgents API 搭建的生产级代码助手智能体DeepAgents Code进行了源码导读重点剖析了其客户端与服务端分离的设计模式。理解了整体架构之后大家应该已经建立起一个宏观认知——但这个认知还不够落地大家真正关心的是一个生产级的智能体服务它的服务端核心到底长什么样在 DeepAgents Code 这个 CLI 智能体项目中智能体核心服务Agent Server的设计与实现是整个系统的重中之重。得益于 DeepAgents SDK 提供的标准化 API开发这样一个 Agent Server 的工作变得结构清晰便于理解。不过一个生产环境中的工业级项目还是有很多的开发技巧——如何切换大模型如何执行代码命令如何进行多智能体开发等都是必须考虑的问题。今天这篇文章笔者就带大家深入 DeepAgents Code 项目的Agent Server 模块看它的核心实现与设计思路。在正式进入代码之前先和大家分享一个高效的源码阅读方法不要一上来就逐文件逐行啃代码那样只会迷失在细节里。 更好的路径是——先思考“一个生产级智能体应该具备哪些功能、采用怎样的架构”然后实际试用一下 DeepAgents Code 智能体带着真实的体感和疑问再去探究“DeepAgents Code 究竟是如何实现这些功能的”。带着问题读源码每一行代码都会变得有迹可循。一、DeepAgents Code Agent Server核心设计DeepAgents Code Agent Server 的核心源码位于项目目录下的agent.py文件中。在笔者看来一个真正生产级别的智能体项目至少要解决好以下四个核心问题大模型的接入与切换如何对接不同模型提供商如何在不中断服务的前提下动态切换模型工具函数的调用如何定义、注册、调用工具如何保证工具执行的安全性与可控性会话记忆的存储复用用户的对话历史和状态如何跨轮次持久化如何实现跨会话的记忆共享多智能体系统的编排当单一智能体能力不足时如何通过子智能体委派来扩展能力边界DeepAgents Code 基于DeepAgents API 的create_deep_agent核心函数通过其中间件机制、工具函数机制和子智能体机制等核心机制实现了上述的各种功能。下图是 DeepAgents Code 智能体服务部分核心模块的结构关系图。在agent.py中DeepAgent Code通过自定义的create_cli_agent函数完成了这一切的整合——大家先有个整体印象接下来笔者会逐个模块展开讲解从上图可以清晰地看到借助 DeepAgents API 的标准化能力DeepAgents Code 的功能模块划分非常干净——每一层各司其职互不越界。这正是优秀架构的魅力所在二、 DeepAgents Code Agent Server 核心模块讲解有了宏观认知之后接下来笔者将深入各个核心模块逐一拆解它们的实现原理与技巧。2.1 Model Provider 模型服务智能体最基础的能力就是接入大模型。DeepAgents Code 同样通过create_deep_agent的model参数传入模型实例agent.py中相关代码如下agentcreate_deep_agent(modelmodel,system_promptsystem_prompt,toolstools,backendcomposite_backend,middlewareagent_middleware,interrupt_oninterrupt_on,context_schemaCLIContextSchema,checkpointercheckpointer,subagentsall_subagentsorNone,name_sanitize_agent_message_name(assistant_id),).with_config(config)model参数传模型这是 LangChain 最标准的用法之一相信大家已经非常熟悉。但很多读者可能会产生一个疑问在像 DeepAgents Code 这样的生产级 CLI 工具中用户经常需要在不重启会话的情况下动态切换模型比如从 GPT-4 切到 Claude 3.5这部分是如何实现的从上面的代码看模型似乎在一开始就“写死”了呀这里 DeepAgents Code 运用了一个非常巧妙的设计核心思路分为两步第一步通过上下文Context传递模型切换指令大家注意create_deep_agent中的一个关键参数context_schemaCLIContextSchema。这个参数定义了智能体运行时的动态上下文结构其定义如下位于_cli_context.pyclassCLIContext(TypedDict,totalFalse):model:str|NoneModel spec to swap at runtime (e.g. provider:model).model_params:dict[str,Any]Invocation params (e.g. temperature, max_tokens) to merge.effective_model:str|NoneResolved provider:model spec actually in use.auto_approve:bool在智能体运行时比如通过agent.stream()执行时可以在context参数中携带用户指定的模型代码位于app.pycontextCLIContext(modelself._model_override,model_paramsself._model_params_overrideor{},...)这个context随后在textual_adapter.py中被传入agent.astream()调用从而将“想切换到的目标模型”传递给执行层asyncforchunkinagent.astream(stream_input,stream_mode[messages,updates],subgraphsTrue,configconfig,contextcontext,durabilityexit,):第二步通过ConfigurableMiddleware中间件在运行时替换模型仅有上下文传递还不够——真正负责“在模型调用前一刻执行替换”的是 DeepAgents Code 自定义的ConfigurableModelMiddleware中间件位于configurable_model.pyclassConfigurableModelMiddleware(AgentMiddleware):Swap the model or per-call settings from runtime.context. ...... defwrap_model_call(# noqa: PLR6301self,request:ModelRequest,handler:Callable[[ModelRequest],ModelResponse],)-ModelResponse:该中间件通过wrap_model_call钩子在每次模型调用前拦截请求。其内部的核心逻辑包括从runtime.context中读取要切换的模型通过model_matches_spec判断当前使用的模型是否与目标模型匹配若不匹配则调用create_model()动态创建新模型实例合并model_params参数如 temperature、max_tokens 等跨提供商切换时自动清理不兼容的配置比如从 Anthropic 切换到 OpenAI 时自动移除cache_control相关参数最后更新系统提示中的### Model Identity部分让新模型“知晓”自己的身份。这套设计流程充分运用了 LangChain 的运行时上下文Runtime Context与中间件Middleware机制实现了“模型切换不中断会话、无需重启服务”的丝滑体验。对中间件机制还不太熟悉的读者可以回顾笔者之前的文章 LangChain 1.0 高阶特性。2.2 Tool Registry三种工具来源的统一管理工具是智能体的“手脚”DeepAgents Code 的工具来源可以划分为以下三类来源说明典型工具内置工具硬编码在代码中的基础工具fetch_url、web_search、get_current_thread_idMCP 工具通过 MCP 协议从远程服务加载用户自定义的 MCP 服务器工具中间件注入工具DeepAgents SDK 运行时自动注入execute、read_file、write_file、edit_file内置工具定义在tools.py文件中包含fetch_url抓取网页内容、web_search网络搜索和get_current_thread_id获取当前会话 ID三个基础工具。MCP 工具通过mcp_tools.py实现。用户接入 MCP 服务后DeepAgents Code 会从 MCP 服务端解析可用的工具列表并注入智能体。关于 MCP 的具体使用方式大家可以参考笔者之前的文章 LangChain 1.0 高阶特性。中间件注入工具是三类工具中最为丰富的一类。笔者在之前的文章 LangChain DeepAgents 速通指南四—— FileSystem中间件让AI Agent拥有系统级记忆管理能力 中曾提到FileSystemMiddleware会自动注入ls、read_file、write_file、edit_file等文件操作工具。而在 DeepAgents Code 中除了文件系统中间件还集成了代码执行中间件等其他组件共同注入了诸如execute执行 Shell 命令等能力。这里有必要提及一下get_current_thread_id这个看似简单却很有意义的工具函数。它的使用场景主要有两个LangSmith 追踪关联LangSmith 是 LangChain 的可观测性平台通过thread_id关联同一会话的所有 Trace。当智能体在运行过程中需要调用 LangSmith API比如上报自定义指标、查询历史 Trace时它需要知道“我是谁”——这个工具让智能体可以主动获取thread_id而非被动等待注入。MCP 工具集成某些 MCP 工具可能需要thread_id来关联上下文。例如一个外部记忆工具需要知道当前会话标识才能存取对应的状态数据。这个设计的精妙之处在于把“获取自身上下文信息”这件事从系统提示或工具参数的静态注入中解耦出来变成一个可主动调用的工具。 智能体“按需获取”而非“被动接收”体现了更灵活的设计哲学。2.3 Subagents多智能体机制笔者在之前的文章 LangChain DeepAgents 速通指南六—— DeepAgents SubAgent 子智能体机制 中已经详细介绍过 DeepAgents SDK 的子智能体机制。其核心思想是通过task工具主智能体可以将复杂任务委派给专门的子智能体执行从而避免上下文过长、职责不清等问题。DeepAgents Code 充分利用了 DeepAgents SDK 的这一原生能力相关代码位于subagents.py。用户可以在agents_dir/{subagent_name}/AGENTS.md中定义子智能体的能力描述DeepAgents Code 在创建主智能体会自动将这些本地自定义的这些能力描述构建为对应的子智能体并添加到subagents参数中。除了本地自定义的子智能体在agent.py中我们还可以看到如下代码all_subagents: list[SubAgent | CompiledSubAgent | AsyncSubAgent] [ *custom_subagents, *(async_subagents or []), ]其中的async_subagents是在config.toml中配置的、部署在远程平台上的智能体服务。这意味着 DeepAgents Code 的子智能体体系同时考虑了两种场景本地自定义用户可以在本地通过 Markdown 文件随时定义新的子智能体远程复用用户也可以接入部署在远程平台上的智能体服务实现能力的远程共享。这种“本地定义 远程复用”的设计既保证了灵活性又兼顾了扩展性非常值得借鉴。三、DeepAgents Code 中间件能力扩展LangChain 1.0 版本引入的中间件Middleware机制是整个LangChain智能体体系框架中最具工程价值的能力没有之一。在前面的系列文章中大家已经看到 DeepAgents SDK 正是通过一系列中间件获得了任务规划、工具选择调用、文件系统操作等核心能力。DeepAgents Code 同样在此基础上做了大量扩展——甚至可以说DeepAgents Code 中相当一部分代码都是在定义和组装中间件这足以说明中间件在LangChain智能体开发体系中的地位。下面笔者就为大家逐一拆解 DeepAgents Code 中几个代表性的中间件看看它们各自解决了什么问题、又是如何巧妙实现的。3.1 LocalContextMiddleware让智能体更懂项目LocalContextMiddleware的设计目的是负责向智能体注入本地环境上下文让它“知道”自己当前在哪个项目中工作而非一个“对项目一无所知”的通用助手。该中间件定义在local_context.py中核心机制如下在每次模型调用前before_model钩子中间件通过执行 Bash 检测脚本自动收集当前项目的环境信息包括但不限于Git 状态当前分支、是否有未提交的更改、远程仓库信息项目结构目录布局、关键文件是否存在包管理器类型检测项目使用的是 npm、pip、cargo 还是其他工具。这些信息在首次交互时自动检测并在每次总结事件后增量更新检测结果会持久化存储在智能体状态中。每次模型调用时中间件会将当前环境快照附加到系统提示中。3.2 ResumeStateMiddleware会话恢复的额外助手当用户中途关闭终端、之后通过/threads命令恢复之前的会话时需要解决两个棘手的问题模型信息丢失LangGraph 检查点中只保存了消息记录却没有记录“这些消息是哪个模型生成的”。假如原会话使用的是上下文窗口较大的模型如gpt-4o恢复时却使用了默认的qwen2.5-72b就可能因上下文窗口不足而导致截断严重影响会话连续性。Token 计数丢失界面状态栏需要显示当前会话的 Token 用量但检查点中没有存储这个数据。重新计算需要遍历全部历史消息性能开销大且不精确。DeepAgents Code 在resume_state.py中定义了ResumeStateMiddleware来解决上述问题。它在每次模型调用完成后的after_model钩子中提取本次调用的 Token 用量和当前模型信息写入一个名为ResumeState的扩展状态classResumeState(AgentState):Extends agent state with per-checkpoint facts restored on resume._context_tokens:Annotated[NotRequired[int],PrivateStateAttr]Total context tokens from the models last usage_metadata._model_spec:Annotated[NotRequired[str],PrivateStateAttr]provider:model spec effectively in use for the latest turn.ResumeState会随messages一起持久化到数据库中。当用户下次恢复会话时中间件从检查点中还原_context_tokens、_model_spec和messages实现会话状态的无损恢复——模型一致、Token 计数准确消息记录完全用户感知不到任何中断。3.3 MemoryMiddleware跨会话的长期记忆MemoryMiddleware负责从AGENTS.md文件加载长期记忆并将其注入系统提示让智能体在跨会话的场景下依然能保持上下文连贯性。官方文档可参考https://docs.langchain.com/oss/python/deepagents/code/overviewDeepAgents Code 支持使用AGENTS.md文件来定义智能体的持久化行为指令。需要注意区分这里的AGENTS.md是针对主智能体的全局记忆而前文子智能体中提到的AGENTS.md则是放在特定子智能体目录下的专属定义——二者层级不同但机制相通。该中间件定义在memory.py中其核心逻辑在before_model钩子中执行从配置的文件系统路径包括用户级~/.deepagents/和项目级.deepagents/读取AGENTS.md文件内容剥离 Markdown 中的 HTML 注释这些注释往往用于开发者备注不应暴露给模型将处理后的内容包装成agent_memory标签注入到 DeepAgents Code 的系统提示中。DeepAgents Code 这种“文件即记忆”的设计让用户可以像编辑文档一样调整智能体的长期行为无需修改任何代码。记忆内容跨会话生效真正实现了“一次设定处处生效”。3.4 SkillsMiddleware: 技能系统的按需加载技能Skill已成为当今智能体能力的基石。DeepAgents Code 中的SkillsMiddleware负责管理整个技能系统其最大的特色是渐进式披露Progressive Disclosure策略——先展示技能概览用户显式调用时才加载完整指令避免系统提示被海量技能详情撑爆。该中间件的before_model钩子执行以下流程从多个目录内置技能、用户级~/.deepagents/agent/skills/、项目级.deepagents/skills/扫描所有SKILL.md文件解析每个文件的 YAML Frontmatter提取技能名称、描述和触发条件构建技能列表摘要按以下格式注入系统提示Available skills:-/deploy:Deploy application to production-/analyze:Analyze code quality当用户通过/skill_name显式调用某个技能时中间件才从对应的SKILL.md中读取完整的指令内容并注入上下文——这就是“按需加载”的精髓所在。3.5 FileSystemBackend、LocalShellBackend等多优先级后端机制在笔者之前的文章 LangChain DeepAgents 速通指南四—— FileSystem中间件让AI Agent拥有系统级记忆管理能力 笔者讲解过DeepAgents SDK内置的FileSystemMiddleware中间件该中间件会自动注入ls、read_file、write_file、edit_file等文件操作工具为 DeepAgents Code 提供最基础的文件系统交互能力。在理解FileSystemMiddleware的过程中大家也学习到了backend参数定义智能体的后端依赖。在agent.py中DeepAgents Code 按照创建逻辑优先级依次尝试三种后端1. 远程沙箱模式最高优先级当sandbox参数不为None时直接使用远程沙箱后端如ModalSandbox、DaytonaSandbox。此时所有文件操作和 Shell 执行均由远程沙箱提供本地不创建任何 Backend。适用于需要隔离执行环境的场景如运行不可信代码或需要访问云端资源的任务。2. 本地 Shell 模式默认当enable_shellTrue且未配置沙箱时创建LocalShellBackend。它同时提供文件读写和 Shell 命令执行能力通过env参数注入精心策划的环境变量如LANGSMITH_PROJECT并通过inherit_envFalse避免重复继承主进程环境保证环境干净可控。这是本地开发的默认模式——DeepAgents Code 执行 Python 代码时本质上就是通过这个 Backend 中的execute工具调用python命令来运行编写的.py文件。3. 纯文件系统模式受限当enable_shellFalse时退化为FilesystemBackend仅提供文件读写能力不执行任何 Shell 命令。适用于“只需编辑文件、无需运行命令”的场景安全性更高。这三种模式的切换本质上是能力降级策略——沙箱 Shell 文件 纯文件。每个 Backend 都实现了统一的BackendProtocol接口中间件层不关心具体实现只通过统一接口调用。这种策略模式让 DeepAgents Code 可以在不同的安全级别与执行环境之间无缝切换极大地增强了系统的适应能力。以上就是本文的全部内容。到这里大家应该对 DeepAgents Code 项目的智能体服务核心层有了全面的了解。关于DeepAgents Code 大家如果不想登录github下载的话可关注笔者的同名微信公众号大模型真好玩每期分享涉及的代码均可在公众号私信:LangChain智能体开发免费获取。四、总结本篇文章笔者对 DeepAgents Code Agent Server 的核心模块进行了全面剖析。从运行时动态模型切换的设计到三类工具的统一管理再到子智能体的双轨委派机制每个模块都在解答生产级智能体必须直面的问题。而中间件机制更是将智能体能力扩展发挥到了极致通过LocalContextMiddleware实现环境感知通过ResumeStateMiddleware实现会话无损恢复通过MemoryMiddleware赋予跨会话长期记忆FileSystemMiddleware等中间件配合三种 Backend 的灵活切换保障了不同安全级别的执行环境。读到这里大家应该能体会到DeepAgents Code 并非对 DeepAgents API 的简单堆砌而是一套精心设计的工程体系。每一条中间件、每一层抽象背后都有真实的工程约束在驱动。在笔者的日常开发经验中状态管理与记忆机制始终是智能体开发最核心也最棘手的环节。下一篇文章笔者将专门深入 DeepAgents Code 的状态管理模块解析其检查点机制、记忆分层与状态迁移设计大家敬请期待~本系列相关内容均列于笔者的专栏《深入浅出LangChainLangGraph AI Agent 智能体开发》该专栏适合所有对智能体开发感兴趣的学习者无论之前是否接触过 LangChain。该专栏基于笔者在实际项目中的深度使用经验系统讲解了使用LangChain/LangGraph如何开发智能体目前已更新 47 讲并持续补充实战与拓展内容。欢迎感兴趣的同学关注笔者的CSDN账号与专栏也可关注笔者的同名微信公众号大模型真好玩每期分享涉及的代码均可在公众号私信:LangChain智能体开发免费获取。