当前位置: 首页 > news >正文

LangChain Frontend 10 大核心模式完整总结

本文基于 LangChain 官方前端文档,覆盖Markdown 渲染、工具调用、人机协同、分支对话、推理 Token、结构化输出、消息队列、断连重连、时光回溯、生成式 UI10 大场景,用通俗语言 + 核心逻辑 + 代码要点 + 最佳实践,完整还原官方用法,不删减、不跳步。


一、Markdown Messages:流式渲染富文本 Markdown

核心作用

把 LLM 输出的标题、列表、代码块、表格等 Markdown 格式,实时流式渲染成富文本,不浪费模型输出的结构化信息。

渲染三步骤

  1. 接收:useStream 实时累积流式文本到 msg.text,响应式更新
  2. 解析:Markdown 库把纯文本转成 HTML/React 元素(聊天长度 < 5ms)
  3. 渲染:插入 DOM,React 用虚拟 DOM,Vue/Svelte/Angular 用净化后 HTML

各框架选型

框架推荐库关键说明
Reactreact-markdown + remark-gfm直接转 React 元素,无需 XSS 净化
Vuemarked + dompurify转 HTML 后必须净化
Sveltemarked + dompurify同 Vue,用 {@html}
Angularmarked + dompurify同 Vue,用 [innerHTML]

关键代码(React)

import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; // 通用Markdown组件 function Markdown({ children }) { return ( <div className="markdown-content"> <ReactMarkdown remarkPlugins={[remarkGfm]}>{children}</ReactMarkdown> </div> ); } // 聊天流中使用 {stream.messages.map(msg => ( AIMessage.isInstance(msg) ? <Markdown key={msg.id}>{msg.text}</Markdown> : <p key={msg.id}>{msg.text}</p> ))}

安全与优化

  • XSS 防护:Vue/Svelte/Angular 必须用 DOMPurify 净化,移除 script、onclick 等
  • 流式优化:长消息(>50KB)用 requestAnimationFrame 节流渲染
  • 样式建议:紧凑间距、小字号,适配聊天气泡

最佳实践

  1. 必开 GFM 支持(表格、删除线、任务列表)
  2. 开启 breaks: true,把单换行转
  3. 空内容判断,避免渲染空容器
  4. 测试富内容:标题、嵌套列表、长代码、宽表格

二、Tool Calling:工具调用富卡片渲染

核心作用

把 Agent 调用天气、计算器、搜索、数据库等工具的 JSON 结果,渲染成带加载 / 成功 / 失败状态的可视化卡片。

工作流程

  1. Agent 发出工具调用(name/args/id)→ 2. 后端执行 → 3. useStream 同步 toolCalls 数组 → 4. 前端渲染状态卡片

核心类型:ToolCallWithResult

interface ToolCallWithResult { call: { id: string; name: string; args: object }; result: ToolMessage | undefined; state: "pending" | "completed" | "error"; // 三状态 }

关键代码

  1. 消息绑定工具调用
function Message({ message, toolCalls }) { // 按消息匹配工具调用 const messageToolCalls = toolCalls.filter(tc => message.tool_calls?.find(t => t.id === tc.call.id) ); return ( <div> <p>{message.content}</p> {messageToolCalls.map(tc => ( <ToolCard key={tc.call.id} toolCall={tc} /> ))} </div> ); }
  1. 工具卡片分发
function ToolCard({ toolCall }) { if (toolCall.state === "pending") return <LoadingCard />; if (toolCall.state === "error") return <ErrorCard />; // 按工具名渲染专属卡片 switch (toolCall.call.name) { case "get_weather": return <WeatherCard />; case "calculator": return <CalculatorCard />; default: return <GenericToolCard />; } }

最佳实践

  1. 必处理三状态:pending/completed/error,不空白
  2. 安全解析:JSON.parse 包 try/catch
  3. 加载态显式:显示工具名 + 参数,让用户知道在做什么
  4. 卡片紧凑:不挤占聊天区域

三、Human-in-the-Loop:人机协同审批流

核心作用

Agent 执行发邮件、删数据、转账等高危操作前,暂停等待人工审批,通过后再继续。

中断流程

  1. Agent 触发中断 → 2. stream.interrupt 抛出待办动作 → 3. UI 渲染审批卡片 → 4. 用户决定(同意 / 拒绝 / 编辑)→ 5. stream.submit 恢复执行

中断数据结构

interface HITLRequest { actionRequests: { action: string; args: object; description?: string }[]; reviewConfigs: { allowedDecisions: ("approve"|"reject"|"edit")[] }[]; }

三种决策

  1. Approve(同意):直接执行
stream.submit(null, { command: { resume: { decision: "approve" } } });
  1. Reject(拒绝):带原因退回
stream.submit(null, { command: { resume: { decision: "reject", reason } } });
  1. Edit(编辑):修改参数后执行
stream.submit(null, { command: { resume: { decision: "edit", args } } });

最佳实践

  1. 清晰上下文:显示动作 + 参数 + 说明
  2. 一键同意:同意最简,拒绝 / 编辑多步
  3. 编辑校验:JSON 格式校验
  4. 持久化中断:刷新页面不丢失
  5. 审计日志:记录所有决策

四、Branching Chat:分支对话(编辑 / 重生成 / 回溯)

核心作用

把对话变成树结构,编辑消息、重生成回答会创建分支,不丢失历史,可自由切换版本。

核心能力

  • 编辑任意用户消息,从该点重跑
  • 重生成任意 AI 回答
  • 分支切换,查看不同对话路径

关键配置

// 必须开启历史获取 const stream = useStream({ apiUrl: AGENT_URL, assistantId: "branching_chat", fetchStateHistory: true, // 关键 });

核心操作

  1. 编辑消息
function handleEdit(stream, originalMsg, metadata, newText) { const checkpoint = metadata.firstSeenState?.parent_checkpoint; stream.submit( { messages: [{ ...originalMsg, content: newText }] }, { checkpoint } ); }
  1. 重生成回答
function handleRegenerate(stream, metadata) { const checkpoint = metadata.firstSeenState?.parent_checkpoint; stream.submit(undefined, { checkpoint }); }
  1. 分支切换
// 分支切换器 function BranchSwitcher({ metadata, onSwitch }) { const { branch, branchOptions } = metadata; // 渲染前后箭头 + 当前版本/总版本 }

最佳实践

  1. 必开 fetchStateHistory
  2. 分支器仅多版本时显示
  3. 悬停显示编辑 / 重生成按钮,保持界面整洁
  4. 切换分支保留滚动位置
  5. 流式中禁用操作

五、Reasoning Tokens:推理过程可视化

核心作用

展示 OpenAI o1/o3、Claude 等模型的思考过程,把推理块和最终回答分开渲染,提升透明感。

两种内容块

// 推理块(思考过程) { type: "reasoning", reasoning: "一步步分析..." } // 文本块(最终答案) { type: "text", text: "答案是42" }

提取逻辑

function extractBlocks(msg) { const reasoning = msg.contentBlocks .filter(b => b.type === "reasoning") .map(b => b.reasoning).join(""); const text = msg.contentBlocks .filter(b => b.type === "text") .map(b => b.text).join(""); return { reasoning, text }; }

思考气泡组件

  • 默认折叠,点击展开
  • 流式中显示加载动画
  • 显示字符数,提示思考量

最佳实践

  1. 默认折叠,不干扰阅读
  2. 视觉区分:淡紫色背景,独立样式
  3. 支持展开 / 收起动画
  4. 处理空推理、多轮推理

六、Structured Output:结构化输出渲染

核心作用

让 Agent 直接输出JSON 结构化数据,而非纯文本,前端映射为卡片、表格、步骤等定制 UI。

实现原理

Agent 用一个纯数据工具返回结构化参数,无实际执行逻辑,只做数据载体。

提取函数

function extractStructuredOutput<T>(messages, requiredFields = []) { const lastAI = messages.filter(AIMessage.isInstance).at(-1); const toolCall = lastAI?.tool_calls?.[0]; if (!toolCall?.args) return null; // 校验必填字段 const hasRequired = requiredFields.every(f => toolCall.args[f] != null); return hasRequired ? (toolCall.args as T) : null; }

渐进式渲染

流式中字段到达即渲染,不用等完整数据,提升体验。

最佳实践

  1. 必校验必填字段
  2. 通用提取函数,适配多 schema
  3. 扁平 schema,易流式渲染
  4. 提供降级方案:富文本 ↔ 结构化

七、Message Queues:消息队列(批量发送)

核心作用

支持用户连续发多条消息,不用等上一条回复,服务端顺序排队执行,前端可查看 / 取消队列。

核心能力

  • 批量提交,自动排队
  • 实时显示待处理列表
  • 单条 / 清空取消
  • 链式提交(onCreated)

队列 API

stream.queue = { entries: QueueEntry[], // 待办列表 size: number, // 数量 cancel: (id) => Promise<void>, // 取消单条 clear: () => Promise<void>, // 清空全部 };

关键代码

// 提交消息自动入队 function handleSubmit(text) { stream.submit({ messages: [{ type: "human", content: text }] }); } // 队列展示与取消 {stream.queue.entries.map(entry => ( <li key={entry.id}> {entry.values.messages[0].content} <button onClick={() => stream.queue.cancel(entry.id)}>取消</button> </li> ))}

最佳实践

  1. 显示消息预览,方便识别
  2. 取消仅影响未开始任务
  3. 新线程清空队列
  4. 处理高并发提交

八、Join & Rejoin Streams:断连重连

核心作用

客户端断网 / 切页 / 后台时,Agent 继续服务端执行,重连后无缝恢复,不丢失进度。

核心配置

// 提交时开启可恢复 stream.submit( { messages }, { onDisconnect: "continue", // 断连后继续执行 streamResumable: true, // 允许重连 } );

核心 API

  • stream.stop ():断开客户端,不停止 Agent
  • stream.joinStream (runId):用运行 ID 重连
  • onCreated:保存 runId(本地存储持久化)

重连逻辑

// 保存 runId const stream = useStream({ onCreated(run) { localStorage.setItem("runId", run.run_id); } }); // 重连 stream.joinStream(localStorage.getItem("runId"));

最佳实践

  1. 必存 runId(状态 + 本地存储)
  2. 显式连接状态指示器
  3. 切页自动重连
  4. 清理过期 runId
  5. 重连失败友好提示

九、Time Travel:时光回溯(检查点回滚)

核心作用

Agent 每步执行生成检查点,可查看任意时刻状态、从历史点恢复执行,相当于对话级别的 Git 回溯。

检查点结构

interface ThreadState { checkpoint: { checkpoint_id, timestamp }; // 快照ID values: AgentState; // 完整状态(消息+自定义数据) tasks: { name, interrupts }[]; // 执行节点 next: string[]; // 下一步节点 }

时光旅行操作

// 从检查点恢复执行 stream.submit(null, { checkpoint: selectedCheckpoint.checkpoint });

界面建议

左右分栏:左侧聊天,右侧时间线,点击切换检查点,查看状态并恢复。

最佳实践

  1. 懒加载历史,避免大量检查点卡顿
  2. 显示节点名 + 消息数,不展示裸 ID
  3. 恢复前二次确认
  4. 高亮当前检查点
  5. 支持键盘步进

十、Generative UI:生成式 UI(AI 直接画界面)

核心作用

AI 不输出文本,直接生成 UI 描述,前端用组件库安全渲染表单、卡片、仪表盘。

三步流程

  1. 定义组件目录:声明 AI 可用组件 + Props 校验(Zod)
  2. AI 生成 Spec:JSON 描述组件树
  3. 安全渲染:json-render 按目录渲染,杜绝非法组件

组件目录示例

const catalog = defineCatalog(schema, { components: { Card: { description: "带标题的卡片", props: z.object({ title: z.string().optional() }) }, Button: { description: "按钮", props: z.object({ label: z.string(), variant: z.enum(...) }) } } });

流式渲染

// 流式中渐进渲染,只渲染完整组件 const spec = useMemo(() => { if (!rawSpec?.root || !rawSpec.elements) return null; // 过滤有效元素 const safeElements = Object.entries(rawSpec.elements) .filter(([_, el]) => el.type && el.props != null) .reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {}); return { root: rawSpec.root, elements: safeElements }; }, [rawSpec, stream.isLoading]);

最佳实践

  1. 组件描述清晰,引导 AI 正确使用
  2. 流式传 loading=true,平滑渲染
  3. 用设计令牌适配明暗主题
  4. 必包 JSONUIProvider
  5. 小目录更精准,避免大而全

通用基础:useStream 统一配置

所有模式都基于 useStream,通用模板:

import type { BaseMessage } from "@langchain/core/messages"; // 1. 定义状态接口 interface AgentState { messages: BaseMessage[] } // 2. 初始化流 const stream = useStream<typeof myAgent>({ apiUrl: "http://localhost:2024", assistantId: "你的助手ID", fetchStateHistory?: true, // 分支/时光旅行用 });

整体总结

这 10 大模式覆盖了AI 聊天前端从基础渲染到高级交互的全场景:

  1. 基础渲染:Markdown Messages
  2. 能力扩展:Tool Calling、Structured Output、Generative UI
  3. 交互增强:Branching Chat、Reasoning Tokens
  4. 流程控制:Human-in-the-Loop、Message Queues
  5. 稳定性:Join & Rejoin
  6. 调试 / 回溯:Time Travel

全部遵循流式优先、安全可控、体验优雅的官方设计理念,可直接用于生产级 AI 聊天前端开发。

http://www.jsqmd.com/news/498849/

相关文章:

  • 知名厂家电动四轮车控制器代码及PCB文件、PDF原理图全齐,风格优良
  • CIrrMap250:中国2000–2020年250米灌溉耕地分布栅格数据|逐年百分比|GeoTIFF格式
  • 在 ASP.NET Core 项目里接入大模型,真没那么难
  • Java毕业设计springboot基于Javaweb的二手图书交易系统76915352
  • Wan2.1 VAE一键部署教程:基于Python的AI图像生成环境快速搭建
  • 全场景定制化开发,适配多品类的盲盒小程序解决方案
  • Qwen3-TTS-Tokenizer-12Hz语音质量评测:PESQ与MOS得分分析
  • 集成高性能物理引擎:JoltPhysics的跨平台实践指南
  • 最新!2026年OpenClaw京东云4分钟云上/MacOS/Linux/Windows集成及使用步骤
  • GTE文本向量-large多任务协同案例:电商评论情感分析→触发事件抽取→生成摘要链路
  • openclaw等主流多Agent框架介绍
  • EasyAnimateV5-7b-zh-InP开源可部署:models目录结构解读与模型热替换
  • 霜儿-汉服-造相Z-Turbo生成效果深度评测:对比不同采样器与参数
  • 本文仅作测试用,无实际意义,请略过
  • #define 与 const 区别
  • 360CDN SDK 游戏盾实测:游戏防护与延迟优化
  • 如何画出优秀的架构图?
  • VibeVoice语音合成系统评测:实时性、音质、易用性三方面分析
  • Python如何将列表的数据清空?
  • SAKURA EMOTION MAGIC 提示词工程指南:如何撰写激发最佳情感分析效果的Prompt
  • 资讯丨SBTi认证费用上涨了!(附官方文件下载)
  • 4个关键行业中的3DDFA实战指南:从技术原理到商业价值
  • Kook Zimage 真实幻想 Turbo Qt界面开发教程
  • Qwen3-ASR-0.6B模型架构解析:AuT编码器详解
  • DeepSeek v4 下周空降?2026 国产 AI 终极悬念:这 3 个杀手锏能否超越 GPT-5.4?
  • lora-scripts效果实测:仅需消费级显卡,两小时完成风格微调训练
  • Llama-3.2V-11B-cot 与Dify集成实战:打造无需编码的视觉AI应用工作流
  • PE文件到Shellcode转换:实现进程注入的新范式
  • AGENTS.md高效开发指南:从环境搭建到测试优化
  • 这套ThinkPHP框架的CRM源码带Uniapp移动端,企业级功能全开源