# Cognition Log 与知识反馈

> 状态：已实现（2026-04）。本文档同时承担**设计理由**和**使用规范**。
> 实现入口与代码位置见文末"七、实现与入口"。

## 文档维护规范

0. **先改文档，再动代码** - 新功能或重大修改需先完成文档更新、并完成审阅后，再进行代码实现；除非改动较小、不被文档涵盖
1. **文档分层，链接代码** - 重要或复杂设计可以另有详细文档；关键实现需标注代码文件路径；格式：`module/file.py:function_name`
2. **简洁快照，日志分离** - 只记录最重要的、与代码准确对应的或者明确的已完成的设计的信息，避免推测、建议、决策历史、修改日志、大量代码；决策依据或修改日志若有必要，可在 `knowhub/docs/decisions.md` 另行记录

---

## 概述

每个 trace 维护一个 `cognition_log.json`，按时间顺序记录所有认知事件（知识查询、评估、提取三态、记忆反思），为知识质量反馈和 Memory 系统的 dream 操作（详见 `agent/docs/memory.md`）提供数据。

> 此文件原名 `knowledge_log.json`，扩展为统一事件流后更名。读取时仍兼容旧文件名和 `entries[]` 字段。

---

## Cognition Log 数据结构

**位置**：`.trace/{trace_id}/cognition_log.json`

```json
{
  "trace_id": "trace-xxx",
  "events": [
    { "type": "query", "sequence": 42, ... },
    { "type": "evaluation", "query_sequence": 42, ... },
    { "type": "extraction_pending", "extraction_id": "pending-abc", ... },
    { "type": "extraction_reviewed", "extraction_id": "pending-abc", "decision": "approve", ... },
    { "type": "extraction_committed", "extraction_id": "pending-abc", "knowledge_id": "knowledge-xyz", ... },
    { "type": "reflection", "sequence_range": [43, 120], ... }
  ]
}
```

所有事件按写入顺序追加（`query` 和 `reflection` 关联 trace 中 message 的 `sequence`；`evaluation` / `extraction_*` 不强依赖 sequence）。框架自动给每个事件写入 `timestamp`。

---

## 事件类型

### `query`：知识查询

Agent 通过 `POST /api/knowledge/ask` 查询知识时记录。一次查询返回 KM Agent 的整合回答及引用的各 source，作为一个整体记录。

```json
{
  "type": "query",
  "sequence": 42,
  "goal_id": "1",
  "query": "goal 的描述文本",
  "response": "KM Agent 整合后的回答...",
  "source_ids": ["knowledge-a1b2", "knowledge-c3d4", "knowledge-e5f6"],
  "sources": [
    {"id": "knowledge-a1b2", "task": "...", "content": "...（截断500字）"},
    {"id": "knowledge-c3d4", "task": "...", "content": "..."}
  ],
  "timestamp": "2026-03-20T10:00:00"
}
```

**写入时机**：`agent/trace/goal_tool.py:inject_knowledge_for_goal`，`POST /api/knowledge/ask` 返回后。

### `evaluation`：知识评估

对某次 query 中各 source 的使用效果评估。通过 `query_sequence` 关联到对应的 query 事件。实际按 knowledge_id 逐条写入（每条知识一个 evaluation 事件）。

```json
{
  "type": "evaluation",
  "query_sequence": 42,
  "knowledge_id": "knowledge-a1b2",
  "eval_result": {"status": "helpful", "reason": "准确定位了问题"},
  "evaluated_at_trigger": "goal_completion",
  "timestamp": "2026-03-20T10:05:00"
}
```

LLM 在侧分支内按 `{evaluations: [{query_sequence, assessments: [{knowledge_id, eval_status, reason}]}]}` 输出；runner 解析后分条写入（一个 evaluation 事件对应一条 knowledge）。

**`status` 可能的值**：

| 状态 | 含义 |
|---|---|
| `irrelevant` | 知识与当前任务无关 |
| `unused` | 知识相关但未被使用 |
| `helpful` | 知识对任务有实质帮助 |
| `harmful` | 知识对任务产生负面作用 |
| `neutral` | 知识相关但无明显影响 |

### `extraction_pending` / `extraction_reviewed` / `extraction_committed`：知识提取三态

Agent 的反思侧分支不再直接 upload 到 KnowHub，而是暂存为 pending，经人工 review 后才 commit。详见 `agent/docs/memory.md` 第三节"提取-审核-提交两阶段"。

#### `extraction_pending`

反思 LLM 调用 `knowledge_save_pending` 工具时写入。payload 字段与 `knowledge_save` 参数一一对应（review 通过后字段透传）。

```json
{
  "type": "extraction_pending",
  "extraction_id": "pending-a1b2c3d4",
  "sequence": 88,
  "goal_id": "g1",
  "branch_id": "reflection-branch-xxx",
  "payload": {
    "task": "...", "content": "...", "types": ["tool"],
    "tags": {...}, "score": 4, "scopes": null, "owner": null,
    "resource_ids": [], "source_name": "", "source_category": "exp",
    "urls": [], "agent_id": "...", "submitted_by": "",
    "capability_ids": [], "tool_ids": []
  },
  "timestamp": "2026-03-20T10:10:00"
}
```

**写入时机**：`agent/tools/builtin/knowledge.py:knowledge_save_pending` 工具调用时。

#### `extraction_reviewed`

人工审核决策。同一 `extraction_id` 可能被多次 review（以最新一条为准），`edit` 决策携带 `edited_payload` 覆盖原 payload。

```json
{
  "type": "extraction_reviewed",
  "extraction_id": "pending-a1b2c3d4",
  "decision": "approve",
  "timestamp": "2026-04-15T14:00:00"
}
```

`decision` 取值：`approve` / `edit` / `discard`。`edit` 时附加 `edited_payload` 字段。

**写入时机**：
- CLI：`python -m agent.cli.extraction_review --review`
- Interactive 菜单第 8 项
- HTTP：`POST /api/traces/{tid}/extractions/{eid}/review`
- 共享核心：`agent/trace/extraction_review.py:review_one`

#### `extraction_committed`

将 approved/edited 的条目实际上传到 KnowHub 后写入。失败条目不写此事件，只记录在 CommitReport 里。

```json
{
  "type": "extraction_committed",
  "extraction_id": "pending-a1b2c3d4",
  "knowledge_id": "knowledge-new-1",
  "timestamp": "2026-04-15T14:05:00"
}
```

**写入时机**：`agent/trace/extraction_review.py:commit_approved`（调用 `knowledge_save` 成功后）。`reflect_auto_commit=True` 时由反思侧分支退出 hook 自动触发 `auto_commit_branch`。

### `reflection`：记忆反思

仅 memory-bearing Agent 使用（详见 `agent/docs/memory.md`）。Dream 操作触发的 per-trace 记忆反思。

```json
{
  "type": "reflection",
  "sequence_range": [43, 120],
  "summary": "这次执行中发现用户偏好XX方向...",
  "consumed_at": "2026-04-07T20:05:00",
  "timestamp": "2026-04-07T20:00:00"
}
```

`sequence_range` 是本次反思覆盖的消息区间 `[start, end]`。`consumed_at` 在跨 trace 整合（dream 的第二阶段）消化了该反思后写入；未消化时此字段缺省。

**写入时机**：`agent/core/dream.py:per_trace_reflect`（写入时 `consumed_at` 缺省）；`agent/core/dream.py:cross_trace_integrate`（整合后补 `consumed_at`）。

---

## 评估触发机制

评估针对的是未评估的 query 事件（即存在 query 事件但没有对应 evaluation 事件的）。

**判断待评估条件**：查找 cognition_log 中所有 `type: "query"` 事件，检查是否存在 `query_sequence` 指向该 query 的 `type: "evaluation"` 事件。

### 触发点 1：Goal 完成

**时机**：Goal status 变为 `completed` 或 `abandoned`

**触发逻辑**（`agent/trace/store.py:update_goal`）：

```
Goal 完成
  ↓
查询 cognition_log 中未评估的 query 事件
  ↓
如果有待评估
  → 设置 trace.context["pending_knowledge_eval"] = true
  → 设置 trace.context["knowledge_eval_trigger"] = "goal_completion"
  ↓
Runner 主循环下一次迭代开头检测到标志（agent/core/runner.py:_agent_loop）
  → 清除标志
  → 将 "knowledge_eval" 加入 force_side_branch 队列
```

### 触发点 2：压缩

**时机**：上下文 token 数超过阈值，即将执行压缩

**触发逻辑**（`agent/core/runner.py:_manage_context_usage`）：

```
压缩条件触发
  ↓
查询 cognition_log 中未评估的 query 事件
  ↓
如果有待评估
  → 设置 trace.context["knowledge_eval_trigger"] = "compression"
  → 侧分支队列：["reflection", "knowledge_eval", "compression"]（启用知识提取时）
  →            或 ["knowledge_eval", "compression"]（未启用时）
  → 返回"需要进入侧分支"信号，暂缓压缩
```

压缩会删除消息历史，必须在压缩前完成评估。

### 触发点 3：任务结束（兜底）

**时机**：主路径无工具调用，Agent 即将结束

**触发逻辑**（`agent/core/runner.py:_agent_loop`）：

```
任务即将结束
  ↓
查询 cognition_log 中未评估的 query 事件
  ↓
如果有待评估
  → 设置 trace.context["knowledge_eval_trigger"] = "task_completion"
  → 将 ["knowledge_eval"] 加入 force_side_branch 队列
  → continue（不 break，下一轮执行评估）
```

---

## 侧分支评估流程

### 侧分支类型

复用 `SideBranchContext` 机制，类型 `"knowledge_eval"`（`agent/trace/models.py:Message.branch_type`）。

### 评估 Prompt 结构

完整实现：`agent/core/runner.py:_build_knowledge_eval_prompt`

```
你是知识评估助手。请评估以下知识查询结果在本次任务执行中的实际效果。

## 当前任务（Mission）       ← trace.task
## 当前 Goal                ← goal_tree.current 的 description
## 待评估知识查询            ← 未评估的 query 事件列表
  对每个 query：展示 query 文本、整合回答、各 source 的 id/task/content
## 评估要求                  ← 按 source_id 逐一评估
## 评估分类                  ← 5 个 status 选项
## 输出格式                  ← JSON
```

Prompt 中**不包含消息历史**。LLM 依据对话上下文中已有的执行过程作出判断。

### 评估输出格式

LLM 直接输出 JSON：

```json
{
  "evaluations": [
    {
      "query_sequence": 42,
      "assessments": [
        {"source_id": "knowledge-a1b2", "status": "helpful", "reason": "..."},
        {"source_id": "knowledge-c3d4", "status": "irrelevant", "reason": "..."}
      ]
    }
  ]
}
```

### 即时写入

每次 LLM 回复后立即解析，三种策略降级：整体 JSON → ` ```json ` 代码块 → 正则裸对象。

解析成功 → 为每个 query 写入对应的 `evaluation` 事件到 cognition_log。解析失败记日志，不中断。

---

## 数据流

```
知识查询（agent/trace/goal_tool.py:inject_knowledge_for_goal）
  ↓
POST /api/knowledge/ask → KM Agent 整合回答
  ↓
写入 cognition_log: type="query"（含 response + source_ids）
  ↓
  ┌─────────────────────────────────────────────┐
  │  触发点 A：Goal 完成（goal_completion）       │
  │  触发点 B：压缩执行前（compression）          │
  │  触发点 C：任务自然结束（task_completion）    │
  └─────────────────────────────────────────────┘
  ↓
Runner 进入 knowledge_eval 侧分支
  ↓
LLM 按 query 维度、逐 source 评估，输出 JSON
  ↓
写入 cognition_log: type="evaluation"（含 assessments per source）
  ↓
侧分支退出 → 恢复主路径

                    ···

知识提取（reflection 侧分支 LLM 调 knowledge_save_pending）
  ↓
写入 cognition_log: type="extraction_pending"
  ↓
  ┌─ reflect_auto_commit=True ─→ 侧分支退出 hook 自动 approve + commit
  │                              写 extraction_reviewed + extraction_committed
  │
  └─ reflect_auto_commit=False（默认）
     ↓
     人工 CLI / Interactive 菜单 / HTTP API 触发
     ↓
     review → 写 extraction_reviewed（approve/edit/discard）
     ↓
     commit → 调 knowledge_save → 写 extraction_committed

                    ···

Dream 触发（memory-bearing Agent，详见 agent/docs/memory.md）
  ↓
Phase 1: per_trace_reflect（逐 trace，reflected_at_sequence < last_sequence）
  ↓ 读取增量消息 + cognition_log 中 query/evaluation/extraction_* 事件
  ↓ 写入 cognition_log: type="reflection"（consumed_at 暂缺）
  ↓ 更新 Trace.reflected_at_sequence

Phase 2: cross_trace_integrate
  ↓ 汇总未消化的 reflection + 当前记忆文件
  ↓ LLM 输出 {updates:[{path,new_content}]} JSON 计划
  ↓ 写记忆文件 + 给参与的 reflection 补 consumed_at
```

---

## 与现有系统的集成点

| 集成位置 | 文件 | 说明 |
|---|---|---|
| 知识查询时写 log | `agent/trace/goal_tool.py:inject_knowledge_for_goal` | `goal(focus=...)` 触发 ask → 写入 `query` 事件 |
| Goal 完成时设置标志 | `agent/trace/store.py:update_goal` | 设置 `trace.context["pending_knowledge_eval"]` |
| 主循环检测标志 | `agent/core/runner.py:_agent_loop` | 每轮迭代开头检测，触发 `["knowledge_eval"]` |
| 压缩前触发评估 | `agent/core/runner.py:_manage_context_usage` | 压缩前检查 pending，先评估再压缩 |
| 任务结束兜底 | `agent/core/runner.py:_agent_loop` | 退出前检查 pending，强制触发评估 |
| 侧分支类型 | `agent/trace/models.py:Message.branch_type` | Literal 中包含 `"knowledge_eval"` |
| 即时写入评估 | `agent/core/runner.py:_agent_loop` | 解析 JSON 后调 `store.update_knowledge_evaluation` |
| 知识提取暂存 | `agent/tools/builtin/knowledge.py:knowledge_save_pending` | LLM 工具，写 `extraction_pending` 事件 |
| 提取审核 / 提交 | `agent/trace/extraction_review.py` | 写 `extraction_reviewed` / `extraction_committed` 事件 |
| 反思侧分支 auto-commit | `agent/core/runner.py`（反思分支退出分支） | `reflect_auto_commit=True` 时调 `auto_commit_branch` |
| 记忆反思写入 | `agent/core/dream.py:per_trace_reflect` | 写 `reflection` 事件（consumed_at 缺省） |
| Reflection 消化标记 | `agent/core/dream.py:cross_trace_integrate` | 整合后补 `consumed_at` |
| Log 文件格式 | `agent/trace/store.py` | ✅ 已从 entries[] 迁移到 events[]；读写兼容旧文件名 |

---

## 七、实现与入口

### 7.1 存储与访问

| 职责 | 位置 |
|---|---|
| Cognition log 文件位置 | `.trace/{trace_id}/cognition_log.json`（新建时文件名）；旧 trace 兼容读 `knowledge_log.json` |
| 读取 | `store.py:get_cognition_log`（两种文件名都认；`entries[]` 自动迁移为 `events[]`） |
| 追加 | `store.py:append_cognition_event`（接受任意 event type，自动补 `timestamp`） |
| 事件 schema 权威清单 | `store.py:append_cognition_event` 的 docstring |

### 7.2 各事件类型的写入与读取

| 事件类型 | 主要写入者 | 主要读取者 |
|---|---|---|
| `query` | `goal_tool.py:inject_knowledge_for_goal` | `_build_knowledge_eval_prompt` 找待评估；`dream.py:_build_reflect_input` 组装反思上下文 |
| `evaluation` | `store.py:update_knowledge_evaluation`（runner 解析 LLM JSON 后调用） | `dream.py:_build_reflect_input` |
| `extraction_pending` | `knowledge_save_pending` 工具 | `extraction_review.py:list_pending`；CLI / HTTP API 显示 |
| `extraction_reviewed` | `extraction_review.py:review_one` | `extraction_review.py:commit_approved`（决定要不要 commit） |
| `extraction_committed` | `extraction_review.py:commit_approved` | `list_pending`（标记 committed 状态） |
| `reflection` | `dream.py:per_trace_reflect` | `dream.py:cross_trace_integrate` |

### 7.3 相关文档

- **Memory 系统整体**：`agent/docs/memory.md` —— cognition_log 是其数据底座，Memory/Dream 设计与使用规范在那里
- **KnowHub 决策历史**：`knowhub/docs/decisions.md` —— 如果需要 knowledge_log → cognition_log 重构等历史决策的背景
