学习笔记 · Obsidian
LangChain TypeScript:Middleware、Context、Runtime 与 HITL
Context engineering 的核心
Agent 质量往往受“模型在某一步看到了什么”支配,而不只是 model 大小。应分别设计三类数据:
| 数据 | 生命周期 | 典型载体 |
|---|---|---|
| Runtime context | 单次调用稳定、通常只读 | contextSchema + invoke 的 { context } |
| Short-term state | 同一 thread 持久、每一步演化 | agent state + checkpointer |
| Long-term memory | 跨 thread/会话共享 | store 的 namespace + key |
另有 model context:真正送入当前模型调用的 prompt、messages、tools 与 schemas。Middleware 的价值就是在适当生命周期读取数据,并只把本步需要的信息投影到 model context。
Runtime:依赖注入,不是全局变量袋
工具和 middleware 可通过 runtime 读取:
context:用户/租户、数据库句柄、feature flags 等调用级依赖;state:当前 thread 的 checkpointed 数据;store:长期记忆;streamWriter:自定义进度;executionInfo:thread ID、run ID 等执行身份;serverInfo:LangGraph Server 上的 assistant、authenticated user 等服务端信息。
serverInfo 在本地非 Agent Server 环境为 null。executionInfo/serverInfo 要求 `deepagents >= 1.9.0` 或 `@langchain/langgraph >= 1.2.8`。认证逻辑必须处理“字段不存在”和“本地运行”两条分支,不能从 prompt 中的 user ID 推断身份。
TypeScript 的 contextSchema 若包含必填字段,agent.invoke 会在编译期要求传入;这能减少漏参,但外部请求仍需运行时校验。
Middleware 生命周期与顺序
Node-style hooks:
beforeAgent/afterAgent:整个 run 前后;beforeModel/afterModel:每次 model call 前后。
Wrap hooks:
wrapModelCall(request, handler):模型选择、prompt、tools、retry/fallback、响应处理;wrapToolCall(request, handler):鉴权、参数处理、timeout、重试、错误转换、审计。
多 middleware 的顺序是:before hooks 按数组正序,after hooks 逆序;wrap 形成洋葱模型,第一个 middleware 位于最外层。顺序会改变语义,例如 PII redaction 应先于日志;timeout 与 retry 的内外关系决定“每次重试超时”还是“整个操作总超时”。应把顺序作为测试契约。
Node hook 返回 state update;wrap hook 要更新 state 时返回 Command。StateSchema 可以用 ReducedValue 描述合并;以下划线开头的私有字段不会出现在最终 agent 结果中,但仍可能存在运行内存/trace,不能当加密机制。
canJumpTo 允许 middleware 跳到 model、tools 或 end。Jump 是控制流能力,应避免在多个 middleware 中隐式竞争。
自定义 middleware 的选择
简单、无配置逻辑可直接使用 hook factory;需要共享状态、复杂配置、多个 hooks 或可复用包时用 createMiddleware。典型生产场景:
- 动态 system prompt / model routing;
- 按租户过滤 tools;
- model/tool retry、fallback、circuit breaker;
- 预算、调用次数和 token 限制;
- 输入/输出审核与 PII 处理;
- trace tags、业务指标和自定义 stream projection。
Middleware 注册 stream transformer 要求 `[email protected]+`。Transformer 应是可组合、顺序明确、支持取消的异步管道。
预置 middleware 地图
| 类别 | 能力 | 边界 |
|---|---|---|
| Context | summarization、context editing | 压缩有损;阈值依赖 model profile 或显式 token 配置 |
| Human control | HITL | 必须 checkpointer + thread;恢复需原 checkpoint |
| Budgets | model/tool call limit、to-do list | 需要定义 run/thread 计数语义 |
| Reliability | model fallback、model/tool retry、tool error | 有限重试;副作用工具必须幂等 |
| Safety | PII detection/redaction/block、guardrails | 规则与模型审核互补;日志链路也要脱敏 |
| Tool selection | LLM tool selector、provider tool search/emulator | 额外模型调用或 provider 依赖可能增加成本 |
| Deep-agent harness | filesystem、subagent | 来自 deepagents;backend、sandbox、持久性和权限另行设计 |
“production-ready”表示实现可配置,不表示默认配置自动满足业务合规、SLA 和安全要求。
Guardrails:确定性规则优先
Guardrail 可作用于输入、模型前后、工具前后:
- 规则型检查适合权限、允许列表、金额/路径限制、schema、正则 PII;
- 模型型审核适合语义风险,但有延迟、费用和误判;
- 高风险副作用最终由工具服务端再鉴权,middleware 不是唯一防线。
处理策略可以 block、redact/mask、替换安全回复、抛出错误或 interrupt。必须明确用户可见错误、内部审计、重试和恢复路径,避免 redaction 后数据仍从 trace/异常/自定义事件泄漏。
HITL 的状态机
humanInTheLoopMiddleware 按 interruptOn 对工具配置审批。每个工具可允许:
allowAccept:批准原动作;allowEdit:修改参数后执行;allowRespond:不执行工具,直接提供反馈。
必要条件:checkpointer、稳定 thread_id、持久保存 interrupt/checkpoint、恢复时使用 Command({ resume: ... })。同一 turn 有多个被暂停工具时,每个 action 都要对应一项 decision,顺序和数量必须一致。
安全边界:
edit后必须重新 schema 校验和鉴权;- 审批 UI 只能把服务端返回的允许动作展示给有权 reviewer;
- 执行恢复可能重复到达,副作用需要幂等 key;
- checkpoint/store 要有租户隔离、保留期和审计;
- timeout/拒绝/无人审批必须有终态。
重要 JS 差异:条件式 `when`/conditional interrupt 当前仅 Python 支持。 TypeScript 页面虽混入 interrupt_on、v2 Python 风格说明,JS 实现应使用实际 interruptOn 与上述 allow 选项,不要宣称具备 Python-only 条件策略。
路由与文档边界
/oss/javascript/langchain/middleware 是可点击别名,当前 308 到 /middleware/overview,所以 sources 同时记录别名和正文;它不代表额外的 middleware 语义。文档数处混入 Python 参数名/代码块,属于模板复用缺陷,不能作为 TypeScript API 契约。
逐页覆盖
| 页面 | 学习结论 |
|---|---|
| Context engineering | runtime context、state、store 与 model context 的生命周期和读写方式。 |
| Middleware overview | agent/model/tool hooks、控制流、顺序与常见用途。 |
| Built-in middleware | summary、HITL、limits、fallback/retry、PII、todo、tool selection、filesystem、subagent。 |
| Custom middleware | hook/createMiddleware、StateSchema、Command、stream transformer 与 context typing。 |
| Runtime | context/state/store/stream writer、executionInfo/serverInfo 及版本要求。 |
| Guardrails | PII、规则/模型检查、block/redact/HITL 和分层安全。 |
| Human-in-the-loop | interrupt policy、accept/edit/respond、checkpoint 和恢复协议;conditional JS 缺口。 |