LangGraph.js 聊天机器人模板:用 LangGraph Studio 构建、调试并扩展 Agent 项目
本文基于 libs/cli/js-examples/ 目录下的 LangGraph.js 新项目模板 README,讲解如何搭建一个带持久化会话记忆的最简聊天机器人模板,并在 LangGraph Studio 中完成热重载调试、状态回放与迭代扩展。读完后,你将掌握该模板的完整工程结构(状态注解、StateGraph 图构建、langgraph.json 配置)、本地启动流程,以及接入 LLM、新增节点/工具、编写单元与集成测试的具体做法。
模板定位:一个面向 LangGraph Studio 的最简聊天机器人
该模板演示了一个用 LangGraph.js 实现的简单聊天机器人,专为 LangGraph Studio 设计。它维持持久化会话记忆,可以在多轮交互中保持上下文连贯。README 对机器人行为的描述是:
- 接收用户 message 作为输入;
- 维护对话历史(conversation history);
- 返回占位响应,并更新对话历史。
模板的核心逻辑位于 graph.ts,是一个“响应用户提问、同时保留前文上下文”的聊天机器人骨架。README 明确强调:它提供的是一个可轻松定制和扩展的基础,用于构建更复杂的对话型 Agent。官方 JavaScript/TypeScript 文档可作为概念参考,且 LangGraph Studio 与 LangSmith 集成以提供追踪(tracing)与团队协作能力。
工程结构与核心文件
从仓库实际目录看,该模板包含以下关键文件:
| 文件 | 作用 |
|---|---|
| src/agent/graph.ts | 图的核心逻辑:节点、边、条件路由、导出编译后的 graph |
| src/agent/state.ts | 通过 Annotation.Root 定义图状态与 reducer |
| langgraph.json | LangGraph 应用配置:图入口、Node 版本、env 文件、依赖 |
| package.json | 依赖、脚本(build/test/lint)与包管理器声明 |
| .env.example | 环境变量文件模板(当前仅注释占位) |
| tests/agent.test.ts | 路由函数单元测试 |
| tests/graph.int.test.ts | 整图 invoke 集成测试 |
| jest.config.js | ESM + ts-jest 的 Jest 配置 |
| tsconfig.json | 严格模式 TypeScript 配置 |
其中 langgraph.json 是 Studio/CLI 识别应用的入口配置,实际内容如下:
{
"$schema": "https://langgra.ph/schema.json",
"node_version": "20",
"graphs": {
"agent": "./src/agent/graph.ts:graph"
},
"env": ".env",
"dependencies": ["."]
}
各字段含义:
node_version: "20":声明运行该 JS 应用所需的 Node.js 大版本为 20;graphs:名为agent的图指向./src/agent/graph.ts模块导出的graph符号(文件:导出名格式,与 graph.ts 中export const graph = builder.compile()对应);env: ".env":声明从根目录.env读取环境变量;dependencies: ["."]:依赖根包本身,即由 package.json 管理依赖安装。
package.json 声明了 packageManager: "yarn@1.22.22"、"type": "module",核心运行时依赖为 @langchain/core ^1.2.4 与 @langchain/langgraph ^1.4.8(并通过 resolutions 锁定 @langchain/langgraph-checkpoint 为 1.0.4)。脚本方面:yarn build 执行 tsc;yarn test 只跑 *.test.ts(排除 *.int.test.ts);yarn test:int 只跑 *.int.test.ts;lint:langgraph-json 通过 node scripts/checkLanggraphPaths.js 校验 langgraph.json 中路径;test:all 将单测、集成测试与该校验串联执行。
状态定义:Annotation 与 messagesStateReducer
state.ts 定义了模板唯一的状态字段 messages:
export const StateAnnotation = Annotation.Root({
messages: Annotation<BaseMessage[], BaseMessageLike[]>({
reducer: messagesStateReducer,
default: () => [],
}),
});
根据源码注释,StateAnnotation 定义了三件事:
- 通道结构:节点间读写哪些“channel”及其类型;
- 默认值:
messages默认为空数组[]; - reducer:决定更新如何应用到状态。这里使用
messagesStateReducer,它会把两列消息按 ID 合并——新消息没有 ID 时 LangGraph 会自动分配一个;默认行为是“追加(append-only)”,除非新消息与已有消息 ID 相同,此时新消息替换旧消息。
messages 字段的类型是 BaseMessage[](读类型),但节点返回值类型放宽为 BaseMessageLike[],即带 role/content 的普通对象也会被 messagesStateReducer 自动转换为 LangChain 消息类——这正是 graph.ts 中直接返回 { role: "assistant", content: ... } 占位消息而无需构造完整消息对象的原因。源码注释还给出了 messages 的典型累积模式:HumanMessage(用户输入)→ 带 .tool_calls 的 AIMessage(选工具)→ ToolMessage(工具结果),循环若干轮后以无工具调用的 AIMessage 收尾,供扩展时参考。
图构建:节点、边与条件路由
graph.ts 展示了 LangGraph.js StateGraph 的最小完整用法,结构如下:
const builder = new StateGraph(StateAnnotation)
.addNode("callModel", callModel)
.addEdge("__start__", "callModel")
.addConditionalEdges("callModel", route);
export const graph = builder.compile();
graph.name = "New Agent";
三个要点(均见 graph.ts 的源码注释):
-
节点:
callModel承载主要逻辑,签名接收(state, config),必须返回StateAnnotation.Update类型的子集。当前实现打印当前状态并返回一条固定的 assistant 占位消息:console.log("Current state:", state); return { messages: [ { role: "assistant", content: `Hi there! How are you?` }, ], };函数体内的大段注释给出了两种接入真实 LLM 的示例:通过 LangChain.js 包装器(
npm i @langchain/anthropic后new ChatAnthropic(...)再model.invoke(state.messages)),或绕过 LangChain 直接调用 SDK(npm i openai后openai.chat.completions.create({ messages: [...], model: "gpt-4o-mini" }))。 -
普通边:
addEdge("__start__", "callModel")表示“节点 A 完成后总是转到节点 B”;__start__与__end__是始终存在的虚拟节点,分别代表图的起点与终点。 -
条件边:
addConditionalEdges("callModel", route)用路由函数动态决定去向。本模板的 route 逻辑是:若state.messages.length > 0返回"__end__"结束,否则回到"callModel"。配合callModel总会追加消息的实现,该条件边在首轮执行后即进入__end__,使每次invoke恰好产出一条 assistant 回复。
本地运行:Getting Started
README 的启动流程以“已安装 LangGraph Studio”为前提,共三步:
-
创建
.env文件。模板默认不需要任何环境变量,但定制时通常会添加(例如ANTHROPIC_API_KEY、OPENAI_API_KEY):cp .env.example .env仓库中的 .env.example 当前只有三行注释占位(“Copy this over: cp .env.example .env / Then modify to suit your needs”),印证了“默认为空、按需填充”的设计。
-
在 LangGraph Studio 中打开该目录。
-
按需修改代码。
此外,README 中保留了两段由 langgraph template lock 自动生成的 HTML 注释(“Setup instruction auto-generated by langgraph template lock. DO NOT EDIT MANUALLY” 与 “Configuration auto-generated by langgraph template lock”),后者内嵌了该模板的配置 schema:
{
"config_schemas": {
"agent": {
"type": "object",
"properties": {}
}
}
}
从该 schema 结构看,agent 图当前未向 Studio 暴露任何可配置参数(properties 为空),即图的全部行为由代码决定。注释同时提醒该块内容禁止手动编辑,应通过模板工具链再生成。
在 LangGraph Studio 中调试与迭代
README 的 Development 章节描述了模板在 Studio 中的迭代工作方式:
- 编辑历史状态重跑:调试特定节点时,可以编辑过往状态(edit past state)并从该状态重新运行应用;
- 热重载:本地代码变更会自动生效(hot reload),修改
graph.ts后无需重启; - 线程语义:后续请求会追加到同一线程(thread),会话历史随之累积;点击界面右上角的
+按钮可以新建一个完全清空历史的新线程; - 推荐实验:修改系统提示词赋予聊天机器人独特个性、为更复杂的对话流新增节点、实现条件逻辑以处理不同用户输入;
- LangSmith 集成:Studio 与 LangSmith 集成后可做更深入的全链路追踪与团队协作分析。
结合模板代码可推断调试路径:由于占位节点会把 console.log("Current state:", state) 打到服务端日志,在 Studio 中观察线程消息变化配合日志即可验证“状态 → 节点 → 更新”的完整闭环;而“编辑过去状态重跑”能力依赖于 LangGraph 的 checkpoint 机制(模板通过 resolutions 固定了 @langchain/langgraph-checkpoint 版本,见 package.json)。
扩展模板的四个方向
README 的 “How to customize” 给出了明确的扩展路径:
- 接入 LLM 调用:从 LangChain.js 生态选择并安装一个聊天模型包装器(如上文注释中的
@langchain/anthropic),或者完全不用 LangChain.js、直接调用模型 SDK; - 扩展图结构:修改 graph.ts 增加节点、边,或改变对话流程——这是模板的核心定制点;
- 添加工具/函数:接入自定义 tools 增强机器人能力;
- 实现 RAG:集成外部 API 或数据库实现检索增强生成,使回答更定制化;
- 业务分支:为特定类型的用户查询或任务实现额外处理逻辑。
测试体系:路由单测与整图集成测试
模板内置两类测试,可直接作为扩展时的回归基线:
- 路由单元测试 tests/agent.test.ts:直接导入
route函数,断言空消息状态下route({ messages: [] })返回"callModel",验证“无消息时回环”的分支; - 整图集成测试 tests/graph.int.test.ts:以
"What is the capital of France?"为输入调用graph.invoke({ input }),断言结果对象包含非空messages数组,且最后一条消息内容包含 "hi"(对应占位响应 “Hi there! How are you?”),超时设为 30 秒。
测试运行环境由 jest.config.js 决定:ts-jest 的 ESM 预设、extensionsToTreatAsEsm: [".ts"]、moduleNameMapper 把 ./xx.js 映射到 ./xx(适配 ESM 下 .ts 源文件导入 .js 后缀的写法)、setupFiles: ["dotenv/config"] 加载环境变量、全局 testTimeout 20 秒。tsconfig.json 则开启了 strict、noUnusedLocals、noUnusedParameters 等严格选项,模块体系为 NodeNext。
小结与适用边界
该模板的价值在于把“LangGraph Studio 可运行的最简 JS 应用”压到了最小文件集:一份 langgraph.json 入口配置、一个 state.ts 状态定义、一个 graph.ts 图定义,加上单测/集成测试与 ESLint/Prettier/Jest 全套工程配置。其适用前提是本地已安装 LangGraph Studio 与 Node.js 20 环境;默认不依赖任何外部 API Key。在此骨架上替换占位节点为真实 LLM 调用、按需扩展 StateAnnotation 字段(源码注释也预留了 additionalField 示例)与图拓扑,即可获得一个可持续迭代的对话型 Agent 工程。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
