Skip to content

生成式 UI

生成式 UI 让 AI 助手不只返回纯文本,还能在聊天消息里展示结构化的投资卡片、图表和确认面板。Investment Agent 采用的是 Server-driven Generative UI:模型不生成 JSX 或 HTML,而是通过受控工具生成 UIArtifact JSON,前端再用白名单组件渲染。

这套方案适合金融产品:界面更清晰,同时保留 schema 校验、审计、消息历史兼容和交易安全边界。

股票行情卡片

展示股票代码、名称、价格、涨跌幅、关键指标和迷你趋势数据。

基金详情面板

展示基金名称、收益指标、风险等级和持仓分布。

受限数据图表

支持折线图、柱状图、饼图,并限制 series 和数据点数量,避免大 payload 拖慢长对话。

交易意图卡片

只表达待确认的买入或卖出意图,不会直接成交。

  1. 用户在聊天中提出投资问题,例如查询股票行情、基金风险或收益曲线。
  2. Hermes Agent 调用业务工具获取结构化数据。
  3. Agent 在需要更丰富展示时调用 create_ui_artifact 工具。
  4. 服务端使用 Zod 校验 artifact 类型和 props。
  5. SSE 流推送 textui_artifact 事件。
  6. 前端把 artifact 写入当前 assistant 消息的 uiArtifacts,并由 GenerativeUIRenderer 渲染。
  7. 消息完成后,contentuiArtifacts 一起持久化到聊天历史。

每条助手消息仍然保留文本内容,生成式 UI 只是额外字段:

interface ChatMessage {
content: string;
uiArtifacts?: UIArtifact[];
}
interface UIArtifact {
id: string;
type:
| 'stock_quote_card'
| 'fund_detail_panel'
| 'data_chart'
| 'trade_intent_card';
version: 1;
props: Record<string, unknown>;
fallbackText: string;
}

fallbackText 是必填字段,用于渲染失败、复制、分享、导出和历史兼容。旧消息没有 uiArtifacts 也可以正常显示。

生成式 UI 的核心原则是“模型选择和填充受控卡片,系统负责校验和渲染”。

  • 模型只能输出 JSON artifact,不能输出 JSX、HTML、scriptstyleiframe
  • artifact type 必须命中前端白名单组件注册表。
  • 每类 props 都必须通过 Zod schema 校验。
  • 未知类型或非法 props 会展示 fallback,而不是渲染任意 UI。
  • 图表数据有数量上限,防止超大 payload 影响虚拟列表性能。
  • 交易意图卡只触发 /api/chat/trade-intent 确认流程,不直接执行交易。
类型用途关键约束
stock_quote_card股票行情卡片metrics 最多 10 项,miniTrend 最多 30 个点
fund_detail_panel基金详情面板returnMetrics 最多 10 项,holdings 最多 20 项
data_chart折线、柱状、饼图最多 5 个 series,每个 series 最多 100 个数据点
trade_intent_card买入/卖出意图确认状态必须是 pending,必须包含 idempotencyKey

当前实现的主要入口如下:

能力文件
Artifact 类型与 Zod 校验src/types/chat/uiArtifact.ts
前端渲染器src/app/(pages)/chat/features/Conversation/components/GenerativeUI/GenerativeUIRenderer.tsx
白名单组件注册表src/app/(pages)/chat/features/Conversation/components/GenerativeUI/registry.ts
Hermes 工具注册src/server/core/agents/hermes/registerBusinessTools.ts
SSE artifact 事件src/server/base/sseEmitter.ts
消息持久化字段drizzle/schema/chat.ts 中的 uiArtifacts
交易意图 APIsrc/app/api/chat/trade-intent/route.ts

新增一种生成式 UI 卡片时,按这个顺序接入:

  1. src/types/chat/uiArtifact.ts 中新增 artifact 类型、props schema 和校验映射。
  2. GenerativeUI/components/ 下实现 React 组件。
  3. GenerativeUI/registry.ts 中注册组件。
  4. 更新 create_ui_artifact 的提示词或工具描述,让 Agent 知道何时使用该类型。
  5. 为 schema、renderer fallback、组件渲染和流式事件补充测试。

trade_intent_card 用于把 AI 的买入或卖出建议转成用户可确认的意图卡。它不是交易执行凭证,也不会绕过服务端验证。

后续接入真实交易前,服务端必须完成:

  • 账户归属校验
  • 用户权限校验
  • 当前价格或报价有效期校验
  • 仓位、单日亏损、交易额度等风控校验
  • 基于 idempotencyKey 的幂等去重

Portal 更适合承载侧边栏里的大产物,例如长文档、报告或可编辑内容。生成式 UI 面向的是聊天气泡内的小型业务卡片:它跟随消息历史保存,适合展示行情、图表摘要和确认面板。