feat(harness,rag): dual LLM audit fields, run conclusion, and hybrid quality
Persist provider reasoning and assistant text separately on agent_reasoning_audit (DeepSeekAssistantMessage path), extract diagnosis_run.conclusion, enrich RAG tool audit (step_id/query/qualityScore), gate empty mysql tools, drop devtools, and align MVP docs after live E2E verification.
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
# Agent 推理审计表:agent_reasoning_audit
|
||||
|
||||
**状态**:当前独立敏感审计表;治理待 ISS-015 收敛
|
||||
**来源**:`V015__create_agent_reasoning_audit.sql`、`AgentReasoningAudit`
|
||||
**状态**:当前独立敏感审计表;治理待 ISS-015 收敛
|
||||
**来源**:`V015__create_agent_reasoning_audit.sql`、`V017__add_content_source_to_agent_reasoning_audit.sql`、`AgentReasoningAudit`、`HarnessAgentAuditHook`
|
||||
|
||||
## 定位
|
||||
|
||||
`agent_reasoning_audit` 保存模型 Provider 在 Agent 步骤 metadata 中实际返回的 reasoning 内容。它与普通 Trace、AgentStep、Evidence Snapshot 和业务发布结果物理分离,不能作为事实证据或诊断结论来源。
|
||||
`agent_reasoning_audit` 按 **Diagnosis Agent 每个模型步骤** 保存两类 LLM 面向文本,并与普通 Trace、AgentStep、Evidence Snapshot、业务发布结果物理分离:
|
||||
|
||||
Provider 未返回 reasoning 时仍写入 unavailable 记录,防止把“没有返回”误判为“审计链路漏写”。系统不得从最终回答、Tool 调用或其他字段生成伪 reasoning。
|
||||
1. **Provider reasoning / thinking**(`reasoning_content`)
|
||||
2. **Assistant 可见正文**(`assistant_text`:最终 prose 和/或 tool-call **计划**)
|
||||
|
||||
它不能作为事实证据或诊断结论来源。Tool **结果**载荷不进本表(见 `tool_invocation`)。
|
||||
|
||||
Provider 未返回 reasoning 时仍写入记录(`reasoning_available=false`),防止把“没有返回”误判为“审计链路漏写”。系统不得从最终回答、Tool 调用或其他字段生成伪 reasoning。
|
||||
|
||||
## 字段
|
||||
|
||||
@@ -19,8 +24,10 @@ Provider 未返回 reasoning 时仍写入 unavailable 记录,防止把“没
|
||||
| `step_index` | INT | 是 | Agent 模型步骤序号 |
|
||||
| `agent_name` | VARCHAR(64) | 是 | Agent 身份,当前为 `diagnosis_agent` |
|
||||
| `reasoning_available` | BOOLEAN | 是 | Provider 是否实际返回非空 reasoning |
|
||||
| `reasoning_content` | LONGTEXT | 否 | Provider reasoning 原文;Hook 当前最多保留 32000 个字符 |
|
||||
| `content_bytes` | INT | 是 | 截断后 reasoning 的 UTF-8 字节数;unavailable 时为 0 |
|
||||
| `reasoning_content` | LONGTEXT | 否 | Provider CoT / thinking 原文;Hook 单字段最多保留 32000 字符 |
|
||||
| `assistant_text` | LONGTEXT | 否 | 本步 assistant 可见正文;若有 tool_call,可附带 `tool_calls:` 计划预览(**不含** tool 结果) |
|
||||
| `content_source` | VARCHAR(64) | 否 | 本步写入摘要:`PROVIDER_REASONING+ASSISTANT_TEXT` / `PROVIDER_REASONING` / `ASSISTANT_TEXT` / `TOOL_CALL_PLAN` / `NONE` |
|
||||
| `content_bytes` | INT | 是 | 截断后 `reasoning_content` + `assistant_text` 的 UTF-8 字节合计 |
|
||||
| `created_at` | DATETIME | 是 | 创建时间,默认当前时间 |
|
||||
|
||||
## 索引
|
||||
@@ -36,15 +43,36 @@ Provider 未返回 reasoning 时仍写入 unavailable 记录,防止把“没
|
||||
- `session_id` 逻辑关联 `chat_session.session_id`。
|
||||
- 通过 `session_id + run_id + step_index` 与 `agent_step` 逻辑对应,不建立数据库外键。
|
||||
|
||||
## 写入规则
|
||||
## 写入规则(HarnessAgentAuditHook)
|
||||
|
||||
- Provider 返回非空 reasoning:`reasoning_available=true`,保存截断后的原文及实际 UTF-8 字节数。
|
||||
- Provider 未返回 reasoning:`reasoning_available=false`,`reasoning_content=NULL`,`content_bytes=0`。
|
||||
- `agent_step.thought` 继续保持为空;普通 Trace 仅保留 availability/bytes metadata。
|
||||
- Reasoning 不进入 SSE、PreviousTurn、Evidence Snapshot、发布结果或应用日志。
|
||||
### 捕获来源(按优先级)
|
||||
|
||||
1. **DeepSeek 生产主路径**:`DeepSeekAssistantMessage.getReasoningContent()`
|
||||
(Spring AI 将 API 的 `message.reasoning_content` 映射到该专用字段,**不是** `AssistantMessage.metadata`)
|
||||
2. 反射 `getReasoningContent()`(兼容序列化/子类)
|
||||
3. metadata 键兜底:`reasoning_content` / `reasoningContent` / `reasoning` / `thinking` / `reasoning_text` / `reasoningText`(单测与其它 Provider)
|
||||
|
||||
`assistant_text` 来自 `AssistantMessage.getText()`;若本步有 tool_calls,追加有界的 `tool_calls:` 名称与 args 预览。
|
||||
|
||||
### 落库语义
|
||||
|
||||
- 有 Provider reasoning:`reasoning_available=true`,写入截断后的 `reasoning_content`。
|
||||
- 无 Provider reasoning:`reasoning_available=false`,`reasoning_content=NULL`;仍可写入 `assistant_text`。
|
||||
- `content_source` 反映本步实际写入组合;两者皆空则为 `NONE`。
|
||||
- `content_bytes` 为两列截断后文本 UTF-8 字节之和。
|
||||
- **禁止**把 tool 执行结果、raw Tool response、用户 Prompt 全文写入本表。
|
||||
|
||||
### 与其它表的边界
|
||||
|
||||
- 普通 Trace / Timeline 只暴露 `reasoning_available`、`reasoning_bytes` / `assistant_bytes`、`content_source` 等有界 metadata,不返回 reasoning/assistant 原文。
|
||||
- `agent_step.model_input` / `model_output` 仍为有界 metadata。
|
||||
- `agent_step.thought` 可作为兼容镜像:优先 Provider reasoning,否则 assistant 正文;完整双字段以本表为准。
|
||||
- Reasoning / assistant 审计原文不进入 SSE、PreviousTurn、Evidence Snapshot、发布结果或应用日志。
|
||||
|
||||
## 查询与治理
|
||||
|
||||
当前独立接口为 `GET /api/diagnosis/{sessionId}/trace/reasoning?runId={runId}`。`runId` 必填,服务端校验其属于 path `sessionId`,并按 `step_index` 返回记录。
|
||||
当前独立接口为 `GET /api/diagnosis/{sessionId}/trace/reasoning?runId={runId}`。`runId` 必填,服务端校验其属于 path `sessionId`,并按 `step_index` 返回记录(含 `reasoningContent`、`assistantText`、`contentSource`)。
|
||||
|
||||
分表和归属校验已经实现,但不能等同于完整安全治理。身份认证、角色授权、保留/删除期限、静态与传输加密以及真实 Provider/V015 验证仍由 ISS-015 阶段 3 跟踪;治理完成前不应将该接口暴露给普通业务用户。
|
||||
**已验证(2026-07-28 live E2E,DeepSeek `deepseek-v4-flash`)**:thinking 模式下两步模型调用均可得到 `reasoning_available=true` 且 `content_source=PROVIDER_REASONING+ASSISTANT_TEXT`。
|
||||
|
||||
分表和归属校验已经实现,但不能等同于完整安全治理。身份认证、角色授权、保留/删除期限、静态与传输加密仍由 ISS-015 跟踪;治理完成前不应将该接口暴露给普通业务用户。
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
# Agent 步骤表:agent_step
|
||||
|
||||
**状态**:当前表
|
||||
**来源**:`V005__create_session_storage.sql`、`V006__fix_agent_step_json_to_text.sql`、`AgentStep`
|
||||
**来源**:`V005__create_session_storage.sql`、`V006__fix_agent_step_json_to_text.sql`、`AgentStep`、`HarnessAgentAuditHook`
|
||||
|
||||
## 定位
|
||||
|
||||
`agent_step` 记录 Diagnosis Agent 模型步骤的有界审计 metadata。`run_id` 是执行隔离边界;当前写入不得保存 Prompt、消息正文、模型正文、Tool arguments 或 Thought。Provider reasoning 使用独立 `agent_reasoning_audit` 表,不复用历史 `thought` 字段。
|
||||
`agent_step` 记录 Diagnosis Agent 模型步骤的有界审计 metadata。`run_id` 是执行隔离边界;当前写入不得保存完整 Prompt、完整消息列表、Tool 结果体。
|
||||
|
||||
**Provider reasoning 与 assistant 正文的完整双字段** 在独立表 `agent_reasoning_audit`;本表只保留步骤级摘要与兼容镜像。
|
||||
|
||||
## 字段
|
||||
|
||||
@@ -17,8 +19,8 @@
|
||||
| `step_index` | INT | 是 | 步骤序号,从 0 开始 |
|
||||
| `agent_name` | VARCHAR(32) | 是 | 当前 Harness 写入固定为 `diagnosis_agent` |
|
||||
| `model_input` | TEXT | 否 | JSON metadata,仅包含 message count 与 roles |
|
||||
| `model_output` | TEXT | 否 | JSON metadata,仅包含 text presence 与 Tool names |
|
||||
| `thought` | TEXT | 否 | 当前 Harness 必须写空;字段仅保留历史兼容 |
|
||||
| `model_output` | TEXT | 否 | JSON metadata:`has_text`、`tool_names`、`reasoning_available`、`reasoning_bytes`、`assistant_bytes`、`content_source` |
|
||||
| `thought` | TEXT | 否 | 兼容镜像:优先 Provider reasoning,否则 assistant 正文;**完整双字段以 `agent_reasoning_audit` 为准** |
|
||||
| `has_tool_call` | BOOLEAN | 否 | 本步骤是否触发工具调用 |
|
||||
| `duration_ms` | INT | 否 | 本步骤耗时 |
|
||||
| `token_count` | INT | 否 | 本步骤 Token 消耗 |
|
||||
@@ -36,12 +38,14 @@
|
||||
|
||||
- `agent_step.run_id` 逻辑关联 `diagnosis_run.run_id`。
|
||||
- `agent_step.session_id` 保留为 `chat_session.session_id` 的冗余关联,便于粗粒度过滤和兼容查询。
|
||||
- `tool_invocation.step_id` 可关联 `agent_step.id`,但当前允许为空且不强制外键。
|
||||
- `tool_invocation.step_id` 应关联当前模型步骤的 `agent_step.id`(由 `AgentStepAuditTracker` 在 beforeModel 绑定)。
|
||||
- `agent_reasoning_audit` 通过相同的 `session_id + run_id + step_index` 逻辑定位模型步骤,不建立数据库外键。
|
||||
|
||||
## 注意点
|
||||
|
||||
- 前端展示步骤时应使用 Trace API 返回顺序;服务端会在同一 `run_id` 范围内整理步骤顺序。
|
||||
- 新 Trace 和验收读路径必须按 exact `run_id` 取数,避免同一 `sessionId` 多次运行混入。
|
||||
- 当前 Run 若出现 `diagnosis_agent` 之外的新写入,或 `thought` 非空,视为审计边界违规。
|
||||
- `model_output` 可保存 `has_text`、`tool_names`、`reasoning_available` 和 `reasoning_bytes` 等有界 metadata,不得保存 reasoning 原文。
|
||||
- 当前 Run 若出现 `diagnosis_agent` 之外的新写入,视为审计边界违规。
|
||||
- `model_output` **不得**保存 reasoning/assistant 原文;只允许有界 metadata。
|
||||
- `thought` 非空 **不再**视为违规:它是受限镜像,便于旧读路径一眼看到“本步在想什么/说什么”;敏感完整审计仍走 `/trace/reasoning`。
|
||||
- 需要同时查看 thinking 与 assistant 正文时,必须查 `agent_reasoning_audit` 或 reasoning Trace API。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 诊断运行表:diagnosis_run
|
||||
|
||||
**状态**:当前诊断运行主表
|
||||
**来源**:`V011__add_session_run_isolation.sql`、`DiagnosisRun`
|
||||
**来源**:`V011__add_session_run_isolation.sql`、`V012__add_chat_release_contract.sql`、`V016__add_conclusion_to_diagnosis_run.sql`、`DiagnosisRun`
|
||||
|
||||
## 定位
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
| `run_id` | VARCHAR(64) | 是 | 运行唯一 ID,格式为 `run-` + UUID |
|
||||
| `session_id` | VARCHAR(64) | 是 | 所属 `chat_session.session_id` |
|
||||
| `query` | TEXT | 是 | 本次 Chat 用户问题 |
|
||||
| `conclusion` | TEXT | 否 | 从安全发布内容提取的短结论,与 `query` 并列便于读出;非 reasoning 原文 |
|
||||
| `status` | VARCHAR(16) | 否 | `PENDING`、`RUNNING`、`SUCCESS`、`FALLBACK`、`FAILED` 或 `CANCELLED` |
|
||||
| `agent_flow` | VARCHAR(32) | 否 | 历史兼容字段;当前公开执行统一来自 Chat Harness |
|
||||
| `answer` | LONGTEXT | 否 | 安全发布的最终文本兼容字段 |
|
||||
| `answer` | LONGTEXT | 否 | 安全发布的最终内容 JSON/文本兼容字段 |
|
||||
| `intent` | VARCHAR(32) | 否 | `SYSTEM_CHAT`、`KNOWLEDGE_QUERY` 或 `DIAGNOSIS` |
|
||||
| `release_outcome` | VARCHAR(16) | 否 | `SUCCESS`、`FALLBACK`、`FAILED` 或 `CANCELLED` |
|
||||
| `published_result` | JSON | 否 | Release Policy 允许发布的结构化安全结果 |
|
||||
@@ -55,4 +56,5 @@
|
||||
- latest run 排序使用 `created_at DESC, id DESC`,避免 feedback 或自评估更新 `updated_at` 后改变回放目标。
|
||||
- 历史 `diagnosis_session` 会被迁移成兼容 run,但旧混合数据不能被还原成真实多轮边界。
|
||||
- 当前诊断发布结果以 `release_outcome + published_result` 为准,不得从旧 self-evaluation 推断 Release Policy 结果。
|
||||
- `diagnosis_run` 不保存 reasoning 原文;普通 Run/Trace 查询也不得通过聚合将其带出。
|
||||
- `conclusion` 由 `RunConclusionExtractor` 在 `finish` 时从 `answer`(安全发布 JSON)提取:优先 `report.conclusion.text`,否则 fallback 的 `type + message` 等;最多约 4000 字符。它是 **业务结论读出字段**,不是 Provider thinking。
|
||||
- `diagnosis_run` 不保存 reasoning 原文;普通 Run/Trace 查询也不得通过聚合 `agent_reasoning_audit` 将其带出。Trace 的 `run.conclusion` 可以返回上述短结论。
|
||||
|
||||
Reference in New Issue
Block a user