# intelligent_cabin BERT 接入 · 冲突分析与整合方案 > 作者:AI 分析 > 日期:2026-05-26 > 状态:待你确认 --- ## 背景速览 | 侧 | 项目 | 技术栈 | 角色 | |---|---|---|---| | **Canvas(前端/编排侧)** | ai-canvas / Next.js | TypeScript + React | 画布渲染、Artifact 管理、LLM 编排、工业工具调用(DBus/PLC)| | **BERT 服务侧** | intelligent_cabin | Python / FastAPI | 本地 NLU:intent + slot,语音控制场景 | 这两个项目目前是独立的,尚未对接。 --- ## 一、冲突点(需要明确决策的地方) ### 冲突 1:Domain 语义完全不匹配 ⚠️ 重要 **问题**:`intelligent_cabin/config/domain.yml` 里的 intent 全部来自车机场景(导航、空调、音乐、车窗、车灯……),与 `DBUS_API.md` 描述的线切割工控场景(电压、电流、速度、NC 加工、空走、回零)**毫无重叠**。 **后果**:如果直接把 BERT 服务接进来,意图识别的类别集合完全覆盖不了工控指令,识别结果几乎全是 unknown/reject。 **需确认**: - [ ] 你们会用智能车机的这套预训练模型做迁移学习,还是重新训练工控专属的 BERT 模型? - [ ] 还是说这个 BERT 服务只是作为基础推理框架,`domain.yml` 需要被替换成工控版 domain? --- ### 冲突 2:置信度阈值体系 vs. Canvas 路由体系 **Canvas 流程**(参考 `architecture_overview.html`)的技术视图里: ``` 输入 → BERT NLU → confidence 判断 → [高置信+设备控制域] / [知识域/低置信] / [smalltalk] ``` **intelligent_cabin 的路由体系**(`router.py`): ``` 输入 → Classifier → FusionGrader → decision = execute / clarify / route_to_cloud / reject 阈值:execute_score=0.55, execute_margin=0.18, route_to_cloud=0.75 ``` 两套路由各有自己的 confidence 分级,**如果串联,会出现双重过滤**: - BERT 服务输出的 `score` 未必能直接映射到 Canvas 的 `confidence ≥ 阈值` 判断 - Canvas 目前只依赖 BERT 输出的 `domain/intent/slot/confidence`,但 BERT 服务输出的是 `intent_id + score + decision` **需确认**: - [ ] Canvas 侧是否需要直接消费 `decision` 字段(execute/clarify/route_to_cloud/reject),还是只取 `intent_id + score`,Canvas 自己做二次路由? --- ### 冲突 3:`textAliases`(大流程 B)vs. BERT 意图识别的竞争 **Canvas 大流程 B(调机流程中)的路由逻辑**: ``` 输入 → 优先匹配 textAliases(如"完成"/"下一步"/"确认") → 未命中 → BERT NLU 重新识别 ``` **intelligent_cabin** 里的 `DialogActEngine`(`dialog_act.py`)也在做相似的事情: ```python affirm: ["确认", "好的", "继续", "可以", "确定"] cancel: ["取消", "算了", "不用了", "停止"] ``` **冲突**: - `textAliases` 是每个 Artifact Step 私有的,属于 Canvas 状态机层面的规则匹配 - `DialogActEngine` 是系统级对话行为分类,优先级/触发顺序未对齐 - 如果两套都跑,"确认"这个词可能被 `DialogActEngine` 吃掉后不再传给 Canvas 的步骤推进逻辑 **整合建议**: - 大流程 B 中,textAliases 匹配应在 BERT 服务之前,Canvas 侧处理,不交给 BERT 服务 - 把 `dialog_acts.yml` 的 `affirm/deny/cancel/modify` 从 BERT 服务中剥离,改为 Canvas 路由层的前置规则 - 或者让 BERT 服务的 dialog_act 结果作为辅助 metadata 透传,Canvas 侧自行决策 --- ### 冲突 4:slot 语义不兼容 **BERT 服务的 slot 体系**(按车机场景设计): - `temperature`:空调温度(16-30°C) - `destination`:导航目的地 - `order_id`:订单号 - `song`:歌曲名 **线切割工控的 slot 需求**(从 `DBUS_API.md` 推导): - `speed`:加工速度(mm/min,1-9999) - `voltage`:放电码/电压 - `current`:跟踪值/电流 - `workpiece_id`:工件编号(0-8) - `knife_id`:刀号(1-11) - `param_type`:参数类型(voltage/current/servo) - `nc_path`:NC 文件绝对路径 - `axis`:轴编号(0-5,X/Y/Z/U/V/C) 两套 slot 定义**完全不同**,需要重写 `domain.yml` 和 `rewrite_engine.py` 里的工控版本。 --- ### 冲突 5:rewrite_engine 的上下文改写逻辑是车机特化的 `rewrite_engine.py` 里写死了: ```python _AC_CONTEXT_INTENTS = {"cabin_set_ac", "cabin_ac_on", "cabin_ac_off", ...} _AC_DEFAULT_TEMPERATURE = 24 _AC_STEP = 2 _AC_MIN_TEMPERATURE = 16 _AC_MAX_TEMPERATURE = 30 ``` 这些都是车机空调的业务逻辑,工控场景需要换成类似: ```python _PARAM_CONTEXT_INTENTS = {"wirecut_set_speed", "wirecut_set_voltage", "wirecut_set_current"} _SPEED_STEP = 5 # mm/min _VOLTAGE_STEP = 5 # 放电码 ``` **但这恰恰也是最有价值可以复用的能力**:多轮相对调节("再快一点"→ 改写为 "速度设为 85mm/min")在工控场景同样刚需。 --- ## 二、可以直接整合的能力(不需要改动或改动很小) ### ✅ 整合点 1:FastAPI 服务直接作为 NLU 微服务接入 Canvas(Next.js 侧)可以通过 HTTP 调用 `POST /api/v1/agent/chat` 或 `POST /api/v1/agent/fill-slots`,作为 Canvas 的 "感知语义层"。 接入位置:Canvas 的"BERT NLU 意图识别"节点(技术流程视图第 2 层) ``` Canvas 输入 → HTTP POST → intelligent_cabin :8000/api/v1/agent/chat ← {intent_id, score, slots, decision} Canvas 路由层根据 intent_id + score 继续分发 ``` ### ✅ 整合点 2:分级融合决策逻辑(router.py)可以直接复用 `MultiStageIntentMatcher` 里的 `execute / clarify / route_to_cloud / reject` 四态决策逻辑,与 Canvas 流程中"高置信执行 / 知识域兜底 / smalltalk" 的三路分发思路高度一致,可以直接用。 Canvas 只需要消费 BERT 服务返回的 `decision` 字段,然后: - `execute` → Canvas 走工具调用路径(DBus) - `clarify` → Canvas 展示澄清确认卡 - `route_to_cloud` → Canvas 走 LLM 兜底路径 - `reject` → Canvas 走 smalltalk / fallback ### ✅ 整合点 3:会话状态管理(session_store.py) `SessionState` 里的 `context_memory` 和 `slots` 持久化机制,可以支持工控场景的多轮短句恢复(比如 "再快一点" → 记住上次速度值)。 ### ✅ 整合点 4:多命令拆分(planner.py) 现有的 `sequence workflow` 和 `conditional workflow` 对工控多命令("先回零,再开始加工")直接可用。 ### ✅ 整合点 5:高风险确认机制(dialog_rules.py) `requires_confirmation` + `confirmation_required_risk_levels` 这套机制,完全可以映射到 Canvas 流程中"操控确认卡"的场景(Canvas 大流程 A 的场景 1),直接支持危险操作二次确认。 --- ## 三、需要新建或重写的工控专属配置 ### 3.1 新建 `config/domain_wirecut.yml` 需要把 DBUS_API.md 里的每个接口映射成 intent: | intent_id | 对应 DBus 方法 | 示例语句 | 需要 slot | |---|---|---|---| | `wirecut_start_run` | `startRun()` | "开始加工" / "启动" | 无 | | `wirecut_stop_run` | `stopRun()` | "停止加工" / "停机" | 无 | | `wirecut_pause_run` | `pauseRun()` | "暂停" / "变频暂停" | 无 | | `wirecut_home_all` | `homeAll()` | "全轴回零" / "回零" | 无 | | `wirecut_start_kongzou` | `startKongZou()` | "开始空走" | 无 | | `wirecut_stop_kongzou` | `stopKongZou()` | "停止空走" | 无 | | `wirecut_set_speed` | `setSpeed(speed)` | "速度调到80" / "加快一点" | `speed:int` | | `wirecut_set_voltage` | `setVoltage(vol)` | "电压设为90" | `voltage:int` | | `wirecut_set_current` | `setCurrent(cur)` | "电流设为5" | `current:int` | | `wirecut_get_status` | `getStatus()` | "查一下状态" / "当前状态" | 无 | | `wirecut_load_nc` | `loadNC(path)` | "加载NC文件" | `nc_path:str` | | `wirecut_set_discharge` | `SetDischargePara(...)` | "设置工件0刀1放电码80" | `workpiece_id, knife_id, param_type, value` | ### 3.2 重写 `rewrite_engine.py` 里的工控上下文改写规则 ```python # 工控版示例 _SPEED_CONTEXT_INTENTS = {"wirecut_set_speed"} _SPEED_STEP = 5 # mm/min 每步调节 _SPEED_MIN = 1 _SPEED_MAX = 9999 _VOLTAGE_CONTEXT_INTENTS = {"wirecut_set_voltage"} _VOLTAGE_STEP = 5 # 改写规则 "再快一点" → "速度设为 {last_speed + 5} mm/min" "再慢一点" → "速度设为 {last_speed - 5} mm/min" "电压再高一点" → "电压设为 {last_voltage + 5}" ``` ### 3.3 更新 `dialog_acts.yml` 适配工控确认场景 当前 `dialog_acts.yml` 的 `affirm/deny/cancel` 词表可以保留,但需要补充工控场景的特化语句: ```yaml # 工控场景补充 affirm: + "执行" / "开始" / "运行" / "启动" cancel: + "停机" / "急停" / "中止" inform: + 纯数字(速度值/电压值/电流值的slot填写) ``` --- ## 四、关于 dialog_act 和 rewrite_engine 能否通过配置文件驱动 **直接回答:当前已经部分支持,但工控场景需要扩展。** ### 4.1 dialog_act 配置化现状 `dialog_act.py` 里的 `DialogActEngine` 是数据驱动的: ```python @dataclass class DialogActEngine: patterns: dict[str, tuple[str, ...]] = field(default_factory=...) ``` `config_loader.py` 里已经实现了从 `dialog_acts.yml` 加载: ```python def _load_dialog_act_engine(self) -> DialogActEngine: ... return DialogActEngine(patterns={item.act_id: tuple(item.phrases) for item in parsed.acts}) ``` **✅ 结论**:`dialog_acts.yml` 已经是配置文件,直接修改 `config/dialog_acts.yml` 就能修改 act 词表,**无需改代码**。 **但是有个缺口**:当前 `dialog_acts.yml` 只支持 `字符串包含` 匹配(`phrase in normalized`),没有支持正则或数值范围匹配。工控场景里 "85" 这样的纯数字(作为速度 slot 的 `inform`)目前是靠 Python 代码里的 `if re.search(r"\d", normalized): return "inform"` 处理的,这个逻辑是硬编码在 `dialog_act.py` 里的,暂时没有配置化。 **建议优化**(详见第五节)。 ### 4.2 rewrite_engine 配置化现状 `rewrite_engine.py` 里的上下文改写逻辑**全部硬编码**,没有配置文件支持: ```python _AC_CONTEXT_INTENTS = {"cabin_set_ac", ...} # 硬编码 _AC_DEFAULT_TEMPERATURE = 24 # 硬编码 _AC_STEP = 2 # 硬编码 ``` **❌ 问题**:不同设备(线切割 / 激光切割 / 注塑机 / 其他)的参数名、步长、范围都不同,每台设备都要改代码是不合理的。 **建议优化**(详见第五节)。 --- ## 五、建议优化:将 rewrite_engine 和 dialog_act 配置化 这是你关心的核心问题,以下是具体方案。 ### 5.1 新增 `config/context_rewrite.yml` ```yaml # context_rewrite.yml param_contexts: - intent_ids: ["wirecut_set_speed"] slot_name: "speed" unit: "mm/min" step: 5 min_value: 1 max_value: 9999 default_value: 80 up_phrases: ["再快一点", "加快", "速度调高", "快一点"] down_phrases: ["再慢一点", "减慢", "速度调低", "慢一点"] rewrite_template: "速度设为 {value} mm/min" - intent_ids: ["wirecut_set_voltage"] slot_name: "voltage" unit: "" step: 5 min_value: 0 max_value: 200 default_value: 90 up_phrases: ["电压高一点", "电压调高"] down_phrases: ["电压低一点", "电压调低"] rewrite_template: "电压设为 {value}" - intent_ids: ["wirecut_set_current"] slot_name: "current" unit: "" step: 1 min_value: 0 max_value: 30 default_value: 5 up_phrases: ["电流大一点", "跟踪值高一点"] down_phrases: ["电流小一点", "跟踪值低一点"] rewrite_template: "电流设为 {value}" ``` 然后修改 `rewrite_engine.py`,从 `context_rewrite.yml` 驱动逻辑,而不是硬编码。 ### 5.2 扩展 `config/dialog_acts.yml` 支持 inform 的数值捕获 ```yaml # dialog_acts.yml 新增字段 acts: - act_id: inform phrases: [] # 新增:数值模式检测 numeric_patterns: ["\\d+"] # 包含数字就认为是 inform ``` 并在 `dialog_act.py` 里支持 `numeric_patterns` 字段,这样 "85" / "22度" 是否算 inform 就可以通过配置控制。 ### 5.3 `Settings`(config.py)里增加工控设备配置项 `app/core/config.py` 里的 `Settings` 类目前通过环境变量驱动,建议增加工控配置路径: ```python # 新增到 Settings 类 context_rewrite_config_path: str = "config/context_rewrite.yml" device_domain_config_path: str = "config/domain_wirecut.yml" # 可按设备切换 ``` 这样不同设备(线切割、激光机)只需要切换 `.env` 文件里的 `AGENT_DEVICE_DOMAIN_CONFIG_PATH` 就能换一套 domain + rewrite 配置,**不改代码**。 --- ## 六、整合架构建议(整体链路) ``` 语音输入 ↓ ASR(前端 / 设备侧) 文本输入 ↓ Canvas 路由层(Next.js / TypeScript) ├── [大流程 B 激活] textAliases 匹配 → 直接推进 Artifact 步骤(不过 BERT) └── [其他] HTTP → intelligent_cabin :8000 ↓ context rewrite(工控版配置化) ↓ BERT NLU(工控 domain) ↓ fusion decision ├── execute → Canvas 走 DBus 工具调用 ├── clarify → Canvas 渲染 Artifact 确认卡 ├── route_to_cloud → Canvas 走 LLM 兜底 + 知识库 └── reject → Canvas smalltalk / fallback ``` --- ## 七、待你确认的清单 | # | 问题 | 选项 | |---|---|---| | 1 | BERT 模型是否会重训成工控版,还是继续用车机模型迁移? | A. 重训工控 BERT B. 车机→工控迁移 C. 暂时用 mock/keyword | | 2 | Canvas 是消费 BERT 的 `decision` 字段,还是只取 `intent_id+score` 自己路由? | A. 消费 decision B. 自路由 | | 3 | 大流程 B 的 textAliases 匹配,确认在 Canvas 侧做,不经过 BERT 服务? | A. 是 B. 也经过 BERT 但 BERT 优先级低 | | 4 | rewrite_engine 配置化的优先级?现在要做还是等工控 domain 确定后一起做? | A. 现在就做 B. 等 domain 定了再做 | | 5 | dialog_acts.yml 的 `inform` 数值识别是否需要配置化? | A. 配置化 B. 保持硬编码即可 | | 6 | 不同设备部署时,是一个 BERT 服务实例 + 不同 `.env` 配置,还是多个实例? | A. 单实例多配置 B. 多实例 | --- *本文档由 Antigravity 生成,请确认后继续推进实现。*