学习笔记 · Obsidian
LangChain TypeScript:前端与 Generative UI
前端不是 token 打字机
v1 frontend SDK 面向耐久 agent 应用:同一个 stream handle 暴露 messages、tool-call lifecycle、interrupt、完整/自定义 state、thread metadata、checkpoints、subagents 和运行状态。标准架构是:
createAgent/ Agent Server ↔ Agent Streaming Protocol ↔ framework SDK ↔ application UI
React、Vue、Svelte 使用各自包的 useStream;Angular 使用 injectStream。TypeScript 的显著优势是 useStream<typeof myAgent> / injectStream<typeof myAgent> 能从 compiled graph 推断 messages、tool calls、interrupts 和自定义 state,不需重复手写 interface。跨仓库或 Python backend 时无法直接 import agent type,才需要共享/生成显式 schema。
四个框架的共同协议
| 框架 | SDK 入口 | 响应式风格 |
|---|---|---|
| React | @langchain/react useStream | hook/state |
| Vue | @langchain/vue useStream | composable/refs |
| Svelte | @langchain/svelte useStream | store/runes |
| Angular | @langchain/angular injectStream | injection/signals |
业务组件应围绕稳定协议状态设计,而不是把框架示例逐行搬运。每个 UI 状态都要覆盖 loading、partial、finished、error、cancelled、reconnected 和 permission denied。
消息、Markdown 与 reasoning
Markdown
流中 msg.text 会持续增长。React 推荐 react-markdown + remark-gfm,直接生成 React elements,不启用 raw HTML;Vue/Svelte/Angular 的 marked 输出必须经 DOMPurify 后再注入 HTML。无论模型还是工具返回的 Markdown 都是不可信输入,需限制链接协议、图片来源和代码渲染。
全量重新解析对常见消息足够简单;大于约 50KB 或高频 token 时应节流、memoize 或增量处理,避免每 token 触发昂贵高亮和布局。
Reasoning
reasoning content blocks 可折叠展示,并保留一条回答中的多个 reasoning cycle。不是所有 provider/model 都提供,且可见内容不等于完整内部推理或事实保证。UI 应遵守 provider policy,优先展示可审计的依据、引用和工具结果,不把隐藏 chain-of-thought 当“透明性证明”。
Tool call UI 与 headless tools
AssembledToolCall 把增量参数与结果组装成 UI 友好对象,常见字段包括 name、callId/id、namespace、input/args、output、status 和 error。使用 ToolCallFromTool<typeof tool> 可从工具定义推断参数,渲染时仍需处理未知工具和 schema 版本不匹配。
Headless tool 是 TypeScript/浏览器侧的强项:服务端共享 schema-only 定义,客户端用 .implement() 绑定 browser/device API,再传给 useStream({ tools })。适合 clipboard、geolocation、camera、DOM selection 等不能在 server 执行的能力。
安全要求:
- server 只能提出调用,浏览器仍需用户权限与业务授权;
- 参数和返回值必须 JSON-serializable;大文件走受控 upload/reference;
- 不把 DOM、token、cookie、任意 fetch 或 shell 暴露为通用工具;
- 页面卸载、重复调用和网络恢复要保证幂等/取消;
- schema 可共享,client implementation 按平台分别实现。
前端 HITL
客户端把 interrupt 渲染成审批卡或自定义表单,通过 stream.submit(null, { command: { resume } }) 恢复。approve/edit/reject/respond 的具体 payload 必须与服务端 review config 对齐;多 action interrupt 要提交全部 decisions。
前端 respond(response, { update }) 可做 optimistic update,把审批卡和用户反馈留在耐久 transcript 中。乐观 UI 不能先执行副作用,服务端仍需校验 reviewer 身份、edited args 和 checkpoint 版本。刷新/换设备后应从 thread 恢复待审批项,而不是依赖组件内 state。
Durable conversation:branch、queue、rejoin、time travel
这些高级能力要求 LangGraph Agent Server(本地 langgraph dev 或部署),仅使用进程内 agent.stream() 不等同于具备 server-side thread/run API。
Branching chat
用 checkpoint metadata 找到某条消息的 parentCheckpointId,编辑或 regenerate 时 forkFrom 创建新分支。原时间线保留,可以在 branches 间导航。UI 必须清楚显示用户处于哪个分支,避免把分支回答误认为原历史。
Message queue
运行中提交消息时使用 multitaskStrategy: "enqueue",通过 submission queue 观察、取消或清空等待项。取消队列项不会取消当前 active run;需要停止执行时调用 stream.stop()。队列还需上限、去重、顺序、过期和跨设备一致性。
Join/rejoin
离开 UI 但让服务端继续执行时调用 stream.disconnect(),它等价于 stop({ cancel: false });stream.stop() 默认会取消 server run。保存 thread ID,重新挂载后加入仍在运行或已完成的 thread。移动端进入后台、网络断开和用户主动“停止”必须映射到不同动作。
Time travel
从 ThreadState 读取 checkpoint、values、tasks 和 next,再用 forkFrom: { checkpointId } 从旧状态建立新执行。原历史不会被覆盖。状态可能包含敏感工具结果,只向有权用户暴露,并记录 fork 来源和操作者。
Structured output 与 Generative UI
Structured output
最终 structuredResponse 可渲染成稳定业务组件。流式 JSON/工具参数在完成前只是 partial,必须通过 schema 后再驱动支付、导航等行为;progressive UI 可显示 skeleton,但不应消费未验证字段。
三种生成式 UI
| 模式 | 模型决定什么 | 可靠性/自由度 |
|---|---|---|
| Controlled | 选择预注册组件及受控 props | 最稳,适合交易和核心业务 |
| Declarative | 生成受约束 UI spec,由 renderer 映射 catalog | 中等,适合 dashboard/form 组合 |
| Open-ended | 生成代码/完整界面,在隔离环境运行 | 最自由、风险最高,需要 sandbox 与严格能力边界 |
Controlled 模式让 tool/structured result 映射业务组件;Declarative 模式可用 json-render 的 catalog/registry、扁平 spec、JSONUIProvider/Renderer,或 A2UI 的 dynamic/fixed 组件;Open-ended UI 必须在外部 sandbox/iframe 中运行,设置 CSP、网络/存储限制、资源配额、人工审查和销毁策略。
第三方集成边界
| 集成 | 作用 | 当前边界 |
|---|---|---|
| AI Elements | shadcn 风格可编辑源码组件,渲染 messages/tools 等 | UI 代码进入应用后由团队维护、安全审查和无障碍测试 |
| assistant-ui | useExternalStoreRuntime 把 LangGraph stream 接到 headless chat runtime | thread/attachment/branch 能力取决于 adapter 与后端 |
| CopilotKit | Hono route + LangGraph deployment + React generative UI | 页面叙述混有 Python/JS;组件 registry 需约束 |
| OpenUI | 模型输出 openui-lang,Renderer 生成 React UI | React 19+、zustand;parser 只接受 camelCase identifier |
OpenUI 的 streaming 需要避免每 token 全量无效 reparse,只有 spec 足够完整时更新 surface;sanitizeIdentifiers 可把模型偶发 snake_case 转 camelCase。Deep Agents 可并行生成多个 panel,stream.subagents + scoped useMessages 把每个 subagent 投影到独立 renderer。
这些页面是 LangChain 官方的集成指南,但库本身由不同项目维护;版本、许可证、安全和 SLA 要到各自官方仓库再次核实。
前端生产清单
- ○ Agent endpoint 有用户认证、tenant authorization、CORS/CSRF 与速率限制。
- ○ thread ID 不是权限凭证;每次 read/join/fork/cancel 都服务端鉴权。
- ○ Markdown/HTML、链接、图片、工具输出全部按不可信内容处理。
- ○ disconnect、cancel、retry、queue、interrupt、branch 有明确 UI 语义。
- ○ partial 数据不触发不可逆业务动作。
- ○ stream 有背压、重连、重复事件和大消息策略。
- ○ keyboard、screen reader、reduced motion、移动端后台和弱网已测试。
逐页覆盖
| 页面组 | 学习结论 |
|---|---|
| Frontend overview | v1 SDK、Agent Server 协议、四框架入口、durable state 与 typeof agent 推断。 |
| Markdown / reasoning / structured output | 安全渲染、流式重解析、reasoning 可用性边界和 partial schema。 |
| Tool calling / headless tools | AssembledToolCall、类型化卡片、浏览器实现与 server schema 分离。 |
| Frontend HITL | interrupt UI、全部 decisions、resume 与 durable optimistic transcript。 |
| Branch / queue / join-rejoin / time travel | checkpoint 分支、enqueue、disconnect vs stop、forkFrom 和 Agent Server 前提。 |
| Generative UI overview + 3 modes | controlled、declarative、open-ended 的控制/风险光谱。 |
| Integrations overview + 4 guides | AI Elements、assistant-ui、CopilotKit、OpenUI 的接入方式与第三方边界。 |