feat(trace): finish run-aware demo verification

This commit is contained in:
zhuyongxin
2026-07-10 21:37:43 +08:00
parent 78c1477198
commit f9df94377b
28 changed files with 779 additions and 459 deletions
+65 -115
View File
@@ -1,69 +1,68 @@
# 会话与 Trace 生命周期
**更新日期**:2026-07-08
**更新日期**:2026-07-10
**状态**:当前可运行架构
**参考历史文档**:`archive/2026-07-05-legacy/session-management.md`
## 1. 定位
旧版会话设计以 Redis 会话为主,MySQL 作为可选长期沉淀。当前 MVP 的可追踪诊断已经转为 MySQL Trace 三表为主:
当前 MVP 把“会话态”和“运行态”拆开:
```text
diagnosis_session
-> agent_step
-> tool_invocation
chat_session(sessionId)
-> diagnosis_run(runId)
-> agent_step(runId)
-> tool_invocation(runId)
```
因此本文描述的是当前可运行链路:
- `sessionId` 是一次诊断和后续 trace/feedback 的关联键。
- `diagnosis_session` 保存会话级状态、问题、答案、自评估和反馈。
- `agent_step` 保存每个 Agent 模型调用。
- `tool_invocation` 保存工具调用事实。
- `DiagnosisTraceService` 聚合三类记录,形成可回放 trace。
- `sessionId` 表示多轮会话目录和 Redis 上下文。
- `runId` 表示一次可回放诊断执行。
- `DiagnosisTraceService` 聚合一个 run 的主记录、步骤和工具调用,形成可回放 Trace。
- `diagnosis_session` 只保留为历史兼容和回滚表。
## 2. 生命周期总图
```mermaid
flowchart TD
Start["request: chat / ai_ops"] --> Resolve["resolve sessionId"]
Resolve --> Create["create or reset diagnosis_session"]
Create --> Running["status = RUNNING"]
Resolve --> Session["ensure chat_session metadata"]
Session --> Run["create diagnosis_run(runId)"]
Run --> Running["run.status = RUNNING"]
Running --> Agent["Agent workflow"]
Agent --> StepHook["AgentLoggingHook"]
StepHook --> Step["agent_step"]
Agent --> Tool["Evidence tools"]
Tool --> Invocation["tool_invocation"]
Agent --> Context["execution context(sessionId, runId)"]
Context --> StepHook["AgentLoggingHook"]
StepHook --> Step["agent_step(session_id, run_id)"]
Context --> Tool["Evidence tools"]
Tool --> Invocation["tool_invocation(session_id, run_id)"]
Invocation --> Gatekeeper["Gatekeeper evidence validation"]
Agent --> Final{"workflow result"}
Final -->|success| Success["status = SUCCESS, answer saved"]
Final -->|failed| Failed["status = FAILED"]
Final -->|success| Success["run.status = SUCCESS, answer saved"]
Final -->|failed| Failed["run.status = FAILED"]
Success --> Evaluation["self_evaluation merge"]
Success --> Evaluation["diagnosis_run.self_evaluation merge"]
Failed --> Evaluation
Evaluation --> Trace["GET /api/diagnosis/{sessionId}/trace"]
Success --> Feedback["POST /api/feedback"]
Feedback --> Case["useful -> case_library"]
Evaluation --> Trace["GET /api/diagnosis/{sessionId}/trace?runId=..."]
Success --> Feedback["POST /api/feedback(sessionId, runId)"]
Feedback --> Case["useful -> case_library(run_id)"]
```
## 3. sessionId 规则
## 3. ID 规则
| 链路 | sessionId 来源 |
|---|---|
| Chat | 如果请求带 sessionId,则复用;否则生成短 UUID |
| AIOps | 如果 payload 带 sessionId,则复用;否则生成 UUID |
| Trace | URL path 中的 `{sessionId}` |
| Feedback | request body 中的 `sessionId` |
| ID | 来源 | 含义 |
|---|---|---|
| `sessionId` | Chat request `Id`、AIOps payload `sessionId`,缺失时由服务生成 | 多轮会话目录和 Redis 上下文 |
| `runId` | 每次有效 Chat/AIOps 执行创建 | 一次诊断运行和 Trace 回放边界 |
设计含义:
- 同一个 `sessionId` 可以贯穿诊断、trace 查询和用户反馈。
- 当前诊断开始时会重置当前 session 的运行态字段,例如 answer、duration、step/tool count。
- `sessionId` 是业务关联键,不依赖数据库自增 ID 暴露给外部。
- 同一个 `sessionId` 可以贯穿多轮 Chat。
- 每次有效 Chat/AIOps 执行都会创建新的 `runId`。
- Trace 和 Feedback 新客户端应传 `runId`;只传 `sessionId` 时兼容解析 latest run。
- latest run 排序使用 `diagnosis_run.created_at DESC, id DESC`,不使用 `updated_at`。
## 4. 状态流转
## 4. 运行状态流转
```mermaid
stateDiagram-v2
@@ -77,14 +76,14 @@ stateDiagram-v2
字段边界:
| 字段 | 含义 |
|---|---|
| `status` | 执行状态:`PENDING` / `RUNNING` / `SUCCESS` / `FAILED` |
| `answer` | Agent 最终返回给用户的报告或答复 |
| `self_evaluation` | 系统自评估 JSON |
| `feedback` | 用户反馈:`useful` / `not_useful` / null |
| 字段 | 所属表 | 含义 |
|---|---|---|
| `status` | `diagnosis_run` | 单次运行执行状态 |
| `answer` | `diagnosis_run` | 本次运行最终报告或答复 |
| `self_evaluation` | `diagnosis_run` | 本次运行系统自评估 JSON |
| `feedback` | `diagnosis_run` | 本次运行用户反馈 |
`feedback` 不修改 `status`。一个执行成功但用户标记 `not_useful` 的 session,仍然应该是 `SUCCESS + feedback=not_useful`。
`feedback` 不修改 `status`。一个执行成功但用户标记 `not_useful` 的 run,仍然应该是 `SUCCESS + feedback=not_useful`。
## 5. agent_step 写入
@@ -93,93 +92,49 @@ stateDiagram-v2
```mermaid
sequenceDiagram
autonumber
participant Agent as ReactAgent
participant Agent as Agent
participant Hook as AgentLoggingHook
participant DB as agent_step
Agent->>Hook: before_model(messages, sessionId)
Hook->>DB: insert step_index / agent_name / model_input
Agent-->>Agent: model call
Agent->>Hook: after_model(messages, sessionId)
Hook->>DB: update model_output / thought / has_tool_call / duration / token_count
Agent->>Hook: before_model(messages, sessionId, runId)
Hook->>DB: insert step(session_id, run_id, model_input, step_index)
Agent->>Hook: after_model(output, sessionId, runId)
Hook->>DB: update model_output, duration, token_count, has_tool_call
```
当前记录:
- `session_id`
- `step_index`
- `agent_name`
- `model_input`
- `model_output`
- `thought`
- `has_tool_call`
- `duration_ms`
- `token_count`
新写入必须带 `run_id`,同时保留 `session_id` 便于粗粒度排查。
## 6. tool_invocation 写入
工具调用记录真实工具事实,不记录模型猜测。
关键字段:
工具调用记录同样通过执行上下文拿到 `sessionId + runId`:
```text
session_id
step_id
tool_name
input_params
output_preview
output_length
retrieval_layer
l0_match_count
l1_match_count
retrieval_details
-> evidence_refs
relevance_level
dedup_reason
duration_ms
success
error_message
ToolInvocationRecorder
-> tool_invocation.session_id
-> tool_invocation.run_id
-> retrieval_details / evidence_refs
```
对 `lookup_knowledge`,`retrieval_details` 会承载 L0/L1、领域、证据状态、去重等检索细节。对日志、指标和知识库工具,`retrieval_details.evidence_refs` 会记录 Gatekeeper 可核验的最小证据引用:
```json
{
"evidence_refs": [
{
"raw_path": "$.logs[0]",
"text": "最小证据文本"
}
]
}
```
当工具明确没有返回匹配证据时,可以记录 `raw_path=$.no_evidence`。该路径只表示“本次工具查询未检索到匹配证据”,不表示问题被排除。
Verifier、Gatekeeper 和 EvaluationService 应按 `run_id` 读取工具调用,避免同一 session 的其他 run 参与评分或证据校验。
## 7. Trace API 聚合
```text
GET /api/diagnosis/{sessionId}/trace
GET /api/diagnosis/{sessionId}/trace?runId=run-...
```
聚合逻辑:
```text
diagnosis_session by sessionId
+ agent_step ordered by step_index
+ tool_invocation ordered by id
diagnosis_run by sessionId + runId
+ chat_session metadata when available
+ agent_step where run_id = runId, ordered by the Trace API
+ tool_invocation where run_id = runId order by id
-> DiagnosisTraceResponse
```
Trace 视图回答的问题:
- 这次诊断是否成功?
- 哪些 Agent 参与了?
- 每一步模型输入输出是什么摘要?
- 调用了哪些工具?
- 工具返回了什么证据?
- Gatekeeper / Verifier / Composer / AIOps rule 是否通过?
- 用户是否反馈有用?
当 `runId` 缺失时,Trace API 为兼容旧客户端解析最新 run,并在响应中返回 resolved `runId`。当 `runId` 属于其他 `sessionId` 时,API 必须拒绝,不能泄漏其他会话的 Trace。
## 8. Chat 与 AIOps 差异
@@ -189,22 +144,17 @@ Trace 视图回答的问题:
| 编排方式 | `SequentialAgent`: Planner -> Executor -> Gatekeeper -> Verifier -> Composer | `SupervisorAgent`: Planner + Executor |
| 自评估 | `rule_evaluation` + `verifier_evaluation` | `aiops_rule_evaluation` |
| 答案字段 | Chat 最终答复 | 告警分析报告 |
| payload | 用户自然语言 + history | alert payload 或 auto-discovery |
| runId 暴露 | `/api/chat` JSON response | `/api/ai_ops` SSE metadata message |
## 9. 清理与边界
当前会话持久化边界:
- MySQL Trace 记录是主要可回放来源。
- Chat 历史仍可作为请求上下文传入 Agent,但不是本文档的主持久化模型。
- Redis 主会话存储是历史设计,不作为当前架构事实。
- `RetrievedDocTracker` 是 session 级运行时去重状态,诊断结束后清理。
- Redis 会话历史用于多轮上下文,不是长期审计记录。
- MySQL `diagnosis_run + agent_step + tool_invocation` 是主要可回放来源。
- `chat_session.expires_at` 只是目录元数据;Redis 消息历史可独立过期。
- `RetrievedDocTracker` 仍是 session 级运行时去重状态,诊断结束后清理。
## 10. 后续增强
可考虑:
1. Trace API 增加更结构化的 `self_evaluation` 展示。
2. `agent_step` 与 `tool_invocation.step_id` 建立更严格关联。
3. 对多轮同 session 诊断增加 run id,避免复用 session 时历史记录混杂。
4. 为 Trace 增加导出能力,服务面试演示和回归分析。
3. 旧 `diagnosis_session` 只读观察期结束后,再评估数据库层面的约束收紧或归档策略。