常见的对话机器人采用 LLM 优先的实现方式:每一轮对话都调用一次大模型完成意图分类。 这一方式的成本与延迟由模型决定,并且与输入本身的难易程度无关——一条「报修」与一条含义模糊的长句,付出的代价相同。
工业现场的输入分布并不均匀。报修、查询设备、查看工单这几类输入占据了绝大多数调用量, 其表达方式高度固定、可预判。对这类输入而言,静态规则匹配即可达到 95% 的准确率, 大模型并不带来可测量的额外收益,只带来延迟与调用成本。
EAMX IntentAgent 的设计原则为渐进式策略:能用静态规则解决的,不访问数据库;能用已缓存的模式解决的,不调用大模型。 每一层遵循同一条规则——命中即返回,未命中才下沉至下一层。层的顺序由代价决定,确定性最高的手段排在前面。
这一顺序同时是一种取舍。别名解析与静态规则的结果可复现,耗时在毫秒级且与输入难易无关; 本地意图模式依赖历史数据,命中质量随使用量逐步上升;大模型层的能力上限最高, 单次调用的代价也最高。三层策略因此把最确定的判断放在最前,把最不确定的判断留到最后, 分工的依据是每一层的可复现程度。
意图识别的关键变量是判定顺序:把结果可复现的判定放在前面,把依赖模型能力的判定留到最后。 顺序安排得当,绝大多数请求在整个过程中不产生模型调用; 顺序安排不当,则每一次输入都要付出与长尾输入相同的代价。
三层策略的划分与源文的步骤编号一一对应:第一层为别名解析(Step 1), 第二层为本地匹配(Step 2,内含 2a 静态关键词规则与 2b 本地意图模式两个分支),第三层为 LLM 兜底分类(Step 3)。 层内两个分支沿用源文的 2a 与 2b 标号,其顺序即为执行顺序。
整条流程设有 100ms 超时保护,用于避免 LLM 调用阻塞主对话管道。
第一层与第二层的共同前提是:系统已经知道用户在说哪台设备。
别名解析因此位于最前——它输出的实体上下文会作为参数进入后续两层,并随置信度一并写入结果对象。
结果对象中的 confidence 字段决定交互方式(见第 07 节),needsConfirmation 为确认交互的开关。
每一层都有两个出口:命中即返回,未命中或置信度不足以支撑决策则交给下一层。 为保证这一顺序可判断,各层在返回意图名称的同时给出置信度, 置信度因此成为贯穿三层的统一量纲,也是第三层与第二层之间的合流依据。
依据:agents/intent.agent.ts 中 preprocessIntent 的主流程与 Step 2a/2b 的分支判断。
现场称呼与台账名称普遍不一致。「3号机」这类简称需要先映射为台账中的规范名称「3号注塑机」,
后续的意图匹配与动作参数才能落到具体设备上。该层的数据来源是两张表:别名字典 entity_aliases 与设备表的 aliases 字段。
| 字段 | 类型 | 说明 |
|---|---|---|
id | UUID PRIMARY KEY | 别名记录主键 |
tenant_id | UUID NOT NULL | 租户隔离键,别名按租户独立 |
alias | TEXT NOT NULL | 现场称呼,例如「3号机」 |
entity_type | TEXT NOT NULL | 实体类别:equipment/spare_part/location |
entity_id | UUID NOT NULL | 指向实体记录 |
canonical_name | TEXT NOT NULL | 规范名称,例如「3号注塑机」 |
usage_count | INT DEFAULT 0 | 命中次数,决定该别名是否留在高频集合内 |
created_at / updated_at | TIMESTAMPTZ | 创建与更新时间 |
查找逻辑分三步执行。第一步按 usageCount 降序取出该租户下用量最高的 100 条别名;
第二步对消息做字符串包含匹配,命中后异步将 usageCount 加一;
第三步在该表未命中时降级扫描 equipments.aliases 这一 JSONB 字段,覆盖设备录入时由人工手工填写的别名。
该层的输出为四项:原始称呼、实体类别、实体主键与规范名称。 它们随结果对象一并向下传递,因此第二层与第三层处理的是已经完成映射的消息与实体, 无需再次处理称呼的不一致问题。
该层有三处设计决定其稳定运行:
usageCount 持续增长而长期留在前 100 条,低质量别名则逐步退出集合。aliases 字段中被找到。口径:该层耗时为 5–15ms(含一次数据库查询往返),在高频场景中承担约 60% 的请求解析。
静态关键词规则是三层中唯一不访问数据库的一层。规则以常量数组的形式随进程加载, 匹配方式为子串包含,命中任意一个关键词即返回对应规则及其置信度。
| 关键词(任一命中即匹配) | 目标意图 | 携带实体 | 置信度 |
|---|---|---|---|
| 故障状态/处于故障/故障的设备/故障设备列表 | list_equipments | operationalStatus: fault | 0.95 |
| 报修/上报故障/提交故障 | create_fault_report | — | 0.93 |
| 我的工作/我的任务/我的工单/我的维修 | list_my_work | — | 0.95 |
| 备件库存/库存查询/查询库存/库存情况 | query_spare_part_stock | — | 0.93 |
12 条规则覆盖设备故障查询、故障上报、工单查看、库存查询、技术标准推荐与资产概览六类最高频意图。 匹配复杂度为 O(n×m):n 为规则条数(12),m 为关键词条数(均小于 10)。 这一规模下的子串包含耗时接近 0ms,引入更复杂的分类器不会带来可测量的收益。 未落入这 12 条规则的输入,交由 2b 与第三层继续处理。
口径:0ms 为内存匹配的实测取值,未计入消息预处理(toLowerCase)的耗时。该层在高频意图中承担约 25% 的请求解析。
未被静态规则覆盖的输入进入本地意图模式库。该层从 intent_patterns 表读取该租户已确认的模式
(条件为 confirmed_count ≥ 1),按确认次数降序取前 50 条,再对当前消息逐条评分。
| 策略 | 触发条件 | 得分计算 |
|---|---|---|
| 策略 1 · 字符串包含 | 历史表达与当前消息互为子串 | score = minLength / maxLength,属最强信号 |
| 策略 2 · 关键词重叠 | 两者公共词不少于 2 个 | score = overlap / maxWords × 0.7 |
| 命中判定 | 两种策略均被计算 | 取二者最高分,达到 0.80 即判为命中 |
字符串包含用于识别表达形式接近的历史模式;关键词重叠用于承接语序不同、用词部分重合的表述。 两种策略取最高分,0.80 的阈值用于控制误匹配。
模式库的来源是使用过程本身。每轮 AI 对话结束后,编排器异步记录一条意图模式:
rawExpression 取用户消息的前 200 个字符,resolvedIntent 取实际执行的工具名,置信度记为 0.85。
写入为 fire-and-forget,失败不影响对话结果。
同一表达反复出现时 confirmedCount 递增;新表达则新建记录。
高频确认的模式会自然上升到前 50 条,从而在本层被优先匹配。
这一机制使模式库随实际使用自我调整,无需人工维护关键词表。
该层的读写路径分开:读取发生在对话进行中,用于匹配当前消息;写入发生在对话结束之后,属于离线积累。 两者不共享事务,因此写入失败不会改变本次对话的结果,也不会使已确认的模式失效。 其代价是模式库存在冷启动阶段——初始记录较少时,长尾表述仍会落到第三层。
口径:该层耗时为 3–8ms(含一次数据库查询往返),在高频场景中承担约 10% 的请求解析。
当前两层均未命中,或其置信度不足以支撑决策时,进入第三层。
该层的提示词由四段构成:系统角色(EAMX 工业设备管理系统的意图分类专家)、
可用操作列表(ACTION_CATALOG,26 个 action 的完整清单)、
用户输入(原始消息与已解析的别名上下文)、任务说明
(返回包含 intent、confidence、entities、reasoning 四个字段的 JSON)。
可用操作列表随上下文注入,因此本层输出的意图名称即为可执行的 action 名称,无需在后续环节再做一次映射。
该层同时承担与第二层的合并职责。本地模式命中而置信度偏低(低于 0.85)时同样调用本层; 若大模型结果与本地一致,按置信度加权合并;若不一致,以大模型结果为准。 合并后的置信度进入第 07 节的分档判断。
调用参数中有两项值得说明。可用操作列表随提示词一次性注入,使本层输出直接落在动作名称上,
后续环节不再需要一层名称映射;temperature 取 0,用于让相同输入得到稳定输出——
本层的输出会直接触发动作,输出波动即执行错误。
口径:AI_FAST_MODEL 当前取 DeepSeek-V3.2,调用参数为 enable_thinking: false、
max_completion_tokens: 300、temperature: 0;实测耗时约 200ms,在高频场景中承担约 5% 的请求解析。
三层输出的 confidence 决定系统采取何种交互方式。阈值分为三档,
分档结果写入 needsConfirmation 与 clarificationQuestion 两个字段。
| 置信度区间 | 系统行为 | 用户侧感知 |
|---|---|---|
≥ 0.85 | 直接执行,不询问 | 直接返回执行结果 |
0.60 – 0.85 | 执行前确认,提示语取意图标签,形如「您是要执行『故障上报』吗」 | 单次确认 |
< 0.60 | 询问澄清,提示用户说明要执行的操作 | 需要补充说明 |
分档的意义在于把人工确认集中在中间区间:高置信度结果不打扰使用者,低置信度结果不静默执行。 与静态规则的 95% 准确率、本地模式的 0.80 阈值相配合,三层策略在此处收口, 未命中与低置信度两类出口均由确认或澄清环节承接。
依据:preprocessIntent 中 needsConfirmation 与 clarificationQuestion 的赋值逻辑。
四步的实测耗时与高频场景命中占比如下表。样本取自高频场景,即报修、查询设备、查看工单三类输入。
| 层级 | 耗时 | 高频场景命中占比 |
|---|---|---|
| Step 1 别名解析 | 5–15ms(数据库) | 60% |
| Step 2a 静态关键词 | 0ms(内存) | 25%(高频意图中) |
| Step 2b 本地意图模式 | 3–8ms(数据库) | 10% |
| Step 3 LLM 兜底 | 约 200ms | 5% |
高频场景中约 95% 的请求在第一层与第二层内完成,不进入大模型调用,整体延迟控制在 15ms 以内。 大模型在此处承担长尾职责,其 200ms 的耗时只作用于剩余的少数请求。
分层带来的差别可以按同一组数字对照:若全部请求都交由第三层处理,单次延迟即为 200ms 量级; 前两层承接其中约 95% 之后,整体延迟降至 15ms 以内。代价分布由此与输入分布对齐—— 固定的高频表达以毫秒级代价处理,不固定的长尾表达才承担模型调用。
口径:耗时为单次请求的分层实测值,数据库项含一次查询往返,LLM 项约为 200ms; 命中占比按高频场景样本统计,不代表全量输入分布。
三层策略的实现集中在两个文件与两张数据表,索引如下。
agents/intent.agent.ts(611 行)— 三层策略的全部逻辑ai/orchestrator.ts L149–156 — Phase 4 意图学习的触发点entity_aliases — 别名字典;intent_patterns — 意图模式库该实现有三处边界需要一并说明。别名字典的高频集合由用量决定, 新录入的别名需要经过数次使用才能进入前 100 条;模式库的匹配质量由确认次数决定, 初始阶段可用的模式较少,长尾输入仍会落到第三层;静态规则的 12 条覆盖范围决定了后两层的负载, 规则之外的表述越多,模式库与大模型层的调用量越大。
agents/intent.agent.ts、ai/orchestrator.ts(L149–156)、entity_aliases 与 intent_patterns 两张表的实现记录12 条静态关键词规则、0.80 的模式匹配阈值、0.85 与 0.60 两档确认边界、5–15ms 与约 200ms 的分层耗时—— 上述各项对应工具清单与业务域的可见范围,可由演示环境核验;耗时口径见第 08 节。