Add global knowledge base with RAG search
- KB module: fastembed (AllMiniLML6V2) for CPU embedding, SQLite for vector storage with brute-force cosine similarity search - Chunking by ## headings, embeddings stored as BLOB in kb_chunks table - API: GET/PUT /api/kb for full-text read/write with auto re-indexing - Agent tools: kb_search (top-5 semantic search) and kb_read (full text) available in both planning and execution phases - Frontend: Settings menu in sidebar footer, KB editor as independent view with markdown textarea and save button - Also: extract shared db_err/ApiResult to api/mod.rs, add context management design doc Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
54
doc/context.md
Normal file
54
doc/context.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Context 管理现状与设计
|
||||
|
||||
## 现状
|
||||
|
||||
当前没有做 context 长度限制,存在超过 model token limit 的风险。
|
||||
|
||||
### 已有的缓解机制
|
||||
|
||||
1. **Phase transition 时 clear**:`step_messages` 在 planning→executing 和 step→step 切换时会 `clear()`,避免跨阶段累积
|
||||
2. **单条 tool output 截断**:bash 输出限制 8000 bytes,read_file 超长时也截断
|
||||
3. **Step context 摘要**:已完成步骤只保留 summary(`step_summaries`),不带完整输出
|
||||
|
||||
### 风险场景
|
||||
|
||||
- 一个 execution step 内 tool call 轮次过多(反复 bash、read_file),`step_messages` 无限增长
|
||||
- 每轮 LLM 的 assistant message + tool result 都 push 进 `step_messages`,没有上限
|
||||
- 最终整个 messages 数组超过模型 context window
|
||||
|
||||
## 方案设计
|
||||
|
||||
### 策略:滑动窗口 + 早期消息摘要
|
||||
|
||||
当 `step_messages` 长度超过阈值时,保留最近 N 轮完整对话,早期的 tool call/result 对折叠为一条摘要消息。
|
||||
|
||||
```
|
||||
[system prompt]
|
||||
[user: step context]
|
||||
[summary of early tool interactions] ← 压缩后的历史
|
||||
[recent assistant + tool messages] ← 完整保留最近 N 轮
|
||||
```
|
||||
|
||||
### 具体实现
|
||||
|
||||
1. **Token 估算**:用字符数粗估(1 token ≈ 3-4 chars 中英混合),不需要精确 tokenizer
|
||||
2. **阈值**:可配置,默认如 80000 chars(约 20k-25k tokens),给 system prompt 和 response 留余量
|
||||
3. **压缩触发**:每次构建 messages 时检查总长度,超过阈值则压缩
|
||||
4. **压缩方式**:
|
||||
- 简单版:直接丢弃早期 tool call/result 对,替换为 `[已执行 N 次工具调用,最近结果见下文]`
|
||||
- 进阶版:用 LLM 生成摘要(额外一次 API 调用,但质量更好)
|
||||
5. **不压缩的部分**:system prompt、user context、最近 2-3 轮完整交互
|
||||
|
||||
### 实现位置
|
||||
|
||||
在 `run_agent_loop` 中构建 messages 之后、调用 LLM 之前,插入压缩逻辑:
|
||||
|
||||
```rust
|
||||
// agent.rs run_agent_loop 内,约 L706-L725
|
||||
let (mut messages, tools) = match &state.phase { ... };
|
||||
|
||||
// 压缩 context
|
||||
compact_messages(&mut messages, MAX_CONTEXT_CHARS);
|
||||
```
|
||||
|
||||
`compact_messages` 函数:从前往后扫描,保留 system/user 头部,计算总长度,超限时将早期 assistant+tool 消息替换为摘要。
|
||||
42
doc/kb.md
Normal file
42
doc/kb.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# 知识库 (KB / RAG)
|
||||
|
||||
## 概述
|
||||
|
||||
全局知识库,所有 project 的 agent 共享。用户在前端用 markdown 编辑,保存时自动切块并索引。Agent 通过 `kb_search` 和 `kb_read` 工具查询。
|
||||
|
||||
## 数据流
|
||||
|
||||
```
|
||||
用户编辑 markdown textarea
|
||||
→ PUT /api/kb
|
||||
→ 原文存 SQLite (kb_content 表,单行)
|
||||
→ 按 ## heading 切块
|
||||
→ fastembed (AllMiniLML6V2) 生成 embedding
|
||||
→ chunk + embedding 存 SQLite (kb_chunks 表)
|
||||
```
|
||||
|
||||
## 切块策略
|
||||
|
||||
按 markdown `##` heading 切分,每个 section 作为一个 chunk。无 heading 的开头部分作为一个 chunk。
|
||||
|
||||
## Agent 工具
|
||||
|
||||
- `kb_search(query: str)` → 向量搜索 top-5,返回相关片段
|
||||
- `kb_read()` → 返回 KB 全文
|
||||
|
||||
## API
|
||||
|
||||
- `GET /api/kb` → 返回 KB 全文 `{ content: string }`
|
||||
- `PUT /api/kb` → 保存全文 + 重新切块索引 `{ content: string }`
|
||||
|
||||
## 技术选型
|
||||
|
||||
- **向量存储**: SQLite (embedding 存为 BLOB,暴力余弦搜索)
|
||||
- **Embedding**: fastembed-rs (AllMiniLML6V2, 384 dim, CPU)
|
||||
- **原文存储**: SQLite (kb_content 表)
|
||||
|
||||
## 前端
|
||||
|
||||
- Sidebar 底部 Settings 弹出菜单 → Knowledge Base
|
||||
- 点击切换到 KB 编辑独立 view(与 project view 平级)
|
||||
- 大 textarea + Save 按钮
|
||||
@@ -9,10 +9,3 @@ template
|
||||
---
|
||||
时间观察app
|
||||
---
|
||||
|
||||
## 代码啰嗦/可精简
|
||||
|
||||
- **agent.rs**:`NewRequirement` 与 `Comment` 分支里「设 final_status → 更新 DB status → broadcast WorkflowStatusUpdate → 查 all_steps → generate_report → 更新 report → broadcast ReportReady」几乎相同,可抽成共用函数(如 `finish_workflow_and_report`);venv 创建/检查(create_dir_all + .venv 存在 + uv venv)两处重复,可抽成 helper。
|
||||
- **api/**:`projects.rs`、`workflows.rs`、`timers.rs` 里 `db_err` 与 `ApiResult<T>` 定义重复,可提到 `api/mod.rs` 或公共模块。
|
||||
- **WorkflowView.vue**:`handleWsMessage` 里多处 `workflow.value && msg.workflow_id === workflow.value.id`,可先取 `const wf = workflow.value` 并统一判断;`ReportReady` 分支里 `workflow.value = { ...workflow.value, status: workflow.value.status }` 无实际效果,可删或改成真正刷新。
|
||||
- **PlanSection.vue / ExecutionSection.vue**:都有 `expandedSteps`(Set)、`toggleStep`、以及 status→icon/label 的映射,可考虑抽成 composable 或共享 util 减少重复。
|
||||
Reference in New Issue
Block a user