Why: Make independent version consumption work from ordinary clones while retaining historical commits and existing branch workspaces. Evidence: SELF Dev task receipts record 24 CI boundary cases, all workflow syntax checks, readonly private-source prefetch in clean exports, provider tests and package installation without acquisition scripts. Platform CI remains pending. Impact: Remove only replaced index links, preserve old physical checkouts, and update dependency guidance. Library consumers retain their immutable versions until an explicit dependency update. Refs: Agent-System-Dev feature/dependency-workspace; approved versioned-dependency r1, U3-U7 and R15.
153 lines
9.3 KiB
Markdown
153 lines
9.3 KiB
Markdown
# Agent-Intent
|
||
|
||
可定义、可配置、可扩展的通用意图识别基础库:把「输入文本 → 意图 + 槽位 + 分支裁决」做成纯内存、确定性的库能力,供宿主在 LLM 之前完成确定性分流——守卫拦截(安全红线、识别即拒绝)、系统功能命令识别、路由提示与多轮澄清入口。
|
||
|
||
本仓库是该模块的源码位置。Go 模块路径为 `git-ssh.u1680832.nyat.app/weichen/Agent-Intent.git`。不依赖 Agent-Native 或 Agent-Squad;文本处理依赖 `golang.org/x/text`,错误码与日志和 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`;原始输入不写入日志。
|
||
|
||
## 版本依赖与消费
|
||
|
||
消费方在已配置私有传输的环境中获取批准提交,由 Go 写入实际版本:
|
||
|
||
```bash
|
||
go get git-ssh.u1680832.nyat.app/weichen/Agent-Intent.git@<approved-commit>
|
||
GOWORK=off go test ./...
|
||
```
|
||
|
||
`go.mod` / `go.sum` 固定错误码与日志依赖,无源码目录 `replace`。正式构建使用 `GOWORK=off`;本地源码联调通过 Dev 的显式组件链接管理。接入后建议在消费方测试里用 `conformance.Run` 跑自己的用例集。
|
||
|
||
旧提交保留其 gitlinks 供历史组合和在途分支重建;本提交已移除已替代指针;本版本 Go 编译不消费这些目录,开发规范由 Dev components.lock.json 固定。在途分支显式迁移 import 与模块前缀,不改意图、命令或历史事件标识。
|
||
|
||
## 验证
|
||
|
||
```bash
|
||
GOWORK=off go vet ./... && GOWORK=off go test -count=1 ./...
|
||
GOWORK=off go test -count=1 -race ./...
|
||
GOWORK=off go list -m all # 核对固定版本与 MVS 解析结果
|
||
```
|
||
|
||
需要 Go 1.27。规则入口见 [AGENTS.md](AGENTS.md),项目事实见 [PROJECT.md](PROJECT.md),设计与验证记录见 `docs/records/`。
|