学习笔记 · Obsidian

LangChain TypeScript:状态、流式与结构化输出

LangChainTypeScript

三个不要混淆的概念

  1. State 是一次 thread 中 agent 执行所需的数据;messages 只是其中一个 channel。
  2. Streaming 是执行过程中如何观察增量,不会自动让 state 持久化。
  3. Structured output 是最终回答的契约,不保证中间工具结果或所有 provider 原始内容都符合该契约。

生产设计通常三者并用:checkpointer 保持 thread;stream 把 token、工具和状态更新送到客户端;最终 structuredResponse 经过 schema 验证后进入业务流程。

短期记忆:thread-scoped state

给 agent 配置 checkpointer 后,使用稳定的 configurable: { thread_id } 调用,LangGraph 会在每一步保存 state 并在下一轮恢复。MemorySaver 只适合本地和测试;生产应选择 PostgreSQL 等持久 checkpointer,并验证连接池、migration、备份、TTL、并发写入和灾难恢复。

自定义 state 使用 StateSchema/Zod 描述字段和 reducer。关键规则:

  • messages 使用消息 reducer,追加新消息并理解 RemoveMessage;
  • 普通字段若有并发更新必须明确归并规则,不能依赖对象覆盖顺序;
  • 请求级、不可序列化的依赖放 runtime context,不放 checkpoint;
  • state 中的 PII、工具结果和文件引用会被持久化,必须有数据分级和清理策略。

控制消息增长

长对话不能无限追加:

  • trim:在模型调用前只取 token/window 内的有效历史;
  • delete:用 RemoveMessage 删除特定消息,或 REMOVE_ALL_MESSAGES 重置;
  • summarize:把旧历史压缩成摘要并保留近期消息;
  • custom strategy:按任务、租户、模型 window 和工具协议定制。

裁剪时必须保持消息合法:不能留下孤立的 ToolMessage,也不能删掉 tool call 却保留其结果。摘要是有损压缩,需要测试关键事实、权限和未完成任务是否仍可恢复。

两套流式接口

传统 stream

agent.stream(input, { streamMode }) 支持:

mode输出适合
updates每一步的 state delta展示 agent 进度、工具阶段
messages模型 token/message chunks + metadata打字机效果、实时 TTS
custom工具或节点通过 writer 发出的自定义事件进度、业务指标、文件生成状态

可以同时请求多个 mode。客户端需要用 mode/event 判别联合类型,不能假设所有 chunk 都是文本。

Event Streaming v3

新应用优先评估 agent.streamEvents(input, { version: "v3" })。它提供类型化 projection,而不是让调用方遍历低层 callback 事件:

  • stream.messages:消息流;每条消息还能迭代 .text、.reasoning、.toolCalls、.output、.usage;
  • root .toolCalls:所有工具调用;
  • .values:完整 state snapshot;
  • .output:最终输出;
  • .subagents / .subgraphs:嵌套执行;
  • .extensions:由 middleware 注入的扩展投影。

若同时消费多个 projection,应并发 drain;只等待一个而让另一个无人消费,可能造成缓冲、背压或遗漏 UI 更新。断线重连、重复事件、取消和慢消费者也要在协议层设计。

TypeScript 特有版本边界

  • middleware 注册的 stream transformer 要求 `[email protected]+`;Python 文档对应版本不同,不能照抄。
  • 页面个别说明使用 Python 名称 stream_events,实际 JavaScript 方法是 streamEvents。
  • 禁止模型流式时使用 streaming: false;fallback 场景的 disableStreaming: true 是不同开关。文档出现 streaming=False 是语言模板残留。
  • 传 thread_id 只有在 agent 配置 checkpointer 后才会保存历史;LangSmith Deployment 会自动配置,本地需显式提供。

Structured output

responseFormat 可接受 Zod、其他 Standard Schema、JSON Schema,或显式 strategy。成功后结果位于 structuredResponse。

两种策略:

策略机制优点风险
Provider strategy使用 provider 原生 structured output通常约束更强、少一次工具语义依赖 provider/model 支持与 schema 子集
Tool strategy把 schema 表示为工具调用兼容面广、可定制错误反馈多一层 tool-call 语义,模型可能参数错误

传入 schema 时,LangChain 会根据 model profile 自动选 provider strategy;该 profile 推断要求 langchain >= 1.1,且 profile 仍属 beta。高风险系统应显式选 strategy 并在部署目标模型上验证,不把自动推断当永久契约。

toolStrategy 可设置 toolMessageContent 和 handleError。验证失败时,默认可把错误反馈给模型重试;应限制重试次数和总耗时,避免无效 schema 造成循环。即使框架已解析成功,进入数据库、支付或权限逻辑前仍应再次做业务校验。

TypeScript schema 实践

  • Zod 同时提供运行时验证和类型推断,是默认首选;
  • Standard Schema 方便复用 Valibot 等生态;
  • JSON Schema 适合跨语言/协议,但 TypeScript 类型需另行生成或绑定;
  • schema 应避免 provider 不支持的递归、过深 union 或松散 additional properties;
  • 不把 prompt 中“请返回 JSON”当 structured output。

前端消费原则

  • 先按 event/projection 做类型收窄,再更新 UI;
  • partial tool args、partial JSON、partial Markdown 都是不可信中间态;
  • UI 可乐观展示,但持久业务状态只由服务端确认事件推进;
  • disconnect、cancel、rejoin 是三种不同语义;
  • usage、reasoning 和 provider metadata 可能缺失,组件要有无数据分支。

逐页覆盖

页面学习结论
Short-term memorycheckpointer + thread、StateSchema、trim/delete/summarize 与生产持久化。
Streamingupdates/messages/custom、并行模式、工具自定义 writer 和持久 thread。
Event streamingv3 typed projections、messages/toolCalls/values/output/subagents/extensions 与 transformer。
Structured outputZod/Standard/JSON Schema,provider/tool strategy、自动选择、错误反馈与验证。

延伸