docs(harness): add agent domain learning note and mark all nine domains complete

- Add agent note: factory assembly, dual interceptors (model budget/token audit,
  tool five gates), use case loop shell, controlled stop recovery, dual-view projection
- Mark agent domain complete in roadmap (all nine domains done)
This commit is contained in:
zhuyongxin
2026-08-10 10:12:04 +08:00
parent e1b8d1fb2c
commit da18fdf4e1
2 changed files with 191 additions and 4 deletions
@@ -0,0 +1,186 @@
# Harness agent 域学习笔记:从框架 ReAct 接入到受控停止
**更新日期**:2026-08-04
**主题**:agent 域完整链路——装配(Factory)/ 双拦截器(Model/Tool)/ 循环外壳(UseCase)/ 受控停止 / 双视图投影
**配套**:[tool 域代码学习笔记](Harness%20tool%20域代码学习笔记-工具的注册调用与执行链路.md)(工具链)、[progress 代码学习笔记](Harness%20progress%20代码学习笔记-从拦截器五道门到唯一发布点.md)(Tool 拦截器五道门)
## 1. 定位:框架 ReAct 接入层(粘合点)
```text
框架(spring-ai-alibaba ReactAgent):负责 ReAct 多轮(模型 ↔ tool_call)
Harness:不复制 loop,只通过 Interceptor 卡住【每次消耗】
→ Model Interceptor:每次模型调用(预算/审计/Token)
→ Tool Interceptor:每次工具调用(五道门)
原则:拦截器是挂点,不是 loop 实现——Harness 不需要知道框架内部怎么循环
```
## 2. 装配图(DiagnosisAgentFactory——粘合点)
```mermaid
flowchart LR
subgraph 框架能力
M["ChatModel"]
T["tools<br/>evidenceTools.callbacks()"]
L["ReactAgent 循环"]
end
subgraph Harness 控制面
I1["HarnessModelInterceptor<br/>预算+Token 审计"]
I2["HarnessToolInterceptor<br/>五道门+投影"]
H["Hooks<br/>agent_step 落库"]
O["outputSchema<br/>DiagnosisDraft(conclusion 可 null)"]
end
M --> L
T --> L
L --> I1
L --> I2
L --> H
L --> O
```
**关键装配决策**:
```text
.parallelToolExecution(false) ← 串行工具:预算与 step 绑定可解释
.returnReasoningContents(true) ← 推理内容返回
.releaseThread(true)
每次 run 新建 Agent(create(context))——拦截器持有 RunContext,不可跨 run 复用
```
## 3. HarnessModelInterceptor(模型拦截器)
```text
interceptModel(request, handler):
core.beforeModelCall(context) ← 预算门(模型调用前扣预算)
call = auditor.begin(...) ← 审计开始(Token 记账)
response = handler.call(request) ← 框架实际调用
recordUsage(call, response) ← 记 prompt/completion tokens
core.checkActive(context) ← 终态检查(预算耗尽在此打断)
return response
异常:记 0 token + 上抛(不吞)
```
**三个动作**:预算(beforeModelCall)→ 记账(auditor.begin/recordUsage)→ 终态(checkActive)——每次模型调用都被 Harness 卡住一次。Usage 字段 null/负数安全兜底(nonNegative)。
## 4. HarnessToolInterceptor(工具拦截器,已深学)
五道门(progress 会话已沉淀):证据工具必炸 handler → 拦截器唯一执行路径 → 边界投影 → 审计落库 → 返回。本会话只补装配视角:`interceptors` 列表里第二个,构造时注入 context + evidenceTools + objectMapper + traceRecorder。
## 5. DiagnosisAgentUseCase(循环外壳)
### 5.1 执行流程
```text
execute(context, input):
checkActive → 输入限制(query/previous_turn/input 字节)
reserveRunBytes(input) ← 输入也占 Run 预算
RunnableConfig.metadata 挂 RunContext ← 显式传递(避免隐式 ThreadLocal)
agent = factory.create(context) ← 每次 run 新建
response = agent.call(inputJson, config) ← ★ 框架跑完整个 ReAct 循环
output → 字节限制 → reserveRunBytes(draft) → parse DiagnosisDraft
→ completed(draft) 或 受控停止
```
### 5.2 受控停止(controlledExecution)——从异常栈捞回可控信号转正常返回值
```text
① DiagnosisCollectionStoppedException(信息饱和后仍强 tool)
→ stopped(stopReason) ← 收集该停(draft=null)
② RunAbortedException + BUDGET_EXHAUSTED
→ markBudgetLimitReached + stopped(BUDGET_LIMIT_REACHED)
③ 其他 RunAborted(取消/超时/内部失败终态)→ 原样再抛
← 留给 Application 写 CANCELLED/FAILED(不降级为正常停止)
④ BudgetExceededException 或 lifecycle 已 BUDGET_EXHAUSTED → 预算 stopped
⑤ 都识别不了 → 包装 DiagnosisAgentOutputException(Agent 执行失败)
```
**关键**:不是笼统「业务异常 → 正常」——**只识别 Harness 约定的可控信号**(沿 cause 链找,因框架可能再包一层);取消/超时必须上抛(诚实终态)。
### 5.3 与 recoverInvalidDraft 的分工
```text
controlledExecution:loop 被预算/收敛打断(往往还没有合法 draft)→ stopped
recoverInvalidDraft:loop 跑完了,但输出不是合法 DiagnosisDraft → 恢复/重试
```
### 5.4 输出解析(严格)
```text
draftReader = FAIL_ON_UNKNOWN_PROPERTIES + FAIL_ON_TRAILING_TOKENS(严格模式)
JsonParseException → INVALID_JSON / SchemaInvalid → SCHEMA_INVALID(分类错误码)
空输出 → EMPTY_DRAFT(分类错误码)
```
## 6. 双视图投影(ToolResultViewProjector)
```text
modelObservation() → 模型观察:只含该工具的内容字段
lookup_knowledge → scope.query + evidence + relevance_level
query_logs → source_kind + scope + patterns + events
query_mysql → scope + columns + rows
+ stop_required/reason(需要停止时附加)
controlView() → 控制视图:evidence_status / relevance_level / returned_count / truncated
(Harness 控制面读,模型看不到)
分工:模型看到「内容」,Harness 看到「控制信息」(判级/截断/进度消费)
```
## 7. 定义层小件
| 类 | 作用 |
|---|---|
| `DiagnosisAgentInput` | query + previous_turn(query 必填) |
| `DiagnosisAgentLimits` | maxQuery/PreviousTurn/Input/DraftBytes 四类字节上限 |
| `DiagnosisAgentPrompt` | classpath 加载系统提示词(prompts/diagnosis-agent-prompt.md) |
| `DiagnosisAgentExecution` | completed(draft, progress) / stopped(progress, stopReason) 双形态 |
| `DiagnosisDraftOutputSchema` | BeanOutputConverter postProcess:conclusion 允许 object/null(无结论合法) |
| `EvidenceToolInvoker` | 函数式:RunContext + toolCallId + arguments → ToolBoundaryResult |
| `ParsedAgentToolCall` | 解析出的工具调用(previousObservation + businessInput + arguments) |
## 8. 关键设计点(面试)
| 设计 | 为什么 |
|---|---|
| **不复制 loop** | 框架 ReAct 是标准能力;Harness 用拦截器挂在每次消耗点,不需要知道框架内部怎么循环 |
| 每次 run 新建 Agent | 拦截器持有 RunContext——Agent 与 run 绑定,防跨 run 串状态 |
| RunContext 显式传(metadata) | 避免隐式 ThreadLocal(框架线程池/异步下 ThreadLocal 不可靠) |
| 串行工具(parallel=false) | 预算与 step 绑定可解释(并行会让「哪一步花多少钱」不可审计) |
| 受控停止只认约定信号 | 取消/超时绝不降级为正常停止(诚实终态) |
| conclusion 允许 null | 无结论也是合法 Draft(FALLBACK 路径) |
| 双视图 | 模型观察 vs 控制视图分离——控制信息(判级/截断)不进模型上下文 |
| 输出严格解析 | FAIL_ON_UNKNOWN/TRAILING——防止模型输出混入意外字段 |
## 9. 易错点
| 易错 | 正确 |
|---|---|
| Harness 自己实现 Agent loop | 框架跑 loop,拦截器挂消耗点(不复制 loop) |
| 任何异常都转 stopped | 只认约定信号(CollectionStopped/预算);取消/超时原样上抛 |
| Agent 复用 | 每次 run 新建(拦截器绑定 RunContext) |
| ThreadLocal 传 context | RunnableConfig metadata 显式传 |
| 并行工具省时间 | 串行(预算与 step 绑定可解释) |
| 模型看到控制信息 | 双视图:模型看内容,Harness 看控制 |
| 输出宽容解析 | FAIL_ON_UNKNOWN + FAIL_ON_TRAILING(严格模式) |
## 10. 面试话术(30 秒)
> "agent 域是框架 ReAct 的接入层:不复制 loop——spring-ai-alibaba 的 ReactAgent 负责多轮循环,Harness 通过两个拦截器卡住每次消耗:Model Interceptor(每次模型调用前 checkActive + 预算,调用后记 Token 审计)、Tool Interceptor(工具调用五道门)。装配在 DiagnosisAgentFactory,每次 run 新建 Agent(拦截器绑定 RunContext,RunnableConfig metadata 显式传递避免 ThreadLocal)。循环外壳 DiagnosisAgentUseCase 做输入/输出字节限制 + Run 预算预留,并实现受控停止——只把 Harness 约定的可控信号(信息饱和、预算耗尽)从异常栈捞回转成 stopped,取消/超时原样上抛留给 Application 写 CANCELLED/FAILED。串行工具保证预算与 step 绑定可解释。"
## 11. 代码位置索引
| 类 | 文件 |
|---|---|
| `DiagnosisAgentFactory` | `src/main/java/com/superbiz/agent/harness/agent/DiagnosisAgentFactory.java` |
| `HarnessModelInterceptor` | `src/main/java/com/superbiz/agent/harness/agent/HarnessModelInterceptor.java` |
| `HarnessToolInterceptor` | `src/main/java/com/superbiz/agent/harness/agent/HarnessToolInterceptor.java` |
| `DiagnosisAgentUseCase` | `src/main/java/com/superbiz/agent/harness/agent/DiagnosisAgentUseCase.java` |
| `ToolResultViewProjector` | `src/main/java/com/superbiz/agent/harness/agent/ToolResultViewProjector.java` |
| `HarnessEvidenceTools` | `src/main/java/com/superbiz/agent/harness/agent/HarnessEvidenceTools.java` |
| `DiagnosisAgentExecution` | `src/main/java/com/superbiz/agent/harness/agent/DiagnosisAgentExecution.java` |
| `DiagnosisAgentOutputException` | `src/main/java/com/superbiz/agent/harness/agent/DiagnosisAgentOutputException.java` |
| 契约(DiagnosisDraft/PreviousTurn) | `src/main/java/com/superbiz/agent/harness/contract/` |
@@ -83,7 +83,7 @@
| `core` | **执行控制**:身份 / deadline / 预算 / 取消 / 唯一终态,checkActive 三道闸 | ✅ 深入 | RunContext、budget、cancel、lifecycle、checkActive、termination | [执行控制笔记](Harness执行控制笔记-终态检查与取消广播.md)、[RunBudget 时序图](RunBudget预算流程-一次Run的资源门禁时序图.md) | | `core` | **执行控制**:身份 / deadline / 预算 / 取消 / 唯一终态,checkActive 三道闸 | ✅ 深入 | RunContext、budget、cancel、lifecycle、checkActive、termination | [执行控制笔记](Harness执行控制笔记-终态检查与取消广播.md)、[RunBudget 时序图](RunBudget预算流程-一次Run的资源门禁时序图.md) |
| `retry` | **显式可计量重试**:分类裁决(技术/业务)、次数/时间/成本三重封顶、attempt 可审计 | ✅ 深入 | 设计动机、分类裁决、剩余超时、幂等性、SDK 关闭 | [Retry 重试机制](Retry重试机制-显式可计量的attempt循环.md) | | `retry` | **显式可计量重试**:分类裁决(技术/业务)、次数/时间/成本三重封顶、attempt 可审计 | ✅ 深入 | 设计动机、分类裁决、剩余超时、幂等性、SDK 关闭 | [Retry 重试机制](Retry重试机制-显式可计量的attempt循环.md) |
| `contract` | **跨层类型化语言**:Draft / PublishedResult / SafeFallback / 状态枚举,防字符串漂移 | ✅ 深入 | 11 个状态枚举五层全景、四个正交轴(RunState⊥ReleaseOutcome、InvocationStatus⊥EvidenceStatus)、纵向映射链、SseOutcome 未接线发现 | [状态流笔记](Harness%20contract%20状态流学习笔记-11个状态枚举的正交全景.md) | | `contract` | **跨层类型化语言**:Draft / PublishedResult / SafeFallback / 状态枚举,防字符串漂移 | ✅ 深入 | 11 个状态枚举五层全景、四个正交轴(RunState⊥ReleaseOutcome、InvocationStatus⊥EvidenceStatus)、纵向映射链、SseOutcome 未接线发现 | [状态流笔记](Harness%20contract%20状态流学习笔记-11个状态枚举的正交全景.md) |
| `agent` | **框架 ReAct 接入**:拦截器把预算/审计/停止协议挂到框架循环上,不复制 loop | ⬜ 部分 | HarnessModelInterceptor(预算/Token 记账) | — | | `agent` | **框架 ReAct 接入**:拦截器把预算/审计/停止协议挂到框架循环上,不复制 loop | ✅ 深入 | 装配(Factory 粘合点)、双拦截器(Model:预算+Token 审计;Tool:五道门)、UseCase 循环外壳(字节/预算限制)、受控停止(异常栈捞回可控信号)、双视图投影(模型观察 vs 控制视图)、串行工具 | [agent 域学习笔记](Harness%20agent%20域学习笔记-从框架%20ReAct%20接入到受控停止.md) |
| `audit` | **可观测账本**:Trace 事件回放、Token 对账、metadata-only(不存敏感正文) | ✅ 深入 | trace 时序线(15 帧真实数据)、Ledger 分账、模型步审计 hook、RunConclusionExtractor、DiagnosisTraceService 三级回放 | [application+audit 笔记](Harness%20application+audit%20学习笔记-从%20Run%20编排到可回放审计.md) | | `audit` | **可观测账本**:Trace 事件回放、Token 对账、metadata-only(不存敏感正文) | ✅ 深入 | trace 时序线(15 帧真实数据)、Ledger 分账、模型步审计 hook、RunConclusionExtractor、DiagnosisTraceService 三级回放 | [application+audit 笔记](Harness%20application+audit%20学习笔记-从%20Run%20编排到可回放审计.md) |
| `application` | **Run 应用所有者**:创建 Run / 路由意图 / 执行分支 / 持久化 / SSE 输出 | ✅ 深入 | 六步编排、取消句柄(CoreRunControl)、统一失败出口、多轮记忆有界化、PublishedResultPolicy 落库 | [application+audit 笔记](Harness%20application+audit%20学习笔记-从%20Run%20编排到可回放审计.md) | | `application` | **Run 应用所有者**:创建 Run / 路由意图 / 执行分支 / 持久化 / SSE 输出 | ✅ 深入 | 六步编排、取消句柄(CoreRunControl)、统一失败出口、多轮记忆有界化、PublishedResultPolicy 落库 | [application+audit 笔记](Harness%20application+audit%20学习笔记-从%20Run%20编排到可回放审计.md) |
| `guard` | **验证分离**:EvidenceGuard 机械验引用真实性 + SemanticGuard 隔离判结论支持度 | ✅ 深入 | 20 个违规码、三层校验(结构/验真/重读投影)、语义不变性、守卫模型受控调用、全栈衔接 | [证据安全链笔记](Harness%20证据安全链学习笔记-从收敛控制到唯一发布点.md) | | `guard` | **验证分离**:EvidenceGuard 机械验引用真实性 + SemanticGuard 隔离判结论支持度 | ✅ 深入 | 20 个违规码、三层校验(结构/验真/重读投影)、语义不变性、守卫模型受控调用、全栈衔接 | [证据安全链笔记](Harness%20证据安全链学习笔记-从收敛控制到唯一发布点.md) |
@@ -110,6 +110,7 @@
| [Harness application+audit 学习笔记-从 Run 编排到可回放审计](Harness%20application+audit%20学习笔记-从%20Run%20编排到可回放审计.md) | application 六步编排/取消句柄/持久化策略;audit 域层次(trace 子体系/Ledger/审计表);**audit vs trace 区别**(真实数据对照)/三级回放 | ✅ 已沉淀 | | [Harness application+audit 学习笔记-从 Run 编排到可回放审计](Harness%20application+audit%20学习笔记-从%20Run%20编排到可回放审计.md) | application 六步编排/取消句柄/持久化策略;audit 域层次(trace 子体系/Ledger/审计表);**audit vs trace 区别**(真实数据对照)/三级回放 | ✅ 已沉淀 |
| [Harness contract 状态流学习笔记-11个状态枚举的正交全景](Harness%20contract%20状态流学习笔记-11个状态枚举的正交全景.md) | 五层状态/四正交轴/纵向映射链/真实数据案例/面试叙事模板与追问应对 | ✅ 已沉淀 | | [Harness contract 状态流学习笔记-11个状态枚举的正交全景](Harness%20contract%20状态流学习笔记-11个状态枚举的正交全景.md) | 五层状态/四正交轴/纵向映射链/真实数据案例/面试叙事模板与追问应对 | ✅ 已沉淀 |
| [Harness 面试复习笔记-五步复习与白板图沉淀](Harness%20面试复习笔记-五步复习与白板图沉淀.md) | **详细版**:30 秒陈述展开/三张白板图/九域五段式讲法(动机→决策→实现→边界→话术)/六易错点带原因/追问应对大全/支付超时案例/纠正认知清单/面试 Checklist | ✅ 已沉淀 | | [Harness 面试复习笔记-五步复习与白板图沉淀](Harness%20面试复习笔记-五步复习与白板图沉淀.md) | **详细版**:30 秒陈述展开/三张白板图/九域五段式讲法(动机→决策→实现→边界→话术)/六易错点带原因/追问应对大全/支付超时案例/纠正认知清单/面试 Checklist | ✅ 已沉淀 |
| [Harness agent 域学习笔记-从框架 ReAct 接入到受控停止](Harness%20agent%20域学习笔记-从框架%20ReAct%20接入到受控停止.md) | agent 域:装配(Factory 粘合点)/双拦截器(Model 预算+Token 审计、Tool 五道门)/UseCase 循环外壳/受控停止/双视图投影/串行工具 | ✅ 已沉淀 |
## 3. 一次请求的完整学习主线 ## 3. 一次请求的完整学习主线
@@ -127,7 +128,7 @@ flowchart LR
## 4. 下一步规划 ## 4. 下一步规划
```text ```text
主线九域全部 ✅ + 面试五步复习 ✅(共沉淀 13 篇笔记) 主线九域全部 ✅(含 agent 域收尾)+ 面试五步复习 ✅(共沉淀 14 篇笔记)
面试前一天建议: 面试前一天建议:
1. 重读「面试速查」§1-2 + §8(30 秒陈述 / 一张图 / 六易错点) 1. 重读「面试速查」§1-2 + §8(30 秒陈述 / 一张图 / 六易错点)
@@ -137,8 +138,8 @@ flowchart LR
5. 2 分钟支付超时案例(复习笔记 §7) 5. 2 分钟支付超时案例(复习笔记 §7)
可选深化(不阻塞面试): 可选深化(不阻塞面试):
1. agent 域收尾:HarnessModelInterceptor / HarnessToolInterceptor 装配细节 1. audit 域深化:RagLookupAuditEnricher 检索审计明细
2. audit 域深化:RagLookupAuditEnricher 检索审计明细 2. 按需深入:模型步 hook 细节 / DiagnosisChatExecutor 恢复路径 / SSE 序列化
``` ```
## 5. 建议每次学完一个域后更新 ## 5. 建议每次学完一个域后更新