149 lines
6.8 KiB
Markdown
149 lines
6.8 KiB
Markdown
# 02 Agent 接入与收敛:让推理可以工作,也可以停止
|
||
|
||
这一篇只回答一个问题:**怎样保留 Agent 的自主推理,同时阻止它重复查询或无限空转?**
|
||
|
||
## 1. 先看一个具体问题
|
||
|
||
Diagnosis Agent 第一次查询 10:00 到 10:10 的支付日志,没有发现异常;第二次换了关键词,仍然没有新信息;第三次又提交了与第一次等价的查询。
|
||
|
||
仅设置“最多调用 10 次 Tool”只能限制最坏损失,却回答不了:
|
||
|
||
- 上一次结果有没有推进诊断?
|
||
- 这次查询是否已经做过?
|
||
- 连续多少次没有新信息后应该停止?
|
||
- Agent 已经收到停止要求,为什么还能继续调用 Tool?
|
||
- 停止后,怎样安全地向用户说明已经检查过什么?
|
||
|
||
这就是 Agent 接入层和 Progress 组件共同解决的问题。
|
||
|
||
## 2. 一轮 ReAct 怎样经过 Harness
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant A as Diagnosis Agent
|
||
participant MI as Model Interceptor
|
||
participant TI as Tool Interceptor
|
||
participant P as Progress Tracker
|
||
participant T as Tool Boundary
|
||
|
||
A->>MI: 发起一轮模型调用
|
||
MI->>MI: 检查 Run、预留预算、记录 Token
|
||
A->>TI: 请求调用 Tool
|
||
TI->>P: 评价上一轮是否有信息增益
|
||
P-->>TI: 可继续 / 重复 / 已饱和 / 协议错误
|
||
alt 允许继续
|
||
TI->>T: 执行业务 Tool
|
||
T-->>TI: Control View + Model Observation
|
||
TI->>P: 登记已完成调用和 scope
|
||
TI-->>A: 只返回 Model Observation
|
||
else 必须停止
|
||
TI-->>A: STOP_REQUIRED
|
||
end
|
||
```
|
||
|
||
第一次阅读可以把它们理解为:
|
||
|
||
- **Agent 接入层是检查站**:把框架原生 ReAct loop 接入预算、Tool 和审计边界。
|
||
- **Progress Tracker 是收敛记录器**:判断是否重复、是否连续无增益、是否必须停止。
|
||
|
||
## 3. 为什么复用框架 ReAct,而不是自己重写循环
|
||
|
||
Diagnosis Agent 需要模型原生 Tool Calling 和多轮 ReAct。项目没有再写一套 `while` 循环,而是通过 Factory、Model Interceptor、Tool Interceptor 和 Audit Hook 接入框架。
|
||
|
||
这样做的决策依据是:
|
||
|
||
- ReAct 的业务推理由框架和模型负责;
|
||
- 预算、Tool 授权、事实保存和停止协议由 Harness 负责;
|
||
- 两者通过明确边界连接,不互相复制实现。
|
||
|
||
如果 Harness 自己维护另一套 ReAct 状态机,就会同时出现“框架认为的下一步”和“Harness 认为的下一步”,调试时很难确定谁才是真理源。
|
||
|
||
主要代码入口:`DiagnosisAgentFactory`、`DiagnosisAgentUseCase`、`HarnessModelInterceptor`、`HarnessToolInterceptor`、`HarnessEvidenceTools`。
|
||
|
||
## 4. Model Interceptor:每一轮模型调用都必须记账
|
||
|
||
一个 Diagnosis Agent 执行不等于一次模型调用。ReAct 可能经历多轮思考和 Tool 返回,因此每一轮都要:
|
||
|
||
1. 检查 Run 是否仍然 active;
|
||
2. 在调用前预留模型预算;
|
||
3. 调用后记录 Provider 返回的 Token usage;
|
||
4. 再次检查取消或迟到结果。
|
||
|
||
Interceptor 不负责重试模型,也不判断输出是否支持根因。它只确保框架内部的每轮调用无法绕过 Harness。
|
||
|
||
## 5. Tool Interceptor:先检查进展,再允许查询
|
||
|
||
模型提交的 Tool Call 不只是业务参数,还携带对上一轮结果的评价。Tool Interceptor 会依次检查:
|
||
|
||
- previous observation 是否完整、顺序是否正确;
|
||
- 上一轮是 `GAINED` 还是 `NO_GAIN`;
|
||
- 当前 Tool scope 是否已经完成过;
|
||
- 收集状态是否已经 `SATURATED`;
|
||
- 通过检查后,才把业务请求交给 ToolBoundary。
|
||
|
||
它不执行后端查询,也不再次扣 Tool 预算。实际执行属于 ToolBoundary;收敛状态属于 ProgressTracker。Interceptor 只是两者与 ReAct 框架之间的接合点。
|
||
|
||
## 6. 为什么“有结果”不等于“有信息增益”
|
||
|
||
Tool 可以客观判断是否返回候选内容,却不知道这些内容是否推进了当前假设。例如同一条超时日志再次出现:
|
||
|
||
```text
|
||
InvocationStatus = READY
|
||
EvidenceStatus = EVIDENCE_FOUND
|
||
InformationGain = NO_GAIN
|
||
```
|
||
|
||
前三个状态回答不同问题:查询是否完成、是否有候选内容、内容是否推进当前诊断。把它们合成一个 `SUCCESS` 会让系统无法正常收敛。
|
||
|
||
当前由 Agent 在**下一次 Tool Call** 中评价上一轮的信息增益。这样评价发生在它真正做出下一步行动时,Harness 也能机械检查调用顺序,而不需要再增加一个 Progress Judge 模型。
|
||
|
||
## 7. Progress Tracker 保存什么
|
||
|
||
Tracker 只保存控制所需的最小状态:
|
||
|
||
- 已完成的 `tool_call_id` 和规范化 scope;
|
||
- 哪个结果仍等待 Agent 评价;
|
||
- 连续 `NO_GAIN` 次数;
|
||
- 收集状态和停止原因;
|
||
- 停止指令是否已经交付。
|
||
|
||
它不保存 raw response,也不判断日志是否证明支付线程池耗尽。业务价值判断仍由 Diagnosis Agent 负责,事实内容仍由 canonical store 负责。
|
||
|
||
主要代码入口:`DiagnosisProgressTracker`、`ToolScopeNormalizer`、`DiagnosisProgressProjector`。
|
||
|
||
## 8. 为什么停止不直接等于失败
|
||
|
||
连续无增益后停止,是一次正常的受控收敛,不是技术异常。Harness 会从已经完成的 canonical Tool 记录中投影 `ProgressSnapshot`,只保留可验真的检查范围、观察事实和限制,再形成安全 Fallback。
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
N["连续 NO_GAIN 或重复查询"] --> S["CollectionState = SATURATED"]
|
||
S --> X["拒绝新的证据 Tool"]
|
||
X --> P["生成安全 ProgressSnapshot"]
|
||
P --> F["发布证据不足的 Fallback"]
|
||
```
|
||
|
||
因此,“没有找到足够证据”可以正常结束;只有违反进展协议、预算耗尽且没有安全进展等情况,才可能升级为失败。
|
||
|
||
## 9. 为什么没有采用其他方案
|
||
|
||
| 方案 | 没有采用的原因 |
|
||
|---|---|
|
||
| 只设 Tool 次数上限 | 只能止损,不能识别查询已经没有价值 |
|
||
| Harness 根据结果条数判断增益 | 条数是客观统计,不代表是否推进业务假设 |
|
||
| 增加 Progress Judge Agent | 增加模型成本和新的非确定性判断点 |
|
||
| 用自然语言相似度判断重复 | 首版难以稳定解释误判,当前只做 typed 参数级 scope 规范化 |
|
||
| 把剩余预算告诉模型 | 容易让模型围绕阈值博弈,硬限制应由 Harness 保持 |
|
||
|
||
## 10. 先记住这些
|
||
|
||
1. 框架负责 ReAct loop,Harness 通过 Interceptor 接入控制能力。
|
||
2. 预算回答“还能不能查”,信息增益回答“继续查有没有价值”。
|
||
3. Tool 是否有结果与结果是否推进诊断是两件事。
|
||
4. ProgressTracker 只保存控制状态,不保存完整证据。
|
||
5. 信息饱和可以正常发布 Fallback,不等于 Run 执行失败。
|
||
|
||
下一篇:[03 Tool 事实边界](03-Tool事实边界-让模型看到必要信息而系统保留真相.md)。
|
||
|
||
需要深入停止协议时,阅读[信息增益停止专题](../Harness信息增益停止-让无证据诊断正常收敛.md)。
|