RAG 实战指南
RAG(Retrieval-Augmented Generation) 让你的 AI 基于私有文档回答问题,而不是依赖训练数据。
🎯 适用场景
| 场景 | 说明 | 案例 |
|---|---|---|
| 📚 企业知识库 | 员工手册、产品文档、FAQ | 客服自动回答 |
| 📝 个人笔记 | Obsidian/Notion 笔记检索 | 快速查找信息 |
| 📄 文档问答 | PDF/Word 文档内容检索 | 合同/报告分析 |
| 💻 代码库检索 | 项目文档、API 文档 | 开发者助手 |
📦 方案对比
方案 A:本地部署(推荐)
技术栈:
- 向量数据库:LanceDB / ChromaDB
- Embedding 模型:本地(embeddinggemma-300m)
- LLM:本地 Ollama 或云端
优点:
- ✅ 数据完全本地,隐私安全
- ✅ 零 API 成本
- ✅ 离线可用
缺点:
- ⚠️ 需要 2GB+ 内存
- ⚠️ 首次配置较复杂
适合:敏感数据、长期运行
方案 B:云端方案
技术栈:
- 向量数据库:Pinecone / Weaviate Cloud
- Embedding:OpenAI / Voyage
- LLM:云端 API
优点:
- ✅ 配置简单
- ✅ 性能稳定
- ✅ 免维护
缺点:
- ⚠️ 数据上传云端
- ⚠️ 持续 API 成本
适合:快速验证、非敏感数据
🛠️ 本地部署实战
第一步:安装依赖
bash
# 安装向量数据库
npm install -g @lancedb/lancedb
# 安装 Embedding 模型(如果还没有)
npm install -g node-llama-cpp --build-from-source第二步:准备文档
支持的格式:
- ✅ Markdown (.md)
- ✅ PDF (.pdf)
- ✅ Word (.docx)
- ✅ 纯文本 (.txt)
文档结构:
knowledge-base/
├── products/
│ ├── product-a.md
│ └── product-b.md
├── faq/
│ ├── general.md
│ └── technical.md
└── handbook/
└── employee.md第三步:创建索引脚本
bash
cat > index-docs.js << 'EOF'
const lancedb = require('@lancedb/lancedb');
const fs = require('fs');
const path = require('path');
async function indexDocuments() {
// 连接数据库
const db = await lancedb.connect('./knowledge-vector-db');
// 读取文档
const docs = [];
const files = fs.readdirSync('./knowledge-base');
for (const file of files) {
const content = fs.readFileSync(`./knowledge-base/${file}`, 'utf8');
docs.push({
id: file,
text: content,
source: file
});
}
// 创建向量表
const table = await db.createTable('documents', docs);
console.log(`✅ 已索引 ${docs.length} 个文档`);
}
indexDocuments();
EOF第四步:创建问答脚本
bash
cat > rag-query.js << 'EOF'
const lancedb = require('@lancedb/lancedb');
async function query(question) {
// 连接数据库
const db = await lancedb.connect('./knowledge-vector-db');
const table = await db.openTable('documents');
// 搜索相关文档
const results = await table
.search(question)
.limit(3)
.execute();
console.log('📚 相关文档:');
results.forEach((r, i) => {
console.log(`${i + 1}. ${r.source}`);
console.log(r.text.substring(0, 200) + '...\n');
});
// TODO: 将结果发送给 LLM 生成答案
}
// 使用示例
query('如何配置 OpenClaw?');
EOF第五步:运行
bash
# 索引文档
node index-docs.js
# 查询
node rag-query.js "如何配置 Telegram?"🔌 集成到 OpenClaw
方案 1:作为技能安装
bash
# 创建 RAG 技能目录
mkdir -p ~/.openclaw/workspace/skills/rag-knowledge
# 创建技能文件
cat > ~/.openclaw/workspace/skills/rag-knowledge/SKILL.md << 'EOF'
---
name: rag-knowledge
description: 基于本地知识库的问答技能
---
# RAG 知识问答
当用户询问文档内容时,使用此技能。
## 用法
```bash
node ~/.openclaw/workspace/skills/rag-knowledge/query.js "问题"EOF
### 方案 2:直接集成到对话
修改 `openclaw.json`:
```json
{
"agents": {
"defaults": {
"tools": {
"rag": {
"enabled": true,
"dbPath": "./knowledge-vector-db"
}
}
}
}
}📊 性能优化
1. 分块策略
问题:长文档直接索引效果差
方案:
javascript
// 按段落分块
function chunkDocument(text, chunkSize = 500) {
const paragraphs = text.split('\n\n');
const chunks = [];
let currentChunk = '';
for (const para of paragraphs) {
if (currentChunk.length + para.length > chunkSize) {
chunks.push(currentChunk);
currentChunk = para;
} else {
currentChunk += '\n\n' + para;
}
}
return chunks;
}2. 混合检索
方案:向量相似度 + 关键词匹配
javascript
const results = await table
.search(question)
.where('category = "technical"') // 过滤
.limit(5)
.execute();3. 缓存热门问题
javascript
const cache = new Map();
async function queryWithCache(question) {
if (cache.has(question)) {
return cache.get(question);
}
const answer = await query(question);
cache.set(question, answer);
return answer;
}🎯 最佳实践
文档准备
| 建议 | 说明 |
|---|---|
| ✅ 结构化 | 使用标题、列表等清晰结构 |
| ✅ 去重 | 避免重复内容影响检索 |
| ✅ 更新 | 定期重新索引最新文档 |
| ❌ 过长 | 单文档最好 <10MB |
检索优化
| 技巧 | 效果 |
|---|---|
| 分块大小 300-500 字 | 检索精度 +20% |
| 限制返回 3-5 条 | 减少 LLM 混淆 |
| 添加元数据过滤 | 准确率 +30% |
📚 相关资源
❓ 常见问题
Q: 支持中文吗?
A: 支持。使用中文 Embedding 模型:
bash
# 推荐模型
nomic-embed-text-v1.5 # 支持多语言Q: 需要多少内存?
A:
- 1000 文档:~500MB
- 10000 文档:~2GB
- 100000 文档:~8GB
Q: 可以实时更新吗?
A: 可以。LanceDB 支持增量更新:
javascript
await table.add([newDocument]);提示:先从少量文档开始测试,验证效果后再扩展。