回答操作事件客户端协议
版本:1.0
状态:客户端已实现
适用范围:Lanque App 回答卡片操作区
1. 目标与边界
回答操作事件用于在最终回答中提供“查看详情、修改展示、继续处理、确认执行”等入口。
客户端只接受声明式 JSON,不接受可执行代码。事件分为两类:
- 本地展示操作:只修改当前回答的展示,不请求模型、不调用 MCP。
- 后续业务操作:转换为一条规范请求,通过当前
chat.send()重新进入既有编排。
本协议不会建立新的工具执行通道。工具选择、MCP 调用、用户权限和高风险工具审批仍由现有编排负责。
2. actions 放置位置
客户端支持在以下两种结构中携带 actions:
2.1 结构化 answer.data
{
"schemaVersion": "1.0",
"answerKind": "maintenance.report",
"datasets": {
"plans": [],
"faults": []
},
"actions": [
{
"id": "continue-analysis",
"type": "conversation.continue",
"label": "继续分析",
"params": {
"prompt": "继续分析异常月份和可能原因"
}
}
]
}
2.2 固定 AnswerPayload
{
"template": "report",
"data": {
"plans": [],
"faults": []
},
"actions": [
{
"id": "show-detail",
"type": "view.detail",
"label": "查看详情"
}
]
}
当两处同时存在时,优先使用 answerData.actions。
3. 通用结构
interface AnswerAction {
id: string;
type: AnswerActionType;
label: string;
style?: 'primary' | 'default' | 'danger';
title?: string;
description?: string;
riskLevel?: 'LOW' | 'MEDIUM' | 'HIGH';
requiresConfirmation?: boolean;
target?: {
dataset?: string;
componentId?: string;
};
params?: {
prompt?: string;
chartType?: ChartEncoding;
};
}
3.1 通用参数
| 参数 | 必填 | 限制 | 用途 |
|---|---|---|---|
id | 是 | 非空,最多 80 字符,同一回答内不可重复 | 操作稳定标识及状态持久化键 |
type | 是 | 必须是客户端白名单事件 | 决定操作路由 |
label | 是 | 非空,最多 32 字符 | 按钮文案 |
style | 否 | primary、default、danger | 只控制按钮视觉,不影响权限 |
title | 否 | 最多 80 字符 | 确认区标题或按钮提示 |
description | 否 | 最多 240 字符 | 操作说明及确认区影响描述 |
riskLevel | 否 | LOW、MEDIUM、HIGH | 客户端确认策略参考 |
requiresConfirmation | 否 | 仅 true 有效 | 强制在执行前确认 |
target.dataset | 否 | 最多 120 字符 | 预留的数据集定位字段;当前版本打开整组数据明细 |
target.componentId | 否 | 最多 120 字符 | 定位当前回答中的图表组件 |
params.prompt | 按事件 | 非空,最多 800 字符 | 交给现有编排的规范请求,或填入输入框的修改前缀 |
params.chartType | 按事件 | 必须是受支持的图表类型 | 本地切换图表形式 |
单条回答最多处理前 8 个合法动作。未知字段不会透传给执行层。
4. 已支持事件
4.1 view.detail
用途:展开当前回答下方的数据明细。
| 项目 | 当前行为 |
|---|---|
| 必填参数 | 无额外参数 |
| 本地执行 | 是 |
| 是否重新请求 | 否 |
| 是否需要确认 | 默认不需要 |
| 持久化状态 | 记录操作成功状态 |
示例:
{
"id": "view-raw-records",
"type": "view.detail",
"label": "查看原始记录",
"target": {
"dataset": "faults"
}
}
当前版本接受 target.dataset,但仍会展开本回答的完整数据明细,不会只筛选某一个数据集。
4.2 render.change
用途:在本地修改指定统计图的呈现形式。
| 项目 | 当前行为 |
|---|---|
| 必填参数 | params.chartType |
| 推荐参数 | target.componentId |
| 本地执行 | 是 |
| 是否重新查询数据 | 否 |
| 是否改变统计口径 | 否 |
| 持久化 | 图表覆盖和操作状态都随会话保存 |
支持的 chartType:
| 值 | 展示形式 |
|---|---|
bar | 柱状图 |
row | 横向条形图 |
line | 折线图 |
area | 面积图 |
donut | 环形图 |
scatter | 散点图标识;当前固定图表渲染会按已有兼容策略处理 |
table | 表格 |
示例:
{
"id": "monthly-plan-to-line",
"type": "render.change",
"label": "换成折线图",
"target": {
"componentId": "monthly-plan-chart"
},
"params": {
"chartType": "line"
}
}
执行限制:
componentId找不到时操作失败。- 未提供
componentId且存在多张兼容图表时,客户端要求进一步指定图表。 - 图表与数据形态不兼容时拒绝切换,例如无序分类数据不能强行表现为时间趋势。
4.3 render.reset
用途:恢复当前回答中所有图表的客户端默认形式。
| 项目 | 当前行为 |
|---|---|
| 必填参数 | 无 |
| 本地执行 | 是 |
| 是否重新请求 | 否 |
| 作用范围 | 当前回答的全部图表覆盖 |
| 持久化 | 保存恢复后的状态 |
示例:
{
"id": "reset-charts",
"type": "render.reset",
"label": "恢复默认展示"
}
4.4 conversation.continue
用途:基于当前回答继续分析或继续查询。
| 项目 | 当前行为 |
|---|---|
| 必填参数 | params.prompt |
| 本地执行 | 否 |
| 执行去向 | 当前运行模式的现有 chat.send() 链路 |
| MCP 与鉴权 | 完全沿用现有编排 |
| 是否确认 | 默认不确认;可通过风险参数强制确认 |
示例:
{
"id": "analyze-anomalies",
"type": "conversation.continue",
"label": "继续分析",
"params": {
"prompt": "继续分析故障高发部件,并说明可能原因"
}
}
4.5 conversation.modify
用途:给用户提供修改当前结果的入口。
| 项目 | 当前行为 |
|---|---|
params.prompt | 可选,缺省为“请修改当前结果:” |
| 本地执行 | 是 |
| 是否自动发送 | 否 |
| 实际行为 | 将修改前缀填入输入框,由用户补充并确认发送 |
示例:
{
"id": "modify-current-view",
"type": "conversation.modify",
"label": "修改展示",
"params": {
"prompt": "请修改当前结果的展示方式:"
}
}
4.6 business.execute
用途:发起创建、下发、修改等会产生业务影响的后续请求。
| 项目 | 当前行为 |
|---|---|
| 必填参数 | params.prompt |
| 客户端确认 | 始终需要 |
| 执行去向 | 确认后进入现有 chat.send() 编排 |
| 是否直接调用工具 | 否 |
| 后端鉴权和 MCP 审批 | 仍然必须通过 |
示例:
{
"id": "create-maintenance-order",
"type": "business.execute",
"label": "生成检修工单",
"style": "primary",
"title": "确认生成检修工单?",
"description": "将为 HXN5-001 发起工单创建请求,最终仍需通过您的业务权限校验。",
"riskLevel": "HIGH",
"params": {
"prompt": "为 HXN5-001 创建检修工单"
}
}
4.7 business.cancel
用途:发起取消任务、取消工单等业务请求。
| 项目 | 当前行为 |
|---|---|
| 必填参数 | params.prompt |
| 客户端确认 | 始终需要 |
| 推荐样式 | danger |
| 执行去向 | 确认后进入现有编排 |
| 是否直接调用工具 | 否 |
示例:
{
"id": "cancel-task-2048",
"type": "business.cancel",
"label": "取消任务",
"style": "danger",
"description": "取消后任务将停止继续调度。",
"params": {
"prompt": "取消任务 TASK-2048"
}
}
4.8 answer.refresh
用途:使用产生当前回答的原问题重新查询。
| 项目 | 当前行为 |
|---|---|
| 必填参数 | 无 |
| 使用内容 | 当前回答对应的原始用户问题 |
| 执行去向 | 现有 chat.send() 编排 |
params.prompt | 当前版本忽略 |
示例:
{
"id": "refresh-report",
"type": "answer.refresh",
"label": "刷新数据"
}
5. 客户端自动补充的入口
即使回答没有携带 actions,客户端也会根据当前内容补充安全操作:
| 条件 | 自动入口 | 事件 |
|---|---|---|
| 回答存在完整数据明细 | 查看详情 | view.detail |
| 当前回答注册了统计图 | 修改展示 | conversation.modify |
| 能找到产生回答的原问题 | 继续处理 | conversation.continue |
客户端不会自动生成 business.execute 或 business.cancel,避免从数据内容猜测业务操作。
如果外部已经提供同类型动作,客户端不再重复补充对应默认入口。
6. 确认策略
满足以下任一条件时,客户端在执行前显示确认区:
requiresConfirmation为true;riskLevel为MEDIUM;riskLevel为HIGH;- 事件类型为
business.execute; - 事件类型为
business.cancel。
确认区会展示:
title,未提供时使用“确认{label}?”;description,未提供时显示默认权限说明;- 即将提交的
params.prompt; - “取消”和“确认执行”按钮。
这里的确认只代表用户允许客户端继续提交请求,不代替后端权限校验和 MCP 高风险审批。
7. 操作状态
type AnswerActionStatus =
| 'idle'
| 'confirming'
| 'running'
| 'success'
| 'error'
| 'cancelled';
| 状态 | 含义 |
|---|---|
idle | 可操作或已将内容填入输入框 |
confirming | 正在等待用户确认 |
running | 正在本地处理或向现有编排提交 |
success | 本地处理完成或请求已被现有编排接收 |
error | 参数、目标、兼容性或提交过程失败 |
cancelled | 用户在确认区取消 |
状态结构:
{
"status": "success",
"message": "展示已修改",
"updatedAt": "2026-08-27T07:00:00.000Z"
}
actionStates 和 chartPresentation 都保存在回答消息的会话检查点中,因此本地展示修改在切换会话后仍可恢复。
“请求已被接收”不代表业务操作最终成功。最终业务结果仍以随后生成的回答及真实工具结果为准。
8. 校验与拒绝规则
以下动作会被直接丢弃,不渲染按钮:
actions不是数组;type不在事件白名单中;- 缺少或超长的
id、label; - 同一回答中出现重复
id; conversation.continue缺少params.prompt;business.execute缺少params.prompt;business.cancel缺少params.prompt;render.change缺少合法的params.chartType。
以下字段即使出现在输入中,也不会进入客户端执行对象:
- 工具名,例如
tool、toolName; - MCP 服务器名;
- URL;
- JavaScript 或回调;
- RPC 方法名;
- 任意业务参数对象;
- 未列入本协议的
params字段。
因此下面的内容不会直接调用 MCP:
{
"id": "unsafe",
"type": "business.execute",
"label": "执行",
"tool": "mcp__delete_all",
"params": {
"prompt": "执行指定业务操作",
"arguments": {
"admin": true
}
}
}
客户端最多只保留合法的 id、type、label、视觉说明、风险信息、受控目标以及 prompt/chartType。其中 tool 和 arguments 会被删除。
9. 完整示例
{
"schemaVersion": "1.0",
"answerKind": "maintenance.report",
"datasets": {
"plans": [],
"faults": []
},
"actions": [
{
"id": "detail",
"type": "view.detail",
"label": "查看详情"
},
{
"id": "chart-line",
"type": "render.change",
"label": "换成折线图",
"target": {
"componentId": "monthly-plan-chart"
},
"params": {
"chartType": "line"
}
},
{
"id": "continue",
"type": "conversation.continue",
"label": "继续分析",
"params": {
"prompt": "继续分析故障高发月份及可能原因"
}
},
{
"id": "create-order",
"type": "business.execute",
"label": "生成工单",
"style": "primary",
"riskLevel": "HIGH",
"description": "将发起工单创建请求。",
"params": {
"prompt": "根据当前检修结果生成待确认的检修工单"
}
}
]
}
10. 当前未实现或预留能力
target.dataset精确展开单个数据集;当前展开全部数据明细。- 任意组件类型之间的通用替换;当前
render.change主要处理已注册统计图。 - 由客户端直接调用 MCP 或后端业务接口。
- 在原回答内部展示后续业务操作的最终执行结果;当前状态表示“已提交”,最终结果作为下一条回答呈现。
- 服务端签发的不可伪造 action token。
- 跨设备同步动作状态;当前跟随本地会话检查点。
11. 对接检查清单
提供 actions 的一方只需确认:
actions与datasets同级。- 每个动作有唯一且稳定的
id。 - 使用本协议列出的
type。 - 按类型提供
prompt或chartType。 - 业务动作的
prompt必须明确对象和动作,不使用“它”“那个”等模糊指代。 - 高风险动作提供清晰的
description和正确的riskLevel。 - 不传工具名、鉴权信息、令牌和任意执行参数。
客户端即使收到格式错误的动作,也只会忽略相应按钮,不会影响回答正文和数据渲染。
讨论
评论
还没有评论,来留下第一条讨论吧。