项目实战

🏗️ 项目实战:做一个可用的 LangGraph.js 应用

把教程里的概念串起来:从图、工具、记忆到部署,完成一个能长期运行的 AI 应用

📚 学习目标

学完这篇文章后,你将能够:

  • 把 LangGraph.js 的核心概念落到一个真实项目的目录结构里
  • 设计一个“用户输入 -> Graph 编排 -> 工具/模型 -> 输出”的端到端链路
  • 为应用加入可恢复的会话(thread_id)和持久化(checkpointer)
  • 为上线准备最基本的测试、可观测性与回归验证清单

前置知识

在开始学习之前,建议先阅读:

你需要了解:

  • Next.js 基础(路由/接口/环境变量)
  • TypeScript 基础

1️⃣ 选一个“可交付”的项目题目

为了让实战更像真实工作,我们先明确“交付物”。建议从这三类里选一个:

项目类型你要解决的问题LangGraph.js 的价值
聊天机器人多轮对话 + 工具调用 + 可恢复会话Loop + 状态 + ToolNode
RAG 问答文档检索 + 引用 + 追问分支/子图 + 结构化状态
编码助手规划 -> 生成 -> 评审 -> 返工多节点闭环 + 多 Agent 协作

本教程的推荐落地路径是:先做“聊天机器人”跑通全链路,再按需升级到 RAG 或编码助手。


2️⃣ 目录结构:把 Graph 当成“业务编排层”

一个好用的项目通常会把“编排(Graph)”和“Web 接口(API)”解耦。

app/
  api/
    chat/
      route.ts          # HTTP 入口:把请求交给 graph 执行
lib/
  graphs/
    chat.graph.ts       # Graph 构建与 compile()
  tools/
    weather.tool.ts     # Tool 定义(zod schema + 实现)
  llm/
    model.ts            # 统一的模型创建与配置

这样做的好处:

  • Graph 可以独立测试(不依赖 HTTP)
  • API 只做“参数校验/鉴权/日志/流式输出”,不耦合业务编排

3️⃣ 最小可用:一个能跑的 Chat Graph

下面是一个“能跑”的最小版本:一个 LLM 节点 + 记忆(messages state)。

import { StateGraph, START, END } from '@langchain/langgraph';
import { MessagesAnnotation } from '@langchain/langgraph';
import { ChatOpenAI } from '@langchain/openai';

const model = new ChatOpenAI({
  model: 'gpt-4o-mini',
  temperature: 0,
});

const callModel = async (state: typeof MessagesAnnotation.State) => {
  const reply = await model.invoke(state.messages);
  return { messages: [reply] };
};

export const chatGraph = new StateGraph(MessagesAnnotation)
  .addNode('model', callModel)
  .addEdge(START, 'model')
  .addEdge('model', END)
  .compile();

代码解析

  1. MessagesAnnotation 提供了“消息列表”的默认 reducer(用于追加历史)。
  2. 节点返回 { messages: [reply] },LangGraph 会把它合并回状态。
  3. 这就是一个最简单的“状态机”:每次调用都执行一次模型,然后结束。

4️⃣ 加上工具调用:让它能“行动”

当你需要查询天气、查数据库、跑脚本……就需要 Tool Calling。

高层结构通常是 ReAct Loop:

你可以直接参考本教程的“工具调用”章节,把 ToolNode 接进来:


5️⃣ 加上记忆与持久化:让它“可恢复”

做成应用后,你会立刻遇到一个现实问题:

  • 页面刷新/服务重启后,对话就没了

LangGraph 的解决方案是 Checkpointer + thread_id

import { MemorySaver } from '@langchain/langgraph';

const checkpointer = new MemorySaver();
export const appGraph = chatGraph; // 这里假设你的 chatGraph 已经构建好

// 注意:compile 时需要传 checkpointer
// const appGraph = new StateGraph(...).compile({ checkpointer })

const config = {
  configurable: {
    thread_id: 'user-123:session-456',
  },
};

const result = await appGraph.invoke(
  { messages: [{ role: 'user', content: '我叫小明' }] },
  config
);

更完整的解释与生产环境替换方案见:


6️⃣ 交付前检查:你至少要能回答这 6 个问题

这不是“模板化流程”,而是为了避免你把 Demo 当产品。

  1. 输入边界:最长输入多少?超长时怎么处理?
  2. 失败路径:模型超时/工具报错/JSON 不合法时,用户看到什么?
  3. 并发与隔离:多个用户同时聊天,thread_id 是否会串?
  4. 成本控制:一次请求最多跑几轮循环?是否设置了 recursionLimit
  5. 可观测性:你能定位一次糟糕回复是“模型问题”还是“工具问题”吗?
  6. 回归验证:你改了一个节点逻辑,怎么确保没把别的用例弄坏?

💡 练习题

  1. 实现题:基于“工具调用”章节,新增一个 searchDocs 工具,并把它接进你的 ReAct Loop。
  2. 调试题:人为让工具抛错(throw Error),你要在最终回复中给出“可理解”的降级提示。
  3. 工程题:设计一个最小的回归用例:固定输入,断言 Graph 输出里必须包含某个关键字段(比如引用列表)。

📚 参考资源

官方文档

本项目相关内容


✅ 总结

你现在应该能做到

  • 以“Graph”为中心组织项目,把编排层和接口层分离
  • 在项目中落地 Tool Calling、循环、记忆与持久化
  • 用一套最小的交付检查清单把 Demo 推到可上线的方向

下一步:去把你的项目跑起来,然后回到对应章节逐个补齐能力(人机交互、时间旅行、并行处理等)。

登录以继续阅读

解锁完整文档、代码示例及更多高级功能。

立即登录

On this page