LangChain+LangGraph实战:从Agent到可控工作流

LangChain + LangGraph 核心组件:从 Agent 封装到可控工作流

文 | AI 编程实战笔记

很多人第一次接触 LangChain,看到的公式是:

复制代码
用户消息 → Model → Tools → Model → 最终答案

这条链路没有错,但它只解释了 Agent 的"主循环",没有解释谁负责切换模型、校验权限、保存对话、处理工具异常,以及在高风险操作前暂停等待人工审批。

更完整的理解应该是:

复制代码
Agent = Model + Harness

Model:
  负责理解、推理和决定下一步动作

Harness:
  Tools + Prompt + Middleware + Context + State + Memory + Runtime

LangChain 负责把这些常用能力封装成容易使用的 Agent API;LangGraph 则把 Agent 进一步展开成状态、节点、边、分支、循环和中断,让开发者精确控制执行过程。

本文会先拆解 LangChain 的 Model、Tool、response format、middleware 和 runtime,再用 State、Node、Edge 解释 LangGraph,最后用 Python 和真实 OpenAI API 跑通一个"识别城市 → 查询天气"的最小 ReAct Agent。

本文 API 根据 2026 年 8 月 LangChain 与 LangGraph 官方 Python 文档整理。两个框架更新较快,旧教程中的 initialize_agentAgentExecutor 等写法,不代表当前推荐入口。


一、先看入口:create_agent 到底创建了什么

当前 LangChain 构建 Agent 的核心入口是 create_agent

复制代码
from langchain.agents import create_agent

agent = create_agent(
    model=model,
    tools=tools,
    system_prompt="你是一个天气助手",
    middleware=middleware,
    response_format=WeatherAnswer,
    checkpointer=checkpointer,
    context_schema=UserContext,
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "杭州今天天气如何?"}]},
    config={"configurable": {"thread_id": "weather-001"}},
    context={"user_id": "u-1001", "role": "member"},
)

这里的 create_agent 并不是立即执行一次模型调用,而是组装出一套可执行框架。真正开始运行的是 agent.invoke()

复制代码
配置阶段:
  model + tools + prompt + middleware
  + response_format + checkpointer + context_schema
  ↓
create_agent:
  编译 Agent 执行图
  ↓
agent.invoke:
  注入本轮 messages、config 和 context
  ↓
运行阶段:
  Model 判断 → Tool 执行 → Observation 回填 → Model 再判断
  ↓
结束阶段:
  返回 messages、结构化结果和更新后的状态

一个容易忽略的事实是:create_agent 底层运行在 LangGraph 上。它返回的不是一个简单函数,而是一张已经编译好的图,因此天然支持 invokestream、状态持久化和中断恢复。

💡 关键洞察 :LangChain 的 create_agent 是预制好的 Agent Harness;LangGraph 是支撑这套 Harness 的图运行时,也是需要精细控制流程时可以直接使用的底层编排能力。


二、Model:用统一接口屏蔽不同模型供应商

Model 是 Agent 的推理引擎。它负责阅读消息和工具定义,判断应该直接回答,还是生成一个或多个 tool call。

LangChain 的价值不是"提供一个模型",而是为不同 Provider 提供相对统一的调用接口:

复制代码
from langchain.chat_models import init_chat_model

model = init_chat_model(
    "openai:gpt-4.1-mini",
    temperature=0,
    timeout=30,
    max_retries=3,
)

如果换成 Anthropic,Agent 上层调用方式基本不变:

复制代码
model = init_chat_model(
    "anthropic:claude-sonnet-4-6",
    temperature=0,
    timeout=30,
    max_retries=3,
)

Model 层可以拆成三部分:

部分 作用 示例
Provider 提供模型服务的厂商或平台 OpenAI、Anthropic、Google、Azure
Model Object 统一的模型调用对象 init_chat_model()ChatOpenAI()
调用策略 控制稳定性与流量分配 temperature、timeout、retry、route、fallback

temperaturetimeoutmax_retries 属于模型对象的基础配置;动态路由、fallback、缓存等更适合放在 middleware 的 wrap_model_call 中。因为路由通常需要结合本轮状态判断,而不是在 Agent 创建时永久写死。

例如:普通问答走小模型,长上下文或高风险任务走强模型;主模型超时后重试,仍失败再切换备用模型。

💡 关键洞察:Model 统一接口解决"怎么调用模型",middleware 解决"这一轮到底调用哪个模型,以及失败后怎么办"。


三、Tool:让普通函数成为模型可选择的动作

Tool 的本质,是把一个普通函数包装成模型能够理解和调用的动作。

一个完整 Tool 通常包含四部分:

字段 模型如何使用 天气工具示例
name 区分工具,生成 tool call 时指定名称 get_weather
description 判断什么时候调用、能解决什么问题 查询指定城市的天气
schema 生成参数,确定字段、类型和必填项 city: str
function 真正执行查询、写入或计算 调用天气 API 或数据库

最简单的写法是使用 @tool

复制代码
from langchain.tools import tool

@tool
def get_weather(city: str) -> dict:
    """查询指定城市的当前天气。仅在已经获得标准城市名后调用。"""
    return {
        "city": city,
        "temperature_c": 26,
        "condition": "晴",
    }

函数名默认成为 Tool name,docstring 成为 description,类型注解生成参数 schema。

复杂参数可以用 Pydantic 显式定义:

复制代码
from pydantic import BaseModel, Field

class WeatherInput(BaseModel):
    city: str = Field(description="标准城市名,例如:杭州")
    unit: str = Field(default="celsius", description="温度单位")

这里需要纠正一个常见误解:模型通常看不到函数源码,也不会阅读 Python 或 TypeScript 里的业务实现。

复制代码
模型能够看到:
  - name
  - description
  - 参数 schema

模型通常看不到:
  - function source code
  - Python 内部实现
  - TypeScript 函数内部逻辑
  - Zod 校验器的源码

在 TypeScript 中常用 Zod 定义 schema,但模型接收到的是转换后的 JSON Schema,不是 Zod 源码。真正决定工具是否容易被正确调用的,是清晰的名称、准确的 description 和不过度复杂的参数结构。

还有一个工程细节:某些参数只供运行时使用,例如 ToolRuntime。这些参数由系统注入,不会暴露给模型,因此可以安全地传递用户身份、当前 State、Store 或 tool call ID。


四、response_format:结构化输出不是"提醒模型返回 JSON"

如果 Agent 的结果还要交给程序消费,仅让模型"请返回 JSON"通常不够稳定。模型可能加 Markdown 围栏、漏字段、写错类型,甚至在 JSON 前后补解释。

LangChain 的 response_format 用 schema 定义最终结果:

复制代码
from pydantic import BaseModel, Field

class WeatherAnswer(BaseModel):
    city: str = Field(description="标准城市名")
    temperature_c: int = Field(description="摄氏温度")
    condition: str = Field(description="天气状况")
    suggestion: str = Field(description="一句出行建议")

创建 Agent 时直接传入:

复制代码
agent = create_agent(
    model=model,
    tools=[resolve_city, get_weather],
    response_format=WeatherAnswer,
)

调用结束后从 structured_response 读取:

复制代码
result = agent.invoke({
    "messages": [{"role": "user", "content": "西湖那边今天热吗?"}]
})

print(result["structured_response"])

LangChain 会根据模型能力选择 ProviderStrategy 或 ToolStrategy:模型原生支持结构化输出时,优先使用 ProviderStrategy;否则可以通过工具调用策略生成并校验结构。

复制代码
"返回 JSON":
  只是在 Prompt 中提出文本要求
  程序仍要自行解析和校验

response_format:
  用 Schema 定义字段、类型和约束
  框架负责结构化生成与校验
  结果作为 typed data 交给下游程序

💡 关键洞察:Tool schema 约束的是"Agent 调用动作时输入什么",response format 约束的是"Agent 最终向业务返回什么"。两者不要混为一谈。


五、Middleware:Agent 的执行控制面

如果 Model 是大脑,Tools 是手脚,middleware 就是控制面。

一次 Agent 调用可能经历多轮模型和工具调用:

复制代码
User Message
  → Model Call
  → Tool Call
  → Tool Result
  → Model Call
  → Tool Call
  → Tool Result
  → Model Call
  → Final Answer

Prompt 很难可靠地承担身份校验、超时、重试、工具权限、成本限制和日志追踪。middleware 可以在每一步做确定性的检查、改写、拦截和兜底。

5.1 节点式 hooks:在阶段前后执行一次

节点式 hooks 适合执行阶段级逻辑:

Hook 触发位置 常见用途
before_agent 整次 Agent 启动前 身份校验、初始化运行状态
before_model 每次 Model 调用前 裁剪消息、改写 Prompt、统计调用次数
after_model 每次 Model 返回后 检查输出、识别异常工具调用、统计 Token
after_agent Agent 结束后 保存结果、写 Trace、记录业务指标

注意:before_modelafter_model 可能执行多次,因为 ReAct Agent 会反复回到模型节点。

5.2 包裹式 hooks:接管某一次调用

wrap hooks 类似在目标调用外面包一层控制器:

Hook 包裹对象 适合处理
wrap_model_call 一次模型调用 模型路由、retry、fallback、cache、动态工具集合
wrap_tool_call 一次工具调用 工具权限、参数过滤、日志、超时、失败兜底

例如,工具异常时返回一条可理解的 ToolMessage,而不是让整个 Agent 直接崩溃:

复制代码
from langchain.agents.middleware import wrap_tool_call
from langchain.messages import ToolMessage

@wrap_tool_call
def handle_tool_error(request, handler):
    try:
        return handler(request)
    except Exception as exc:
        return ToolMessage(
            content=f"工具暂时不可用:{exc}",
            tool_call_id=request.tool_call["id"],
        )

生产环境也可以直接使用 ModelRetryMiddlewareToolRetryMiddleware 等预制中间件,不必为通用逻辑重复造轮子。

复制代码
节点式 hook:
  在某个阶段前后增加处理节点

wrap hook:
  接管一次具体调用
  可以决定是否执行、执行几次、换谁执行,以及异常如何返回

middleware 并不是另一个独立运行时。它最终也会成为 create_agent 所编译 LangGraph 中的一部分。


六、Runtime:一次 invoke 运行需要哪些数据

agent.invoke() 不只是传一段 Prompt。一次完整运行通常有三类输入:

输入 生命周期 用途
messages / state 会随流程更新 用户消息、模型回答、工具结果、业务状态
config 控制本次执行 thread_id、callbacks、tags、metadata
context 本次运行只读业务信息 user_id、role、tenant_id、feature_flags

可以把它们记成一句话:

复制代码
State:流程正在处理和修改的数据包
Config:框架如何运行这一次任务
Context:业务系统告诉 Agent"你正在为谁、以什么权限运行"

6.1 context 不是对话记忆

context 适合存放本次运行依赖但不应该由模型随意修改的信息:

复制代码
from dataclasses import dataclass

@dataclass
class UserContext:
    user_id: str
    role: str
    tenant_id: str

创建 Agent 时声明 context_schema,调用时传入 context:

复制代码
agent = create_agent(
    model=model,
    tools=tools,
    context_schema=UserContext,
)

agent.invoke(
    {"messages": [{"role": "user", "content": "查询杭州天气"}]},
    context=UserContext(
        user_id="u-1001",
        role="member",
        tenant_id="t-01",
    ),
)

Tool 或 middleware 可以通过 Runtime 读取这些信息,执行租户隔离或权限判断。

6.2 checkpointer + thread_id 才能保存多轮状态

如果希望第二次调用记住第一次对话,需要给 Agent 配置 checkpointer,并在调用时使用稳定的 thread_id

复制代码
from langgraph.checkpoint.memory import InMemorySaver

checkpointer = InMemorySaver()

agent = create_agent(
    model=model,
    tools=tools,
    checkpointer=checkpointer,
)

config = {"configurable": {"thread_id": "weather-001"}}

相同 thread_id 指向同一条会话状态;换一个 thread_id,就是另一条独立会话。

组件 保存什么 适合场景
Checkpointer 单个 thread 的 State 快照 多轮对话、故障恢复、人工审批
Store 跨 thread 的长期数据 用户偏好、共享知识、长期记忆

示例中的 InMemorySaver 只适合本地演示。进程退出后内容会消失,生产环境应换成数据库支持的持久化 Checkpointer。


七、LangChain 与 LangGraph 到底有什么区别

LangChain 和 LangGraph 不是二选一,也不是简单的"低级框架与高级框架"。两者解决的是不同层面的问题。

对比维度 LangChain LangGraph
核心关注 Model、Tools、middleware、structured output State、Node、Edge、分支、循环、暂停、调度
开发方式 使用封装好的高层 API 快速搭建 Agent 显式设计状态图和执行路径
默认决策 模型根据上下文决定是否调用工具 代码和状态共同决定走哪条边
灵活度 常见 Agent 模式开箱即用 可精确控制每个节点和状态变化
适合场景 问答、检索、工具型助手、标准 ReAct 多分支流程、审批、长任务、复杂恢复逻辑
主要成本 深度定制时可能受到预制循环限制 需要自行设计 State、Node、Edge 和测试
复制代码
优先选择 LangChain:
  目标是快速搭建标准工具调用 Agent
  主流程就是 Model ↔ Tools 循环
  使用 middleware 已能满足控制要求

优先直接使用 LangGraph:
  业务包含多个确定性分支
  需要显式循环、并行、暂停或人工审批
  需要精确保存和恢复每一步状态
  不希望所有流程选择都交给模型

实际项目经常组合使用:用 create_agent 构建一个标准 Agent,再把它作为 LangGraph 中的一个 Node 或 Subgraph。

💡 关键洞察:LangChain 关注"一个 Agent 需要哪些能力",LangGraph 关注"这些能力按照什么状态和路径运行"。


八、State + Node + Edge:把 Agent 展开成一张图

LangGraph 最重要的三个概念是 State、Node 和 Edge:

复制代码
State:运行时携带的数据包
Node:读取 State、执行处理、返回 State 更新的函数
Edge:决定执行完当前 Node 后去哪里

State + Node + Edge = Agent Flow

8.1 State:流程携带的数据包

天气 Agent 的 State 可以包含:

复制代码
from typing_extensions import TypedDict
from langgraph.graph import MessagesState

class WeatherState(MessagesState):
    city: str | None
    weather: dict | None
    retry_count: int

其中:

State 字段 保存内容
messages 用户 Message、模型回答、tool call、ToolMessage
city 标准化后的城市名
weather 工具返回的天气结构
retry_count 查询失败后的重试次数

State 不是一次性 Prompt,而是整张图运行时持续携带和更新的数据。

8.2 Node:流程中的处理步骤

Node 本质上是函数。它读取当前 State,执行一个明确步骤,并返回局部更新:

复制代码
def resolve_city_node(state: WeatherState):
    city = parse_city(state["messages"][-1].content)
    return {"city": city}

def query_weather_node(state: WeatherState):
    weather = weather_api(state["city"])
    return {"weather": weather}

常见 Node 包括:

  • 调用模型

  • 查询工具或数据库

  • 校验结果

  • 人工审核

  • 生成最终答案

Node 应该有清晰职责。一个节点同时查询数据库、调用模型、写文件并发送通知,会让状态恢复和失败重试变得困难。

8.3 Edge:决定下一步去哪里

普通边是固定路线:

复制代码
builder.add_edge("resolve_city", "query_weather")

表示 resolve_city 执行完后,一定进入 query_weather

条件边根据 State 动态选择路径:

复制代码
def route_after_model(state):
    last_message = state["messages"][-1]
    if last_message.tool_calls:
        return "tools"
    return "end"

这正是标准 ReAct Agent 的核心条件:

复制代码
如果模型返回 tool_call:
  进入 Tools Node
  执行工具并把结果写回 messages
  再回到 Model Node

如果模型没有返回 tool_call:
  说明模型准备给出最终答案
  流程进入 END

Model 和 Tools 之间的循环,并不是神秘的"智能涌现",而是条件边和回边共同形成的执行路径。


九、Interrupt:让 Agent 在关键动作前停下来

当流程准备合并代码到 main 分支时,完全自动执行往往风险过高。更合理的流程是:先查询 CR 状态、生成审核建议,再暂停等待人工决定。

在这个案例中:

复制代码
State:
  repo、branch、cr_status、review_summary、approved

Node:
  query_cr、generate_review、human_approval、merge_main、reject

普通 Edge:
  query_cr → generate_review → human_approval

条件 Edge:
  approved = true  → merge_main
  approved = false → reject

LangGraph 使用 interrupt() 暂停:

复制代码
from langgraph.types import interrupt

def human_approval(state: ReviewState):
    approved = interrupt({
        "question": "是否同意合并到 main?",
        "cr_status": state["cr_status"],
        "review_summary": state["review_summary"],
    })
    return {"approved": approved}

为了恢复流程,必须同时具备:

  1. 编译图时配置 Checkpointer。

  2. 首次执行时提供稳定的 thread_id

  3. 恢复时使用同一个 thread_id

  4. 通过 Command(resume=...) 传入人工结果。

    from langgraph.checkpoint.memory import InMemorySaver
    from langgraph.types import Command

    graph = builder.compile(checkpointer=InMemorySaver())
    config = {"configurable": {"thread_id": "merge-20260802-001"}}

    第一次运行,在 interrupt 处暂停

    paused = graph.invoke(initial_state, config=config)

    人工确认后恢复;True 会成为 interrupt() 的返回值

    result = graph.invoke(Command(resume=True), config=config)

需要特别注意:恢复时,包含 interrupt() 的 Node 会从节点开头重新执行。因此,写在 interrupt 前面的数据库写入、扣费、发送消息等副作用必须保证幂等,或者移到审批后的独立 Node。

💡 关键洞察:interrupt 不是"让进程睡眠等待",而是保存 State、结束当前执行,等外部输入到来后再按 thread_id 恢复。


十、实战:用 Python 搭建最小 ReAct 天气 Agent

现在用真实 OpenAI API 跑通一个最小案例。

用户可以说"西湖那边今天热吗",Agent 需要先把地点解析为标准城市"杭州",再调用天气工具,最后返回结构化结果。

为了把注意力放在 Agent 机制上,天气数据使用本地模拟字典;模型调用是真实的 OpenAI API。生产环境只需要把 get_weather 内部替换成真实天气服务。

10.1 安装依赖

复制代码
python -m venv .venv
source .venv/bin/activate
pip install -U langchain langgraph langchain-openai pydantic
export OPENAI_API_KEY="你的 OpenAI API Key"

10.2 完整代码

复制代码
import os
from dataclasses import dataclass

from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.tools import ToolRuntime, tool
from langgraph.checkpoint.memory import InMemorySaver
from pydantic import BaseModel, Field


@dataclass
class UserContext:
    user_id: str
    role: str


class WeatherAnswer(BaseModel):
    city: str = Field(description="标准城市名")
    temperature_c: int = Field(description="当前摄氏温度")
    condition: str = Field(description="天气状况")
    suggestion: str = Field(description="一句简短出行建议")


@tool
def resolve_city(place: str) -> str:
    """把景点、简称或自然语言地点转换成中国标准城市名。

    当用户没有直接提供标准城市名时先调用本工具。
    """
    aliases = {
        "西湖": "杭州",
        "魔都": "上海",
        "羊城": "广州",
        "帝都": "北京",
    }
    return aliases.get(place, place)


@tool
def get_weather(city: str, runtime: ToolRuntime[UserContext]) -> dict:
    """查询标准城市名对应的当前天气。

    只有获得标准城市名后才调用。不要把景点名或城市简称直接传入。
    """
    if runtime.context.role not in {"member", "admin"}:
        raise PermissionError("当前用户没有天气查询权限")

    weather_data = {
        "杭州": {"temperature_c": 31, "condition": "多云"},
        "上海": {"temperature_c": 30, "condition": "小雨"},
        "广州": {"temperature_c": 33, "condition": "晴"},
        "北京": {"temperature_c": 28, "condition": "晴"},
    }
    return {
        "city": city,
        **weather_data.get(
            city,
            {"temperature_c": 25, "condition": "暂无实时数据"},
        ),
    }


model = init_chat_model(
    os.getenv("OPENAI_MODEL", "openai:gpt-4.1-mini"),
    temperature=0,
    timeout=30,
    max_retries=3,
)

agent = create_agent(
    model=model,
    tools=[resolve_city, get_weather],
    system_prompt=(
        "你是天气助手。用户输入景点或城市别名时,先调用 resolve_city;"
        "得到标准城市名后,再调用 get_weather;最后给出简短出行建议。"
    ),
    response_format=WeatherAnswer,
    context_schema=UserContext,
    checkpointer=InMemorySaver(),
)

config = {"configurable": {"thread_id": "weather-demo-001"}}

result = agent.invoke(
    {
        "messages": [
            {"role": "user", "content": "西湖那边今天热吗?"}
        ]
    },
    config=config,
    context=UserContext(user_id="u-1001", role="member"),
)

print(result["structured_response"])

一次典型输出类似:

复制代码
city: 杭州
temperature_c: 31
condition: 多云
suggestion: 天气较热,建议穿轻薄衣物并注意补水。

10.3 这段代码如何形成 ReAct

虽然我们没有手写 while 循环,但 create_agent 已经生成了标准的 Model ↔ Tools 循环:

复制代码
第 1 轮 Model:
  发现"西湖"不是标准城市名
  生成 tool_call: resolve_city(place="西湖")

第 1 次 Tool:
  返回"杭州"
  结果作为 ToolMessage 写回 State

第 2 轮 Model:
  已获得标准城市名
  生成 tool_call: get_weather(city="杭州")

第 2 次 Tool:
  从 Runtime 读取 role
  权限通过后返回结构化天气数据

第 3 轮 Model:
  根据工具结果生成出行建议
  按 WeatherAnswer Schema 返回 structured_response

在这条链路中:

代码元素 对应组件
init_chat_model() Model 统一接口
@tool 函数 Tools
WeatherAnswer response format
UserContext runtime context
InMemorySaver() checkpointer
thread_id 会话状态标识
create_agent() 组装 Harness 并编译执行图
agent.invoke() 启动一次运行

这就是使用 LangChain 的价值:不需要手写 StateGraph,也能获得一个标准 ReAct Agent。

严格来说,这个示例里的 resolve_cityget_weatherTools,不是独立 SKILL。Tool 是模型可以直接调用的函数;SKILL 更像一套可复用的任务说明、步骤、参考资料和脚本。如果要把它升级成"天气查询 SKILL",可以在 SKILL 中规定城市标准化、数据源选择、异常处理和输出格式,再把这两个 Tools 作为执行能力交给 Agent。


十一、什么时候应该把它改写成 LangGraph

上面的天气 Agent 没有必要直接手写 LangGraph,因为它的流程非常标准:Model 判断、调用 Tool、拿到结果、继续判断,直到输出答案。

但如果需求变成下面这样,LangGraph 的价值会明显增加:

复制代码
复杂天气服务:
  1. 先判断用户所在租户和数据权限
  2. 国内城市走供应商 A,海外城市走供应商 B
  3. 查询失败时最多重试两次
  4. 极端天气进入风险评估节点
  5. 高风险预警必须经过人工确认
  6. 确认后同时发送短信和企业消息
  7. 任一步失败都能从检查点恢复

这时,应该把关键业务路径显式建模:

复制代码
State:
  city、country、weather、risk_level、approved、retry_count

Nodes:
  resolve_city、route_provider、query_weather、assess_risk
  human_approval、send_alert、handle_failure

Edges:
  普通边连接固定步骤
  条件边根据 country、risk_level、retry_count 选择路径
  interrupt 在高风险通知前暂停

选择标准不是代码行数,而是业务流程是否需要显式控制。

能用 create_agent + middleware 清楚表达,就先用 LangChain;当状态、分支、循环和人工介入成为业务核心,再直接设计 LangGraph。


十二、生产环境最容易踩的六个坑

12.1 Tool description 写得太宽泛

"查询信息"几乎没有决策价值。应该说明输入前提、调用时机、能力边界和不能做什么。

12.2 把所有控制逻辑塞进 Prompt

权限、超时、重试、预算和审计属于确定性控制,应该进入 middleware、Tool Gateway 或图节点,不应只靠模型自觉遵守。

12.3 混淆 context、state 和 store

context 是本次运行注入的业务依赖;state 是流程中不断更新的数据;store 是跨会话长期保存的数据。混用会导致权限信息被模型修改,或者不同会话互相串数据。

12.4 使用 checkpointer 却忘记 thread_id

Checkpointer 需要通过 thread_id 确定保存和恢复哪条会话。首次执行和恢复执行必须使用同一个 ID。

12.5 interrupt 前执行不可重复的副作用

恢复时节点会从开头重新运行。interrupt 前的扣款、发送消息或数据库写入必须幂等,最好拆到审批后的独立节点。

12.6 无限制地让 Model ↔ Tools 循环

生产 Agent 应限制最大步数、总时长、Token、成本和工具重试次数,并监控重复 tool call。否则一个参数错误就可能演变成高成本死循环。


写在最后

理解 LangChain 和 LangGraph,关键不是记住更多 API,而是分清两个层次:

复制代码
LangChain:
  Model + Tools + Prompt + Middleware
  + Structured Output + Runtime + Memory
  快速搭建一套标准 Agent Harness

LangGraph:
  State + Node + Edge
  + Branch + Loop + Interrupt + Persistence
  精确描述 Agent 如何流转和恢复

create_agent 帮我们快速得到一套成熟的 Model ↔ Tools 循环;middleware 把路由、权限、重试和观测放进执行控制面;runtime 把用户、租户和会话信息带入本次运行;response format 保证结果能被程序可靠消费。

当流程出现复杂分支、长时间运行、人工审批和失败恢复时,再把 Agent 展开为 LangGraph:让 State 携带数据,让 Node 执行步骤,让 Edge 决定路径。

最终,两者不是竞争关系,而是同一套 Agent 工程的不同抽象层。


参考资料

  • LangChain Agents 官方文档

  • LangChain Models 官方文档

  • LangChain Tools 官方文档

  • LangChain Middleware 官方文档

  • LangChain Runtime 官方文档

  • LangChain Structured Output 官方文档

  • LangGraph Persistence 官方文档

  • LangGraph Interrupts 官方文档

相关推荐
2601_949950631 小时前
练题簿:把备考资料装进小程序,随时开启高效在线刷题
人工智能·小程序·刷题·练习·小程序推荐
nagualky1231 小时前
AI Agent上线后怎么升级?先建立一套可回滚的变更控制
人工智能·机器学习·语言模型·软件工程
浅思科技集1 小时前
AI软件工厂是什么?2026年企业如何构建智能化软件研发体系?
人工智能
码农学院1 小时前
零售电商GEO踩坑复盘:商品列表页懒加载让 AI 爬虫只抓到八分之一的商品,前端改造全程记录
人工智能·geo优化·ai优化aio
IT_陈寒1 小时前
Java序列化坑了我三天,原来问题出在这个默认方法
前端·人工智能·后端
YOLO数据集集合1 小时前
渔船船只检测数据集 | 船只检测 渔船识别 拖船检测 海事监管 目标检测 YOLO格式 深度学习数据集 计算机视觉9076期
人工智能·深度学习·yolo·目标检测·计算机视觉
stereohomology1 小时前
一个可能有用的经验:api key在Workbuddy或Trae IDE上使用
人工智能·llm·薅羊毛
小刘快学习1 小时前
企业提示词资产如何集中治理:AI网关的提示词管理能力
人工智能
刘天远1 小时前
Agent最小权限实现:策略表、临时令牌与撤权回归
java·jvm·人工智能·sqlite