恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
【学习笔记】框架层坍缩——LangChain 们正在被重新定义-14/15:从 LangGraph 到 Harness,Agent 编排的下一站在哪
首页
资讯中心
/
【学习笔记】框架层坍缩——LangChain 们正在被重新定义-14/15:从 LangGraph 到 Harness,Agent 编排的下一站在哪
【学习笔记】框架层坍缩——LangChain 们正在被重新定义-14/15:从 LangGraph 到 Harness,Agent 编排的下一站在哪
发布时间:2026/10/8 17:32:14
1. 从 LangChain 到 LangGraph框架层坍缩到底发生了什么如果你在 2023 年用 LangChain 搭过一个 Agent大概率写过这些东西Router Chain 判断意图、Agent Executor 管理工具调用顺序、OutputParser 把模型吐出来的文本抠成 JSON、RetryParser 处理格式错误。这些代码当时是刚需因为模型自己不会。到了 2026 年情况变了。你直接调 Claude 或 GPT 的 API把工具列表丢过去模型自己决定调哪个、调几次、按什么顺序调。结构化输出用 tool_choice 强制走 schema格式错误率低到可以忽略。这就是「框架层坍缩」——不是框架死了是框架过去承担的胶水职责一部分被模型原生能力吸收一部分上移到 Harness 层。我试过把一个 2023 年的 LangChain 项目做减法删掉 Router、删掉 OutputParser、删掉手写重试循环代码量少了将近一半跑起来反而更稳。原因很简单模型变聪明了你不需要在中间层替它做决策。但坍缩不等于「什么都不用管」。持久化、确定性重放、可观测性、基础设施错误恢复这四件事模型再强也做不了。模型没有跨会话记忆不知道自己花了多少钱不知道 API 被限流了。这些是 Harness 的活。所以现在的迁移路径很清晰链式调用Chain→ 状态图编排LangGraph→ 轻量 Harness规则写进提示 基础设施工具。LangGraph 之所以成为中间站是因为它提供的 Checkpoint、状态机、条件分支正好落在「模型替代不了」的那 20% 里。这篇文章交付三样东西一份可复制的 LangGraph 状态图配置、一套本地验证步骤、以及怎么用 TaoToken 统一 Key 和 API 通道把模型调用联调跑通。适合正在纠结「我的项目要不要从 LangChain 迁到 LangGraph」的人。2. TaoToken 前置准备统一 Key 与 API 通道在写 LangGraph 之前先把模型调用通道理顺。LangGraph 本身不绑定模型供应商它只负责编排模型调用是你自己传进去的。所以你需要一个稳定的 Base URL 和 Key。TaoToken 在这里的作用是统一入口一个 Key 走多个模型Base URL 固定省得你在 LangGraph 节点里为每个模型维护不同的 client 配置。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 。操作步骤第一步打开控制台创建 API Key。地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 登录后在 API Keys 页面生成一个 Key复制保存。这个 Key 后面会写进环境变量不要硬编码到代码里。第二步确认你要用的模型 ID。在模型对话页面可以先试一下地址是 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。输入一句话看返回是否正常同时记下你选的模型 ID比如 claude-sonnet-4-6 这类。LangGraph 节点里要用这个 ID。第三步把 Key 和 Base URL 写进环境变量。Linux/macOS 下export TAOTOKEN_API_KEYsk-你的key export TAOTOKEN_BASE_URLhttps://taotoken.net/apiWindows PowerShell$env:TAOTOKEN_API_KEYsk-你的key $env:TAOTOKEN_BASE_URLhttps://taotoken.net/api注意Base URL 后面不要加 /v1具体路径由 SDK 拼接。如果你用的是 Anthropic SDK它默认会拼 /v1/messages所以 Base URL 填到 /api 即可。第四步装依赖。LangGraph 和 Anthropic SDKpip install langgraph anthropic如果你打算用 OpenAI 兼容格式调用也可以装 openai 包把 base_url 指向同一个地址。两种方式都行看你习惯。这一步做完你手里应该有三样东西一个可用的 Key、一个固定的 Base URL、一个确认能返回的模型 ID。这三件套是后面所有配置的基础。缺任何一个LangGraph 跑起来都会在节点调用时报错。3. 可复制的 LangGraph 状态图配置片段现在进入核心部分。下面这份配置是一个最小可用的 LangGraph 状态图包含三个节点规划、执行、检查。状态里带一个 checkpoint 字段用来演示持久化。先看状态定义和模型客户端import os from typing import TypedDict, Annotated from langgraph.graph import StateGraph, END from langgraph.checkpoint.memory import MemorySaver import anthropic client anthropic.Anthropic( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ[TAOTOKEN_BASE_URL], ) MODEL_ID claude-sonnet-4-6 class AgentState(TypedDict): task: str plan: str result: str step: int这里 AgentState 就是状态图的「共享内存」。每个节点读它、改它、传下去。step 用来计数防止无限循环。规划节点def plan_node(state: AgentState) - AgentState: resp client.messages.create( modelMODEL_ID, max_tokens1024, system你是一个任务规划器。把用户任务拆成 1-3 个可执行步骤只输出步骤列表。, messages[{role: user, content: state[task]}], ) return {plan: resp.content[0].text, step: state.get(step, 0) 1}执行节点def execute_node(state: AgentState) - AgentState: resp client.messages.create( modelMODEL_ID, max_tokens2048, system你是一个执行器。根据计划完成任务输出结果。, messages[{ role: user, content: f任务{state[task]}\n计划{state[plan]} }], ) return {result: resp.content[0].text, step: state[step] 1}检查节点决定是否继续def check_node(state: AgentState) - AgentState: if state[step] 3: return {result: state[result] \n[达到最大步数停止]} return state条件路由函数def should_continue(state: AgentState) - str: if state[step] 3: return end return continue组装状态图graph StateGraph(AgentState) graph.add_node(plan, plan_node) graph.add_node(execute, execute_node) graph.add_node(check, check_node) graph.set_entry_point(plan) graph.add_edge(plan, execute) graph.add_edge(execute, check) graph.add_conditional_edges( check, should_continue, {continue: execute, end: END}, ) memory MemorySaver() app graph.compile(checkpointermemory)这份配置的关键点checkpointer 是 LangGraph 相对 LangChain 的核心增量。MemorySaver 是内存版生产环境换成 SqliteSaver 或 PostgresSaver就能实现跨会话恢复。这就是「模型替代不了」的那部分。如果你用 OpenAI 兼容格式把 client 换成from openai import OpenAI client OpenAI( api_keyos.environ[TAOTOKEN_API_KEY], base_urlos.environ[TAOTOKEN_BASE_URL], )然后调用改成 client.chat.completions.createmodel 参数填同样的 MODEL_ID。两种方式在 TaoToken 上都通。4. 本地验证请求与成功结果配置写完了跑一遍看结果。调用代码config {configurable: {thread_id: test-001}} result app.invoke( {task: 用一句话解释什么是状态图编排, step: 0}, configconfig, ) print(PLAN:, result[plan]) print(RESULT:, result[result]) print(STEP:, result[step])预期输出类似PLAN: 1. 定义状态图编排的概念 2. 说明它与链式调用的区别 3. 给出一个应用场景 RESULT: 状态图编排是把任务建模成节点和边... STEP: 3看到 STEP 是 3说明条件路由生效了没有无限循环。看到 PLAN 和 RESULT 都有内容说明模型调用通道正常。再验证一下 checkpoint 是否工作。用同一个 thread_id 再调一次state app.get_state(config) print(当前状态:, state.values)如果返回的是上一次的完整状态说明 MemorySaver 生效了。换成 SqliteSaver 后重启进程再查状态还在这就是跨会话恢复。验证模型通道是否走的是 TaoToken可以在调用前后看控制台的用量记录。地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 在用量页面能看到刚才两次调用的 token 消耗。如果这里没有记录说明你的 Base URL 或 Key 配错了请求没走到 TaoToken。实测下来整个链路跑通大概需要 10 分钟其中 5 分钟在配环境变量和装依赖。真正写状态图的时间不多因为 LangGraph 的 API 比 LangChain 的 Chain 组合直观得多。5. 本篇常见错误排查跑不通的时候对照下面几个真实报错。401 UnauthorizedKey 没读到或写错了。检查 os.environ 里有没有 TAOTOKEN_API_KEY或者 Key 复制时带了空格。TaoToken 的 Key 以 sk- 开头如果打印出来是空字符串说明环境变量没 export 成功。local proxy failed / connection errorBase URL 写错了。确认是 https://taotoken.net/api 不要多写 /v1也不要少写 /api。如果你在公司网络里检查是否有本地代理拦截这种情况需要把代理配置清掉再试。reading choices 报错 / KeyError: choices这是 OpenAI 兼容格式下常见的。说明返回结构和你解析的字段对不上。先 print(response) 看原始返回确认是 Anthropic 格式还是 OpenAI 格式。Anthropic 是 content[0].textOpenAI 是 choices[0].message.content。混用会报这个错。OAuth / authentication_error如果你用的是 Claude Code 或 Codex 这类工具它们有自己的 auth.json 或 OAuth 流程。这种情况要写全三件套Base URL 填 https://taotoken.net/api Key 填 TaoToken 的 KeyModel ID 填你确认过的模型。三个缺一个都会认证失败。CC Switch 或 Cline MCP 配置时同理Base URL、Key、Model ID 一个都不能少。GraphRecursionError状态图无限循环了。检查你的条件路由函数确保有终止条件。上面例子里的 step 3 就是终止条件。没有它execute 和 check 会一直转。Checkpoint 不生效确认 compile 时传了 checkpointer且 invoke 时传了 config 里的 thread_id。两个都传了还不生效检查 MemorySaver 是不是每次新建的——它要作为模块级变量存在不能每次调用重新创建。排障时如果拿不准先去接入文档对一遍参数https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。文档里有完整的 Base URL、鉴权头、模型列表说明。6. 迁移决策与统一通道收尾回到最初的问题你的项目要不要从 LangChain 迁到 LangGraph判断标准很简单。如果你的工作流是线性的、单次的、不需要跨会话恢复那连 LangGraph 都不用上直接调 SDK 最干净。如果你的工作流有条件分支、需要断点恢复、有人工审批节点那 LangGraph 的 Checkpoint 和状态机就是刚需值得迁。至于 Harness 层记住那四件模型替代不了的事持久化、确定性重放、可观测性、基础设施错误恢复。这四件事用 LangGraph 的 checkpointer 加基础设施工具比如追踪和成本监控就能覆盖不需要引入更重的框架。统一 Key 和 API 通道这件事越早做越好。你后面不管是用 LangGraph 编排、还是用 Claude Code 做编码、还是跑 Coding Plan 做长期任务都走同一个 Base URL 和 Key切换成本最低。Coding Plan 的入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 适合需要长期跑 Agent 的场景。API Keys 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 需要新建或轮换 Key 时从这里进。最后留一个实用技巧把 AGENTS.md 或 CLAUDE.md 放在项目根目录把「改代码前先跑测试」「每完成子任务 commit 一次」「不要动 .env」这些规则写进去。这是最轻量的 Harness零框架依赖任何 Agent 都能读。动态流程控制交给 LangGraph静态规则交给 Markdown 文件两者配合就是框架层坍缩之后比较务实的架构。