☰
用 LangGraph 手写 Agent 到第三个,我决定把 create_deep_agent 拆开看看 TaoToken 通道怎么接
2026/10/3 12:09:29 网站建设 项目流程

1. 从第三个手写 Agent 说起:LangGraph 里那些重复劳动到底该谁干

如果你已经用 LangGraph 手写过两个以上的 Agent,第三个开始大概率会有一种熟悉的疲惫感。State 要重新定义一遍,ReAct 循环要重新搭一遍,Tool 调用要自己包,上下文超长要自己写摘要节点,checkpoint 要自己接,子任务委派还得自己 compile 一堆子图再想清楚它们之间怎么调。每个项目都把这套样板抄一遍,抄到最后你会怀疑:这些代码是不是本来就应该被框架吃掉。

这篇就是从这个疑问出发的。核心检索词先摆清楚:LangGraph 是图执行运行时,LangChain 的 create_agent 是它之上的最小 Agent harness,而 DeepAgents 的 create_deep_agent 是在 create_agent 之上更 opinionated 的一层封装,带电池、带默认编排、带状态管理。它适合谁?适合已经会 LangGraph、正在写第三个甚至第 N 个 Agent、被重复样板拖慢节奏的人;也适合想做一个“通用工作型 Agent”但不想从零搭文件系统、上下文压缩、子 Agent 委派的人。

我试过把同一个需求分别用手写 LangGraph 和 create_deep_agent 各写一遍,差异不在那十几行入口代码,而在于 DeepAgents 默认替你装好了文件读写、上下文摘要、子任务委派、工具审批这些长任务里绕不开的能力。下面我会先讲清楚三层抽象的关系,再给出 create_deep_agent 的最小可运行配置,然后对照手写 LangGraph 图列出它到底替你做了什么,最后用 TaoToken 统一 Key/API 通道完成一次真实 Agent 调用的验证,并把常见的 401、local proxy failed、reading choices 这类报错逐个排掉。

先明确一件事:DeepAgents 不是 LangGraph 的替代品。三者是同一栈的不同抽象层,上下叠着,不是互相取代。你想完全控制图结构、节点、状态 reducer,就用 LangGraph;你想要一个轻量 Agent 循环、自己加中间件,就用 LangChain create_agent;你想直接拿一个能干长任务的 Agent,就用 DeepAgents。更关键的一点是,任何 LangGraph 的 CompiledStateGraph 都可以当 Sub-agent 塞进 Deep Agent,你过去写的复杂图没白写,可以直接当子能力挂上来。这就是为什么第三个 Agent 之后值得停下来看看封装层:不是放弃手写,而是把重复劳动交给默认能力,把精力留给真正有业务差异的部分。

2. TaoToken 前置:统一 Key 与 API 通道,让 Agent 调用不再到处配环境

在拆 create_deep_agent 之前,得先把模型通道这件事解决掉。手写 Agent 到第三个,另一个烦人的点就是每个项目都要重新配一遍模型 provider:这个项目用 OpenAI SDK,那个项目用 Anthropic SDK,换一个又要改 base_url、改 key、改 model id。DeepAgents 本身不绑定某一家模型,它接受任何支持 tool calling 的模型,所以通道层越统一,后面切换和验证越省事。

TaoToken 在这里扮演的就是统一 Key/API 通道的角色。官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api (这个不加 UTM)。它的价值不是“又一个中转”,而是把模型调用收敛成一套 Base URL + Key + Model ID 的三件套,你在 LangGraph、create_agent、create_deep_agent 里都用同一套配置,换模型只改 Model ID,不动业务代码。

前置准备分三步。第一步,拿到 API Key。进入控制台后创建 key,路径是 console 下的 api-keys 页面,对应 deep link 是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog&utm_content=api_keys&utm_campaign=rewrite 。创建完把 key 复制出来,注意它通常只完整显示一次,先存到环境变量里,别硬编码进代码。

第二步,确认 Base URL。所有 SDK 里统一填 https://taotoken.net/api ,不要带结尾斜杠,也不要在后面再拼 /v1 之类的路径,具体以接入文档为准。文档入口是 https://taotoken.net/doc?utm_source=taotoken_aicg_blog&utm_content=doc&utm_campaign=rewrite ,里面有各语言 SDK 的完整示例,遇到路径拼接问题先翻这里。

第三步,选 Model ID。DeepAgents 的 model 参数接受形如 “provider:model” 的字符串,比如 “openai:gpt-4o”。走 TaoToken 通道时,你需要把 provider 指向兼容 OpenAI 协议的入口,Model ID 填你在通道里可用的模型名。如果你不确定某个模型是否支持 tool calling,先在模型对话页面手动试一次带工具的请求,入口是 https://taotoken.net/models?utm_source=taotoken_aicg_blog&utm_content=models&utm_campaign=rewrite ,确认能正常返回 tool_calls 再写进 Agent。

环境变量建议这样设,后面所有代码都从环境变量读,避免 key 泄漏:

export TAOTOKEN_API_KEY="sk-你的key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"

如果你打算长期做编码类 Agent,或者要跑多步骤、带子 Agent 的长任务,可以顺带了解 Coding Plan,入口是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog&utm_content=coding_plan&utm_campaign=rewrite ,它更适合这种持续调用的场景。前置做完,通道就统一了,接下来 create_deep_agent 和手写 LangGraph 用的是同一套模型配置,对照起来才干净。

3. 可复制配置:create_deep_agent 最小可运行 + 与手写 LangGraph 对照

这一节是全文的技术核心。先给最小可运行配置,再给手写 LangGraph 的对照清单,让你清楚 DeepAgents 到底替你做了哪些编排与状态管理。

先装依赖。Python 版本用 deepagents 包:

uv add deepagents # 或者 pip install deepagents

装完通常还要装对应 provider 的 SDK,走 OpenAI 兼容协议的话:

pip install langchain-openai

然后是 create_deep_agent 的最小可运行代码。注意 model 这里走 TaoToken 通道,需要显式传 base_url 和 api_key,所以用 init_chat_model 或 ChatOpenAI 构造模型对象再传进去,比直接写字符串更可控:

import os from langchain_openai import ChatOpenAI from deepagents import create_deep_agent def get_weather(city: str) -> str: """查询某个城市的天气(演示用,写死)。""" return f"{city} 今天 26°C,多云。" model = ChatOpenAI( model="gpt-4o", # 换成你通道里可用的、支持 tool calling 的 Model ID base_url=os.environ["TAOTOKEN_BASE_URL"], api_key=os.environ["TAOTOKEN_API_KEY"], temperature=0, ) agent = create_deep_agent( model=model, tools=[get_weather], system_prompt="你是一个研究助手,回答问题前先想清楚是否需要工具。", ) result = agent.invoke({"messages": "北京天气怎么样?"}) print(result["messages"][-1].content)

这段代码和手写 LangGraph 搭一个 ReAct Agent 的差异,关键不在这十几行,而在于默认能力。下面这张对照表是我自己整理的手写 LangGraph 图 vs create_deep_agent,逐项对照:

能力手写 LangGraph 要自己做create_deep_agent 默认
Sub-agents自己 compile 多个 graph,自己定义调用关系直接配置,子 Agent 上下文隔离
Filesystem自己写 read/write tool,自己处理后端内置文件读写工具,可换本地/沙箱/远程后端
Context Management自己写摘要节点、自己决定何时压缩自动摘要、工具结果自动落盘
Persistent Memory自己接 checkpointer / storeState 和 Store 可插拔,跨会话记忆开箱可用
Shell自己包装 subprocess 工具内置沙箱 shell
Skills没有这个抽象按需加载的可复用行为包
HITL自己用 LangGraph 的 interrupt 机制工具调用前可 approve/edit/reject,配置即可
ToolsLangChain Tool 或自定义兼容 LangChain Tool + MCP Server

如果你用 Claude Code 那套工作流,或者想把这套 Agent 接到本地开发环境,配置三件套要写全:Base URL 填 https://taotoken.net/api ,Key 填你的 TAOTOKEN_API_KEY,Model ID 填通道里可用的模型名。这三件套在 create_deep_agent、create_agent、手写 LangGraph 里是一致的,换层不换配置。

再给一个 settings 风格的配置片段,方便你放进项目配置文件里复用:

{ "model": { "provider": "openai-compatible", "base_url": "https://taotoken.net/api", "api_key_env": "TAOTOKEN_API_KEY", "model_id": "gpt-4o", "temperature": 0 }, "agent": { "system_prompt": "你是一个研究助手,回答问题前先想清楚是否需要工具。", "enable_filesystem": true, "enable_subagents": true, "enable_hitl": false } }

对照下来你会发现,手写 LangGraph 时你花在文件读写、上下文摘要、子任务委派上的时间,在 create_deep_agent 里变成了几个开关。这不是说手写没价值,而是说这些能力在长任务里高度通用,交给默认实现更划算。真正需要你手写的,是那些有业务差异的节点和状态机。

4. 验证请求:跑通一次 Agent 调用并确认结果

配置写完,必须跑一次真实调用确认通道和 Agent 都正常。这一步别跳过,很多问题在静态配置里看不出来,一跑就暴露。

先做最小验证,确认模型通道本身通:

import os from langchain_openai import ChatOpenAI model = ChatOpenAI( model="gpt-4o", base_url=os.environ["TAOTOKEN_BASE_URL"], api_key=os.environ["TAOTOKEN_API_KEY"], ) resp = model.invoke("用一句话说明什么是 Agent。") print(resp.content)

如果这一步就报错,先别往下走,去第 5 节排错。如果正常返回,说明 Base URL、Key、Model ID 三件套没问题,再跑 Agent:

result = agent.invoke({"messages": "北京天气怎么样?"}) for m in result["messages"]: print(type(m).__name__, getattr(m, "content", ""))

跑通后重点观察三个点,这是判断封装层值不值的关键。第一,看 result[“messages”] 里 Agent 自己产生了哪些消息,有没有反思、有没有计划步骤,这反映它的编排行为。第二,把任务换成长任务,比如让它写一份报告,观察它是不是主动调用文件系统写中间产物,这是 DeepAgents 默认文件能力在起作用。第三,如果你接了 LangSmith trace,去看它内部的图结构,你会发现底层确实就是 LangGraph,封装层没有另起炉灶,只是把常用节点和状态管理预置好了。

成功结果大概长这样:最后一条 message 的 content 是“北京今天 26°C,多云”,中间能看到 tool 调用消息和 tool 返回消息。如果你看到的是空 content 或者模型反复调用同一个工具,多半是模型 tool calling 不稳定,换一个支持更稳的 Model ID 再试。

验证通过后,你可以把同一个 agent 对象接到更长的流程里,比如让它先规划再执行再写文件。这时候 create_deep_agent 的默认能力会明显省事:你不用自己写摘要节点,上下文超长时它会自动压缩;你不用自己写子任务委派,配置好 Sub-agent 它自己调。这一步跑顺了,再回头看手写 LangGraph 的第三个 Agent,你会更清楚哪些代码该留、哪些该交给封装。

5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth

这一节按真实报错来,遇到哪个查哪个。

401 Unauthorized。最常见的原因是 Key 没读到或者读错。先确认环境变量真的注入了,在 Python 里 print(os.environ.get(“TAOTOKEN_API_KEY”)) 看是不是 None。如果是 None,说明 export 没生效或者跑在了另一个 shell。如果 Key 有值还 401,检查是不是复制时带了空格或换行,重新去 api-keys 页面生成一个再试。还有一种情况是 Base URL 写成了带 /v1 的路径,导致鉴权头没被正确识别,统一用 https://taotoken.net/api 。

local proxy failed。这个报错通常出现在你本地配了某些网络层,但 Agent 进程没走通。先确认你的运行环境能正常访问 Base URL,用 curl 直接打一次:

curl -s -X POST "$TAOTOKEN_BASE_URL/chat/completions" \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4o","messages":[{"role":"user","content":"hi"}]}'

如果 curl 通而 Python 不通,多半是 Python 进程的环境变量或代理设置不一致,检查 requests/httpx 是否读了系统代理。如果 curl 也不通,先解决网络可达性,再回到 Agent。

reading choices 相关报错。这个一般出现在模型返回结构不符合预期时,比如你用的 Model ID 实际不支持 tool calling,或者返回体里没有 choices 字段。先确认 Model ID 是通道里可用的、支持工具调用的模型。如果模型支持但偶发,可能是并发或超时导致返回体被截断,加个重试和超时设置:

model = ChatOpenAI( model="gpt-4o", base_url=os.environ["TAOTOKEN_BASE_URL"], api_key=os.environ["TAOTOKEN_API_KEY"], timeout=60, max_retries=2, )

OAuth 相关报错。如果你用的是需要 OAuth 的客户端或 CLI,报错通常指向 token 过期或 scope 不对。这类问题先确认你走的是 API Key 通道而不是 OAuth 通道,两者不要混用。如果你在 Claude Code 或类似工具里配置,三件套要写全:Base URL 是 https://taotoken.net/api ,Key 是你的 API Key,Model ID 是通道里可用的模型名。配置完重启客户端再试,很多 OAuth 报错其实是旧配置缓存导致的。

还有一个高频坑:模型必须支持 tool calling。本地跑的小模型工具调用经常空转,表现为 Agent 反复调用同一个工具或者不调用工具直接瞎答。建议验证阶段直接用能稳定 tool calling 的模型,跑通流程后再考虑换小模型。另外 pip install deepagents 之外还要装 provider SDK,装完发现 import 报错先检查 langchain-openai 之类有没有装。默认带的工具不少,第一次跑别急着加自己的 tool,先看它默认装了什么,避免重复造轮子。

6. 语义一致 CTA:把通道固定下来,再决定要不要深入封装层

走到这里,你已经跑通了一次 create_deep_agent 调用,也对照清楚了它和手写 LangGraph 的差异。接下来怎么走,取决于你的实际场景。

如果你现在的主要问题是接入和排障,比如 401、local proxy failed、reading choices 这些还没彻底解决,优先去把 API Key 和接入文档过一遍。API Keys 入口是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog&utm_content=api_keys&utm_campaign=rewrite ,接入文档入口是 https://taotoken.net/doc?utm_source=taotoken_aicg_blog&utm_content=doc&utm_campaign=rewrite ,里面有各语言 SDK 的完整示例和路径说明,照着配比猜快。

如果你只是想先验证某个模型能不能稳定做 tool calling,再去模型对话页面手动试一次带工具的请求,入口是 https://taotoken.net/models?utm_source=taotoken_aicg_blog&utm_content=models&utm_campaign=rewrite ,确认返回里有 tool_calls 再写进 Agent,能省掉很多调试时间。

如果你已经确定要长期做编码类 Agent、多步骤长任务、带子 Agent 的编排,那 Coding Plan 更合适,入口是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog&utm_content=coding_plan&utm_campaign=rewrite 。它面向的就是这种持续调用、需要稳定通道的场景。

回到最初那个判断:你最近的 Agent 项目里,是不是已经第二次在写文件读写工具、上下文摘要、子任务委派?如果是,那 create_deep_agent 值得你花几个小时拆开看看,它省下来的样板代码是每个项目几百行。如果不是,你只是想要“调一次 tool 然后返回”,那 create_agent 更轻,甚至手写 LangGraph 更直接。通道先固定成一套 Base URL + Key + Model ID,封装层用不用、用哪层,你随时可以换,业务代码不用动。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询