# 知识管理系统

## 文档维护规范

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

---

## 架构

KnowHub Server 是统一的知识管理服务，包含两个子系统：

1. **Knowledge 系统**：结构化知识管理（任务场景 + 经验内容）
2. **Resource 系统**：原始资源存储（代码、凭证、Cookie等）→ 详见 `knowhub/docs/resource-storage.md`

```
Agent                           KnowHub Server
├── knowledge_search 工具   →   GET /api/knowledge/search
├── knowledge_save 工具     →   POST /api/knowledge
├── knowledge_update 工具   →   PUT /api/knowledge/{id}
├── goal focus 自动注入     →   GET /api/knowledge/search
└── resource 资源引用        →   GET /api/resource/{id}
```

### 存储架构

KnowHub 采用 Milvus Lite 单一存储架构（详见 `knowhub/docs/decisions.md#13`）：

```
┌─────────────────────────────────────────────────────┐
│                   KnowHub Server                     │
├─────────────────────────────────────────────────────┤
│                                                      │
│              ┌─────────────────────┐                │
│              │   Milvus Lite       │                │
│              │   (单一存储)         │                │
│              ├─────────────────────┤                │
│              │ knowledge 集合       │                │
│              │ - id                │                │
│              │ - embedding (向量)   │                │
│              │ - task/content      │                │
│              │ - types/tags/scopes │                │
│              │ - owner/eval/source │                │
│              │ - resource_ids      │                │
│              └─────────────────────┘                │
│                                                      │
│  检索流程：向量召回 → LLM 精排 → 返回 top k          │
└─────────────────────────────────────────────────────┘
```

**Milvus Lite**：
- 存储完整知识数据（所有字段）+ 向量
- 提供高效的语义向量检索
- 支持标量字段过滤和查询
- 本地文件存储，部署简单

实现位置：
- Milvus 封装：`knowhub/vector_store.py`
- Embedding 生成：`knowhub/embeddings.py`
- 检索逻辑：`knowhub/server.py:knowledge_search`

---

## 知识结构

单条知识的数据格式（基于 `agent/docs/knowledge.md` 定义）：

```json
{
  "id": "knowledge-20260305-a1b2",
  "message_id": "msg-xxx",
  "types": ["strategy", "tool"],
  "task": "在什么场景下要完成什么目标",
  "tags": {
    "category": "preference",
    "domain": "coding_style"
  },
  "scopes": ["org:cybertogether"],
  "owner": "agent:research_agent",
  "content": "核心知识内容",
  "resource_ids": ["code/selenium/login", "credentials/website_a"],
  "source": {
    "name": "资源名称",
    "category": "exp",
    "urls": ["https://example.com"],
    "agent_id": "research_agent",
    "submitted_by": "user@example.com",
    "timestamp": "2026-03-05T12:00:00Z",
    "message_id": "msg-xxx"
  },
  "eval": {
    "score": 4,
    "helpful": 5,
    "harmful": 0,
    "confidence": 0.9,
    "helpful_history": [],
    "harmful_history": []
  },
  "created_at": "2026-03-05T12:00:00Z",
  "updated_at": "2026-03-05T12:00:00Z"
}
```

### 字段说明

- **id**: 唯一标识，格式 `knowledge-{timestamp}-{random}`
- **message_id**: 来源 Message ID（用于精确溯源到具体消息）
- **types**: 知识类型数组（可多选）
  - `user_profile`: 特定用户的偏好、习惯、背景
  - `strategy`: 执行经验（从反思中获得）
  - `tool`: 工具使用方法、优缺点、代码示例
  - `usecase`: 用户背景、方案、步骤、效果
  - `definition`: 概念定义、技术原理、应用场景
  - `plan`: 流程步骤、决策点、方法论
- **task**: 任务描述，什么场景、在做什么
- **tags**: 业务标签（JSON 对象），如 `{"category": "preference", "domain": "coding_style"}`
- **scopes**: 可见范围数组，默认 `["user:owner"]`
- **owner**: 所有者，默认取用户的git email
- **content**: 核心知识内容
- **resource_ids**: 关联的资源 ID 列表（可选），引用 Resource 系统中的资源。每个资源可能包含公开内容（body）和敏感内容（secure_body）
- **source**: 来源信息（嵌套对象）
  - **name**: 资源名称
  - **category**: 来源类别（paper/exp/skill/book）
  - **urls**: 参考来源链接数组
  - **agent_id**: 创建者 agent ID
  - **submitted_by**: 提交者
  - **timestamp**: 创建时间戳
  - **message_id**: 可选，用于溯源
- **eval**: 评估信息（嵌套对象）
  - **score**: 评分 1-5
  - **helpful**: 好用次数
  - **harmful**: 不好用次数
  - **confidence**: 置信度 0-1
  - **helpful_history**: 好用案例历史
  - **harmful_history**: 不好用案例历史

---

## Agent 工具

Agent 通过以下工具与 KnowHub Server 交互。工具只是 API 调用的封装，核心逻辑在 Server 实现。

实现位置：`agent/tools/builtin/knowledge.py`

### `knowledge_search`

检索知识。

```python
@tool()
async def knowledge_search(
    query: str,
    top_k: int = 5,
    min_score: int = 3,
    types: Optional[List[str]] = None
) -> ToolResult
```

调用 `GET /api/knowledge/search?q={query}&top_k={top_k}&min_score={min_score}&types={types}`

### `knowledge_save`

保存新知识。

```python
@tool()
async def knowledge_save(
    task: str,
    content: str,
    types: List[str],
    tags: Optional[Dict[str, str]] = None,
    scopes: Optional[List[str]] = None,
    owner: Optional[str] = None,
    source_name: str = "",
    source_category: str = "exp",
    urls: List[str] = None,
    agent_id: str = "research_agent",
    submitted_by: str = "",
    score: int = 3,
    message_id: str = ""
) -> ToolResult
```

调用 `POST /api/knowledge`

**默认值**（在 agent 代码中设置）：
- `scopes`: `["org:cybertogether"]`
- `owner`: `f"agent:{agent_id}"`

### `knowledge_update`

更新已有知识的评估反馈。

```python
@tool()
async def knowledge_update(
    knowledge_id: str,
    add_helpful_case: Optional[Dict] = None,
    add_harmful_case: Optional[Dict] = None,
    update_score: Optional[int] = None,
    evolve_feedback: Optional[str] = None
) -> ToolResult
```

调用 `PUT /api/knowledge/{knowledge_id}`

**知识进化**：当提供 `evolve_feedback` 时，Server 使用 LLM 重写知识内容。

### `knowledge_batch_update`

批量反馈知识有效性。

```python
@tool()
async def knowledge_batch_update(
    feedback_list: List[Dict[str, Any]]
) -> ToolResult
```

调用 `POST /api/knowledge/batch_update`

### `knowledge_list`

列出已保存的知识。

```python
@tool()
async def knowledge_list(
    limit: int = 10,
    types: Optional[List[str]] = None,
    scopes: Optional[List[str]] = None
) -> ToolResult
```

调用 `GET /api/knowledge?limit={limit}&types={types}&scopes={scopes}`

### `knowledge_slim`

知识库瘦身，合并相似知识。

```python
@tool()
async def knowledge_slim(
    model: str = "google/gemini-2.0-flash-001"
) -> ToolResult
```

调用 `POST /api/knowledge/slim`

---

## Resource 引用机制

Knowledge 可以通过 `resource_id` 和 `secure_resource_id` 引用 Resource 系统中的原始资源。

### 使用场景

**场景 1：复杂代码工具**

当工具实现逻辑复杂（如 Selenium 绕过检测、复杂的 API 调用封装）时：
- 将代码片段保存为 Resource（`content_type=code`）
- Knowledge 记录使用场景和经验，通过 `resource_ids` 引用代码

```json
{
  "task": "使用 Selenium 登录某网站并绕过反爬检测",
  "content": "使用 undetected_chromedriver 可以绕过大部分检测。关键点：1) 设置合适的 user-agent 2) 随机延迟 3) 避免频繁请求",
  "types": ["tool", "strategy"],
  "resource_ids": ["code/selenium/undetected_login"]
}
```

对应的 Resource：
```json
{
  "id": "code/selenium/undetected_login",
  "title": "Selenium 绕过检测登录代码",
  "body": "import undetected_chromedriver as uc\n\ndriver = uc.Chrome()...",
  "content_type": "code",
  "metadata": {"language": "python"}
}
```

**场景 2：账号密码凭证**

当发现或配置了有用的工具账号时：
- 将敏感信息（账号、密码）保存为 Resource（`content_type=credential`，存入 `secure_body`）
- Knowledge 记录使用方法和注意事项，通过 `resource_ids` 引用凭证

```json
{
  "task": "登录某网站进行数据采集",
  "content": "使用测试账号登录，注意：1) 每天限额 100 次 2) 需要在工作时间访问 3) 登录后 session 有效期 2 小时",
  "types": ["tool", "usecase"],
  "resource_ids": ["credentials/website_a"]
}
```

对应的 Resource：
```json
{
  "id": "credentials/website_a",
  "title": "某网站测试账号",
  "body": "使用方法：直接登录即可，每天限额 100 次",
  "secure_body": "账号：user@example.com\n密码：SecurePass123",
  "content_type": "credential",
  "metadata": {"acquired_at": "2026-03-06T10:00:00Z"}
}
```

**场景 3：Cookie 和登录态**

当获取了有效的 Cookie 时：
- 将 Cookie 保存为 Resource（`content_type=cookie`，存入 `secure_body`，设置 `expires_at`）
- Knowledge 记录获取方法和使用场景，通过 `resource_ids` 引用

```json
{
  "task": "使用已登录的 Cookie 访问某网站 API",
  "content": "Cookie 获取方法：手动登录后从浏览器导出。使用时直接设置到请求头。注意检查过期时间。",
  "types": ["tool"],
  "resource_ids": ["cookies/website_a"]
}
```

对应的 Resource：
```json
{
  "id": "cookies/website_a",
  "title": "某网站 Cookie",
  "body": "适用于：已登录状态的 API 调用",
  "secure_body": "session_id=abc123; auth_token=xyz789",
  "content_type": "cookie",
  "metadata": {
    "acquired_at": "2026-03-06T10:00:00Z",
    "expires_at": "2026-03-07T10:00:00Z"
  }
}
```

**场景 4：多资源引用**

一个知识可以同时引用多个资源（如代码 + 凭证）：

```json
{
  "task": "使用 Selenium 登录某网站",
  "content": "使用 undetected_chromedriver 绕过检测，配合测试账号登录",
  "types": ["tool", "usecase"],
  "resource_ids": ["code/selenium/undetected_login", "credentials/website_a"]
}
```

### 提交流程

1. **识别需要提取的 Resource**：在知识反思时，识别复杂代码、凭证、Cookie 等
2. **调用 `resource_save` 工具**：提交 Resource 到 KnowHub
3. **调用 `knowledge_save` 工具**：保存 Knowledge 并关联 Resource ID

实现位置：
- Resource 提交工具：`agent/tools/builtin/knowledge.py:resource_save`
- Knowledge 保存工具：`agent/tools/builtin/knowledge.py:knowledge_save`
- 知识反思 prompt：`agent/core/prompts/knowledge.py:KNOWLEDGE_EXTRACTION_PROMPT`

---

## 知识注入机制

知识注入在 goal focus 时自动触发。

实现位置：`agent/trace/goal_tool.py:focus_goal`

### 注入流程

```python
# 1. LLM 调用 goal 工具
goal(action="focus", goal_id="goal-123")

# 2. goal 工具内部自动执行
current_goal = goal_tree.find("goal-123")
knowledge_results = await knowledge_search(
    query=current_goal.description,
    top_k=3,
    min_score=3
)

# 3. 保存到 goal 对象
current_goal.knowledge = knowledge_results.metadata["items"]

# 4. 持久化到 trace store
await trace_store.update_goal_tree(trace_id, goal_tree)

# 5. 返回给 LLM
return ToolResult(
    title="✅ Goal 已聚焦",
    output=f"当前 Goal: {current_goal.description}\n\n📚 相关知识 ({len(knowledge_results)} 条):\n..."
)
```

### 知识展示

注入的知识会显示在 GoalTree 的「📚 相关知识」部分。

---

## 调研决策

调研决策与知识注入分离，通过 system prompt 引导。

### 决策流程

```
1. goal focus → 自动注入知识
   ↓
2. LLM 看到 GoalTree 中的「📚 相关知识」
   ↓
3. LLM 自主判断：
   ├─ 知识充足 → 直接制定计划
   └─ 知识不足 → 调用 agent 工具启动调研子任务
```

### System Prompt 引导

```markdown
## 知识管理

当你使用 `goal(action="focus")` 聚焦到某个 goal 时，系统会自动检索相关知识并显示在 GoalTree 的「📚 相关知识」部分。

根据知识充足性判断：

**知识充足**：
- 如果相关知识足以完成任务，直接制定计划
- 使用 `goal` 工具创建执行计划的子 goal

**知识不足**：
- 如果相关知识不足，需要进行调研
- 调用 `agent` 工具启动调研子任务
- 调研完成后，使用 `knowledge_save` 保存结果

调研完成后，再次 focus 该 goal，新保存的知识会被自动注入。
```

### 调研 Skill

调研指南存储在 `agent/skill/skills/research.md`。

---

## KnowHub Server API

### `GET /api/knowledge/search`

检索知识。使用向量召回 + LLM 精排策略。

**参数**：
- `q`: 查询文本
- `top_k`: 返回数量（默认 5）
- `min_score`: 最低评分过滤（默认 3）
- `types`: 按类型过滤（可选，逗号分隔）
- `owner`: 按所有者过滤（可选，支持多个owner用逗号分隔，如 "user1@example.com,user2@example.com"）

**检索流程**：

1. **向量召回**（快速、便宜）
   - 生成查询向量（使用 OpenAI text-embedding-3-small 或本地模型）
   - Milvus Lite 检索语义相似的知识，召回 `top_k * 3` 个候选
   - 支持标量过滤（types、owner、scopes、min_score）

2. **LLM 精排**（准确、贵）
   - 使用 LLM（gemini-2.5-flash-lite）对候选重新排序
   - 根据查询意图和知识内容，选出最相关的 `top_k` 条
   - 输出按相关性从高到低排序

3. **Fallback**（保证可用性）
   - 如果 LLM 精排失败或超时，直接返回向量召回的 `top_k` 结果
   - 保证检索始终可用

实现位置：
- `knowhub/server.py:knowledge_search` - 主检索逻辑
- `knowhub/server.py:llm_rerank` - LLM 精排

**响应**：

```json
{
  "results": [
    {
      "id": "knowledge-xxx",
      "task": "...",
      "content": "...",
      "types": ["strategy", "tool"],
      "tags": {"category": "preference"},
      "eval": {
        "score": 4,
        "helpful": 2,
        "harmful": 0,
        "confidence": 0.9
      }
    }
  ],
  "count": 3,
  "reranked": true
}
```

### `POST /api/knowledge`

保存新知识。

**请求体**：

```json
{
  "task": "在什么场景下要完成什么目标",
  "content": "核心知识内容",
  "types": ["tool", "strategy"],
  "tags": {"category": "preference", "domain": "coding_style"},
  "scopes": ["org:cybertogether"],
  "owner": "agent:research_agent",
  "source": {
    "name": "资源名称",
    "category": "exp",
    "urls": ["https://example.com"],
    "agent_id": "research_agent",
    "submitted_by": "user@example.com",
    "message_id": "msg-xxx"
  },
  "score": 4
}
```

实现位置：`knowhub/server.py:save_knowledge`

### `PUT /api/knowledge/{id}`

更新知识。

**请求体**：

```json
{
  "add_helpful_case": {
    "task": "任务描述",
    "outcome": "成功",
    "timestamp": "2026-03-05T12:00:00Z"
  },
  "add_harmful_case": {
    "task": "任务描述",
    "outcome": "失败",
    "reason": "原因",
    "timestamp": "2026-03-05T12:00:00Z"
  },
  "update_score": 4,
  "evolve_feedback": "改进建议（触发知识进化）"
}
```

**知识进化**：当提供 `evolve_feedback` 时，Server 使用 LLM 重写知识内容。

实现位置：`knowhub/server.py:update_knowledge`

### `POST /api/knowledge/batch_update`

批量反馈知识有效性。

**请求体**：

```json
{
  "feedback_list": [
    {
      "knowledge_id": "knowledge-xxx",
      "is_helpful": true,
      "case": {
        "task": "任务描述",
        "outcome": "成功",
        "timestamp": "2026-03-05T12:00:00Z"
      }
    }
  ]
}
```

实现位置：`knowhub/server.py:batch_update_knowledge`

### `GET /api/knowledge`

列出知识。

**参数**：
- `limit`: 返回数量（默认 10）
- `types`: 按类型过滤（可选，逗号分隔）
- `scopes`: 按可见范围过滤（可选，逗号分隔）

实现位置：`knowhub/server.py:list_knowledge`

### `POST /api/knowledge/slim`

知识库瘦身，合并相似知识。

**请求体**：

```json
{
  "model": "google/gemini-2.0-flash-001"
}
```

实现位置：`knowhub/server.py:slim_knowledge`

---

## 实现位置

| 组件 | 实现位置 |
|------|---------|
| KnowHub Server | `knowhub/server.py` |
| Agent 工具 | `agent/tools/builtin/knowledge.py` |
| goal 工具（知识注入） | `agent/trace/goal_tool.py:focus_goal` |
| 调研 skill | `agent/skill/skills/research.md` |

---

## 设计原则

1. **统一服务**：KnowHub Server 是唯一的知识存储和管理服务
2. **Server 端逻辑**：检索、进化等核心逻辑在 Server 实现，Agent 工具只是 API 封装
3. **自动注入**：知识注入在 goal focus 时自动触发
4. **分离关注点**：知识注入（自动）与调研决策（显式）分离
5. **工具自治**：知识注入逻辑在 goal 工具中，不在 runner 中
6. **精确溯源**：使用 message_id 而非 trace_id，可精确定位到具体消息
7. **质量保证**：两阶段检索（语义路由 + 质量精排）确保准确性
