From c3f1ae9209d45df976e01965e856c8acb08c52b6 Mon Sep 17 00:00:00 2001 From: weichen Date: Tue, 29 Sep 2026 15:52:51 +0000 Subject: [PATCH] Correct the positioning: an attachable capability Details (original message): Correct the positioning: an attachable capability, never an Agent-System replacement; make Native attachable via an optional decorator. --- .../2026-09-29-decoupling-and-llm-layering.md | 117 ++++++++++-------- 1 file changed, 66 insertions(+), 51 deletions(-) diff --git a/docs/records/2026-09-29-decoupling-and-llm-layering.md b/docs/records/2026-09-29-decoupling-and-llm-layering.md index f902b2b..c0132dc 100644 --- a/docs/records/2026-09-29-decoupling-and-llm-layering.md +++ b/docs/records/2026-09-29-decoupling-and-llm-layering.md @@ -1,14 +1,26 @@ -# 意图栈解耦档位与 LLM 分层设计(含 Agent-Squad 接入方案 v2) +# 意图栈解耦档位与 LLM 分层设计(含 Squad / Native 接入方案) -状态:待审;owner:weichen;主任务:本文件。授权与交付终点:本方案获批后实施 Agent-Squad 接入(v1 不含 LLM 层)。 +状态:待审(2026-09-29 第二次修订:勘误模块定位——不替换 Agent-System;Agent-Native 同为可接入宿主);owner:weichen;主任务:本文件。 +授权与交付终点:本方案获批后实施 Squad 与 Native 的接入(v1 均不含 LLM 层)。 关联:[2026-09-29-agent-intent-design.md](2026-09-29-agent-intent-design.md)、[2026-09-29-implementation-verification.md](2026-09-29-implementation-verification.md)。 -## 问题与证据 +## 〇、勘误:模块定位(本轮修订核心) -1. Agent-Native 已定为"不接入"(无自然语言入口,闸门属于调用方)。Agent-Squad 是否也能与意图识别完全解耦? -2. 意图栈中存在需要 LLM 的层(歧义重排、复杂分句、澄清生成、目标改写)。这部分 LLM 依赖如何接:宿主直连 LLM?保持解耦?调用 Agent-Native 执行?还是其他设计? +此前版本的两处错误表述,勘误如下: -证据(现状):Agent-Squad 核心包已直接 import agent-native(`squad/backend.go` 的 `adapters/native`、`exec`、`runtime/llm`),其 LLM 规划器复用 `runtime/llm.Client` 传输层而非跑完整 agent 执行(`squad/planner_llm.go`、`cli/cli.go:114`)——即"库需要 LLM 时复用 Native 的传输层、不开工作区不跑循环"在本生态已有先例。 +1. **Agent-System 不是迁移目标。** 上一版"剩余项"写了"Agent-System 未来以本模块替换 internal/intent"——错误。正确关系:Agent-System 是本模块**机制设计的参考来源**(四级漏斗、保护域、元数据等借鉴自它),两者**各自独立演进、互不迁移**;Agent-System 继续维护自己的 internal/intent。 +2. **Agent-Native 同为可接入宿主。** 上一版表述为"Native 不接入"。正确形态:Native 的**核心保持零感知**(不变,这正是解耦),但接入能力以**可选装饰器**形式提供,使直接以 Native 构建的应用获得现成接线(见第三节 b)。 + +本模块的定位:**独立的、随时可配置可修改、可插拔的通用意图识别能力**。接入对象:Agent-Squad、Agent-Native、以及未来的宿主应用。 + +**适用判据(一个宿主要不要接)**: + +| 场景 | 特征 | 结论 | +|---|---|---| +| 通用智能体应用(类 Kimi) | 自由对话为主,能力都是"通用智能体本来就知道的"(搜索、写码、成文) | 原生 LLM 意图能力通常足够;可不接,或只接少量守卫(安全红线类) | +| 带专有功能的系统 | 存在通用智能体**不知道**的系统功能/命令(私有操作、系统指令、领域路由) | 在交给智能体之前接入本模块,确定性识别这些功能意图(守卫拦截 / 系统命令 / 定向路由),其余照常交给智能体 | + +"随时可配置、可修改"的现有支撑:JSON overlay(新增/覆盖/禁用,版本递增)+ Go 内置基线双源合并;运行期 `Reload`(原子替换、revision 递增、失败保留旧快照);embed 与文件系统均可作配置来源,不重启进程即可换一套意图。 ## 一、解耦的四个档位 @@ -16,18 +28,16 @@ | 档位 | 含义 | 删除/回退成本 | 适用 | |---|---|---|---| -| T0 行为解耦 | 未配置意图 ⇒ 行为与原系统逐字节一致(gate 为 nil,或快照零 spec ⇒ 每次 Decide 返回 nil ⇒ 引擎走原代码路径) | 无需删除 | **所有档位共同底线,必须测试证明** | -| T1 结构解耦(编译期可选) | 核心包零 import agent-intent;唯一接入点 = 一个适配器包 + 组合根约 20 行接线 | 删 1 个包 + 接线块 + go.mod/submodule(引擎零改动) | **推荐**:Squad 自带 CLI/serve 是一等入口,单一二进制要保留意图能力 | -| T2 仓库级零依赖 | Squad 仓完全不引用 agent-intent(只定义 IntentGate 端口);桥与意图化二进制放独立组合仓(或产品仓 Agent-System) | 删组合仓即可;Squad 仓从未被触碰 | Squad 定位为纯库、永远不单独带意图运行 | -| T3 进程解耦 | 意图闸门做成 sidecar 服务,Squad 经 HTTP 调用 | 下线服务 + 删 HTTP 客户端 | 多语言宿主、独立部署节奏、跨团队所有权 | +| T0 行为解耦 | 未配置意图 ⇒ 行为与原系统逐字节一致(gate 为 nil / 装饰器未 Wrap / 快照零 spec ⇒ 恒透传原路径) | 无需删除 | **所有档位共同底线,必须测试证明** | +| T1 结构解耦(编译期可选) | 核心包零 import agent-intent;唯一接入点 = 一个适配器/装饰器包 + 组合根少量接线 | 删 1 个包 + 接线 + go.mod/submodule,核心零改动 | **推荐**:Squad 与 Native 均以此形态接入 | +| T2 仓库级零依赖 | 宿主仓完全不引用 agent-intent(只定义窄端口);桥放独立组合仓/产品仓 | 宿主仓从未被触碰 | 宿主定位纯库、永不自带意图运行 | +| T3 进程解耦 | 意图做成 sidecar 服务,宿主经 HTTP 调用 | 下线服务 + 删客户端 | 多语言宿主、独立部署节奏、跨团队所有权 | -判断依据:**桥必须存在于某个组合根**——Native 零接入是因为它的入口是 Go API 而非自然语言;Squad 的 `run ` / `POST /v1/runs` 是自然语言入口,桥无处可藏,只能选择放在哪个仓、以什么粒度删。 +判断依据:**桥必须存在于某个组合根**。Squad 的自然语言入口是 `run ` / `POST /v1/runs`;Native 自身入口是 Go API(`exec.Backend.Execute` / `runtime`),它的自然语言入口属于直接以 Native 构建的应用。因此 Native 的接入不是"不需要",而是形态不同:**可选装饰器**——核心零感知,直接宿主即插即用。 -- T1 比生态既有模式更松:现状 `squad` 核心包直接 import agent-native,T1 把意图依赖隔离在 `squadintent/` 适配器 + cli 接线两处,`go list -deps ./squad ./server` 不含 agent-intent(可脚本断言)。 -- T2 的代价要说清:Squad 自带 CLI 永远没有意图能力,需要第二个二进制(组合仓提供 main);若 Squad 还会独立使用(当前事实如此),T2 把能力从主入口挪走。 -- T3 不推荐:单人生态引入常驻服务、网络故障面与配置面;重新考虑的条件是出现多语言宿主或独立发布节奏。 - -**不变式(T0,任何档位都必须成立并验证)**:`gate == nil` 与 `gate 配置了但快照零 spec` 两种引擎,对同一输入集产出与"从未有过此功能"的系统一致的运行结果。验证方式:现有 conformance 套件跑在无 gate 引擎上(等价回归)+ 新增"零配置等价"对比测试。 +- T1 比生态既有模式更松:Squad 现状是核心包直接 import agent-native(`squad/backend.go`);T1 把意图依赖隔离在单一适配器包,`go list -deps` 核心包可断言不含 agent-intent。 +- T2 的代价:宿主自带 CLI 永远没有意图能力,需要第二个二进制。 +- T3 不推荐:单人生态引入常驻服务与网络故障面;出现多语言宿主或独立发布节奏时再评估。 ## 二、意图栈的 LLM 分层 @@ -39,61 +49,66 @@ | 2 | Ambiguous 重排(Classifier 接口) | 宿主实现 | 不启用 | LLM 对候选重打分 | 失败保持 Ambiguous(agent-intent 已内建,识别不失败) | | 3 | 多意图分句(Segmenter 接口) | 宿主实现 | 规则分句(确定性) | LLM 分句 | 失败回退规则分句 | | 4 | 澄清提问生成 / 多轮对话 | 宿主(对话面) | 无 | LLM 生成 | 失败退固定话术 | -| 5 | 目标改写 / 任务简报结构化 | 宿主 | 规则 | LLM(Agent-System RewriteQuery 先例) | 失败用原文 | +| 5 | 目标改写 / 任务简报结构化 | 宿主 | 规则 | LLM | 失败用原文 | | 6 | 离线:spec 草案生成、评测集扩充 | intentctl(未来) | 无 | LLM 辅助 | 人在环审批,不入库不生效 | -### 2.2 LLM 依赖的接法:不是单选,是按层分派 +### 2.2 LLM 依赖的接法:按层分派,不是单选 -**agent-intent 本体:永不直接接 LLM(既定硬边界,不变)。** LLM 层全部以接口注入宿主实现。任何 LLM 适配器都不进 agent-intent 仓——否则引入 LLM 传输依赖与配置面,并破坏"禁止依赖 agent-native"的防循环边界。 - -**同步轻量层(#2、#3):宿主适配器复用 `agent-native/runtime/llm.Client` 传输层,不跑 agent 执行。** 这就是 Squad LLMPlanner 的既有模式:同一个在组合根构造的 client 实例,包装成 Classifier/Segmenter 实现。约束:严格 JSON 输出 + 显式超时 + fail-open(失败降级到 Ambiguous/规则分句,绝不使识别失败)。理由:这两层在请求热路径上,需要亚秒延迟与低开销;走完整 agent 执行(工作区、会话落盘、多轮循环)是秒级成本,且让路由决策的可用性耦合到执行内核。 - -**异步重层(#4、#5 及未来的语料挖掘):走 Agent-Native `exec.Request`(reasoning 档)做一次真正的受治理执行。** 这些层本质是"小任务"而非"路由判断":产出是生成文本(提问、改写、spec 草案),有交付物语义,应当享受 exec.Result、稳定错误码、trace、会话审计的统一治理,而不是在路由热路径里私接 LLM 调用。 - -**热路径可用性原则:LLM 不可用时,意图栈退化为纯规则,永远不阻断原路径。** 规则能判则不调 LLM(Agent-System intentflow 的 `RulesCanDecide` 门控同一逻辑);LLM 层全部是增强项而非依赖项。 +- **agent-intent 本体永不直接接 LLM**(接口注入,硬边界)。LLM 适配器不进 agent-intent 仓——否则引入传输依赖与配置面,并破坏防循环边界(Native 接入时)。 +- **同步轻量层(#2、#3)**:宿主适配器复用 `agent-native/runtime/llm.Client` 传输层(Squad LLMPlanner 既有模式),不跑 agent、不开工作区;严格 JSON + 显式超时 + fail-open(失败降级到 Ambiguous/规则分句,识别不失败)。理由:请求热路径需要亚秒延迟;走完整 agent 执行是秒级成本且让路由可用性耦合执行内核。 +- **异步重层(#4、#5 及语料挖掘)**:走 Agent-Native `exec.Request`(reasoning 档)做受治理执行——这些本质是"小任务"(产出是生成文本),应有 exec.Result、稳定错误码、trace、审计,不该在热路径私接 LLM。 +- **热路径可用性原则**:LLM 不可用时意图栈退化为纯规则,永远不阻断原路径;规则能判则不调 LLM。 ### 2.3 确定性与审计契约 -- 规则层确定性承诺不变(同输入+同快照+同分支语义);LLM 参与的结果显式标注(`Reason` 含 `refined_by=classifier` 等),确定性作用域随之收窄为"含该 LLM 层的行为契约",不算破坏承诺。 -- 每次裁决记录:分支、top、快照 revision(可复现)、命中的层。LLM 层额外记录 prompt 摘要与模型名(不记原始输入全文,沿用脱敏纪律)。 +规则层确定性承诺不变;LLM 参与的结果显式标注(`refined_by=classifier` 等)。每次裁决记录分支、top、快照 revision(可复现);LLM 层额外记录 prompt 摘要与模型名,不记原始输入全文。 -### 2.4 对 Agent-Squad v1 的直接结论 +### 2.4 按场景落到 LLM 层 -**Squad v1 接入不需要任何 LLM 层。** 闸门只消费三类结果:GuardHit→拒绝、Matched→蓝图定向、其余(Ambiguous/Fallback)→透传原路径(`Blueprints.Match` 关键词计分保持原行为,意图只增不删)。Squad 没有对话面,#2–#5 均不适用;LLM 分层策略约束的是未来的对话型宿主(Agent-System 或产品仓)。 +- **类 Kimi 应用**:通常只接守卫层(#1,无 LLM),甚至不接——与定位判据一致。 +- **带专有功能的系统**:核心仍是 #1 规则层;#2–#5 按 2.2 分派,仅在确有歧义/多意图/对话澄清压力时逐层启用。 +- **Agent-Squad v1:不接任何 LLM 层**。闸门只消费 GuardHit→拒绝、Matched→蓝图定向、其余透传原路径(意图只增不删)。 -## 三、Agent-Squad 接入设计(T1 具体化,v1 范围) - -### 3.1 Squad 仓内变更 +## 三 a、Agent-Squad 接入设计(T1,v1 范围) | 位置 | 变更 | 规模 | |---|---|---| -| `squad/intent.go`(新) | `IntentGate` 窄接口 + `IntentDecision`(`Reject{Reason,Guidance}` / `Blueprint{Key}` / nil=透传)+ `Options.IntentGate` 字段;`Run()` 入口调用一次(入口语义;澄清续跑不重复过闸) | ~60 行,零外部依赖 | -| `squadintent/`(新包) | **全仓唯一 import agent-intent 处**。`Gate` 构造(宿主 Go 内置守卫 spec + JSON root → Registry/Recognizer)与 `Decide` 映射:GuardHit→Reject;Matched→`Metadata["blueprint"]`→Blueprint key,映射的蓝图不存在则 fail-closed(同"未知 backend 拒绝"先例);Ambiguous/Fallback→nil;空快照→恒 nil | 适配器 + 单测 | -| `cli/cli.go` assemble | `-intent-root` flag + `AGENT_SQUAD_INTENT_ROOT` env(双通道,同 planner 先例);未设置→gate=nil;配置存在但构建失败→启动失败(fail-closed) | ~20 行 | -| `scripts/submodule-consistency.sh` | 加 `deps/agent-intent` 及其嵌套三子模块与外层同仓 gitlink 比对 | 数行 | -| 文档 | AGENTS 硬边界补一行(意图闸门可选,唯 squadintent 与组合根可 import agent-intent);PROJECT 依赖表、policy 采纳记录、docs/records 接入记录 | 文档 | +| `squad/intent.go`(新) | `IntentGate` 窄接口 + `IntentDecision`(`Reject{Reason,Guidance}` / `Blueprint{Key}` / nil=透传)+ `Options.IntentGate`;`Run()` 入口调用一次(入口语义;澄清续跑不重复过闸) | ~60 行,零外部依赖 | +| `squadintent/`(新包) | **全仓唯一 import agent-intent 处**。构造(宿主 Go 内置守卫 spec + JSON root)与 `Decide` 映射:GuardHit→Reject;Matched→`Metadata["blueprint"]`→蓝图 key,映射的蓝图不存在 fail-closed(同未知 backend 先例);Ambiguous/Fallback→nil;空快照→恒 nil | 适配器 + 单测 | +| `cli/cli.go` assemble | `-intent-root` flag + `AGENT_SQUAD_INTENT_ROOT` env;未设置→gate=nil;配置存在但构建失败→启动失败(fail-closed) | ~20 行 | +| `scripts/submodule-consistency.sh` | 加 `deps/agent-intent` 及其嵌套三子模块 gitlink 比对 | 数行 | +| 文档 | AGENTS 硬边界、PROJECT 依赖表、policy 采纳记录、docs/records 接入记录 | 文档 | -依赖方向:`squadintent → agent-intent → (errcode/logsys 轻接入)`;`squad / server / store → 无 agent-intent`。 +### 解耦证明(随实施交付) -### 3.2 解耦证明(随实施交付的测试) +1. 零配置等价:同一输入集在「无 gate」与「空配置 gate」两引擎上结果一致。 +2. 既有 conformance 全量跑在无 gate 引擎上(等价回归)。 +3. 透传保持:配置了意图但输入 Fallback 时,结果与无 gate 引擎一致。 +4. 结构断言:`go list -deps ./squad/... ./server/...` 不含 agent-intent。 +5. squadintent 跑 agent-intent `conformance.Run` + 自有语料。 -1. **零配置等价**:同一输入集在「无 gate 引擎」与「空配置 gate 引擎」上 RunResult 关键字段一致。 -2. **既有 conformance 全量跑在无 gate 引擎上**:等价回归,证明引擎路径未被改写。 -3. **透传保持**:配置了意图但输入 Fallback 时,结果与无 gate 引擎一致(意图只增不删)。 -4. **结构断言**:`go list -deps ./squad/... ./server/...` 输出不含 `agent-intent`(进一致性脚本)。 -5. squadintent 适配器跑 agent-intent `conformance.Run` + 自有语料。 +回退程序:删 `squadintent/`、`squad/intent.go`、cli 接线、go.mod 三行、`.gitmodules` 一条、submodule、脚本对应行——引擎与其余包零改动。 -### 3.3 回退程序(精确到文件) +## 三 b、Agent-Native 接入设计(T1 对称,v1 范围) -删 `squadintent/`、`squad/intent.go`(或仅置 Options.IntentGate 为 nil 亦即行为回退)、cli 接线块、go.mod 的 require/replace 三行、`.gitmodules` 一条、submodule、一致性脚本对应行。`squad` 引擎与其余包零改动。 +形态:**可选装饰器**,核心零改动。 + +- `adapters/intentgate/`(Native 仓内可选包,**全仓唯一 import agent-intent 处**): + - `intentgate.Wrap(next exec.Backend, rec intent.Recognizer, snap *intent.Snapshot, onIntent func(ctx, exec.Request, intent.Result) (exec.Result, error)) exec.Backend` + - `Execute` 时先对 `req.Prompt` 识别:分支为 GuardHit/Matched/ExpectationHit(即"有意图裁决")→ 调用 `onIntent` 回调,由**宿主**解释 Candidate(Handler/Metadata/Risk)并产出执行结果或错误——装饰器不发明合成 Result 的语义;Fallback/Ambiguous → 原样透传 `next`。 + - 未 Wrap 或快照零 spec ⇒ 行为与裸 backend 完全一致(T0)。 +- 组合根:直接以 Native 构建的应用在自己的 main 里 Wrap 与配置;Native 的 `adapters/native` 组合根不变。 +- 解耦证明与 Squad 对称:零配置等价测试;`go list -deps` 核心包(contract/exec/runtime/adapters/*)不含 agent-intent;删除 = 删装饰器包 + go.mod/submodule。 +- 备选(更轻):Native 仓不放代码,仅在 Agent-Intent 的 examples 提供"Native 直宿主接线模式"样例,由应用自行组装。→ 决策 D7。 ## 决策与剩余项 -- **D1 档位**:T1(推荐,理由见上)vs T2(Squad 永不单独带意图时选)。 -- **D2 蓝图映射缺失**:fail-closed 报错(推荐,同未知 backend 先例)vs 透传原路径。 +- **D1 Squad 档位**:T1(推荐)。 +- **D2 蓝图映射缺失**:fail-closed 报错(推荐,同未知 backend 先例)vs 透传。 - **D3 Guard 拒绝错误码**:Error-Code-System 新增 `squad.intent_refused`(推荐,400/warn/never/none,需上游 PR)vs 复用 `squad.plan_rejected`。 - **D4 配置来源**:flag + env 双通道(推荐)。 -- **D5 Squad v1 不接 LLM 层**(推荐);#2/#3 的 llm.Client 适配器留给需要的宿主仓实现。 -- **D6 结构断言**进 `submodule-consistency.sh`(推荐)还是仅文档约定。 +- **D5 Squad v1 不接 LLM 层**(推荐)。 +- **D6 结构断言**进一致性脚本(推荐)。 +- **D7 Native 接入形态**:仓内 `adapters/intentgate` 装饰器(推荐,即插即用、与 Squad 对称)vs 仅 examples 文档模式。 -剩余项:Agent-System 未来以本模块替换 `internal/intent` 时,其 intentflow/对话组件按 2.2 的分层归位(同步层复用 llm.Client、异步层走 exec);`intentctl` 的 LLM 辅助草案生成(#6)另立任务。 +剩余项:Agent-System 与本模块并行演进、互不迁移(定位勘误后明确,不再列为任何阶段目标);`intentctl` 的 LLM 辅助草案生成(#6)另立任务。