固定回答模板扩展指南
本文说明如何在 lanque-app 中修改现有固定回答模板、增加数据组件,或接入一个全新的模板类型。
1. 先判断属于哪一种改动
| 需求 | 示例 | 主要改动范围 |
|---|---|---|
| 修改现有模板视觉 | 调整 report 的字号、留白或表格 | 对应 src/answers/**/*Template.vue 或其子组件 |
| 给现有模板增加组件 | 为 report 增加一种真实数据图表 | 完整模板、src/answers/composed/、组件注册表 |
| 给现有模板增加数据字段 | report.data 新增一种 MCP 原始记录 | 类型、Schema、提示词、模板及文本导出 |
| 新增全新模板 ID | 新增 inventory、production | 完整运行链路,不能只新增 Vue 文件 |
| 新增全新业务域 | 在 AGV、机车检修之外增加库存域 | 全新模板链路,加业务域识别和 MCP 工具过滤 |
最重要的区别:
src/answers负责“数据最后怎么画”。- 意图分类、MCP 取数、数据契约和校验负责“什么时候使用、给什么数据、数据是否可信”。
2. 当前运行链路
用户问题
↓
意图分类:选择 template ID
↓
业务域识别:agv / rail
↓
发现并按业务域筛选 MCP 工具
↓
模型规划、调用工具并收集本轮真实结果
↓
client__submit_answer_payload
├─ 使用该模板的 JSON Schema 约束参数
├─ 校验业务域
└─ 校验每条记录能否在本轮 MCP 结果中找到来源
↓
生成 { template, data } 固定载荷
↓
前端再次执行 normalize + Ajv 校验
↓
整页大卡片或数据组件拼接
因此,仅把一个 Vue 文件放进 src/answers 不会让模板自动生效。
3. 只修改现有模板
当前主要固定模板为:
agv.status:src/answers/AgvStatusTemplate.vueworkorder:src/answers/WorkOrderTemplate.vuereport:src/answers/ReportTemplate.vue
agv.dispatch 主要用于历史数据兼容,新 AGV 请求会落到 agv.status,不建议以它作为新功能入口。
3.1 只调整样式或布局
如果 template ID 和 data 结构均不变化,只需调整对应模板或它引用的子组件,不必修改模型、MCP 和 Schema 逻辑。
3.2 给现有模板增加数据组件
当前整页模式与拼接模式共用同源子组件。建议按以下方式接入:
- 在
src/answers/composed/<业务目录>/新增组件。 - 组件接收当前模板的原始
data,不要自行请求 MCP。 - 在完整
*Template.vue中以embedded方式组合该组件。 - 在
src/answers/composed/registry.ts注册拼接模式下的出现条件、顺序、区域和宽度。
推荐组件约定:
defineProps<{
data: SomeTemplateData;
embedded?: boolean;
}>();
embedded: true:作为完整大卡片内部区块,不渲染第二层卡片边框。- 默认模式:作为独立拼接组件,使用克制的卡片外壳。
3.3 空数据语义
模板应区分下面两种情况:
// 没有该字段:本轮没有查询这项数据
{}
// 字段存在且为空:查询过,真实结果为 0 条
{ plans: [] }
判断“是否查询过”应使用 own-property,而不是只写 data.plans ?? []。非空数组才渲染大型内容区块;全局空态只保留一个,避免每个组件重复显示空卡。
4. 新增全新模板 ID
假设新增模板 ID 为 inventory,至少需要完成以下步骤。
4.1 定义 TypeScript 数据契约
文件:src/contracts/answers.ts
需要:
- 将
inventory加入AnswerTemplate。 - 定义
InventoryData,字段应贴近 MCP 的真实返回。 - 定义
InventoryAnswer。 - 将其加入
AnswerPayload联合类型。 - 在
TEMPLATE_TITLE中加入用户可见标题。
不要把图表坐标、卡片颜色、标题文案或模型计算的 KPI 放进数据契约。契约应以真实业务记录为主,统计值由客户端确定性派生。
4.2 定义 JSON Schema
文件:src/contracts/answerSchemas.ts
需要:
- 为新数据结构定义严格 Schema。
- 明确 required、enum、数组元素和
additionalProperties。 - 将 Schema 加入
dataSchemas。
同一份 Schema 会同时用于:
client__submit_answer_payload的模型函数参数。- 前端收到载荷后的 Ajv 校验。
未登记 Schema 时,即使模型返回了新模板,前端也会判定为未知模板并拒绝渲染。
只有在确实需要兼容常见格式错误时,才调整 normalizeAnswerPayload();不得利用 normalize 生成缺失的业务事实。
4.3 注册整页模板
文件:src/answers/registry.ts
导入新的 Vue 模板,并建立:
['inventory', InventoryTemplate]
模板组件必须能够接收 data prop。
项目中虽然已有 registerTemplate() 和 registerAnswerSchema(),但目前没有自动扫描目录或自动加载插件模板的入口。因此,现阶段仍然需要显式注册。
4.4 配置模板提示词和本地意图
文件:src/llm/systemPrompt.ts
需要补充:
TEMPLATE_PAYLOAD_RULES:模型应原样提交哪些 MCP 字段,以及严禁补造哪些字段。DATA_COLLECTION_NEEDS:为该视图应收集哪些数据维度。selectAnswerTemplate():明确关键词时的本地快速路由和分类失败兜底。
提示词只描述数据需求和真实性约束,不描述 HTML、CSS 或图表坐标。
4.5 扩展模型意图分类器
文件:src/ipc/openai/OpenAiIpcClient.ts
需要同步修改:
ClassifiedTemplate的合法值判断。- 兼容普通文本响应时使用的模板解析。
- 意图分类器 system prompt 中的模板说明。
select_answer_template函数的 enum。- 客户端执行进度中使用的模板名称。
遗漏这里时,真实模型不会选择新模板,即使渲染组件和 Schema 已经存在。
4.6 定义复制与语音摘要
文件:src/utils/answerText.ts
分别为新模板实现:
answerPayloadToPlainText():复制、无障碍文本等场景使用。answerPayloadToSpeechText():TTS 使用的简洁摘要。
不要把 JSON、全部表格或视觉坐标直接交给 TTS。
5. 新增业务域时的额外工作
如果新模板属于 AGV 和机车检修之外的业务域,还需要扩展:
5.1 业务域类型与识别
文件:src/llm/systemPrompt.ts
BusinessDomainselectBusinessDomain()
回答形态和业务域是两个维度。例如 report 是回答形态,它可以承载 AGV 报表,也可以承载机车检修报表。
5.2 MCP 工具域过滤
文件:src/ipc/openai/OpenAiIpcClient.ts
需要检查并扩展:
relatedDeniedTools()toolMatchesDomain()filterDiscoveryForDomain()submittedDomainIssue()
这些逻辑决定模型能看到哪些 MCP 工具,以及最终提交的数据能否跨业务域。
模板接入不会自动授予 MCP 权限。对应 Server、Tool、Skill 权限仍需由平台授权配置或应用配置提供。
6. 组件拼接模式
如果新模板需要支持设置页中的“数据组件拼接”,还要修改:
src/components/AnswerCard.vue:将新 template ID 加入拼接模式允许范围。src/answers/composed/registry.ts:扩展数据联合并注册组件。
每个组件注册项应明确:
supports:支持哪些 template ID。when:哪些真实字段到达时出现。order:阅读顺序。zone:概览、分析、关系或明细。span:所占宽度。
如果不接入拼接模式,新模板仍可走整页模式,但设置切换到拼接模式时会回退到整页模板。产品上应明确这是预期行为还是遗漏。
7. 体验配套项
以下不是数据链的核心,但完整产品通常应该同步处理。
7.1 等待骨架与状态文案
src/components/ViewSkeleton.vue:增加新模板的骨架形状。src/features/chat/MessageStream.vue:增加步骤标签到模板的映射,以及等待阶段名称。
7.2 Mock 模式
文件:src/ipc/mock/fixtures.ts
如果未配置 API 时也要演示新模板,需要增加:
- 合法的固定 payload fixture。
- Mock 意图匹配规则。
- Mock 回答选择分支。
只运行真实模型时可以暂不添加,但会失去无 API 场景的回归能力。
7.3 设置页
当前“整页大卡片 / 数据组件拼接”是全局显示模式,不需要为每个模板增加一个设置项。
8. 数据真实性约束
新模板应继续遵守当前固定视图链路的约束:
- 模型只整理本轮成功 MCP 结果中的原始记录。
- 模型不生成 HTML、CSS、SVG、图表坐标或视觉配置。
- 模型不补齐 MCP 没有返回的工单号、负责人、路线、ETA 等事实。
- 汇总、排序、状态翻译和图表序列尽量由前端纯函数计算。
- 每条非空记录必须能在本轮 MCP 结果中找到来源。
- 空数组是有效结果;缺字段不能被解释为业务数量为零。
- 可选字段缺失时隐藏对应细节或显示“—”,不得制造默认业务值。
9. 推荐目录结构
src/answers/
InventoryTemplate.vue
registry.ts
composed/
inventory/
presentation.ts
InventoryOverviewBlock.vue
InventoryDistributionBlock.vue
InventoryListBlock.vue
registry.ts
src/contracts/
answers.ts
answerSchemas.ts
presentation.ts 只放确定性的展示派生,例如排序、分组、计数和格式化;不要在这里请求网络或补造记录。
10. 验收清单
必测数据场景
- 字段未查询。
- 已查询但数组为空。
- 单条记录。
- 多条及大量记录。
- 可选字段缺失。
- 超长编号和长文本。
- 无效 enum、错误类型和额外字段能够被 Schema 拒绝。
必测界面场景
- 整页大卡片模式。
- 数据组件拼接模式。
- 桌面宽度与小窗口宽度。
- 明暗主题。
- 横向、纵向滚动。
- 复制内容。
- TTS 摘要。
- 流式等待骨架与最终视图切换。
必测运行场景
- 明确关键词能命中新模板。
- 模型分类器能返回新 template ID。
- 分类接口失败时本地规则能合理兜底。
- 只向模型暴露当前业务域的 MCP 工具。
- MCP 返回真实数据时可以提交并通过来源校验。
- 无相关数据时不生成模拟记录或空壳视图。
11. 本地验证命令
在项目根目录运行:
.\node_modules\.bin\vue-tsc.cmd --noEmit
.\node_modules\.bin\vite.cmd build
随后至少在应用内分别用整页、拼接两种模式测试一次真实问题。
12. 最小接入清单
新增全新模板 ID 时,可按下面顺序执行:
-
contracts/answers.ts:模板 ID、Data、Answer、联合类型、标题。 -
contracts/answerSchemas.ts:严格数据 Schema。 -
answers/*Template.vue:完整视图。 -
answers/registry.ts:整页模板注册。 -
llm/systemPrompt.ts:字段规则、数据需求、本地意图。 -
OpenAiIpcClient.ts:分类枚举、说明、解析与进度名。 - 新业务域时:MCP 工具域过滤和提交域校验。
-
utils/answerText.ts:复制文本和 TTS 摘要。 - 需要拼接时:
AnswerCard.vue与answers/composed/registry.ts。 -
ViewSkeleton.vue与MessageStream.vue:等待体验。 -
ipc/mock/fixtures.ts:Mock 回归。 - 类型检查、生产构建及界面矩阵验证。
讨论
评论
还没有评论,来留下第一条讨论吧。