☰
LangChain v1.0 核心解析:create_agent、LCEL 与 LangGraph 实战指南
2026/9/26 7:04:42 网站建设 项目流程

1. 从零理解 LangChain v1.0 的定位与核心变化

LangChain 这个项目从 2022 年底开始进入大众视野,到 v1.0 版本落地,中间经历了至少三次比较大的架构调整。我最早接触它的时候,整个库还处于一种“什么都想做”的状态,链、代理、记忆、检索、工具调用全部混在一起,API 变动频繁,今天写的代码下周可能就跑不通了。v1.0 最大的意义在于,它终于把职责边界划清楚了:LangChain 负责模型抽象、工具定义、消息协议和 Agent 循环,LangGraph 负责有状态编排和复杂控制流,LCEL 负责声明式的链式组合。这三者各司其职,不再互相打架。

如果你之前用过旧版本的initialize_agent或者AgentExecutor,v1.0 会给你一种“换了个框架”的错觉。实际上核心思路没变,只是把原来藏在黑盒里的东西暴露出来了。最典型的就是create_agent这个新入口,它取代了以前一堆零散的 agent 构造函数,把模型、工具、提示词、中间件这几个关键要素统一到一个函数签名里。这个设计的好处是,你不需要再去记create_react_agent、create_openai_tools_agent、create_structured_chat_agent这些名字,一个create_agent走天下,底层根据你传入的模型能力自动选择最合适的执行策略。

那 v1.0 到底解决了什么问题?我总结下来是三个痛点。第一,旧版 Agent 的调试体验极差,出错之后你根本不知道是模型选错了工具,还是工具执行抛了异常,还是提示词格式不对。v1.0 引入了中间件机制,你可以在 Agent 循环的每个关键节点插入钩子,把中间状态打出来。第二,LCEL 和 Agent 之间的割裂,以前用 LCEL 写的链很难直接塞进 Agent 里当工具用,现在通过统一的Runnable接口,链和工具可以互相转换。第三,状态管理混乱,旧版靠memory对象,多轮对话一长就丢上下文,LangGraph 的引入让状态变成了显式的、可持久化的图结构。

适合谁来学这套东西?我的判断是:如果你只是想让模型调用一两个 API 做个 demo,其实用原生 SDK 就够了,LangChain 反而增加理解成本。但如果你要做的场景涉及多步骤推理、多工具协同、需要人工介入审批、需要断点续跑、需要把整个执行过程可视化追踪,那 LangChain v1.0 加 LangGraph 这套组合是目前 Python 生态里比较成熟的选择。特别是做工业智能体、复杂工作流自动化的团队,这套东西能帮你省掉大量自己造轮子的时间。

1.1 LangChain、LangGraph、LCEL 三者的分工关系

很多人搞不清楚这三个东西到底谁管什么,我用一个类比来说明。假设你要开一家餐厅:

  • LCEL是菜谱,它定义了“先切菜、再炒、最后装盘”这种线性流程,每一步的输出是下一步的输入,语法上用管道符|串起来,非常直观。
  • LangChain是厨房里的设备和食材供应商,它提供统一的接口去调用不同品牌的灶台(各种大模型)、冰箱(向量库)、刀具(工具函数)。
  • LangGraph是餐厅的运营管理系统,它管的是“如果客人不满意就退回重做”“同时开三个灶台做不同菜”“某个菜需要等另一个菜做完才能上”这种带分支、带循环、带并行、带状态的复杂调度。

在 v1.0 里,这三者的边界非常清晰。你写一个简单的问答链,用 LCEL 就够了,不需要碰 LangGraph。你要做一个能自己决定调用哪个工具、调用几次、失败了怎么重试的 Agent,那就用create_agent,它内部已经帮你把 LangGraph 的图搭好了。你要做的是一个多 Agent 协作系统,每个 Agent 有自己的职责,之间还要传递消息和共享状态,那就直接上手 LangGraph,用它的StateGraph自己画流程图。

注意:v1.0 之后,官方文档里AgentExecutor已经被标记为 legacy,新项目不要再用了。如果你在网上搜到旧教程还在讲AgentExecutor,那套代码在 v1.0 里虽然还能跑,但很多新特性用不上,建议直接看新版文档。

1.2 为什么 v1.0 要引入中间件机制

中间件这个词在 Java 微服务里很常见,比如 Spring Boot 的 Filter、Nacos 的配置监听,本质都是在主流程的某个切面上插入自定义逻辑。LangChain v1.0 把这个概念搬过来,解决的是 Agent 执行过程中的可观测性和可干预性问题。

在没有中间件之前,Agent 的一次完整执行是这样的:你给它一个任务,它内部循环“思考→选工具→执行工具→看结果→再思考”,直到得出最终答案。整个过程对你来说是个黑盒,你只能看到最后的输出。如果中间某一步工具调用失败了,你只能从最终的错误信息里猜是哪一步出了问题。

有了中间件之后,你可以在这些节点插入钩子:

  • before_model:模型调用之前,你可以修改提示词、注入额外上下文、做输入校验。
  • after_model:模型返回之后,你可以检查它选的工具是否合法、是否需要强制修正。
  • before_tool:工具执行之前,你可以做权限检查、参数脱敏、记录审计日志。
  • after_tool:工具执行之后,你可以对结果做后处理、缓存、异常兜底。

这套机制在实际项目里非常有用。比如你做的是一个工业设备控制 Agent,工具调用会真实地操作物理设备,那你在before_tool里加一道人工审批中间件,所有危险操作必须等人工确认后才能执行。再比如你做的是客服 Agent,在after_model里加一个敏感词过滤中间件,模型生成的回复先过一遍过滤器再发给用户。

2. create_agent 的核心参数与实操拆解

create_agent是 v1.0 里最核心的入口函数,它的签名看起来简单,但每个参数背后都有讲究。我先把一个最小可运行的例子摆出来,然后逐个拆解。

from langchain.agents import create_agent from langchain_openai import ChatOpenAI from langchain_core.tools import tool @tool def get_weather(city: str) -> str: """查询指定城市的天气""" return f"{city}今天晴,气温25度" model = ChatOpenAI(model="gpt-4o", temperature=0) agent = create_agent( model=model, tools=[get_weather], system_prompt="你是一个天气助手,用中文回答用户问题。", ) result = agent.invoke({"messages": [{"role": "user", "content": "北京天气怎么样"}]}) print(result["messages"][-1].content)

这段代码跑起来之后,Agent 会自动判断需要调用get_weather工具,传入city="北京",拿到结果后再组织语言回复用户。整个过程不需要你手动写循环,create_agent内部已经用 LangGraph 搭好了一个标准的 ReAct 图。

2.1 model 参数:不只是传一个模型对象

model参数接受的是BaseChatModel的实例,但不同模型的能力差异会直接影响 Agent 的行为。比如 GPT-4o 支持原生 tool calling,Agent 会优先用模型自带的工具调用能力;而一些开源模型如果不支持 tool calling,Agent 会退化成用提示词解析的方式来决定调哪个工具。

这里有个坑我踩过:temperature 设成 0 并不保证每次选同一个工具。因为工具选择本质上是一个分类任务,模型在概率接近的时候仍然会有随机性。如果你需要严格可复现的工具调用,除了 temperature=0,还要在中间件里加一层校验,或者在 system_prompt 里把工具选择的规则写死。

另外,v1.0 支持传入一个模型列表做 fallback。比如主模型用 GPT-4o,备用模型用 Claude,当主模型调用失败或者超时,自动切到备用模型。这个配置在create_agent里通过model参数传一个列表实现,底层会按顺序尝试。

2.2 tools 参数:工具定义的质量决定 Agent 的上限

工具是 Agent 的手和脚,工具定义写得好不好,直接决定 Agent 能不能正确使用它们。我见过太多项目,Agent 表现差不是因为模型不行,而是因为工具描述写得太烂。

一个高质量的工具定义包含三个要素:

  1. 函数名要语义明确:get_weather比func1好一万倍,模型靠名字做第一轮筛选。
  2. docstring 要写清楚用途和参数含义:模型会读 docstring 来决定什么时候调用这个工具。如果你的 docstring 只写“查询天气”,模型可能不知道要不要传城市参数。
  3. 参数类型标注要准确:用str、int、Literal这些类型,模型会据此生成合法的参数。如果参数是枚举值,用Literal["北京", "上海", "广州"]比str好,能大幅降低模型传错参数的概率。
from typing import Literal from langchain_core.tools import tool @tool def query_order( order_id: str, action: Literal["查询状态", "申请退款", "修改地址"] ) -> str: """根据订单号执行指定操作。 Args: order_id: 订单编号,格式为 ORD 开头的12位字符串 action: 要执行的操作类型,只能是查询状态、申请退款、修改地址三者之一 """ # 实际业务逻辑 return f"订单{order_id}的{action}操作已完成"

这个工具定义里,Literal类型让模型只能在三个选项里选,避免了它自由发挥传一个“取消订单”这种不存在的操作。docstring 里明确写了订单号的格式,模型在生成参数时会尽量遵守。

实操心得:工具数量超过 10 个之后,模型的工具选择准确率会明显下降。这时候有两个优化方向,一是用中间件做工具的动态筛选,根据用户输入先召回最相关的几个工具再传给模型;二是用 LangGraph 做分层路由,先让一个轻量模型判断任务类型,再路由到对应的工具子集。

2.3 system_prompt 参数:Agent 的行为准则

system_prompt不是随便写一句“你是一个助手”就完事了。它是 Agent 的宪法,决定了 Agent 的角色、边界、输出格式和异常处理策略。我通常会把 system_prompt 分成四个部分来写:

  • 角色定义:你是谁,你的职责范围是什么。
  • 工具使用规则:什么情况下必须调用工具,什么情况下不能调用,工具调用失败后怎么处理。
  • 输出格式要求:最终回复用什么格式,是否需要结构化输出。
  • 安全边界:哪些操作绝对不能做,遇到不确定的情况怎么处理。

举个例子,一个电商客服 Agent 的 system_prompt 可能是这样的:

你是一个电商平台的客服助手,负责处理用户的订单咨询和售后请求。 工具使用规则: - 用户询问订单状态时,必须先调用 query_order 工具查询,不能凭记忆回答。 - 用户申请退款时,先查询订单状态,只有状态为"已发货"或"已完成"的订单才能申请退款。 - 如果工具返回错误,向用户说明情况并建议稍后重试,不要编造结果。 输出格式: - 用简洁的中文回复,不超过三句话。 - 涉及金额时保留两位小数。 安全边界: - 不讨论与订单无关的话题。 - 不透露其他用户的订单信息。

这种颗粒度的 system_prompt 能显著降低 Agent 的幻觉和越界行为。实测下来,同样的模型和工具,system_prompt 写得好,任务成功率能从 60% 提到 85% 以上。

2.4 中间件参数:v1.0 最值得花时间研究的部分

中间件在create_agent里通过middleware参数传入,是一个列表,按顺序执行。v1.0 内置了几种常用的中间件,也支持自定义。

内置中间件里我用得最多的是这几个:

  • HumanInTheLoopMiddleware:在指定工具调用前暂停,等待人工审批。做危险操作时必加。
  • SummarizationMiddleware:当对话历史太长时,自动摘要压缩,避免超出模型上下文窗口。
  • ToolRetryMiddleware:工具调用失败时自动重试,可以配置重试次数和退避策略。

自定义中间件的写法是继承AgentMiddleware基类,实现对应的钩子方法。下面是一个记录工具调用日志的中间件示例:

from langchain.agents.middleware import AgentMiddleware class AuditLogMiddleware(AgentMiddleware): def before_tool(self, state, tool_name, tool_input): print(f"[审计] 准备调用工具: {tool_name}, 参数: {tool_input}") return state def after_tool(self, state, tool_name, tool_output): print(f"[审计] 工具 {tool_name} 返回: {tool_output}") return state

这个中间件看起来简单,但在生产环境里非常关键。所有工具调用都有日志留痕,出了问题可以回溯。我在一个金融项目里就是靠这个中间件定位到模型在某次调用中传错了参数,导致查询了错误的账户。

3. LCEL 链式组合的实战用法

LCEL 是 LangChain Expression Language 的缩写,核心思想是用管道符把多个Runnable串起来,前一个的输出作为后一个的输入。它的语法极简,但能表达的能力很丰富。

3.1 从最简单的链开始理解 LCEL

from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser prompt = ChatPromptTemplate.from_template("用一句话解释{concept}") model = ChatOpenAI(model="gpt-4o") parser = StrOutputParser() chain = prompt | model | parser result = chain.invoke({"concept": "量子纠缠"}) print(result)

这个链的执行流程是:prompt 接收字典输入,渲染成消息列表;model 接收消息列表,返回 AIMessage;parser 接收 AIMessage,提取文本内容。每一步都是独立的Runnable,可以单独测试,也可以自由组合。

LCEL 最大的好处是自动支持流式输出、批量处理和异步调用。你不需要改任何代码,chain.invoke换成chain.stream就变成流式,换成chain.batch就变成批量,换成chain.ainvoke就变成异步。这是旧版 Chain 类做不到的。

3.2 用 RunnableParallel 做并行分支

有时候你需要同一个输入同时走多条链,最后把结果合并。比如用户输入一段文本,你既要提取关键词,又要做情感分析,还要生成摘要。这三件事互不依赖,可以并行跑。

from langchain_core.runnables import RunnableParallel keyword_chain = ChatPromptTemplate.from_template("提取关键词:{text}") | model | parser sentiment_chain = ChatPromptTemplate.from_template("判断情感倾向:{text}") | model | parser summary_chain = ChatPromptTemplate.from_template("生成摘要:{text}") | model | parser parallel_chain = RunnableParallel( keywords=keyword_chain, sentiment=sentiment_chain, summary=summary_chain, ) result = parallel_chain.invoke({"text": "..."}) # result 是一个字典,包含 keywords、sentiment、summary 三个键

RunnableParallel会并发执行三条链,总耗时取决于最慢的那条,而不是三条之和。这在处理长文本分析时能省不少时间。

3.3 用 RunnableBranch 做条件路由

条件路由的场景很常见:根据用户输入的类型,走不同的处理链。比如用户输入如果是问题就走问答链,如果是投诉就走投诉处理链,如果是闲聊就走闲聊链。

from langchain_core.runnables import RunnableBranch qa_chain = ChatPromptTemplate.from_template("回答问题:{input}") | model | parser complaint_chain = ChatPromptTemplate.from_template("处理投诉:{input}") | model | parser chat_chain = ChatPromptTemplate.from_template("闲聊回复:{input}") | model | parser router = RunnableBranch( (lambda x: "投诉" in x["input"], complaint_chain), (lambda x: "?" in x["input"] or "?" in x["input"], qa_chain), chat_chain, # 默认分支 ) result = router.invoke({"input": "我要投诉订单延迟"})

RunnableBranch按顺序检查条件,第一个为真的分支被执行,都不满足就走默认分支。这个机制比在 prompt 里让模型自己判断要可靠得多,因为路由逻辑是确定性的代码,不受模型随机性影响。

注意事项:RunnableBranch的条件函数接收的是整个输入字典,不是上一步的输出。如果你需要根据上一步的输出做路由,要先用RunnablePassthrough.assign把中间结果存到字典里。

3.4 LCEL 和 Agent 的互相转换

v1.0 里,LCEL 链可以直接当工具塞给 Agent 用。比如你有一个用 LCEL 写的翻译链,想让它成为 Agent 的一个工具:

from langchain_core.tools import tool translate_chain = ChatPromptTemplate.from_template("把以下内容翻译成英文:{text}") | model | parser @tool def translate(text: str) -> str: """把中文翻译成英文""" return translate_chain.invoke({"text": text}) agent = create_agent(model=model, tools=[translate])

反过来,Agent 本身也是一个Runnable,可以塞进 LCEL 链里。比如你先用一条链做输入预处理,再把处理后的结果交给 Agent:

preprocess_chain = ChatPromptTemplate.from_template("把用户输入改写成标准查询:{input}") | model | parser full_chain = preprocess_chain | agent result = full_chain.invoke({"input": "那个啥,帮我看看明天天气"})

这种组合能力让 LCEL 和 Agent 不再是两个独立的世界,而是可以互相嵌套的积木。

4. LangGraph 状态编排与复杂控制流

LangGraph 是 v1.0 体系里负责“重活”的部分。当你的流程不是简单的线性链,而是有分支、有循环、有并行、有状态持久化需求时,LCEL 就不够用了,得上 LangGraph。

4.1 StateGraph 的基本结构

LangGraph 的核心是StateGraph,它由三部分组成:状态定义、节点、边。

from langgraph.graph import StateGraph, START, END from typing import TypedDict class AgentState(TypedDict): messages: list next_step: str def node_a(state: AgentState): return {"messages": state["messages"] + ["经过节点A"]} def node_b(state: AgentState): return {"messages": state["messages"] + ["经过节点B"]} graph = StateGraph(AgentState) graph.add_node("a", node_a) graph.add_node("b", node_b) graph.add_edge(START, "a") graph.add_edge("a", "b") graph.add_edge("b", END) app = graph.compile() result = app.invoke({"messages": [], "next_step": ""})

状态是一个TypedDict,每个节点接收当前状态,返回一个字典表示状态的更新。LangGraph 会自动把更新合并到全局状态里。默认的合并策略是覆盖,但你可以用Annotated指定自定义的 reducer,比如operator.add表示追加而不是覆盖。

4.2 条件边实现动态路由

条件边是 LangGraph 最强大的特性之一。它允许你根据当前状态动态决定下一步走哪个节点。

def should_continue(state: AgentState) -> str: last_message = state["messages"][-1] if "需要工具" in last_message: return "tool_node" return "end" graph.add_conditional_edges( "agent_node", should_continue, { "tool_node": "tool_node", "end": END, } )

这个机制就是 Agent 循环的本质:模型节点判断是否需要调工具,需要就去工具节点,不需要就结束。create_agent内部搭的图就是这个结构,只不过它帮你封装好了,你不需要自己写。

但当你需要更复杂的控制流时,比如“工具调用失败后先重试两次,还失败就走人工审批节点,审批通过后继续,不通过就结束”,这种逻辑用create_agent表达不了,必须自己用 LangGraph 画。

4.3 状态持久化与断点续跑

LangGraph 支持 checkpoint,可以把每一步的状态存到数据库里。这意味着一个长时间运行的任务可以在中途暂停,过几天再继续跑,状态不会丢。

from langgraph.checkpoint.sqlite import SqliteSaver memory = SqliteSaver.from_conn_string("checkpoints.db") app = graph.compile(checkpointer=memory) config = {"configurable": {"thread_id": "user-123"}} result = app.invoke({"messages": ["开始任务"]}, config) # 中断后重新调用,会从上次的状态继续 result = app.invoke({"messages": ["继续"]}, config)

这个特性在做需要人工介入的审批流时特别有用。Agent 执行到需要审批的节点,把状态存下来,等人工在后台系统里点了通过,再用同一个thread_id恢复执行。

实操心得:checkpoint 的存储后端选择要根据场景来。开发阶段用 SQLite 就够了,生产环境建议用 PostgreSQL,因为并发写入更稳定。如果状态数据量大,还要考虑定期清理旧的 checkpoint,不然数据库会膨胀得很快。

4.4 LangGraph 和 LangChain 的边界怎么划

我自己的判断标准是:如果流程可以用“输入→处理→输出”的线性方式描述,用 LCEL;如果需要“根据中间结果决定下一步做什么”,用 LangGraph。

具体来说,以下场景必须用 LangGraph:

  • 需要循环执行直到满足某个条件(比如 Agent 的多轮工具调用)。
  • 需要并行执行多个分支再合并结果。
  • 需要人工审批节点,流程要暂停等待。
  • 需要状态持久化,支持断点续跑。
  • 多个 Agent 之间需要协作和消息传递。

而以下场景用 LCEL 就够了:

  • 简单的提示词模板加模型调用。
  • 固定的多步骤处理流程,步骤之间没有条件分支。
  • 需要流式输出或批量处理的场景。

5. 常见问题排查与避坑指南

这一部分是我在实际项目里踩过的坑和总结出来的排查思路,网上大部分教程不会讲这些。

5.1 工具调用失败的高频原因

问题现象可能原因排查方法解决方案
模型不调用工具,直接编答案工具描述不清晰,或 system_prompt 没要求必须调用打印模型返回的 tool_calls 字段在 system_prompt 里明确“必须先调用工具查询”
工具参数格式错误参数类型标注不准确检查工具的 args_schema用 Pydantic 模型定义参数,加 Literal 约束
工具调用后 Agent 不继续工具返回值格式不对检查工具返回的是否为字符串或可序列化对象工具统一返回字符串,复杂结构先 json.dumps
多个工具之间选择混乱工具功能重叠,描述相似打印每次调用的工具名合并功能相似的工具,或加中间件做动态筛选

5.2 上下文窗口超限的处理策略

多轮对话一长,消息列表就会超出模型的上下文窗口。v1.0 提供了几种处理方式:

  • SummarizationMiddleware:自动把旧消息摘要成一段话,保留最近几条原始消息。配置简单,效果稳定。
  • 手动裁剪:在中间件里根据 token 数裁剪消息列表,只保留最近 N 条。
  • 向量检索:把历史消息存到向量库,每次根据当前问题检索最相关的几条塞回去。

我一般用 SummarizationMiddleware 打底,再配合手动裁剪做兜底。摘要中间件的触发阈值要设得比模型窗口小一些,留出空间给工具返回结果。

5.3 流式输出在 Agent 场景下的特殊处理

Agent 的流式输出比普通链复杂,因为中间夹杂着工具调用。你看到的流可能先是模型的一段思考文本,然后是一个工具调用请求,然后工具执行结果,然后又是模型文本。v1.0 的astream_events可以让你精确地区分这些事件类型:

async for event in agent.astream_events(input, version="v2"): kind = event["event"] if kind == "on_chat_model_stream": print(event["data"]["chunk"].content, end="") elif kind == "on_tool_start": print(f"\n[调用工具: {event['name']}]") elif kind == "on_tool_end": print(f"[工具返回: {event['data']['output']}]")

这样你可以在前端把工具调用的过程也展示出来,用户能看到 Agent 在做什么,体验比只显示最终答案好很多。

5.4 模型选择与成本控制

Agent 场景下 token 消耗比普通对话大得多,因为每次工具调用都要把完整的消息历史重新发给模型。一个五轮工具调用的任务,token 消耗可能是普通对话的十倍。

控制成本的几个手段:

  • 用便宜模型做路由:先用一个小模型判断任务类型,简单任务直接处理,复杂任务才转给大模型。
  • 工具返回结果精简:工具返回的内容越短,后续模型调用的 token 越少。不要把整个数据库查询结果塞回去,只返回关键字段。
  • 设置 max_iterations:限制 Agent 的最大循环次数,防止它陷入死循环烧 token。
  • 缓存重复调用:相同的工具调用参数,结果可以缓存,避免重复执行。

注意:max_iterations设得太小会导致复杂任务做不完,设得太大又浪费 token。我的经验值是 10 到 15 之间,具体看任务复杂度调整。

5.5 调试 Agent 的实用技巧

Agent 出问题的时候,最有效的调试手段是把完整的消息历史打出来。v1.0 的返回结果里messages字段包含了每一轮的 HumanMessage、AIMessage、ToolMessage,按顺序看一遍就能定位问题。

result = agent.invoke({"messages": [{"role": "user", "content": "..."}]}) for msg in result["messages"]: print(f"[{msg.__class__.__name__}] {msg.content[:200]}") if hasattr(msg, "tool_calls") and msg.tool_calls: print(f" 工具调用: {msg.tool_calls}")

另一个技巧是用 LangSmith 做追踪。它能把整个执行过程可视化,每个节点的输入输出、耗时、token 消耗都看得到。虽然要额外配置,但在排查复杂问题时能省大量时间。

6. 从学习到落地的路径建议

学 LangChain v1.0 最容易走的弯路是一上来就啃文档,把每个 API 都看一遍,结果看完还是不知道怎么写项目。我的建议是以项目驱动学习,先定一个你想做的场景,然后缺什么补什么。

如果你是完全新手,按这个顺序走:

  1. 先用 LCEL 写一个最简单的问答链,理解prompt | model | parser这个模式。
  2. 加一个工具,用create_agent做一个能调用工具的 Agent。
  3. 给 Agent 加一个中间件,观察中间件的执行时机。
  4. 用 LangGraph 手写一个带条件分支的图,理解状态和边的概念。
  5. 把前面写的东西组合起来,做一个完整的小项目。

如果你已经有旧版 LangChain 的经验,重点看三个地方:create_agent的新参数、中间件机制、LangGraph 的状态管理。旧版的AgentExecutor、initialize_agent、ConversationBufferMemory这些都可以忘掉了。

最后分享一个我在实际项目里的体会:不要为了用框架而用框架。LangChain v1.0 的能力很强,但它的抽象层也厚。如果你的场景很简单,直接用模型 SDK 可能更直接。框架的价值在于处理复杂性,当你的流程复杂到需要状态管理、需要中间件、需要可视化追踪的时候,它才真正发挥作用。判断标准很简单:如果你发现自己开始手写循环、手写状态机、手写重试逻辑,那就是该上 LangGraph 的时候了。

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

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

立即咨询