1333 lines
41 KiB
Markdown
1333 lines
41 KiB
Markdown
# 工业 AI 交互画布方案草案
|
||
|
||
版本:v0.2
|
||
目标:把第一阶段产品交互、系统边界和技术路线收敛清楚。本文档默认采用推荐方案,不再把每个决策点作为待选项展开。
|
||
|
||
## 1. 背景与目标
|
||
|
||
这个项目不是一个“AI 聊天框”,而是一个面向工业生产现场的 **AI 交互画布**。AI 的回复不应该主要表现为长文字,而应该表现为漂亮、清晰、可交互的组件。
|
||
|
||
核心目标有三类:
|
||
|
||
1. **自然语言控制工业能力**
|
||
用户先通过文字输入,后续再接入语音,要求 AI 调用工业软件、上位机软件、PLC/HMI 或其他工具能力,例如调参、开机、开灯、开泵、读取状态、执行生产动作。
|
||
|
||
2. **自然语言查询设备知识**
|
||
用户询问设备说明书、调机经验、故障处理、生产注意事项时,AI 不直接堆大段文字,而是生成像教学卡片一样的组件:视频、图片、步骤、重点、展开详情、专业说明、引用来源都分层显示。
|
||
|
||
3. **引导式调机流程**
|
||
AI 能带技师一步步完成调机。流程里既有 AI 自动调用工具完成的步骤,也有需要人工操作并反馈结果的步骤。第一阶段反馈来自鼠标点击和文字输入,后续再接入语音反馈。
|
||
|
||
当前项目已经有一个很好的雏形:左侧聊天,右侧画布,根据 tool invocation 渲染不同组件。后续把它从“根据工具名写死渲染”升级为 **结构化 Artifact 协议 + React 组件注册表 + 状态机**。
|
||
|
||
## 2. 产品定位
|
||
|
||
### 2.1 不做什么
|
||
|
||
- 不把这个系统做成完整工业软件 GUI 的替代品。
|
||
- 不把 PLC Web HMI 的所有操作搬进 AI 界面。
|
||
- 不让 LLM 随意生成前端代码并直接运行。
|
||
- 第一阶段不实现权限体系、动作分级、ASR 和完整安全审计。
|
||
|
||
### 2.2 要做什么
|
||
|
||
- 做工业软件和 HMI 之外的 **AI 辅助交互层**。
|
||
- 对关键动作提供清晰的可视化反馈、确认、进度、结果、失败原因和恢复建议。
|
||
- 对知识查询提供“先简洁、后展开”的教学式体验。
|
||
- 对调机任务提供流程引导、状态保存、点击/文字统一操作,语音操作作为后续扩展。
|
||
|
||
## 3. 两类工业场景的交互边界
|
||
|
||
### 3.1 上位机 GUI 场景
|
||
|
||
设备本身已有上位机软件 GUI。AI 页面只做补充,不重复展示所有 GUI。
|
||
|
||
适合展示:
|
||
|
||
- AI 即将执行的动作。
|
||
- 参数变更前后对比。
|
||
- 当前动作的执行前提示。
|
||
- 动作执行进度和结果。
|
||
- 异常时的解释和下一步建议。
|
||
- 调机步骤的引导卡片。
|
||
|
||
不适合展示:
|
||
|
||
- 完整工艺界面。
|
||
- 所有实时数据点。
|
||
- 原软件已有的复杂操作面板。
|
||
|
||
### 3.2 PLC + Web HMI 场景
|
||
|
||
PLC 是主控,另有 Web HMI 做实操显示。AI 画布重点是交互效果和辅助理解。
|
||
|
||
适合展示:
|
||
|
||
- “水泵已启动”“探照灯打开中”“产线准备中”等动画状态。
|
||
- 当前 HMI 页面之外的解释性信息。
|
||
- AI 对当前动作的总结。
|
||
- 面向技师的流程提示、确认卡片、注意事项。
|
||
|
||
不适合展示:
|
||
|
||
- 替代 HMI 的核心控制界面。
|
||
- 密集的实时仪表盘。
|
||
- 需要毫秒级闭环控制的操作。
|
||
|
||
## 4. 总体架构建议
|
||
|
||
如果只想快速看宏观结构和下一步优化方向,优先看这份 HTML 总览:[`architecture_overview.html`](./architecture_overview.html)。
|
||
|
||
第一阶段采用下面的分层:
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
U["技师 / 操作员"] --> V["文字输入 / 鼠标点击"]
|
||
V --> R["意图路由器"]
|
||
R --> A["AI 编排层"]
|
||
A --> T["工业工具层"]
|
||
A --> K["知识库 / 说明书 / 视频图片"]
|
||
A --> S["Artifact 状态管理"]
|
||
S --> C["前端组件画布"]
|
||
C --> E["Action Event"]
|
||
E --> R
|
||
T --> S
|
||
K --> S
|
||
```
|
||
|
||
关键点:
|
||
|
||
- **AI 编排层**:负责理解用户需求、选择工具、组织知识、决定展示什么组件。
|
||
- **工业工具层**:由你后续实现,负责真正调用工业软件、PLC、HMI、设备接口。
|
||
- **Artifact 状态管理**:保存当前组件、流程步骤、可点击动作、文本别名、状态快照。
|
||
- **前端组件画布**:只渲染受控组件,不运行 LLM 生成的任意代码。
|
||
- **意图路由器**:判断一句输入是在操作当前组件,还是在问新问题,还是要中断流程。
|
||
|
||
后续语音接入时,ASR 只负责把语音变成文本;BERT NLU 可以放在意图路由器前后,用来提升当前组件操作、新问题、流程控制等意图分类的稳定性。第一阶段不实现 ASR 和 BERT NLU,只保证路由接口可以承接它们。
|
||
|
||
### 4.1 宏观分层架构图
|
||
|
||
后续接入语音识别、Python NLU、工业工具和可视化配置后,建议整体分成 7 层:
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph L1["交互输入层"]
|
||
Mic["麦克风 / 语音流"]
|
||
TextInput["文字输入"]
|
||
Click["组件点击"]
|
||
end
|
||
|
||
subgraph L2["感知与语义层"]
|
||
ASR["ASR 服务\n语音转文本"]
|
||
Normalize["文本归一化\n单位/数字/同义词"]
|
||
NLU["Python NLU 服务\nDomain / Intent / Slot"]
|
||
end
|
||
|
||
subgraph L3["会话与路由层(TS)"]
|
||
Session["Session Context\n当前设备/当前流程/当前 Artifact"]
|
||
Router["Input Router\n当前组件优先 + NLU + LLM 兜底"]
|
||
end
|
||
|
||
subgraph L4["编排层(TS)"]
|
||
Orchestrator["AI / Tool Orchestrator\n选择工具、组织结果"]
|
||
UIInspect["inspect_ui_state\n让 LLM 读取画布摘要"]
|
||
end
|
||
|
||
subgraph L5["能力与配置层"]
|
||
ToolRegistry["Tool Registry\n工具目录 / 输入输出 Schema"]
|
||
VizRegistry["Visualization Registry\n工具到组件的绑定配置"]
|
||
Knowledge["Knowledge Registry\n说明书 / SOP / 视频 / 图片"]
|
||
end
|
||
|
||
subgraph L6["执行层"]
|
||
ToolGateway["Industrial Tool Gateway\n上位机 / PLC / HMI / Mock 工具"]
|
||
KnowledgeSearch["知识检索服务"]
|
||
end
|
||
|
||
subgraph L7["展示层"]
|
||
ArtifactStore["Artifact Store\n状态快照 / 流程实例"]
|
||
Canvas["React Artifact Canvas\n参数卡 / 动画卡 / 知识卡 / 流程卡"]
|
||
end
|
||
|
||
Mic --> ASR --> Normalize
|
||
TextInput --> Normalize
|
||
Click --> Router
|
||
Normalize --> Router
|
||
Router --> NLU
|
||
NLU --> Router
|
||
Session --> Router
|
||
Router --> Orchestrator
|
||
Orchestrator --> ToolRegistry
|
||
Orchestrator --> VizRegistry
|
||
Orchestrator --> Knowledge
|
||
Orchestrator --> ToolGateway
|
||
Orchestrator --> KnowledgeSearch
|
||
UIInspect --> ArtifactStore
|
||
ToolGateway --> ArtifactStore
|
||
KnowledgeSearch --> ArtifactStore
|
||
ArtifactStore --> Canvas
|
||
Canvas --> Click
|
||
```
|
||
|
||
各层职责:
|
||
|
||
- **交互输入层**:接收语音、文字、点击,不判断业务含义。
|
||
- **感知与语义层**:ASR 产出文本,Python NLU 产出结构化意图。
|
||
- **会话与路由层**:决定一句话是在操作当前组件,还是开启新任务。
|
||
- **编排层**:根据 NLU/LLM 结果选择工具,生成 artifact。
|
||
- **能力与配置层**:维护工具目录、工具输入输出结构、可视化组件绑定。
|
||
- **执行层**:真正调用工业软件、PLC、HMI、知识库。
|
||
- **展示层**:渲染组件、保存流程状态、接收用户反馈。
|
||
|
||
## 5. Artifact 组件协议
|
||
|
||
### 5.1 推荐思路
|
||
|
||
LLM 不直接返回 React/HTML,而是返回结构化组件数据。前端根据 `type` 从组件注册表中选择固定组件渲染。
|
||
|
||
示例:
|
||
|
||
```ts
|
||
type InteractionArtifact = {
|
||
artifactId: string;
|
||
type:
|
||
| "parameter_change"
|
||
| "device_action"
|
||
| "production_start"
|
||
| "knowledge_lesson"
|
||
| "guided_procedure"
|
||
| "media_gallery"
|
||
| "alarm_explanation";
|
||
title: string;
|
||
status: "draft" | "waiting_confirmation" | "running" | "success" | "failed" | "paused";
|
||
props: Record<string, unknown>;
|
||
actions: ArtifactAction[];
|
||
llmContext: ArtifactLLMContext;
|
||
snapshotPolicy: "ephemeral" | "session" | "persistent";
|
||
};
|
||
|
||
type ArtifactAction = {
|
||
actionId: string;
|
||
label: string;
|
||
kind: "primary" | "secondary" | "danger" | "input" | "toggle" | "choice";
|
||
textAliases: string[];
|
||
voiceAliases?: string[];
|
||
requiresConfirmation?: boolean;
|
||
disabled?: boolean;
|
||
};
|
||
```
|
||
|
||
这样做的好处:
|
||
|
||
- UI 风格稳定,可控。
|
||
- 工业执行边界更清晰。
|
||
- 组件可以持续迭代,不依赖每次 LLM 生成。
|
||
- 点击、文字指令和后续语音可以共用同一个 `actionId`。
|
||
- LLM 可以只看到必要摘要,不必看到复杂 UI 细节。
|
||
|
||
### 5.2 已确定的组件渲染路线
|
||
|
||
第一阶段采用 **React 组件注册表 + JSON Artifact 协议**。
|
||
|
||
具体做法:
|
||
|
||
- 控制、调参、流程类交互全部使用固定 React 组件。
|
||
- LLM 或后端编排层只产出结构化 JSON,不直接产出 JSX/HTML。
|
||
- 前端根据 `artifact.type` 从组件注册表选择组件。
|
||
- 知识内容中的长说明可以使用受限 Markdown,但外层仍由固定教学组件承载。
|
||
- 暂不做动态远程组件,也不允许 LLM 生成任意 UI 代码。
|
||
|
||
## 6. 工业控制类交互设计
|
||
|
||
### 6.1 参数设置组件
|
||
|
||
典型输入:
|
||
|
||
- “把主轴转速调到 1800。”
|
||
- “把水泵压力上限改成 0.8MPa。”
|
||
- “温度补偿加 2 度。”
|
||
|
||
组件应该展示:
|
||
|
||
- 参数名称。
|
||
- 当前值。
|
||
- 目标值。
|
||
- 单位。
|
||
- 影响范围。
|
||
- 是否需要确认。
|
||
- 执行结果。
|
||
- 可恢复/回滚信息。
|
||
|
||
建议组件:`ParameterChangeCard`
|
||
|
||
状态流:
|
||
|
||
```mermaid
|
||
stateDiagram-v2
|
||
[*] --> Preview: 解析参数变更
|
||
Preview --> WaitingConfirm: 展示旧值/新值
|
||
WaitingConfirm --> Running: 用户确认
|
||
WaitingConfirm --> Cancelled: 用户取消
|
||
Running --> Success: 工具执行成功
|
||
Running --> Failed: 工具执行失败
|
||
Failed --> WaitingConfirm: 修改后重试
|
||
```
|
||
|
||
交互细节:
|
||
|
||
- 第一阶段统一采用“预览 -> 用户确认 -> 工具执行 -> 展示结果”的闭环。
|
||
- 确认可以来自按钮点击,也可以来自文字输入,例如“确认修改”“执行”。
|
||
- 后续接入语音时,语音确认也转换为同一个 `actionId`,不单独做一套逻辑。
|
||
|
||
### 6.2 具象设备控制组件
|
||
|
||
典型输入:
|
||
|
||
- “打开探照灯。”
|
||
- “启动水泵。”
|
||
- “关闭除尘风机。”
|
||
- “开始生产。”
|
||
|
||
建议组件:
|
||
|
||
- `DeviceActionCard`:打开灯、泵、阀、风机等单设备动作。
|
||
- `ProductionStartCard`:开机生产、启动工艺、产线准备。
|
||
- `MachineStatusAnimation`:动作动画,例如灯光亮起、水流动、泵叶旋转、设备进入运行态。
|
||
|
||
展示内容:
|
||
|
||
- 设备图标和动画。
|
||
- 当前状态:关闭、准备中、启动中、运行、失败。
|
||
- 执行动作。
|
||
- 工具调用进度。
|
||
- 执行前提示。
|
||
- 执行后的状态确认。
|
||
|
||
控制类动作不一定都需要长文字。界面可以用动画、状态徽标、颜色和短句表达结果。
|
||
|
||
### 6.3 第一阶段控制执行边界
|
||
|
||
第一阶段不实现权限体系、动作风险分级和高风险确认策略。控制类能力先按“可演示、可模拟、可替换真实工具”的方式设计。
|
||
|
||
执行边界:
|
||
|
||
- Mock 工具阶段:所有控制动作都可以完整演示 UI、状态流和失败处理。
|
||
- 接真实工业工具后:工具层由你负责控制实际可执行范围,本项目只负责把意图、参数、确认和结果组织成清晰交互。
|
||
- 所有控制类组件都保留“预览/确认/执行中/成功/失败”的状态结构,方便未来加权限、动作分级或审计。
|
||
- `ProductionStartCard` 先作为交互样板,不在第一阶段实现复杂生产安全策略。
|
||
|
||
## 7. 知识查询类交互设计
|
||
|
||
### 7.1 展示原则
|
||
|
||
知识问答不应该每次都显示大段文字。推荐采用“儿童教学式”的结构,但视觉和语言仍保持工业专业感:
|
||
|
||
1. 先给一句结论。
|
||
2. 展示核心图、视频或步骤。
|
||
3. 给 3 到 5 个关键点。
|
||
4. 专业细节折叠起来。
|
||
5. 引用说明书或知识库来源。
|
||
6. 用户需要时再展开。
|
||
|
||
建议组件:`KnowledgeLessonArtifact`
|
||
|
||
模块:
|
||
|
||
- 顶部结论。
|
||
- 设备/部件示意图。
|
||
- 视频卡片。
|
||
- 图片步骤卡。
|
||
- “为什么这样做”解释区。
|
||
- “专业详情”折叠区。
|
||
- “继续调机”按钮。
|
||
- “查看原文/来源”按钮。
|
||
|
||
### 7.2 知识内容生成流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Q["用户问题"] --> R["检索说明书/知识库"]
|
||
R --> P["提取关键段落、图片、视频"]
|
||
P --> G["AI 组织教学结构"]
|
||
G --> A["生成 Knowledge Artifact"]
|
||
A --> UI["画布分层展示"]
|
||
```
|
||
|
||
建议每次知识回答都保留来源:
|
||
|
||
- 文档名称。
|
||
- 页码或章节。
|
||
- 图片/视频 ID。
|
||
- 知识库条目版本。
|
||
- 生成时间。
|
||
|
||
### 7.3 已确定的知识展示路线
|
||
|
||
第一阶段采用 **固定教学外壳 + block 内容**。
|
||
|
||
具体做法:
|
||
|
||
- 外层固定为 `KnowledgeLessonArtifact`。
|
||
- 内部使用 block 列表表达结论、步骤、图片、视频、注意事项、专业详情、引用来源。
|
||
- 大段文字默认折叠,不直接铺满主界面。
|
||
- block 协议先保持简单,后续可以自然演进成更完整的卡片编排器。
|
||
|
||
示例 block:
|
||
|
||
```ts
|
||
type KnowledgeBlock =
|
||
| { type: "summary"; text: string }
|
||
| { type: "key_points"; items: string[] }
|
||
| { type: "steps"; steps: Array<{ title: string; body: string; media?: MediaRef[] }> }
|
||
| { type: "media"; media: MediaRef[] }
|
||
| { type: "details"; title: string; markdown: string; defaultOpen?: boolean }
|
||
| { type: "citations"; citations: KnowledgeCitation[] };
|
||
```
|
||
|
||
## 8. 引导式调机流程
|
||
|
||
### 8.1 流程步骤类型
|
||
|
||
调机流程建议抽象成 `GuidedProcedure`:
|
||
|
||
```ts
|
||
type ProcedureStep =
|
||
| {
|
||
type: "auto_tool";
|
||
title: string;
|
||
toolName: string;
|
||
args: Record<string, unknown>;
|
||
}
|
||
| {
|
||
type: "manual_action";
|
||
title: string;
|
||
instruction: string;
|
||
expectedFeedback: string[];
|
||
media?: MediaRef[];
|
||
}
|
||
| {
|
||
type: "measurement_input";
|
||
title: string;
|
||
field: string;
|
||
unit: string;
|
||
validRange?: [number, number];
|
||
}
|
||
| {
|
||
type: "decision_branch";
|
||
title: string;
|
||
choices: string[];
|
||
}
|
||
| {
|
||
type: "checklist_gate";
|
||
title: string;
|
||
checks: string[];
|
||
};
|
||
```
|
||
|
||
### 8.2 自动步骤与人工步骤
|
||
|
||
自动步骤:
|
||
|
||
- AI 调用工具读取状态。
|
||
- AI 设置参数。
|
||
- AI 触发设备动作。
|
||
- AI 查询报警或日志。
|
||
|
||
人工步骤:
|
||
|
||
- 技师更换夹具。
|
||
- 技师观察指示灯。
|
||
- 技师测量间隙。
|
||
- 技师确认工件位置。
|
||
- 技师上传或选择现场照片。
|
||
|
||
每一步都应该有明确状态:
|
||
|
||
- 未开始。
|
||
- 正在执行。
|
||
- 等待人工反馈。
|
||
- 已完成。
|
||
- 失败。
|
||
- 已跳过。
|
||
- 已暂停。
|
||
|
||
### 8.3 鼠标和文字输入统一操作
|
||
|
||
所有按钮都应该映射为 `actionId`。鼠标点击和文字命令最终都生成同一种事件;后续接入语音后,语音识别结果也走同一个事件协议:
|
||
|
||
```ts
|
||
type ArtifactActionEvent = {
|
||
artifactId: string;
|
||
actionId: string;
|
||
source: "click" | "text" | "voice" | "system";
|
||
value?: unknown;
|
||
transcript?: string;
|
||
confidence?: number;
|
||
createdAt: string;
|
||
};
|
||
```
|
||
|
||
示例:
|
||
|
||
- 点击“已完成”按钮:`actionId = "step.complete"`
|
||
- 文字输入“这一步完成了”:`actionId = "step.complete"`
|
||
- 文字输入“压力是 0.72”:`actionId = "measurement.submit"`,`value = 0.72`
|
||
|
||
这样前端、文字输入、未来语音和后端流程引擎不会各做一套逻辑。
|
||
|
||
## 9. 输入路由策略:新问题还是操作当前组件
|
||
|
||
这是本项目最关键的体验问题之一。
|
||
|
||
### 9.1 推荐核心原则
|
||
|
||
当存在正在进行的调机流程或控制确认时,系统进入 **前台任务模式**。这时用户输入优先解释为对当前组件的操作,而不是立刻开启新话题。
|
||
|
||
可以把当前组件理解为持有一个“前台交互权”:
|
||
|
||
- 当前组件有可执行动作。
|
||
- 当前流程有等待反馈的步骤。
|
||
- 用户没有明确输入“暂停当前流程”。
|
||
|
||
在这种情况下,输入路由优先级如下:
|
||
|
||
1. 全局流程指令:取消、暂停、继续、返回。
|
||
2. 当前组件按钮或输入项:确认、取消、下一步、已完成、数值反馈。
|
||
3. 当前流程相关问题:例如“这一步为什么要这样做?”
|
||
4. 临时查询问题:例如“顺便查一下这个报警码。”
|
||
5. 新任务或新流程。
|
||
6. 闲聊。
|
||
|
||
### 9.2 已确定的输入路由路线
|
||
|
||
第一阶段采用 **规则优先 + LLM 兜底**。
|
||
|
||
具体做法:
|
||
|
||
- 当前组件按钮、确认、取消、下一步、已完成等短指令,用规则和 `textAliases` 直接匹配。
|
||
- 数值输入用规则解析,例如“压力 0.72”“测量值是 3.1”。
|
||
- 当前流程相关的解释性问题、新问题、复杂表达交给 LLM。
|
||
- 后续接入 BERT NLU 时,把 BERT 输出作为意图路由器的一个信号源,不改变 Artifact Action Event 协议。
|
||
|
||
### 9.3 防止闲聊打断调机流程
|
||
|
||
推荐策略:
|
||
|
||
- 调机流程进行中时,不允许普通新问题直接覆盖当前画布。
|
||
- 新问题默认以“侧边临时回答”或“小浮层”展示,不替换主流程。
|
||
- 如果新问题会打开新的大型组件,系统先问:“当前调机流程正在第 3 步,要暂停并打开新内容吗?”
|
||
- 用户可以输入“暂停这个”“先问个问题”“继续刚才”。
|
||
- 每个流程步骤都保存快照,随时可以恢复。
|
||
|
||
### 9.4 组件状态快照
|
||
|
||
建议保存:
|
||
|
||
- 当前 artifact。
|
||
- 当前流程 ID。
|
||
- 当前步骤 ID。
|
||
- 已完成步骤。
|
||
- 已调用工具及结果。
|
||
- 人工反馈记录。
|
||
- 当前可用 action 列表。
|
||
- 当前画布摘要。
|
||
- 最近 N 条用户输入 transcript。
|
||
|
||
状态快照用途:
|
||
|
||
- 防止误打断。
|
||
- 支持恢复流程。
|
||
- 支持 LLM 理解当前界面。
|
||
- 支持恢复和复盘。
|
||
|
||
## 10. LLM 如何理解当前组件
|
||
|
||
你提出的判断很对:工具调用后直接显示组件,而不是把完整组件都给 LLM 看,是合理的。但如果用户围绕界面内容提问,LLM 必须知道当前界面上有什么。
|
||
|
||
### 10.1 推荐方案:组件提供 LLM 可读摘要
|
||
|
||
每个组件除了 `props`,还提供一个 `llmContext`:
|
||
|
||
```ts
|
||
type ArtifactLLMContext = {
|
||
visibleSummary: string;
|
||
currentState: string;
|
||
activeStep?: string;
|
||
visibleFields: Array<{
|
||
label: string;
|
||
value: string;
|
||
}>;
|
||
availableActions: Array<{
|
||
actionId: string;
|
||
label: string;
|
||
textAliases: string[];
|
||
voiceAliases?: string[];
|
||
}>;
|
||
lastEvents: string[];
|
||
};
|
||
```
|
||
|
||
LLM 不需要看完整 DOM 或截图,只需要看这个结构化摘要。
|
||
|
||
### 10.2 已确定的 LLM 查看组件路线
|
||
|
||
第一阶段采用 **极简上下文 + `inspect_ui_state` 工具**:
|
||
|
||
- 每轮 prompt 默认带:当前是否有前台流程、当前步骤、是否等待用户反馈。
|
||
- 当用户输入“这个按钮是什么意思”“为什么让我做这一步”“刚才显示的目标值是多少”时,LLM 调用 `inspect_ui_state` 获取详细组件状态。
|
||
|
||
### 10.3 示例工具
|
||
|
||
```ts
|
||
inspect_ui_state({
|
||
detailLevel: "summary" | "actions" | "full",
|
||
artifactId?: string
|
||
})
|
||
```
|
||
|
||
返回:
|
||
|
||
```json
|
||
{
|
||
"artifactId": "artifact_123",
|
||
"type": "guided_procedure",
|
||
"title": "主轴换型调机流程",
|
||
"status": "waiting_confirmation",
|
||
"currentStep": "第 3 步:确认夹具锁紧",
|
||
"visibleSummary": "画布正在等待技师确认夹具已经锁紧。",
|
||
"availableActions": [
|
||
{ "actionId": "step.complete", "label": "已完成" },
|
||
{ "actionId": "step.need_help", "label": "需要帮助" },
|
||
{ "actionId": "procedure.pause", "label": "暂停流程" }
|
||
]
|
||
}
|
||
```
|
||
|
||
## 11. 工具调用与组件显示的关系
|
||
|
||
### 11.1 推荐拆分
|
||
|
||
一次工业工具调用应该拆成三类结果:
|
||
|
||
```ts
|
||
type ToolResponse = {
|
||
machineResult: unknown;
|
||
llmSummary: string;
|
||
artifact?: InteractionArtifact;
|
||
executionRecord: {
|
||
toolName: string;
|
||
args: unknown;
|
||
resultCode: string;
|
||
createdAt: string;
|
||
};
|
||
};
|
||
```
|
||
|
||
- `machineResult`:给系统内部使用。
|
||
- `llmSummary`:给 LLM 用,让它知道发生了什么。
|
||
- `artifact`:给前端画布渲染。
|
||
- `executionRecord`:保存最小执行记录,方便前端恢复状态和调试。
|
||
|
||
这样可以避免把过多 UI 细节塞给 LLM,同时又能让 LLM 知道关键事实。
|
||
|
||
### 11.2 已确定的工具结果展示路线
|
||
|
||
第一阶段采用 **工具只执行,编排层生成 artifact**。
|
||
|
||
具体做法:
|
||
|
||
- 工业工具层只返回执行结果,不关心 UI。
|
||
- AI 编排层或后端 Artifact Builder 根据工具结果生成 `InteractionArtifact`。
|
||
- 前端只消费 artifact,不直接理解工业工具内部数据结构。
|
||
- 这样后续替换 Mock 工具为真实工业工具时,UI 协议保持稳定。
|
||
|
||
### 11.3 第二版:工具可视化组件分类与维护
|
||
|
||
第二版需要增加一个“工具和可视化组件维护中心”,让工具能力和画布组件之间不再完全写死在代码里。这样新增工业工具时,可以配置它应该用哪种可视化方式呈现。
|
||
|
||
工具可视化先分为三类:
|
||
|
||
| 类型 | 用途 | 示例组件 | 适用工具 |
|
||
|---|---|---|---|
|
||
| 检索信息类型 | 展示查询、检索、知识库或设备资料结果 | `KnowledgeLessonArtifact`、`AlarmExplanationCard`、`MediaGalleryCard` | 查说明书、查报警码、查调机经验、查设备状态摘要 |
|
||
| 图标动画类型 | 展示具象设备动作和执行状态 | `DeviceActionCard`、`ProductionStartCard`、`MachineStatusAnimation` | 开灯、开泵、开阀、启动风机、开机生产 |
|
||
| 用户自定义类型 | 允许用户把某个工具绑定到自定义组件配置 | `CustomToolArtifact`、自定义 schema 驱动组件 | 特定设备动作、厂内专用流程、业务定制工具 |
|
||
|
||
第二版建议增加 `ToolVisualizationConfig`:
|
||
|
||
```ts
|
||
type ToolVisualizationConfig = {
|
||
toolName: string;
|
||
displayName: string;
|
||
visualizationType: "retrieval_info" | "icon_animation" | "custom";
|
||
artifactType: InteractionArtifact["type"] | "custom_tool";
|
||
icon?: string;
|
||
animationPreset?: string;
|
||
propMapping: Array<{
|
||
from: string;
|
||
to: string;
|
||
transform?: "string" | "number" | "boolean" | "status" | "media_list";
|
||
}>;
|
||
defaultActions?: ArtifactAction[];
|
||
customSchema?: Record<string, unknown>;
|
||
enabled: boolean;
|
||
};
|
||
```
|
||
|
||
维护中心需要支持:
|
||
|
||
- 查看所有工具。
|
||
- 给工具选择可视化类型。
|
||
- 配置工具结果字段到 artifact props 的映射。
|
||
- 配置按钮、文本别名和后续语音别名。
|
||
- 配置图标、动画预设、状态文案。
|
||
- 对用户自定义类型提供 schema 校验,避免组件收到不可渲染的数据。
|
||
|
||
第二版不要求用户直接写 React 组件。更稳的方式是先提供“可配置组件模板”:
|
||
|
||
- 信息卡模板。
|
||
- 状态动画模板。
|
||
- 步骤流程模板。
|
||
- 参数对比模板。
|
||
- 媒体资料模板。
|
||
|
||
真正的远程自定义组件可以作为更后面的能力,因为它会带来版本、样式、执行边界和兼容性问题。
|
||
|
||
## 12. 数据与状态设计
|
||
|
||
### 12.1 核心对象
|
||
|
||
建议至少有这些对象:
|
||
|
||
- `ConversationSession`:一次对话会话。
|
||
- `ArtifactSession`:当前画布状态。
|
||
- `WorkflowInstance`:调机流程实例。
|
||
- `ToolExecution`:每次工具调用记录。
|
||
- `ActionEvent`:每次点击、文字、未来语音、系统事件。
|
||
- `KnowledgeCitation`:知识来源。
|
||
- `OperatorContext`:当前操作员、班组、设备。第一阶段不展开权限模型。
|
||
|
||
### 12.2 状态保存级别
|
||
|
||
| 级别 | 用途 | 示例 |
|
||
|---|---|---|
|
||
| 临时态 | 普通问答卡片 | 查一个概念 |
|
||
| 会话态 | 当前任务内有效 | 当前参数修改确认 |
|
||
| 持久态 | 可恢复、可复盘 | 调机流程、生产动作、工具调用 |
|
||
|
||
调机流程和生产动作建议进入持久态。第一阶段先保证能恢复流程和复盘交互,不做完整审计系统。
|
||
|
||
## 13. 输入与 NLU 接入边界
|
||
|
||
### 13.0 汽车语音助手里的 Domain / Intent / Slot / 上下文状态
|
||
|
||
汽车语音助手常用的 NLU 体系可以理解成四层语义结构:
|
||
|
||
| 概念 | 含义 | 汽车例子 | 工业设备例子 |
|
||
|---|---|---|---|
|
||
| Domain | 业务领域,先判断用户在说哪类事情 | 空调、导航、车窗、音乐 | 参数设置、设备控制、报警知识、调机流程 |
|
||
| Intent | 用户想完成的动作 | 打开空调、导航到公司、调高音量 | 设置参数、打开设备、查询报警、进入调机 |
|
||
| Slot | 动作需要的参数 | 温度 24 度、目的地公司、音量 8 | 参数名主轴转速、目标值 1800、设备探照灯 |
|
||
| Context State | 当前对话/界面/设备状态 | 正在导航、刚打开空调、当前温度 22 度 | 当前 Artifact、当前调机步骤、当前设备、等待确认 |
|
||
|
||
例如汽车里一句话:“把空调调到 24 度”:
|
||
|
||
```json
|
||
{
|
||
"domain": "climate",
|
||
"intent": "set_temperature",
|
||
"slots": {
|
||
"temperature": 24,
|
||
"unit": "celsius"
|
||
},
|
||
"contextState": {
|
||
"vehicleArea": "front"
|
||
}
|
||
}
|
||
```
|
||
|
||
工业设备里一句话:“把主轴转速调到 1800”:
|
||
|
||
```json
|
||
{
|
||
"domain": "machine_parameter",
|
||
"intent": "set_parameter",
|
||
"slots": {
|
||
"parameter": "主轴转速",
|
||
"value": 1800,
|
||
"unit": "rpm"
|
||
},
|
||
"contextState": {
|
||
"deviceId": "machine_01",
|
||
"activeArtifactId": "artifact_123"
|
||
}
|
||
}
|
||
```
|
||
|
||
这里最容易混淆的是 **Intent 和 Tool**:
|
||
|
||
- `intent` 是用户意图,例如 `set_parameter`。
|
||
- `tool` 是系统能力,例如 `write_machine_parameter`。
|
||
- 一个 intent 可能映射到多个 tool;同一个 tool 也可能被多个 intent 使用。
|
||
|
||
所以 NLU 不应该直接决定 UI,也不应该强耦合具体 React 组件。NLU 的核心输出是“用户想做什么 + 参数是什么 + 置信度多少”。TS 编排层再根据工具目录和可视化配置决定调用哪个工具、展示哪个组件。
|
||
|
||
### 13.1 第一阶段输入链路
|
||
|
||
第一阶段只做文字输入和鼠标点击,不实现 ASR,也不实现 BERT NLU。为了后续接入语音和 BERT,当前架构要提前把“用户输入文本”和“组件动作事件”分开。
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
I["文字输入"] --> N["归一化文本"]
|
||
B["按钮点击"] --> E["ActionEvent"]
|
||
N --> R["意图路由器"]
|
||
R --> C["当前组件动作"]
|
||
R --> L["LLM 新问题/复杂语义"]
|
||
C --> E["ActionEvent"]
|
||
L --> O["AI 编排层"]
|
||
```
|
||
|
||
### 13.2 后续语音和 BERT NLU 接入位置
|
||
|
||
后续接入时建议链路是:
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
M["麦克风"] --> A["ASR"]
|
||
A --> T["识别文本"]
|
||
T --> N["BERT NLU"]
|
||
N --> R["意图路由器"]
|
||
R --> E["ActionEvent / LLM 编排"]
|
||
```
|
||
|
||
这里的边界是:
|
||
|
||
- ASR 只负责语音转文字。
|
||
- BERT NLU 负责稳定识别短命令、当前组件动作、流程控制、数值输入等意图。
|
||
- LLM 负责复杂问答、知识组织、流程解释和 artifact 生成。
|
||
- 不管输入来自文字、ASR 还是 BERT,最终都尽量落到统一的 `ArtifactActionEvent`。
|
||
|
||
本文档后续不展开 ASR 和 BERT NLU 的具体模型方案,只保留接口位置。
|
||
|
||
### 13.3 推荐职责边界
|
||
|
||
建议不要让 Python NLU 服务成为“工具和 UI 的唯一配置中心”。更清晰的边界是:
|
||
|
||
| 模块 | 负责什么 | 不负责什么 |
|
||
|---|---|---|
|
||
| ASR 服务 | 音频转文本、置信度、分段、最终文本 | 不判断业务意图,不调工具 |
|
||
| Python NLU 服务 | domain、intent、slot、置信度、候选工具建议 | 不调用工业工具,不决定最终 UI |
|
||
| TS Input Router | 当前组件动作优先、规则匹配、调用 NLU、决定是否 LLM 兜底 | 不训练模型 |
|
||
| Tool Registry | 工具列表、输入 Schema、输出 Schema、工具描述、示例 | 不做语义识别 |
|
||
| Visualization Registry | 工具/intent 到 artifact 组件的绑定、字段映射、默认动作 | 不执行工具 |
|
||
| Tool Orchestrator | 选择工具、调用工具、生成 artifact、维护状态 | 不做 ASR 和模型训练 |
|
||
|
||
也就是说,NLU 服务可以暴露它“理解哪些 domain/intent/slot”,也可以返回候选工具名,但工具目录和可视化绑定建议由 TS 项目或单独配置中心维护。
|
||
|
||
### 13.4 ASR 到 TS 的接口协议
|
||
|
||
第一阶段可以先做非流式接口,后面再升级 WebSocket 流式识别。
|
||
|
||
```http
|
||
POST /asr/transcribe
|
||
Content-Type: multipart/form-data
|
||
```
|
||
|
||
请求字段:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| audio | file | 音频文件或音频片段 |
|
||
| sessionId | string | 当前会话 ID |
|
||
| deviceId | string | 当前设备 ID |
|
||
| language | string | 默认 `zh-CN` |
|
||
| sampleRate | number | 采样率 |
|
||
|
||
响应:
|
||
|
||
```ts
|
||
type ASRResult = {
|
||
requestId: string;
|
||
sessionId: string;
|
||
text: string;
|
||
normalizedText?: string;
|
||
confidence: number;
|
||
isFinal: boolean;
|
||
segments?: Array<{
|
||
text: string;
|
||
startMs: number;
|
||
endMs: number;
|
||
confidence: number;
|
||
}>;
|
||
};
|
||
```
|
||
|
||
后续流式接口可以用 WebSocket:
|
||
|
||
```txt
|
||
Client -> ASR: audio_chunk
|
||
ASR -> Client/TS: partial_transcript
|
||
ASR -> Client/TS: final_transcript
|
||
```
|
||
|
||
但无论是否流式,进入 TS Input Router 的都应该是统一文本事件:
|
||
|
||
```ts
|
||
type InputTextEvent = {
|
||
eventId: string;
|
||
sessionId: string;
|
||
source: "text" | "asr";
|
||
text: string;
|
||
normalizedText?: string;
|
||
confidence?: number;
|
||
createdAt: string;
|
||
};
|
||
```
|
||
|
||
### 13.5 TS 到 Python NLU 的接口协议
|
||
|
||
核心解析接口:
|
||
|
||
```http
|
||
POST /nlu/parse
|
||
Content-Type: application/json
|
||
```
|
||
|
||
请求:
|
||
|
||
```ts
|
||
type NLUParseRequest = {
|
||
requestId: string;
|
||
sessionId: string;
|
||
text: string;
|
||
normalizedText?: string;
|
||
locale: "zh-CN";
|
||
context: {
|
||
deviceId?: string;
|
||
activeArtifact?: {
|
||
artifactId: string;
|
||
type: string;
|
||
status: string;
|
||
availableActions: Array<{
|
||
actionId: string;
|
||
label: string;
|
||
textAliases: string[];
|
||
}>;
|
||
};
|
||
activeWorkflow?: {
|
||
workflowId: string;
|
||
currentStepId: string;
|
||
currentStepTitle: string;
|
||
};
|
||
};
|
||
toolCatalogVersion?: string;
|
||
nluSchemaVersion?: string;
|
||
};
|
||
```
|
||
|
||
响应:
|
||
|
||
```ts
|
||
type NLUParseResponse = {
|
||
requestId: string;
|
||
modelVersion: string;
|
||
schemaVersion: string;
|
||
domain: string;
|
||
intent: string;
|
||
confidence: number;
|
||
slots: Record<
|
||
string,
|
||
{
|
||
value: string | number | boolean;
|
||
rawText?: string;
|
||
confidence?: number;
|
||
unit?: string;
|
||
}
|
||
>;
|
||
routeHint:
|
||
| "artifact_action"
|
||
| "tool_call"
|
||
| "knowledge_query"
|
||
| "workflow_control"
|
||
| "smalltalk"
|
||
| "fallback";
|
||
candidateTools?: Array<{
|
||
toolName: string;
|
||
confidence: number;
|
||
reason?: string;
|
||
}>;
|
||
clarification?: {
|
||
required: boolean;
|
||
question?: string;
|
||
missingSlots?: string[];
|
||
};
|
||
};
|
||
```
|
||
|
||
示例:
|
||
|
||
```json
|
||
{
|
||
"requestId": "req_001",
|
||
"modelVersion": "bert-nlu-2026-05",
|
||
"schemaVersion": "nlu_schema_v1",
|
||
"domain": "machine_parameter",
|
||
"intent": "set_parameter",
|
||
"confidence": 0.94,
|
||
"slots": {
|
||
"parameter": { "value": "主轴转速", "rawText": "主轴转速", "confidence": 0.96 },
|
||
"value": { "value": 1800, "rawText": "1800", "confidence": 0.98, "unit": "rpm" }
|
||
},
|
||
"routeHint": "tool_call",
|
||
"candidateTools": [
|
||
{ "toolName": "write_machine_parameter", "confidence": 0.91 }
|
||
]
|
||
}
|
||
```
|
||
|
||
### 13.6 NLU 元数据接口
|
||
|
||
NLU 服务需要暴露自己支持的 domain、intent、slot,方便 TS 做校验、版本对齐和调试。
|
||
|
||
```http
|
||
GET /nlu/metadata
|
||
```
|
||
|
||
响应:
|
||
|
||
```ts
|
||
type NLUMetadata = {
|
||
serviceName: string;
|
||
modelVersion: string;
|
||
schemaVersion: string;
|
||
domains: Array<{
|
||
name: string;
|
||
description: string;
|
||
intents: Array<{
|
||
name: string;
|
||
description: string;
|
||
requiredSlots: string[];
|
||
optionalSlots: string[];
|
||
examples: string[];
|
||
}>;
|
||
}>;
|
||
slots: Array<{
|
||
name: string;
|
||
type: "string" | "number" | "boolean" | "enum";
|
||
values?: string[];
|
||
units?: string[];
|
||
}>;
|
||
};
|
||
```
|
||
|
||
### 13.7 工具目录接口
|
||
|
||
工具目录建议由 TS 项目或工业工具网关维护,NLU 可以读取它来训练/更新候选工具映射,但不要让 NLU 成为工具真实执行的源头。
|
||
|
||
```http
|
||
GET /tools/catalog
|
||
```
|
||
|
||
响应:
|
||
|
||
```ts
|
||
type ToolCatalog = {
|
||
version: string;
|
||
tools: Array<{
|
||
toolName: string;
|
||
displayName: string;
|
||
domain: string;
|
||
description: string;
|
||
inputSchema: Record<string, unknown>;
|
||
outputSchema: Record<string, unknown>;
|
||
examples: string[];
|
||
aliases: string[];
|
||
enabled: boolean;
|
||
}>;
|
||
};
|
||
```
|
||
|
||
示例:
|
||
|
||
```json
|
||
{
|
||
"version": "tool_catalog_v1",
|
||
"tools": [
|
||
{
|
||
"toolName": "write_machine_parameter",
|
||
"displayName": "写入设备参数",
|
||
"domain": "machine_parameter",
|
||
"description": "把目标参数写入指定工业设备。",
|
||
"inputSchema": {
|
||
"type": "object",
|
||
"required": ["deviceId", "parameter", "value"],
|
||
"properties": {
|
||
"deviceId": { "type": "string" },
|
||
"parameter": { "type": "string" },
|
||
"value": { "type": ["number", "string"] },
|
||
"unit": { "type": "string" }
|
||
}
|
||
},
|
||
"outputSchema": {
|
||
"type": "object",
|
||
"properties": {
|
||
"previousValue": { "type": ["number", "string"] },
|
||
"targetValue": { "type": ["number", "string"] },
|
||
"status": { "type": "string" }
|
||
}
|
||
},
|
||
"examples": ["把主轴转速调到 1800", "温度补偿加 2 度"],
|
||
"aliases": ["调参数", "设置参数", "修改参数"],
|
||
"enabled": true
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 13.8 工具到可视化组件的绑定协议
|
||
|
||
工具调用结果不应该直接等于 UI。第二版通过 Visualization Registry 维护工具和可视化组件的绑定。
|
||
|
||
```http
|
||
GET /visualizations/config
|
||
PUT /visualizations/config/:bindingId
|
||
```
|
||
|
||
配置结构:
|
||
|
||
```ts
|
||
type ToolVisualizationBinding = {
|
||
bindingId: string;
|
||
target: {
|
||
type: "tool" | "intent";
|
||
name: string;
|
||
};
|
||
visualizationType: "retrieval_info" | "icon_animation" | "custom";
|
||
artifactType:
|
||
| "parameter_change"
|
||
| "device_action"
|
||
| "production_start"
|
||
| "knowledge_lesson"
|
||
| "guided_procedure"
|
||
| "custom_tool";
|
||
propMapping: Array<{
|
||
from: string;
|
||
to: string;
|
||
transform?: "string" | "number" | "boolean" | "status" | "media_list";
|
||
}>;
|
||
defaultActions: ArtifactAction[];
|
||
enabled: boolean;
|
||
};
|
||
```
|
||
|
||
示例:参数写入工具绑定到参数对比卡:
|
||
|
||
```json
|
||
{
|
||
"bindingId": "viz_write_parameter",
|
||
"target": {
|
||
"type": "tool",
|
||
"name": "write_machine_parameter"
|
||
},
|
||
"visualizationType": "custom",
|
||
"artifactType": "parameter_change",
|
||
"propMapping": [
|
||
{ "from": "tool.input.parameter", "to": "props.parameterName", "transform": "string" },
|
||
{ "from": "tool.output.previousValue", "to": "props.currentValue" },
|
||
{ "from": "tool.input.value", "to": "props.targetValue" },
|
||
{ "from": "tool.input.unit", "to": "props.unit" }
|
||
],
|
||
"defaultActions": [
|
||
{
|
||
"actionId": "artifact.confirm",
|
||
"label": "确认执行",
|
||
"kind": "primary",
|
||
"textAliases": ["确认", "执行", "确认执行"]
|
||
}
|
||
],
|
||
"enabled": true
|
||
}
|
||
```
|
||
|
||
### 13.9 一次完整链路
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant UI as React 画布
|
||
participant ASR as ASR 服务
|
||
participant Router as TS Input Router
|
||
participant NLU as Python NLU
|
||
participant Tools as Tool Registry
|
||
participant Viz as Visualization Registry
|
||
participant Exec as 工业工具网关
|
||
participant Store as Artifact Store
|
||
|
||
UI->>ASR: 音频或语音片段
|
||
ASR-->>UI: transcript
|
||
UI->>Router: InputTextEvent
|
||
Router->>Store: inspect active artifact
|
||
alt 命中当前组件动作
|
||
Router->>Store: ArtifactActionEvent
|
||
Store-->>UI: 更新当前组件
|
||
else 需要语义识别
|
||
Router->>NLU: /nlu/parse(text + context)
|
||
NLU-->>Router: domain / intent / slots / candidateTools
|
||
Router->>Tools: 查询工具 schema
|
||
Router->>Exec: 调用工具
|
||
Exec-->>Router: tool result
|
||
Router->>Viz: 查询工具可视化绑定
|
||
Router->>Store: 生成并保存 artifact
|
||
Store-->>UI: 渲染交互组件
|
||
end
|
||
```
|
||
|
||
## 14. 第一阶段最小记录
|
||
|
||
第一阶段先不实现权限、动作分级、高风险确认和完整审计系统。这里仅保留产品运行所需的最小记录能力,目的是支持状态恢复、问题排查和后续扩展。
|
||
|
||
最小记录内容:
|
||
|
||
- 当前会话 ID。
|
||
- 当前 artifact 快照。
|
||
- 当前流程步骤。
|
||
- 用户输入 transcript。
|
||
- 点击或文字触发的 `ActionEvent`。
|
||
- Mock/真实工具调用名称、参数、结果码、时间。
|
||
- 异常时展示明确的失败原因和恢复步骤。
|
||
- 支持暂停、取消、恢复。
|
||
|
||
后续如果要进入真实生产控制,再单独补权限、动作分级、二次确认、审计日志和合规要求。
|
||
|
||
## 15. 前端组件库初始清单
|
||
|
||
第一阶段建议做 8 个核心组件:
|
||
|
||
| 组件 | 用途 |
|
||
|---|---|
|
||
| `ParameterChangeCard` | 参数前后对比、确认、执行结果 |
|
||
| `DeviceActionCard` | 开灯、开泵、开阀、风机等具象设备动作 |
|
||
| `ProductionStartCard` | 开机生产、启动前检查、启动进度 |
|
||
| `KnowledgeLessonArtifact` | 说明书/知识库教学式回答 |
|
||
| `GuidedProcedureArtifact` | 调机流程引导 |
|
||
| `MeasurementInputCard` | 人工输入测量值,后续可支持语音填数 |
|
||
| `MediaGalleryCard` | 视频、图片、说明资料展示 |
|
||
| `AlarmExplanationCard` | 报警解释、原因、处理步骤 |
|
||
|
||
## 16. 当前项目演进建议
|
||
|
||
当前 `src/app/page.tsx` 里已经是左侧聊天 + 右侧画布。可以按这个路线演进:
|
||
|
||
1. 把 `activeTool.toolName === "getWeather"` 这种判断抽成组件注册表。
|
||
2. 定义 `InteractionArtifact` 类型。
|
||
3. API 不再只返回工具结果,而是返回 `artifact`。
|
||
4. 前端用 `artifact.type` 渲染组件。
|
||
5. 所有组件按钮都发 `ArtifactActionEvent`。
|
||
6. 加一个 `artifact store` 保存当前组件快照。
|
||
7. 后端加 `inspect_ui_state` 工具,让 LLM 可按需读取当前组件摘要。
|
||
8. 预留后续 BERT NLU/语音入口,把未来语音也转成 `ArtifactActionEvent`。
|
||
|
||
## 17. 阶段计划
|
||
|
||
### 阶段 1:交互画布原型
|
||
|
||
目标:
|
||
|
||
- 固定组件注册表。
|
||
- Mock 工业工具。
|
||
- 参数变更组件。
|
||
- 设备动作动画组件。
|
||
- 知识教学组件。
|
||
|
||
验收:
|
||
|
||
- 用户输入“把转速改到 1800”,右侧显示参数前后对比。
|
||
- 用户确认后显示执行中、成功或失败。
|
||
- 用户输入“打开探照灯”,右侧显示灯光动画和状态。
|
||
- 用户问知识问题,右侧显示教学式卡片,而不是大段文本。
|
||
|
||
### 阶段 2:流程引导
|
||
|
||
目标:
|
||
|
||
- 实现 `GuidedProcedureArtifact`。
|
||
- 支持自动步骤和人工步骤。
|
||
- 支持暂停、恢复、跳过、失败重试。
|
||
- 支持文字反馈“已完成”“数值是 0.72”。
|
||
|
||
验收:
|
||
|
||
- 一个调机流程可以从第 1 步走到最后。
|
||
- 中途问临时问题不会覆盖流程。
|
||
- 可以输入“继续刚才”恢复流程。
|
||
|
||
### 阶段 3:LLM 读取 UI 状态
|
||
|
||
目标:
|
||
|
||
- 实现 `llmContext`。
|
||
- 实现 `inspect_ui_state`。
|
||
- 用户围绕界面提问时,LLM 能知道当前组件和步骤。
|
||
|
||
验收:
|
||
|
||
- 用户问“刚才让我确认的目标值是多少”,AI 能答对。
|
||
- 用户问“这个按钮是什么意思”,AI 能解释当前按钮。
|
||
- 用户问“这一步为什么要做”,AI 能结合流程上下文回答。
|
||
|
||
### 阶段 4:工业工具接入
|
||
|
||
目标:
|
||
|
||
- 接入你实现的工业软件能力。
|
||
- 保持工具执行结果到 artifact 展示的稳定映射。
|
||
- 保留最小执行记录和异常处理。
|
||
|
||
验收:
|
||
|
||
- 工具调用结果能稳定驱动组件状态变化。
|
||
- 工具失败时组件能给出恢复建议。
|
||
|
||
## 18. 已收敛的技术路线
|
||
|
||
本阶段不再保留多个待选决策,统一采用以下路线:
|
||
|
||
| 方向 | 已采用方案 |
|
||
|---|---|
|
||
| 组件渲染 | React 组件注册表 + JSON Artifact 协议 |
|
||
| 知识展示 | 固定教学外壳 + block 内容 |
|
||
| 输入路由 | 规则优先 + LLM 兜底 |
|
||
| 流程状态 | 后端持久化 `WorkflowInstance`,原型阶段可先用会话态模拟 |
|
||
| LLM 理解界面 | 每轮给极简上下文,需要时调用 `inspect_ui_state` |
|
||
| 工具展示关系 | 工具只执行,编排层生成 artifact |
|
||
| 第一阶段输入 | 文字输入 + 鼠标点击 |
|
||
| 后续 NLU | 预留 BERT NLU 接口,但本阶段不实现 |
|
||
| 语音/ASR | 预留接口,本阶段不实现 |
|
||
| 权限/动作分级/高风险确认 | 本阶段不实现 |
|
||
| 第二版工具可视化维护 | 增加工具和可视化组件维护中心,支持检索信息、图标动画、用户自定义三类 |
|
||
|
||
## 19. 我建议的第一版 MVP 范围
|
||
|
||
第一版不要做太大,建议只做这 5 条闭环:
|
||
|
||
1. 参数修改:旧值/新值/确认/执行结果。
|
||
2. 设备控制:打开探照灯或水泵的动画状态。
|
||
3. 知识问答:说明书内容变成教学卡片。
|
||
4. 调机流程:3 到 5 步,包含一个自动步骤和一个人工反馈步骤。
|
||
5. 文字输入操作当前组件:确认、取消、下一步、已完成、数值输入。
|
||
|
||
这 5 条跑通后,再扩展到真实工业软件和 PLC/HMI。
|
||
|
||
## 20. 下一步建议
|
||
|
||
建议按下面顺序进入实现:
|
||
|
||
1. 先定义 `InteractionArtifact`、`ArtifactAction`、`ArtifactActionEvent` 类型。
|
||
2. 建立组件注册表,把当前写死的 weather/stock 渲染替换成 artifact 渲染。
|
||
3. 先实现两个控制类组件:`ParameterChangeCard` 和 `DeviceActionCard`。
|
||
4. 再实现 `KnowledgeLessonArtifact`,支持 summary、key_points、steps、media、details、citations 这些 block。
|
||
5. 再实现 `GuidedProcedureArtifact`,跑通 3 到 5 步调机流程。
|
||
6. 加入 `inspect_ui_state`,让 LLM 能按需读取当前画布摘要。
|
||
7. 最后预留 BERT NLU/ASR 接口,但不在第一阶段接入。
|
||
|
||
完成后,这个项目就会从“聊天 + 单个工具卡片 demo”变成一个真正可扩展的工业 AI 交互画布原型。
|