14 KiB
14 KiB
OpenCode RAG 插件设计文档
本文档详细说明了 ocrag 项目的设计目的、技术选型考量、架构构思和实现细节。
1. 设计背景与目标
1.1 问题背景
在大型代码库中进行 AI 辅助开发时,AI 需要理解项目中的大量代码才能给出准确的建议和答案。然而:
- 上下文窗口有限:无法将整个代码库放入 AI 提示词
- 实时性需求:开发者需要 AI 能立即理解刚编写的代码
- 本地化优先:代码不应该上传到外部服务器
1.2 设计目标
为 OpenCode 构建一个本地代码知识库 RAG 系统,实现:
| 功能 | 描述 |
|---|---|
| 实时添加 | 将代码文件或目录添加到本地知识库 |
| 语义搜索 | 通过自然语言查询获取相关代码片段 |
| 智能管理 | 支持删除和列出知识库中的条目 |
1.3 设计原则
- 本地化优先:所有数据和计算都在本地完成,不依赖外部服务
- 轻量高效:避免引入复杂的服务端组件,保持极低的延迟
- 零运维:嵌入式数据库,无需安装配置,即装即用
- AI 友好:生成可被 AI 直接理解和使用的上下文
2. 技术选型详解
2.1 为什么选择 Python
| 考量因素 | Python | Rust |
|---|---|---|
| 开发效率 | ✅ 高 | ⚠️ 中 |
| LLM 生成质量 | ✅ 高(AI 更熟悉 Python) | ⚠️ 中 |
| 生态丰富度 | ✅ 成熟 | ⚠️ 一般 |
| 运行时性能 | ⚠️ 中(可通过 C 扩展优化) | ✅ 高 |
| 社区支持 | ✅ 丰富 | ⚠️ 有限 |
结论:Python 的高开发效率和 AI 生成质量优势明显,即使运行时性能略低,但对于 RAG 这种 I/O 密集型应用影响有限。
2.2 为什么选择 LanceDB
传统向量数据库对比:
| 数据库 | 特点 | 缺点 |
|---|---|---|
| Chroma | 简单易用 | 不支持持久化、不适合生产 |
| Milvus | 功能强大 | 需要 Docker 部署 |
| Qdrant | Rust 实现,高性能 | 需要单独部署 |
| LanceDB | 嵌入式、零运维、Python 原生 | 相对较新 |
LanceDB 优势:
- 嵌入式:数据库就是一个文件夹,无需单独服务
- 零运维:安装即用,自动管理
- Python 优先:原生 Python SDK,类型提示完善
- 性能优秀:基于 Apache Arrow,查询速度快
2.3 为什么选择 langchain-text-splitters(而非 chonkie)
最初设计考虑使用 chonkie 实现语法感知分块,但经过实践发现:
| 方案 | 优势 | 劣势 |
|---|---|---|
| chonkie | 语法感知分块 | 需要额外下载 GPT-2 tokenizer,初始化慢 |
| langchain-text-splitters | 无需额外模型、纯规则、速度快 | 非语法感知 |
最终选择 langchain-text-splitters:
- 对于 RAG 场景,分块精度不是最关键因素
- langchain 的方案更加轻量,启动更快
- 代码按自然段落(函数、类)边界切分,效果足够好
2.4 为什么使用 Qwen3-Embedding-0.6B
| 模型 | 维度 | 优势 | 劣势 |
|---|---|---|---|
| all-MiniLM-L6-v2 | 384 | 快速、小巧 | 英文为主 |
| Qwen3-Embedding-0.6B | 1024 | 中文优化、中英双语 | 较大、首次加载慢 |
选择理由:
- 开源可本地部署,代码安全
- 中文支持优秀
- 适合代码+文档混合场景
2.5 为什么不用 MCP 服务器
MCP 方案的劣势:
- 需要额外部署 MCP 服务器
- 增加系统复杂度
- 调试困难
CLI 方案的优势:
- 零额外组件
- 通过
bash工具直接调用 - 易于调试和扩展
3. 架构设计
3.1 整体架构
┌─────────────────────────────────────────────────────────────────┐
│ OpenCode AI │
└────────────────────────────┬──────────────────────────────────┘
│ 1. rag_add / rag_search
▼
┌─────────────────────────────────────────────────────────────────┐
│ TypeScript Plugin (ocrag-plugin.ts) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
│ │ rag_add │ │rag_search│ │ Skill 指令 │ │
│ └────┬─────┘ └────┬─────┘ └──────────────┘ │
└───────┼─────────────────┼───────────────────────────────────────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ Python CLI (ocrag) │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────┐ │
│ │ add │ │ search │ │ remove │ │ list │ │
│ └───┬─────┘ └────┬─────┘ └───┬─────┘ └──────┬──────┘ │
└──────┼───────────────┼─────────────┼──────────────────┼──────────┘
│ │ │ │
▼ ▼ ▼ │
┌─────────────────────────────────────────┐ │
│ Processing Pipeline │ │
│ │ │
│ ┌────────────┐ ┌────────────────┐ │ │
│ │ Chunker │───▶│ Embedder │──┼────────────┤
│ │ (分块) │ │ (向量化) │ │ │
│ └────────────┘ └────────────────┘ │ │
└─────────────────────────────────────────┼────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ LanceDB (向量数据库) │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ documents 表 │ │
│ │ ┌──────────┬──────────────────────┬──────────────────┐ │ │
│ │ │ text │ vector │ metadata │ │ │
│ │ │ (文本) │ (1024维向量) │ (JSON元数据) │ │ │
│ │ └──────────┴──────────────────────┴──────────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
3.2 数据流设计
添加文件流程
用户请求 → Plugin → CLI:add → Chunker → Embedder → LanceDB → 返回结果
详细步骤:
- 文件收集:递归遍历目录或单个文件
- 内容读取:以 UTF-8 编码读取文件内容
- 代码分块:按语言和语法结构切分代码
- 向量化:使用 Embedder 将文本转为 1024 维向量
- 存储入库:将文本、向量、元数据存入 LanceDB
搜索流程
用户查询 → Plugin → CLI:search → Embedder → LanceDB → 返回结果
详细步骤:
- 查询向量化:将自然语言查询转为向量
- 相似度搜索:LanceDB 执行向量相似度检索
- 结果排序:按相似度距离排序
- 元数据提取:解析 JSON 元数据
- 结果返回:格式化的代码片段列表
3.3 模块职责划分
| 模块 | 职责 | 依赖 |
|---|---|---|
cli.py |
命令行入口,参数解析 | click |
chunker.py |
代码分块处理 | langchain-text-splitters |
embedder.py |
文本向量化 | sentence-transformers |
db.py |
向量数据库操作 | lancedb, pyarrow |
commands/*.py |
各命令实现 | cli, chunker, embedder, db |
utils.py |
工具函数 | - |
4. 核心算法设计
4.1 代码分块算法
设计思路:按代码的语义结构进行分块
# Python 语言的分隔符优先级
separators = [
"\n\nclass ", # 类定义
"\n\ndef ", # 函数定义
"\n\nasync def ", # 异步函数
"\n\n", # 空行段落
"\n", # 换行
" ", # 空格
"" # 字符
]
分块参数:
chunk_size=2000:每块约 2000 字符chunk_overlap=200:块之间保留 200 字符重叠,保证上下文连贯
4.2 向量化策略
模型选择:Qwen3-Embedding-0.6B
- 输出维度:1024
- 向量归一化:L2 归一化,便于余弦相似度计算
批量处理:
- 一次性对多个文本块进行编码
- 利用 GPU/CPU 的批处理能力提升吞吐量
4.3 搜索策略
相似度度量:LanceDB 默认使用余弦相似度
top_k 参数:控制返回结果数量,默认 5 条
5. 安全与性能考量
5.1 安全性设计
| 风险点 | 防护措施 |
|---|---|
| SQL 注入 | 使用 Pandas 过滤而非 SQL 字符串拼接 |
| 路径遍历 | 仅处理指定路径,不执行动态导入 |
| 数据泄露 | 所有数据本地存储,不涉及网络传输 |
5.2 性能优化
已实现:
- ✅ 批量 embedding 减少 I/O 开销
- ✅ 单例模式避免重复加载模型
- ✅ 向量归一化加速相似度计算
可优化项:
- 文件哈希缓存避免重复添加
- GPU 加速 embedding 计算
- 增量索引更新而非全量重建
5.3 性能基准
| 指标 | 实测结果 | 说明 |
|---|---|---|
| 搜索延迟 | 63-70 ms | 包含 embedding + 向量检索 |
| 数据库写入 | 2-3 ms/块 | LanceDB 性能优秀 |
| 分块速度 | <1 ms | 纯规则,无模型加载 |
| Embedding | ~2.5秒/块 | Qwen3 模型较大 |
6. 扩展性设计
6.1 多语言支持
只需在 LANGUAGE_MAP 中添加新扩展名即可:
LANGUAGE_MAP = {
".py": "python",
".js": "javascript",
# 添加新语言...
".kt": "kotlin",
".swift": "swift",
}
6.2 自定义 Embedding 模型
修改 embedder.py 中的模型路径:
model_path = "path/to/your/model"
6.3 增量同步(Watch 模式)
使用 watchdog 库监听文件变化,自动更新知识库:
observer = Observer()
observer.schedule(RAGSyncHandler(), path, recursive=True)
observer.start()
7. 与 OpenCode 的集成
7.1 插件架构
OpenCode
├── TypeScript Plugin
│ ├── rag_add 工具
│ └── rag_search 工具
│
└── Skill 指令
└── SKILL.md
7.2 工具定义
| 工具名 | 参数 | 功能 |
|---|---|---|
rag_add |
paths: string[], recursive?: boolean |
添加文件到知识库 |
rag_search |
query: string, top_k?: number |
搜索知识库 |
7.3 错误处理
所有工具调用都包裹在 try-catch 中:
execute: async (args) => {
try {
const result = await Bun.$`${cmd}`.text();
return result;
} catch (error) {
return `Error: ${error.message}`;
}
}
8. 设计总结
8.1 核心创新
- 零 MCP 架构:通过 CLI 直接集成,简化系统复杂度
- 本地化优先:数据不出本地,保证代码安全
- 轻量高效:嵌入式数据库,秒级启动
- AI 原生:输出格式专为 AI 消费设计
8.2 适用场景
| 场景 | 适用性 | 说明 |
|---|---|---|
| 个人项目知识管理 | ✅ 非常适合 | 本地存储,隐私安全 |
| 小团队代码库问答 | ✅ 适合 | 轻量易部署 |
| 大型企业代码库 | ⚠️ 需优化 | 可能需要分布式扩展 |
| 跨语言代码库 | ✅ 支持 | 多语言分块支持 |
8.3 未来展望
- 语义分块升级:集成更智能的分块算法
- 多模态支持:支持图片、图表等非文本内容
- 增量索引:支持大型代码库的实时更新
- 分布式部署:支持多节点协同检索
附录:术语表
| 术语 | 解释 |
|---|---|
| RAG | Retrieval-Augmented Generation,检索增强生成 |
| Embedding | 将文本转为向量的过程 |
| 向量数据库 | 专门存储和检索向量的数据库 |
| Chunk | 分块后的文本片段 |
| LanceDB | 嵌入式向量数据库 |
文档版本:1.0
最后更新:2026年4月15日