篇三:从手写循环到 LangGraph —— 把 Agent 循环交给框架

第一篇我们搞清楚了 Agent 是什么(大模型 + 工具调用能力),第二篇我们手写了那个"模型决策 + 代码执行"的循环。这一篇我们要把那个循环交给框架------看看 LangGraph 是怎么封装它的。

先放结论:LangGraph 不是另一个框架,它就是 LangChain Agent 的运行时引擎。 LangChain 1.0 的 create_agent 底层直接跑在 LangGraph 上,两者的关系从"二选一"变成了"分层协作":LangChain 帮你快速搭起来,LangGraph 帮你可靠跑下去。

为什么手写循环不够用

第二篇那个 for 循环,逻辑上完全正确:

ini 复制代码
for (let round = 0; round < maxRounds && response.tool_calls?.length; round++) {
    messages.push(response);
    for (const call of response.tool_calls) {
        const result = await readFileTool.invoke(call.args);
        messages.push(new ToolMessage({ content: result, tool_call_id: call.id }));
    }
    response = await modelWithTools.invoke(messages);
}

但它有几个硬伤:

  • 状态是隐式的messages 数组就是全部状态,没有结构、没有类型约束,多节点协作时很容易乱
  • 没有持久化:程序一崩溃,全部重来,没法从断点恢复
  • 没法人工介入:如果某个工具调用需要人审批(比如删数据库),手写循环很难优雅地暂停
  • 没法并行:如果模型同时请求调两个工具,手写循环只能串行执行
  • 调试困难 :出了问题只能靠 console.log,没有可视化、没有执行轨迹

LangGraph 解决的就是这些问题。

LangGraph 的三个核心概念

LangGraph 把 Agent 工作流建模成一张有向图,由三个元素组成:

State(状态) :整个图共享的数据容器。不是每个节点自己存一份,而是所有节点读写同一个中央状态。状态更新时用 Reducer 决定合并策略------比如 messages 字段用 operator.add 追加而不是覆盖,这样多轮对话历史就不会丢。

Node(节点) :最小执行单元,就是一个函数。输入是当前 State,返回状态更新(不是完整状态,是增量)。LLM 调用是一个节点,工具执行是一个节点,条件路由也可以是一个节点。

Edge(边) :定义节点之间的跳转规则。普通边是固定下一步(A → B),条件边根据 State 动态决定去向(如果还有 tool_calls 就去工具节点,否则去结束节点)。条件边是实现循环的关键------工具节点执行完后,条件边检查状态,把流程指回 LLM 节点,形成"思考 → 行动 → 观察 → 再思考"的闭环。

用 LangGraph 重写第二篇的 Agent

javascript 复制代码
import { StateGraph } from '@langgraph/graph';
import { END } from '@langgraph/graph';

// 1. 定义 State
const AgentState = {
    messages: {
        value: (x, y) => x.concat(y), // Reducer:追加
        default: () => [],
    },
};

// 2. 定义节点
async function modelNode(state) {
    const response = await modelWithTools.invoke(state.messages);
    return { messages: [response] };
}

async function toolsNode(state) {
    const lastMessage = state.messages[state.messages.length - 1];
    const results = [];
    for (const call of lastMessage.tool_calls) {
        const result = await readFileTool.invoke(call.args);
        results.push(new ToolMessage({
            content: result,
            tool_call_id: call.id,
        }));
    }
    return { messages: results };
}

// 3. 条件边:决定下一步去哪
function route(state) {
    const lastMessage = state.messages[state.messages.length - 1];
    if (lastMessage.tool_calls?.length) {
        return 'tools';
    }
    return END;
}

// 4. 构建图
const workflow = new StateGraph({ channels: AgentState });
workflow.addNode('model', modelNode);
workflow.addNode('tools', toolsNode);
workflow.setEntryPoint('model');
workflow.addEdge('tools', 'model');
workflow.addConditionalEdges('model', route);

// 5. 编译运行
const app = workflow.compile();
const result = await app.invoke({
    messages: [
        new SystemMessage('你是一个专业的代码助手...'),
        new HumanMessage('请读取 tool.mjs 并解释代码'),
    ],
});

看起来代码量差不多,但底层能力完全不同:

  • 状态是显式的AgentState 定义了结构,Reducer 保证了消息追加不会覆盖
  • 天然支持持久化 :加一个 checkpointer 就能自动存状态,程序崩溃后从断点恢复
  • 天然支持人工介入 :在任意节点抛 interrupt(),图就暂停,等人审批后继续
  • 天然支持并行:如果模型同时返回多个 tool_calls,LangGraph 可以并行执行工具节点
  • 可视化调试:LangGraph Studio 可以实时看到图的执行轨迹和状态快照

LangChain 1.0 的 create_agent

如果你觉得上面建图还是麻烦,LangChain 1.0 提供了一个更高层的 API:

php 复制代码
import { createAgent } from '@langchain/core/agents';

const agent = createAgent({
    model: modelWithTools,
    tools: [readFileTool],
    systemPrompt: '你是一个专业的代码助手...',
});

const result = await agent.invoke({
    messages: [new HumanMessage('请读取 tool.mjs 并解释代码')],
});

一行建图,内部自动帮你搭好了 model 节点、tools 节点、条件边、循环逻辑。create_agent 返回的就是一个编译好的 LangGraph 图,你可以直接用它,也可以继续往图上加节点。

四层循环栈:从"会做事"到"做得稳"

LangChain 官方博客把 Agent 的工程栈拆成了四层循环,这是很多人第一次理解"生产级 Agent"时看到的形态:

第一层 Agent Loop:就是我们前面一直在讲的"调用模型 → 检查工具 → 执行工具 → 重复"。这是基础,没有这一层 Agent 就只是一轮问答。

第二层 Verification Loop(验证循环) :在 Agent 输出后加一个校验器(Grader),用明确的标准检查结果:链接能不能打开?CI 是否通过?修改范围有没有超出需求?检查不通过就把失败原因带回给 Agent,让它修一轮。这层会增加延迟和成本,但在生产场景里通常值得。

第三层 Event-driven Loop(事件驱动循环) :解决"谁来启动它"的问题。任务来自外部事件:webhook 触发、cron 定时、Slack 频道里有人发消息。Agent 从被临时调用的脚本,变成了系统里长期运行的组件。

第四层 Learning Loop(学习循环) :从运行记录里改进。分析哪些工具调用成功了、哪些失败了、哪些提示词效果更好,持续优化 Agent 的行为策略。

小结

  • LangGraph 是 LangChain Agent 的运行时 ,不是另一个框架。LangChain 1.0 的 create_agent 底层跑在 LangGraph 上
  • 三个核心概念:State(共享状态)、Node(执行单元)、Edge(控制流),条件边是实现循环的关键
  • 四层循环栈:Agent Loop → Verification Loop → Event-driven Loop → Learning Loop,从"会做事"到"做得稳"

第二篇我们让模型能"做",这一篇我们让"做"变得可靠。下一篇我们聊聊记忆------怎么让 Agent 记住之前说过什么、做过什么。

相关推荐
4SAPI1 小时前
大模型接口管理平台推荐:多模型时代的API Gateway架构与选型分析
人工智能·agent
Luhui Dev2 小时前
大模型 Token 与成本优化工程指南
人工智能·ai·agent·luhuidev
星火10243 小时前
【从 0 到 1 动手造 Agent】(组件篇)06、向量库:让 Agent 按「意思」找东西
人工智能·agent
蜡台3 小时前
AI Agent:大模型基础、底层架构与核心工作原理(深度技术拆解)
ai·agent
Raistwen3 小时前
Agent架构师从0出发(第9篇):从RAG到Agent——检索增强与行动决策的融合与边界
agent
花间相见3 小时前
【AI应用开发|Agent记忆】—— Codex 与 Claude Code 持久化记忆对比:两条不用向量库的路线
后端·agent
用户3134672143543 小时前
Agent 开发学习笔记(六):LCEL:把组件串成链
langchain·agent
小马过河R3 小时前
开篇|3天从0到1入门AI应用开发
人工智能·语言模型·llm·agent·ai编程·deepagent