多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

一文带你入门DeepAgents:用TaoToken统一Key跑通FunctionCall与SubAgent

一文带你入门DeepAgents:用TaoToken统一Key跑通FunctionCall与SubAgent 1. 从 FunctionCall 到 DeepAgents为什么单步工具调用不够用如果你已经用 LangChain 写过tool装饰的函数让大模型根据用户问题决定调用哪个工具那你其实已经摸到了 Agent 的门槛。FunctionCall 解决的是大模型怎么连外部数据这件事比如查天气、查数据库、调内部接口一个tool加一句描述就能跑通。但真正把它放到稍微复杂一点的业务里问题会一个接一个冒出来。我拿一个真实场景举例用户说帮我调研一下这家公司然后写一份分析报告最后存成文件。FunctionCall 的做法是模型先调get_company_profile拿到信息然后……然后就没有然后了。它不会主动去规划先查资料、再分析、再写报告、再落盘这条链路也不会记住上一轮用户说过报告要控制在 800 字以内这种偏好。你只能靠自己在代码里写死流程或者反复拼接 prompt 去引导写着写着就变成了一坨 if-else。这就是 DeepAgents 想解决的问题。它在 FunctionCall 的基础上补了五块能力Planning 让 Agent 自己拆任务Memory 让偏好跨会话留存SubAgent 把专业任务隔离出去Backend 提供文件系统读写Skill 用渐进式披露的方式把怎么做教给 Agent。这五块拼起来Agent 才从被动回答变成主动完成。本文面向第一次接触 DeepAgents 的开发者目标很明确用 TaoToken 的统一 Key 和 API 通道把 FunctionCall 和 SubAgent 的最小可跑链路搭起来。你会拿到可复制的环境变量配置、Base URL 设置、Skill 与 MCP 的接入示例以及用日志确认调用链真的生效的验证动作。不需要你提前懂 LangGraph跟着敲就能跑。先说清楚适合谁如果你已经能跑通一个create_agent或者create_react_agent想往多步骤、多代理方向走这篇正好。如果你连 FunctionCall 都没写过建议先把tool和ChatOpenAI的基础跑一遍再回来不然容易卡在环境上。TaoToken 在这里的角色是统一入口。DeepAgents 底层还是走 OpenAI 兼容协议模型可以是 Qwen、DeepSeek、Claude 系列等只要把base_url指向同一个通道、api_key用同一个 Key切换模型时不用改代码结构。对初学者来说少一个每个模型配一套 Key的坑调试成本会低很多。2. TaoToken 前置准备统一 Key 与 Base URL 怎么配在写第一行 DeepAgents 代码之前先把通道打通。这一步做对了后面 90% 的 401 和连接报错都能提前避开。TaoToken 的 API 地址是https://taotoken.net/api注意这里不带任何查询参数直接作为base_url使用。官网入口在https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content注册后在控制台生成 API Key。Key 的形态通常是一串sk-开头的字符串复制下来先别急着写进代码放进.env文件更安全。为什么强调用.env因为 DeepAgents 的示例代码里经常出现os.getenv(QWEN_API)这种写法如果你直接把 Key 硬编码进.py文件一旦提交到 Git 就泄露了。用python-dotenv加载本地开发舒服换机器也只需要改一个文件。先装依赖。DeepAgents 目前通过 pip 安装同时需要 LangChain 的 OpenAI 兼容层和 dotenvpip install deepagents langchain-openai python-dotenv langgraph装完之后在项目根目录建一个.env文件内容长这样# .env TAOTOKEN_API_KEYsk-你的TaoToken密钥 TAOTOKEN_BASE_URLhttps://taotoken.net/api MODEL_IDqwen-plus这里MODEL_ID我用了qwen-plus作为示例你可以换成通道里支持的其他模型 ID。关键是TAOTOKEN_BASE_URL必须精确到/api不要多加斜杠也不要写成/v1否则请求会打到错误的路径上。接下来验证 Key 是否可用。最直接的方式是用 curl 打一次模型列表或者一次最小对话请求curl https://taotoken.net/api/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: qwen-plus, messages: [{role: user, content: ping}] }如果返回里带choices字段说明 Key 和通道都正常。如果返回 401先检查 Key 有没有复制完整、有没有多余空格如果返回 404检查base_url是不是写成了https://taotoken.net而漏了/api。对于用 Claude Code 或者 Cline 这类工具的读者配置逻辑是一样的只是入口不同。Claude Code 的配置文件里需要填ANTHROPIC_BASE_URL和ANTHROPIC_API_KEYCline 的 MCP 配置里则是baseUrl和apiKey两个字段。无论哪种三件套都是 Base URL、Key、Model ID缺一不可。TaoToken 的接入文档在https://taotoken.net/doc里面有各客户端的截图级步骤卡住的时候对着看。有一点要提醒不要把生产数据库的直连地址塞进 MCP 配置里。MCP 是给 Agent 调外部服务的协议直连生产库风险极高测试阶段用只读账号或者 mock 数据。这个坑我在早期项目里踩过Agent 一个误操作把测试数据写进了正式表排查了半天。3. 可复制配置FunctionCall 与 SubAgent 最小链路这一节是全文的核心给你一份能直接跑的配置。我会把 FunctionCall 工具、SubAgent 委派、以及 Skill 目录结构都串起来你复制到本地改一下.env就能运行。先看目录结构。DeepAgents 的 Skill 依赖文件系统 Backend所以项目根目录下要有skills/、memories/、workspaces/三个文件夹deepagents-demo/ ├── .env ├── main.py ├── skills/ │ └── analyze-company/ │ ├── SKILL.md │ └── references/ │ └── guide.md ├── memories/ │ └── user_preferences.md └── workspaces/SKILL.md的内容用 YAML front matter 加正文front matter 里的name和description是给 Agent 看的元数据正文是触发后加载的操作指南--- name: analyze-company description: 分析公司的基础信息。当用户需要了解某家公司时使用。 --- # 公司分析技能 当需要分析公司时请按以下步骤进行 1. 使用 get_company_profile 工具获取公司信息 2. 分析公司业务和发展状况 3. 给出总结建议然后是main.py。这份代码同时包含 FunctionCall 工具、SubAgent 定义、Backend 和 Skill 挂载import os from pathlib import Path from dotenv import load_dotenv, find_dotenv from langchain_openai import ChatOpenAI from langchain.tools import tool from deepagents import create_deep_agent from deepagents.backends import CompositeBackend, FilesystemBackend from langgraph.store.memory import InMemoryStore load_dotenv(find_dotenv()) API_KEY os.getenv(TAOTOKEN_API_KEY) BASE_URL os.getenv(TAOTOKEN_BASE_URL) MODEL_ID os.getenv(MODEL_ID) root Path(find_dotenv()).parent MEMORY_DIR (root / memories).as_posix() SKILLS_DIR (root / skills).as_posix() WORKSPACE_DIR (root / workspaces).as_posix() tool def get_company_profile(company_name: str) - str: 获取公司基础信息名称、成立时间、创始人、核心业务等 return f{company_name}成立于2019年是一家专注于人工智能技术的创新公司核心业务包括大模型应用与智能硬件。 model ChatOpenAI( modelMODEL_ID, api_keyAPI_KEY, base_urlBASE_URL, temperature0, ) composite_backend CompositeBackend( defaultFilesystemBackend(root_dirroot, virtual_modeTrue), routes{ /memories/: FilesystemBackend(root_dirMEMORY_DIR, virtual_modeTrue), /skills/: FilesystemBackend(root_dirSKILLS_DIR, virtual_modeTrue), /workspace/: FilesystemBackend(root_dirWORKSPACE_DIR, virtual_modeTrue), }, ) store InMemoryStore() writer_agent { model: model, name: writer-agent, description: 用于撰写文字报告, system_prompt: 你是一个专业作家负责根据材料撰写结构清晰的分析报告。, } agent create_deep_agent( modelmodel, tools[get_company_profile], subagents[writer_agent], skills[/skills/analyze-company/SKILL.md], memory[/memories/user_preferences.md], backendcomposite_backend, storestore, ) if __name__ __main__: inputs {messages: [(user, 请查询疼讯公司信息并让 writer-agent 写一份简短分析)]} for msg, metadata in agent.stream(inputs, stream_modemessages): if msg.content and not isinstance(msg.content, list): print(msg.content, end, flushTrue)这份配置里有几个点值得单独说。CompositeBackend的routes把不同虚拟路径映射到不同物理目录Agent 在读写/skills/时实际访问的是项目下的skills/文件夹这样 Skill 的渐进式披露才能生效。subagents传的是一个字典列表每个字典至少要有name、description、system_prompt和model主 Agent 会根据description决定什么时候把任务委派出去。如果你用 Cline 的 MCP 模式接入配置片段是 JSON 形态字段名和 Python 略有不同{ mcpServers: { taotoken-deepagents: { command: python, args: [main.py], env: { TAOTOKEN_API_KEY: sk-你的密钥, TAOTOKEN_BASE_URL: https://taotoken.net/api, MODEL_ID: qwen-plus } } } }注意env里三个变量要和.env保持一致Base URL 依然是https://taotoken.net/api。Codex 的auth.json场景下字段是base_url和api_keyModel ID 单独在配置里指定三件套逻辑不变。4. 验证请求用日志确认 FunctionCall 与 SubAgent 真的被调用代码跑起来不等于链路生效。很多时候 Agent 会假装调用了工具实际上只是模型自己编了一段回答。所以必须用日志确认调用链。最直接的方式是打开 LangChain 的调试日志。在main.py顶部加两行环境变量import os os.environ[LANGCHAIN_VERBOSE] true os.environ[LANGCHAIN_TRACING_V2] falseLANGCHAIN_VERBOSEtrue会把每次工具调用、每次模型请求的输入输出打到控制台。运行python main.py你会看到类似这样的输出[chain/start] [chain:Agent] Entering Chain run [tool/start] [tool:get_company_profile] Entering Tool run with input: {company_name: 疼讯公司} [tool/end] [tool:get_company_profile] Exiting Tool run with output: 疼讯公司成立于2019年... [chain/start] [chain:writer-agent] Entering Chain run看到tool:get_company_profile的 start 和 end说明 FunctionCall 真的被触发了。看到chain:writer-agent说明 SubAgent 委派成功。如果只有模型输出、没有 tool 日志那大概率是工具描述写得不够清楚模型没识别出该调用它。另一种验证方式是直接问 Agent 它有哪些 SubAgent。把输入改成inputs {messages: [(user, 直接回答我不要调用任何工具你有什么 subagent)]}正常返回里应该出现writer-agent和它的描述。如果返回的是我没有子代理检查subagents参数有没有传进去或者description是不是写得太模糊。Skill 的验证稍微绕一点。因为 Skill 是渐进式披露元数据始终加载正文只在触发时加载。你可以这样问inputs {messages: [(user, 请读取一下你的 analyze-company 的 SKILL)]}如果 Agent 能复述出 SKILL.md 里的三步流程说明 Backend 的/skills/路由和skills参数都配对了。如果它说找不到这个技能先确认SKILL.md的 front matter 格式正确name和description之间没有多余空行。实测下来最容易出问题的是路径。skills[/skills/analyze-company/SKILL.md]里的路径是虚拟路径对应CompositeBackend里routes的 key。如果你把routes写成/skill/而参数里写/skills/就会静默失败Agent 读不到文件但也不报错。这种问题只能靠日志和路径对照来排。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth这一节把新手最容易撞的四个报错拆开讲每个都给定位方法和修复动作。401 Unauthorized。这是最高频的。报错长这样openai.AuthenticationError: Error code: 401 - {error: {message: Invalid API key}}先检查.env里的TAOTOKEN_API_KEY有没有复制完整前后有没有空格。然后确认load_dotenv(find_dotenv())真的加载到了文件——如果.env不在当前工作目录find_dotenv()会往上找但如果你在子目录里跑脚本可能找不到。最稳的做法是打印一下os.getenv(TAOTOKEN_API_KEY)[:8]看前几位是不是sk-开头。如果 Key 没问题还是 401检查base_url是不是写成了https://taotoken.net漏了/api路径不对有时也会返回 401 而不是 404。local proxy failed。这个报错通常出现在你本地配了某些网络工具的情况下表现为连接被拒绝或者超时httpx.ConnectError: [Errno 111] Connection refused处理方式是检查系统环境变量里有没有HTTP_PROXY、HTTPS_PROXY、ALL_PROXY这类设置有的话临时清掉再跑。在 Python 里可以在load_dotenv之后加for k in [HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, http_proxy, https_proxy]: os.environ.pop(k, None)清完之后重新请求如果通了说明就是本地网络配置干扰。注意不要在生产环境里长期这么干只在调试时用。reading choices 相关报错。典型形态是KeyError: choices或者TypeError: NoneType object is not subscriptable这通常意味着返回体结构和你预期的不一样。可能是模型 ID 写错了通道返回了一个错误对象而不是正常的 completion 结构也可能是流式和非流式混用stream_modemessages下拿到的msg.content有时是 list 而不是 str。代码里那句if msg.content and not isinstance(msg.content, list)就是为了过滤这种情况。如果还是报错先把stream换成invoke跑一次看result[messages][-1].content能不能正常打印能的话再切回流式。OAuth 相关报错。如果你用 Claude Code 或者某些客户端可能会看到OAuth token expired or invalid这类客户端有时会优先走 OAuth 流程而不是 API Key。解决方式是在配置里显式指定 API Key 模式把ANTHROPIC_API_KEY填成 TaoToken 的 KeyANTHROPIC_BASE_URL填https://taotoken.net/api。如果客户端同时存在 OAuth 缓存和 API Key 配置清掉缓存目录再重启。Claude Code 的配置细节在https://taotoken.net/doc里有说明对着改就行。排障的通用思路是先确认 Key 和 Base URL 三件套再看日志里请求有没有发出去最后看返回体结构。大部分问题出在前两步真正到模型层面的反而少。6. 把链路跑顺之后Skill 与 MCP 的协作方式链路跑通只是起点。真正让 DeepAgents 好用起来的是 Skill 和 MCP 的配合。Skill 解决的是怎么做的问题。它用三层结构管理上下文元数据层始终加载只有 name 和 description大概 100 词正文层在技能触发时加载包含核心工作流控制在 5k 词以内资源层按需加载脚本、参考文档、素材都放这里。这种渐进式披露的设计让 Agent 在面对上万个 Skill 时也不会把上下文撑爆。当然如果 Skill 数量真的到了万级单靠目录检索不够需要引入向量化做语义检索把文字转成向量坐标按相似度找最相关的几个 Skill 再加载。MCP 解决的是连什么的问题。它有三个组件Tools 是 Agent 能调用的操作Resources 是能读取的数据Prompts 是可复用的提示模板。三者协作的典型链路是用户请求触发 SkillSkill 指导 Agent 去调某个 MCP 服务MCP 连上外部数据源Tool 执行具体处理结果返回给用户。比如分析中美经济对比这个请求Skill 告诉 Agent 用 worldbank MCP 拿 GDP 数据MCP 负责连接Tool 负责处理最后汇总成回答。Tool、MCP、Skill 三者的关系可以用一句话区分Tool 是原子函数做具体操作MCP 是外部服务协议负责连接Skill 是知识包告诉 Agent 什么时候用什么工具。FunctionCall 阶段你只有 ToolDeepAgents 阶段你把三者串起来Agent 才具备处理复杂任务的能力。最后给一个实用建议调试阶段把temperature设成 0减少模型随机性带来的干扰Skill 的description写得越具体触发越准SubAgent 的system_prompt要明确职责边界不然主 Agent 不知道该委派什么。这些细节不影响跑通但影响跑得稳不稳。如果你想把这条链路用到长期编码或者 Agent 项目里Coding Plan 的额度模型比按次调用更适合高频调试入口在https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。需要单独验证某个模型的表现时模型对话页面可以直接试地址是https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。Key 的管理和生成在https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content接入细节查文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。Claude Code 用户看https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content里面有 Anthropic 协议的对接说明。
返回列表