Files
Agent-Intent/README.md
weichen b2fa5be60f Add deterministic slot constraints with labels and questions
Details (original message):
Add deterministic slot constraints with labels and questions, and the planner-facing capability catalog.
2026-09-29 16:32:50 +00:00

155 lines
9.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`,由宿主决定澄清(配合挂起预期)。
## 快速开始
```go
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 文档形如:
```json
{
"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)
```bash
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 映射](deps/error-code-system/docs/agent-intent-mapping.md)。错误类型实现 `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`:
```bash
git submodule add ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Intent.git deps/agent-intent
```
```text
require agent-intent v0.0.0
replace agent-intent => ./deps/agent-intent
```
依赖模块内部的 replace 在上层构建中不生效:消费方须自带 `error-code-system` 与 `logging-system` 的 require + replace,并保持与本仓 gitlink 相同的组合。接入后建议在消费方测试里用 `conformance.Run` 跑自己的用例集。
## 验证
```bash
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](AGENTS.md),项目事实见 [PROJECT.md](PROJECT.md),设计与验证记录见 `docs/records/`。