Why: I2 layering - between rules and the L2 classifier there is now a deterministic host-scored semantic layer (rules then semantic then model), and fallback can be rescued by a validated command generator instead of going straight to the default channel. Evidence: go vet clean; full suite ok, including ten new tests (rerank resolve/below-threshold/tie/error-then-L2, generator valid/invalid/error, catalog top-k). Impact: IntentSpec gains Examples; Options gains Semantic (with threshold), Generator; ambiguous candidates rerank through host scores before L2; fallback validates generated commands (action/slots/kind fail-closed) and synthesizes Top with slots; generated commands are no longer overwritten by deriveCommands; CatalogTopK by priority. Refs: Documents proposal 2026-10-07-agent-stack-n1q1i1-plans.md I2
Agent-Intent
可定义、可配置、可扩展的通用意图识别基础库:把「输入文本 → 意图 + 槽位 + 分支裁决」做成纯内存、确定性的库能力,供宿主在 LLM 之前完成确定性分流——守卫拦截(安全红线、识别即拒绝)、系统功能命令识别、路由提示与多轮澄清入口。
本仓库是该模块的源码位置。Go 模块路径为 agent-intent。不依赖 Agent-Native、Agent-Squad 或任何第三方模块;错误码与日志和 Error-Code-System / Logging-System 轻接入对齐(常量对齐 + 鸭子接口,核心包不依赖错误码库)。
设计目标与边界:
- 机制与内容分离:本仓只提供识别流水线与定义框架,不内置任何业务意图;词表、正则、守卫内容一律由宿主以 Go 注册或 JSON 配置提供。
- 确定性:同输入 + 同快照 → 同结果;识别路径纯内存、无 I/O、无时间与随机因素,「无匹配」(fallback)是正常结果而非错误。
- fail-closed 配置:spec 校验或配置加载失败时整批原子拒绝,保留上一生效快照并给出可定位到字段与来源的错误。
- 扩展点只留接口:LLM 分类器、会话挂起预期、分句等由宿主实现并注入。
分层
| 包 | 职责 | 依赖边界 |
|---|---|---|
| intent | spec 定义与校验、注册表与不可变快照、JSON overlay 加载合并、四级漏斗识别器、槽位抽取、诊断 | 标准库 + 可选 logging-system |
| conformance | 消费方行为验收套件(Recognizer 公开契约正反例) | 只用公开 API |
| catalogcheck | 本仓错误常量与错误码库 intent 域的对齐断言 |
仅测试,import error-code-system |
| examples | 最小接入示例(embed 配置端到端) | 只用公开 API |
| cmd/intentctl | 配置 lint / 单条解释 / 评测集跑批的只读诊断 CLI | 组合根之一 |
识别流水线
Stage 0 Guard 守卫域规则(Options.GuardDomains;命中 → GuardHit,可表达"识别即拒绝")
Stage 1 Expectation 会话挂起预期(可选注入 ExpectationProvider;命中 → ExpectationHit)
Stage 2 Rules 规则计分:includes_any / includes_all / excludes_any / patterns
Stage 3 Adjudicate 置信度裁决:唯一过阈 → Matched;前两名分差 < AmbiguityMargin → Ambiguous;全不过 → Fallback
计分与裁决规则:
- 单 spec 得分
score = base + (任一 pattern 命中 ? pattern_bonus : 0),上限 1.0,四位小数舍入;score ≥ 该 spec 的 threshold才进入候选。 - 命中条件:
excludes_any全不命中 且includes_all全命中 且(includes_any至少一词命中 或 任一pattern命中;仅配置includes_all时以全命中为准)。 - 候选排序:置信度降序 →
priority降序 → 合并注册序 → id 字典序,全程确定性。 - Ambiguous 分支可注入
Classifier(典型为宿主的 LLM 客户端适配器)重排;分类器失败保持 Ambiguous,不会使识别失败。 - 槽位:Top 候选才抽取槽位;必填槽位未命中不撤销匹配,记录在
Top.MissingRequiredSlots,由宿主决定澄清(配合挂起预期)。
快速开始
b := intent.NewRegistryBuilder(intent.Options{
ProtectedDomains: []string{"guard"}, // overlay 不得覆盖/禁用
GuardDomains: []string{"guard"}, // Stage 0 演练的域
})
// 守卫内容宿主内置;业务意图走 JSON overlay(embed 或目录均可)。
if err := b.Register(guardSpecs...); err != nil { ... }
reg, err := b.BuildFS(ctx, specFS, "specs") // fs.FS + roots,root 为目录或单文件
if err != nil { ... } // fail-closed:配置坏则构建失败
rec := intent.NewRecognizer(intent.Options{}, nil, nil) // 可选挂起预期 / 分类器
res, err := rec.Recognize(ctx, "查询任务 42 的进度", reg.Snapshot())
// res.Branch == intent.BranchMatched
// res.Top.ID == "demo.run.status_query"; res.Top.Slots["run_id"] == "42"
// res.Top.Handler / Risk / RequiresConfirm / Metadata 由宿主解释
if err := reg.Reload(ctx); err != nil { ... } // 显式重读配置;失败保留旧快照
多意图输入用 intent.NewRuleSegmenter().Segment(input) 先分句再逐句识别。
意图定义(IntentSpec)
Go 与 JSON 共用同一结构;JSON overlay 文档形如:
{
"intents": [
{
"id": "demo.run.status_query",
"domain": "demo",
"version": 1,
"description": "查询任务运行进度",
"matcher": {
"includes_any": ["进度", "状态"],
"includes_all": ["任务"],
"excludes_any": ["配置"],
"patterns": ["(?:查询|看).{0,6}(?:进度|状态)"],
"case_sensitive": false
},
"slots": [
{"key": "run_id", "required": false, "pattern": "(?:run|任务)[:# ]*([A-Za-z0-9-]+)", "group": 1}
],
"confidence": {"base": 0.8, "pattern_bonus": 0.2, "threshold": 0.7},
"priority": 100,
"risk": "low",
"requires_confirm": false,
"handler": "taskrun.query_status",
"metadata": {"channel": "dialogue"}
}
],
"disable": ["demo.run.restart"]
}
字段说明:
| 字段 | 说明 |
|---|---|
id |
全局唯一;首段必须等于 domain,各段 ^[a-z][a-z0-9_-]{0,63}$,可多级(demo.run.status_query) |
version |
≥1;overlay 覆盖同 id 时必须递增 |
matcher |
见上文计分规则;至少一个正向条件;case_sensitive 只作用于词表,pattern 用 (?i) |
slots |
group 默认 1;required 未捕获记录到 MissingRequiredSlots;label/question 供 HITL 提问与目录展示;enum/format/normalize(trim|lower|upper)/validator(RegisterSlotValidator 注册)构成确定性校验链,非法值进 Top.InvalidSlots(与"缺失"区分) |
confidence |
缺省 base=0.7 / pattern_bonus=0.2 / threshold=0.6 |
risk / requires_confirm / handler / metadata |
模块不解释,透传给宿主做授权、确认与路由 |
disabled |
定义但停用(灰度暂存) |
合并语义:Go 内置为基线;目录 root 内 *.json 按文件名字典序、roots 按给定顺序应用;同 id 覆盖需版本递增;disable 按 id 禁用(保护域整批失败);未知字段拒绝并定位到文件。数量上限见 Options(spec 总数、单 spec 正则/槽位数、输入长度),防止配置膨胀。
能力目录(Catalog)
Snapshot.Catalog()/CatalogMarkdown() 把启用的非守卫 spec 渲染为规划者/领导 Agent 可消费的声明式目录:有哪些可直接调用的能力、必填槽位与提问建议、风险与确认要求。用于"目录驱动的编排"——规划者据此把子任务短路给系统功能、按槽位 question 生成定向 HITL(Agent-Squad 已按此接入,见其 squadintent 与 docs/records)。
诊断(intentctl)
go run ./cmd/intentctl lint -root configs/intents # 校验 + 冲突提示
go run ./cmd/intentctl explain -root configs/intents "查询任务进度" # 分支/候选/槽位/裁决轨迹
go run ./cmd/intentctl eval -root configs/intents evals/corpus.json
go run ./cmd/intentctl catalog -root configs/intents # 能力目录(注入规划者提示词)
评测集格式见 intent/testdata/corpus.json(name / input / expect_branch / expect_top / expect_slots / expect_missing_slots)。评测集放在配置目录之外。注意:宿主以 Go 内置注册守卫时,守卫用例只能在宿主自己的测试(或 conformance.Run)中验证;intentctl 只加载 JSON 配置。
错误与日志
错误常量与 Error-Code-System 对齐(intent.invalid_spec / intent.spec_protected / intent.load_failed,调用方错误复用 sys.invalid_argument),catalogcheck 测试防双权威;映射表见 Error-Code-System 的 agent-intent 映射。错误类型实现 ErrorCode() / ErrorFields(),logsys 自动展开码与字段。日志为可选注入(Options.Log,nil→Nop),事件:intent recognized(branch/top/confidence/revision/duration)、intent snapshot reloaded、intent config rejected;原始输入不写入日志。
作为 submodule 使用
消费方把本库固定为 submodule,推荐路径 deps/agent-intent;版本以消费方 gitlink 为准,不执行 submodule update --remote:
git submodule add ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Intent.git deps/agent-intent
require agent-intent v0.0.0
replace agent-intent => ./deps/agent-intent
依赖模块内部的 replace 在上层构建中不生效:消费方须自带 error-code-system 与 logging-system 的 require + replace,并保持与本仓 gitlink 相同的组合。接入后建议在消费方测试里用 conformance.Run 跑自己的用例集。
验证
GOWORK=off go vet ./... && GOWORK=off go test -count=1 ./...
GOWORK=off go test -count=1 -race ./...
GOWORK=off go list -m all # 仅标准库 + 两个生态模块
需要 Go 1.27。规则入口见 AGENTS.md,项目事实见 PROJECT.md,设计与验证记录见 docs/records/。