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

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


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

核心作用

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

渲染三步骤

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

各框架选型

框架 推荐库 关键说明
React react-markdown + remark-gfm 直接转 React 元素,无需 XSS 净化
Vue marked + dompurify 转 HTML 后必须净化
Svelte marked + dompurify 同 Vue,用 {@html}
Angular marked + 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 (


    {message.content}


    {messageToolCalls.map(tc => (
    <ToolCard key={tc.call.id} toolCall={tc} />
    ))}

    );
    }

  2. 工具卡片分发

    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" } } });

  2. Reject(拒绝):带原因退回

    stream.submit(null, { command: { resume: { decision: "reject", reason } } });

  3. 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 }
    );
    }

  2. 重生成回答

    function handleRegenerate(stream, metadata) {
    const checkpoint = metadata.firstSeenState?.parent_checkpoint;
    stream.submit(undefined, { checkpoint });
    }

  3. 分支切换

    // 分支切换器
    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 聊天前端开发。

相关推荐
勇往直前plus2 小时前
LangChain content_blocks:统一处理多模态与跨模型厂商消息内容
langchain
Pu_Nine_93 小时前
前端SSE(Server-Sent Events)实现详解:从原理到前端AI对话应用
前端·langchain·sse·ai对话
无风听海3 小时前
Deep Agents 的 Planning Capabilities 技术解析
langchain·deep agents
Familyism12 小时前
langchain应用
langchain
chaors17 小时前
从零学RAG0x0f:RAG 评估指标提升实战
langchain·llm·ai编程
1941s18 小时前
Google Agent Development Kit (ADK) 指南 第五章:工具集成与自定义
人工智能·python·langchain·agent·adk
在未来等你19 小时前
AI Agent Skill Day 11:RAG Retrieval技能:检索增强生成的技能封装
langchain·知识库问答·向量检索·rag·ai agent·检索增强生成·技能开发
DamianGao20 小时前
MiniMax-M2.7 与 LangChain ToolStrategy 兼容性问题解决
python·langchain
勇往直前plus21 小时前
大模型开发手记(十二):langchain skills(上):讲清楚什么是skills,优势是什么
langchain