Files
Agent-System-Documents/docs/guides/intent-recognition.md
T
weichen 09d968cb2f Add architecture guide set for overview, intent, runs, and squads
Why: 系统缺少面向新人与新任务的现状导览;把结构/意图识别/任务执行/小队
四条主线的架构、模型与调用链整理成五篇参考文档,降低跨仓定位成本。

Evidence: 锚点核验于 Dev 组合 218fc4b1ba00b0a03b5bb79f292b3eba6c987a58
(2026-10-08,引用的函数入口行号逐一 grep 定位);git diff --check 通过;
五篇互链相对路径全部可解析。SRC=SELF(本地核验,任务卡有记录)。

Impact: 纯文档新增(docs/guides 五篇),无代码/契约/配置影响。

Refs: Dev 任务分支 feature/architecture-guides(R0 218fc4b1)。
2026-10-08 09:33:13 +00:00

13 KiB
Raw Blame History

Agent 的意图识别:架构、模型与调用链

基准:Agent-System-Dev 组合 218fc4b1ba00b0a03b5bb79f292b3eba6c987a58(R0,2026-10-08 锚点核验)。 行号为该提交下的函数入口位置(个别内部区段为约略范围),随代码演进漂移;文件与函数名是稳定锚点。 internal/ 指 modules/backend/internal/。


1. 一句话结论

意图识别是**"确定性规则漏斗为主体、语义向量与 LLM 为可选慢通道(默认关闭)"的混合 分层架构**:识别主体在独立库 deps/agent-intent(零 LLM 依赖),backend 通过 internal/intentgate 闸门接入,识别结果由 internal/route 统一裁决为 命令 / 工作流 / 普通回合三分支。


2. 识别架构:四级漏斗

核心识别器 FunnelRecognizer(deps/agent-intent/intent/recognizer.go:23, 入口 Recognize 在 recognizer.go:41,内部 recognize 在 :71),四级依次短路:

级 名称 行为 代码
Stage 0 守卫(guard_hit) 守卫域 spec 命中即短路,表达"识别即拒绝" recognizer.go 守卫分支
Stage 1 挂起预期(expectation_hit) 多轮澄清场景:宿主注入 ExpectationProvider 声明上轮预期意图 接口 intent/expectation.go:17
Stage 2+3 规则计分 + 置信度裁决 全部非守卫 spec 线性扫描(intent/registry.go 规则计分与裁决),score = base + (正则命中 ? pattern_bonus : 0),上限 1.0;唯一过阈或前两名分差 ≥ margin(默认 0.1)→ matched,同分比 priority → 否则 ambiguous,无命中 → fallback intent/spec.go:17-29(默认值)、recognizer.go:146 附近同分裁决
Stage 4 慢通道(可选) ambiguous → 语义向量重排 semanticRerank(recognizer.go:292);fallback → LLM 命令生成 generateCommands(recognizer.go:333) 见下节

识别分支共五种(deps/agent-intent/intent/result.go): guard_hit / expectation_hit / matched / ambiguous / fallback。


3. 用什么模型:三层各自不同

层 是否 LLM 实现与模型来源 状态
规则层(守卫/计分/裁决) 否,永不引入 纯 Go 确定性计算。设计文档明确规则层永不引入 LLM(deps/agent-intent/docs/records/2026-09-29-decoupling-and-llm-layering.md §2.1) 主体,默认生效
语义重排(SemanticScorer) 向量模型(非生成式) modules/backend/internal/intentsem/scorer.go:18 EmbeddingScorer:对输入与 spec 的 examples 各取向量算最大余弦相似度。Provider 走 OpenAI 兼容 /embeddings(internal/rag/embed.go),模型/端点来自 settings models.embedding.*;默认阈值 0.8(intent/spec.go) 可选,默认关(settings runtime.intentSemantic)
命令生成(CommandGenerator) 生成式 LLM modules/backend/internal/intentsem/generator.go:18 LightGenerator:走 agentllm.Client.Stream,用轻量档模型(internal/runtime/model.go:84 ResolveLightweightModel,settings models.lightweight.model,缺省回落主 chat 档),MaxTokens 默认 1024;system prompt 在 generator.go:100-129(只暴露 id/描述/槽位键,防提示词注入) 可选,默认关(settings runtime.intentGenerator)
Classifier(LLM 重打分,L2) 生成式 LLM 接口在 intent/classifier.go:9 接口预留,backend 未接线

慢通道装配点:modules/backend/internal/app/app.go:351,357(开关开启才 gate.SetSemantic(...) / gate.SetGenerator(...))。关闭时行为与纯规则版完全一致。

失败安全:agent-intent 库本体零 LLM 依赖,只定义 SemanticScorer (intent/semantic.go:9)与 CommandGenerator(intent/generator.go:14)窄接口由 宿主注入;所有慢通道失败均回退规则结论(fail-open/closed 到 safe 分支),识别永不因 LLM 失败而失败。生成器幻觉有校验兜底:validateGenerated (recognizer.go:368)要求 action.id/槽位键必须都在目录内,否则 fail-closed 回 fallback。


4. 意图目录(Intent Catalog / Schema)

意图定义 IntentSpec(deps/agent-intent/intent/spec.go:74 附近,Go 注册与 JSON overlay 共用):

  • 标识:id(必须 domain.助记 多段,spec.go:122 校验)、domain、version、 description、priority、disabled。
  • matcher(spec.go:32-39):includes_any / includes_all / excludes_any 词表 + patterns 正则 + case_sensitive + boundary(词界匹配,压制中文子串误命中)。
  • slots(spec.go:44-62):key/required/pattern(抽取正则)/group,加 HITL 字段 label/question(建议澄清提问)与校验链 enum/format/normalize/validator。
  • confidence(spec.go:66-70):base 默认 0.7、pattern_bonus 默认 0.2、threshold 默认 0.6。
  • 动作绑定:action(kind ∈ command/workflow/blueprint/handler,intent/command.go:32-43) 优先,其次 metadata["blueprint"]、再次 handler,否则 auto(宿主在命令总线与工作流间裁决)。
  • risk(low/medium/high)+ requires_confirm(透传宿主做授权确认)。
  • examples:示例句数组——语义慢通道按它们算相似度。

配置文件形态(intent/loader.go:12-19):

{ "intents": [ { …IntentSpec… } ], "disable": ["demo.run.status_query"] }

插件可经 intents/*.json overlay 注入(internal/plugins/host.go:216-220 采集)。 样例:deps/agent-intent/examples/specs/demo.json。

识别产物命令集(intent/command.go:11-26):start / set_slot / change_slot / cancel / clarify / chitchat / handoff;规则漏斗只产出 start/set_slot/clarify(deriveCommands 在 command.go:85)。能力目录 Snapshot.Catalog() / CatalogMarkdown() (intent/catalog.go:36,68)把启用意图渲染为 Markdown,供小队规划者/Leader 提示词注入 (deps/agent-squad/adapters/intent/catalog.go 消费)。


5. 端到端调用链:用户输入一条消息后发生了什么

# 步骤 调用方 → 被调方 位置
1 HTTP 入口 路由注册 POST /api/conversations/{id}/messages internal/server/server.go:168(注册)、:574 postMessage
2 slash 短路 / 前缀非技能命令 → handleCommand(server.go:756)→ 命令总线,不进意图识别 server.go:623
3 附件摄取 ingest.Parse(name, mime, content) → core.ParsedDocument(与意图识别并行、互不依赖) server.go:643;internal/ingest/ingest.go
4 识别调用 s.recognize(ctx, text)(端口 NLIntentGate,server.go:79-85) server.go:655
5 进入闸门 intentgate.Gate.Recognize internal/intentgate/gate.go:137
6 四级漏斗 FunnelRecognizer.Recognize(ctx, input, reg.Snapshot()) gate.go:144 附近 → deps/agent-intent/intent/recognizer.go:41
7 结果投影 库 Result → MatchResult{Branch, ID, Slots, Missing, Commands};guard/expectation 折叠为 fallback;缺槽位附 spec 的 Question gate.go:148-176
8 统一路由 route.Decide(recognized, route.Env{HasCommand, WorkflowFor, SquadReady}) server.go:656;internal/route/route.go:60
9a 命令分支 KindCommand → s.Bus.Dispatch(Entrance="chat",槽位透传 Params) server.go:701-717
9b 工作流分支 KindWorkflow → mgr.StartClaimedWorkflowRun(缺槽位列表随行) server.go:725;internal/runmgr/runmgr.go:996
9c 回合分支 KindTurn → ClaimConversation 抢槽 → AppendMessageWithRequest 落库 → mgr.StartClaimedConversationRun server.go:679, 727;runmgr.go:980, 991
10 澄清/HITL 工作流缺必填槽位 → 逐个发 HITLCard{Kind:Input, AllowFreeInput} 人工输入卡 internal/wfcompile/run.go:47 起 RunCompiled 槽位补齐段
11 HITL 转轨 POST /api/hitl/{id}/resolve → mgr.ResolveHITL:自由输入以 / 开头 → pivot=command;否则再过 gate.Recognize + route.Decide,命中其他意图则取消挂起 run 并 pivot server.go:883;runmgr.go:1261(转轨判定 :1293 附近)

启动期装配链

# 内容 位置
A1 app.Run 建 gate := intentgate.New() 并 mgr.SetGate(gate) internal/app/app.go:309-310;runmgr.go:142
A2 插件装载回调:pluginHost.OnIntents = overlay → gate.Rebuild(overlay)(fail-closed:解析失败保留上一快照) app.go:324;internal/plugins/host.go:216-220;gate.go:96
A3 开关开启时接线慢通道:gate.SetSemantic(intentsem.EmbeddingScorer{…}) / gate.SetGenerator(intentsem.LightGenerator{…}) app.go:351,357;gate.go:66,75

6. intentgate 与 intentsem 的分工

  • intentgate(internal/intentgate/gate.go):宿主闸门适配器。持 Registry + FunnelRecognizer;负责插件 overlay 装载(Rebuild,:96)、分支折叠(非 matched/ambiguous 一律折叠为 fallback,gate.go:148-155)、补槽位 Question、 类型投影(让 runmgr/route 只依赖本包表面)、慢通道接线(:66,75)。 不做缓存——识别是纯函数 Query,快照不可变无锁读(intent/registry.go)。
  • intentsem(internal/intentsem/):慢通道实现包。EmbeddingScorer 出错原样上抛 (库保持 Ambiguous);LightGenerator 解析失败/模型不可达返回错误(库保持 fallback)。

7. 识别结果的去向与失败路径

  • 识别结果 Result(intent/result.go)是纯内存 Query 结果,不落库(store 无 intent 表)。去向仅三处:① HTTP 响应;② logsys 结构化日志 intent recognized (recognizer.go:62 附近,不记原文);③ 作为 run 启动参数(workflow slots/missing、命令 ID)。
  • ambiguous(重排后仍歧义)→ gate 折叠 → route.Decide 返回 KindTurn (route.go:61-63)→ 走普通 LLM 回合自由对话兜底(不是强制澄清)。
  • matched 但缺必填槽位 → Commands=[start, clarify](intent/command.go:110 附近)→ workflow 路径把 Missing(含建议 Question)传入 run → 发 HITL 输入卡澄清。
  • guard_hit / expectation_hit → 折叠为 fallback → turn。
  • 低置信度(未过 threshold)→ fallback → turn。

route 决策细节(internal/route/route.go:55-114):优先级 命令 > 工作流 > 普通回合;blueprint → KindSquad,但当前不可达—— server.go:664 明确注释 SquadReady 保持 false(per-run entry 覆盖未就位), 小队的实际启动走别的路径(见小队与子 Agent 启动)。 声明目标不可解析时不静默错配,回落 turn 并写 Reason。


8. 辅助工具与测试

  • deps/agent-intent/cmd/intentctl/:只读诊断 CLI(lint 校验配置+词条冲突、 explain 单条输入裁决轨迹(recognizer.go:226 Snapshot.Explain)、 eval 语料评测 Precision/Recall、catalog 输出目录)。
  • deps/agent-intent/conformance/conformance.go:识别器公开契约行为验收 (分支/槽位断言 + 确定性 + 并发冒烟)。
  • deps/agent-intent/catalogcheck/align_test.go:断言库错误码与 Error-Code-System intent 域种子码逐个相等,防两套平行权威。

9. 关键文件清单

文件 职责
deps/agent-intent/intent/recognizer.go 四级漏斗识别器、语义重排(:292)、生成兜底(:333)、Explain 诊断(:226)
deps/agent-intent/intent/spec.go IntentSpec/MatchSpec/SlotSpec/ConfidenceSpec 定义与校验
deps/agent-intent/intent/registry.go 编译、不可变 Snapshot、双源合并、原子 Reload
deps/agent-intent/intent/loader.go JSON overlay 加载
deps/agent-intent/intent/command.go 命令模型 + deriveCommands(:85)展开
deps/agent-intent/intent/catalog.go 能力目录与 Markdown 渲染(:36/:68/:128)
deps/agent-intent/intent/semantic.go generator.go classifier.go expectation.go 四个可注入端口
deps/agent-intent/cmd/intentctl/main.go 诊断 CLI
modules/backend/internal/intentgate/gate.go 闸门适配器(overlay :96、投影、慢通道接线 :66/:75)
modules/backend/internal/intentsem/generator.go scorer.go LLM 命令生成(含 system prompt :100)/ embedding 重排
modules/backend/internal/route/route.go 唯一 Router(Decide :60 三分支裁决)
modules/backend/internal/server/server.go 消息入口 postMessage(:574)、recognize(:655)、resolveHITL(:883)、SSE events(:275)
modules/backend/internal/plugins/host.go 插件 intents/*.json overlay 采集(:216-220)
modules/backend/internal/app/app.go 组合根装配(:309-310、:324、:351/:357)