State 是什么?LangGraph 里最重要的不是节点

State 是什么?LangGraph 里最重要的不是节点

上一篇文章里,我们讨论了从 Chain 到 Graph 的变化。

一个重要结论是:

当 AI 应用开始出现分支、循环、重试和人工介入时,线性流程就会变得吃力。

LangGraph 用图结构把复杂 Agent Workflow 显式组织起来。

但学习 LangGraph 时,很多人第一反应是:

我要写哪些 Node?

每个 Node 调哪个模型?

Edge 怎么连?

这些问题当然重要。

但在 LangGraph 里,真正决定系统是否清晰、稳定、可维护的,往往不是节点,而是 State。

这篇文章就讨论:

State 到底是什么?

为什么它是 LangGraph 里最重要的设计之一?

State 不是普通变量

很多人会把 State 理解成一个普通变量集合。

比如:

query answer history

这样理解只对了一部分。

在 LangGraph 里,State 更像是整个图运行过程中的共享上下文。

它记录了当前流程知道什么、做到哪一步、下一步判断需要依据什么。

一个 Agent Workflow 可能需要的 State 包括:

用户输入 消息历史 任务类型 当前步骤 检索结果 工具调用结果 失败次数 中间分析结论 是否需要人工确认 最终答案

Node 读取 State。

Node 执行任务后更新 State。

Edge 根据 State 决定下一步。

所以 State 不是附属品。

它是图运行的核心。

为什么 State 很重要?

一个 Agent 流程能不能稳定,取决于系统能不能清楚回答几个问题:

现在用户想做什么? 系统已经完成了哪些步骤? 当前有哪些可用信息? 哪些工具已经调用过? 哪些结果可信? 是否需要继续执行? 是否应该结束?

这些答案都来自 State。

如果 State 设计混乱,就会出现很多问题。

比如:

节点之间传递信息不清楚 重复调用工具 检索结果被覆盖 错误信息丢失 分支判断没有依据 循环无法正确结束 人工介入后无法恢复

很多 LangGraph 项目后期难维护,不是因为 Node 不会写。

而是因为 State 从一开始就没有设计好。

State 决定节点边界

Node 应该做什么,往往取决于 State 怎么设计。

比如你有一个检索节点。

它读取:

query tenant_id permission_context

然后写入:

retrieval_results retrieval_scores sources

这样节点边界就很清楚。

如果 State 没有定义这些字段,节点就容易把结果塞到任意位置。

后面的 Rerank 节点、生成节点、日志节点也不知道该读哪里。

所以 State 是节点之间的契约。

它告诉每个节点:

你可以依赖什么 你应该产出什么 你不要随便改什么

这对工程化非常重要。

State 和 Prompt 不是一回事

有些人会把所有上下文都塞进 Prompt。

比如:

用户问题 历史对话 工具结果 检索结果 失败记录 任务目标

全部拼成一个大 Prompt。

这样做在小 Demo 里能跑。

但它有几个问题。

第一,结构不清楚。

你很难知道哪些内容是任务状态,哪些内容是用户上下文,哪些内容是工具结果。

第二,成本高。

所有信息都塞给模型,会浪费 token。

第三,不利于分支判断。

流程判断最好基于结构化 State,而不是让模型在大段文本里自己猜。

第四,不利于调试。

出问题时,你很难复盘是哪部分状态导致了错误。

更好的做法是:

State 结构化保存信息。

Prompt 只拿当前节点真正需要的部分。

State 应该包含哪些内容?

不同项目的 State 不一样。

但可以从几个维度思考。

第一,用户输入。

user_query original_input

第二,对话上下文。

messages conversation_summary

第三,任务状态。

task_type current_step plan progress

第四,检索状态。

rewritten_query retrieval_results rerank_results sources

第五,工具状态。

tool_calls tool_results tool_errors retry_count

第六,控制状态。

need_human_review should_continue final_answer error_message

这些字段不一定都要有。

关键是根据业务需要设计。

不要一开始就把 State 做得特别大。

也不要只放一个 messages,把所有东西都混进去。

State 过小的问题

State 过小,最常见的表现是所有信息都临时传递。

比如:

节点 A 返回一个结果 节点 B 临时接收 节点 C 又重新包装

这种方式一开始看起来简单。

但流程一复杂,就会出现问题。

比如某个节点想知道前面工具失败了几次,却没有地方记录。

某个条件边想判断是否继续检索,却不知道检索结果质量如何。

人工介入后想恢复流程,却不知道之前停在哪一步。

这些都是 State 过小带来的问题。

State 太小,流程就没有记忆。

图看起来在运行,但上下文是断的。

State 过大的问题

State 过大也麻烦。

有些人会把所有内容都塞进 State:

完整文档 完整日志 所有中间 Prompt 所有模型原始输出 所有外部系统响应

这样会带来几个问题。

第一,状态难理解。

字段太多,没人知道哪个字段真的重要。

第二,节点耦合变强。

每个节点都可能随便读写很多字段。

第三,存储和恢复成本变高。

如果后续使用 Checkpoint,过大的 State 会影响性能和成本。

第四,隐私风险增加。

敏感数据如果无脑进入 State,日志和持久化都会变危险。

所以 State 要够用,但不要无限膨胀。

State 要服务于路由判断

LangGraph 里很多 Edge 会根据 State 判断下一步。

比如:

如果 retrieval_results 为空,进入 rewrite_query。 如果 risk_level 为 high,进入 human_review。 如果 retry_count 超过 3,进入 fallback。 如果 final_answer 已生成,进入 END。

这意味着 State 字段要能支持决策。

不要让条件边依赖一段模糊文本。

更好的方式是让节点输出结构化字段。

比如:

is_answerable: true risk_level: low need_more_context: false retry_count: 1

这些字段非常适合做路由。

Agent Workflow 的可控性,很大一部分来自这些结构化状态。

State 要服务于可观测性

State 还有一个价值:

帮助排查问题。

当某次运行结果不对时,你需要知道:

用户原始问题是什么? 问题有没有被改写? 检索到了哪些资料? Rerank 后留下了哪些内容? 工具调用结果是什么? 为什么进入这个分支? 最终答案基于哪些信息?

这些信息如果都在 State 里有清晰记录,排查会容易很多。

当然,生产环境不能把敏感信息无脑写进日志。

但从设计上,State 应该支持流程复盘。

否则系统越复杂,越只能靠猜。

一个简单 State 示例

假设我们做一个带 RAG 的问答 Agent。

State 可以先设计成这样:

messages user_query rewritten_query retrieval_results rerank_results need_more_context answer sources error

对应流程可能是:

接收问题 ↓ 改写问题 ↓ 检索 ↓ 判断资料是否足够 ├─ 不足:继续改写或追问 └─ 足够:生成答案

这里每个字段都有明确用途。

rewritten_query给检索节点使用。

retrieval_results给 Rerank 节点使用。

need_more_context给条件边使用。

answersources给最终输出使用。

这就比把所有东西塞到一个字符串里清楚得多。

常见误区

第一个误区,是只关注 Node,不设计 State。

Node 是执行单元,State 才是流程上下文。

第二个误区,是把所有内容都放进 messages。

messages 适合保存对话,但不适合承载全部任务状态。

第三个误区,是 State 字段没有边界。

每个字段都应该知道由谁写、被谁读。

第四个误区,是 State 过大。

状态不是垃圾桶,不应该无脑塞所有原始数据。

第五个误区,是 State 不能支持路由。

如果条件判断依赖模糊文本,流程就不稳定。

总结

LangGraph 里最重要的概念之一是 State。

因为 State 决定了节点之间如何传递信息,流程如何判断下一步,系统如何恢复,问题如何复盘。

Node 是做事的地方。

Edge 是连接路径。

但 State 是整个图的上下文和记忆。

一个好的 LangGraph 项目,不是节点越多越好,而是 State 设计清楚。

State 要足够表达任务进度、工具结果、检索结果和控制信号。

但也不能无限膨胀,变成难维护的大杂烩。

下一篇文章,可以继续讨论 Node 怎么设计。

因为有了清晰的 State,才能进一步决定每个节点应该承担什么职责。