第 20 期:知识库运维 — 增量更新、过期清理与检索质量监控
RAG 不是一次性工程
很多团队在建好 RAG 后就"放任不管"。但知识库与代码一样,需要持续维护。
graph TB
subgraph "RAG 运维闭环"
Index["📥 索引 (Ep 17)"] --> Retrieve["🔍 检索 (Ep 18)"]
Retrieve --> Optimize["⚡ 优化 (Ep 19)"]
Optimize --> Monitor["📊 监控质量"]
Monitor --> Update["🔄 增量更新"]
Update --> Clean["🗑️ 过期清理"]
Clean --> Index
end
style Monitor fill:#f59e0b,stroke:#d97706,color:#fff
style Update fill:#22c55e,stroke:#16a34a,color:#fff1. 增量更新管道
graph TB
Schedule[⏰ Schedule Trigger
每天凌晨 3:00] --> Scan[📂 扫描文档目录]
Scan --> Query[查询 Data Table
'已索引文件列表']
Query --> Compare{新增/修改文件?}
Compare -->|"有新文件"| NewPipe["📄 提取 → ✂️ 分块 → 🧮 嵌入
→ 💾 写入 Qdrant"]
Compare -->|"文件已修改"| UpdatePipe["🗑️ 删除旧向量
→ 重新索引"]
Compare -->|"无变化"| Skip[⏭️ 跳过]
NewPipe --> Record["📝 更新 Data Table
记录文件名 + hash + 时间"]
UpdatePipe --> Record
style Schedule fill:#6366f1,stroke:#4f46e5,color:#fff// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 增量更新核心逻辑 (Code 节点)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
const currentFiles = $input.all(); // 目录中的所有文件
const indexedFiles = $('Data Table').all(); // 已索引的文件记录
const newFiles = [];
const updatedFiles = [];
for (const file of currentFiles) {
const record = indexedFiles.find(r =>
r.json.fileName === file.json.fileName
);
if (!record) {
newFiles.push(file); // 新增文件: 全量索引
} else if (record.json.fileHash !== file.json.fileHash) {
updatedFiles.push(file); // 已修改: 删旧 + 重建
}
// else: 文件未变化, 跳过
}
return [
...newFiles.map(f => ({ json: { ...f.json, action: 'insert' } })),
...updatedFiles.map(f => ({ json: { ...f.json, action: 'update' } }))
];
2. 过期文档清理
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 清理策略: 删除 90 天前索引的文档向量
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 在 Code 节点中调用 Qdrant API 删除过期数据:
const ninetyDaysAgo = $now.minus({ days: 90 }).toISO();
const response = await fetch('http://qdrant:6333/collections/knowledge-base/points/delete', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
filter: {
must: [{
key: "metadata.indexedAt",
range: {
lt: ninetyDaysAgo // 索引时间 < 90 天前
}
}]
}
})
});
// 同步清理 Data Table 中对应的记录
// → 确保索引记录与实际向量数据一致
3. 检索质量监控
graph TB
subgraph "质量监控工作流"
Test[📋 测试问答对
20 组标准 Q&A] --> Loop[Loop Over Items]
Loop --> Search[🔍 执行 RAG 检索]
Search --> Compare["🧠 LLM Judge
评分: 1-5 分"]
Compare --> Record[📊 记录到 Data Table]
Record --> Loop
Loop -->|完成| Report[📈 生成质量报告]
Report --> Alert{平均分 < 3?}
Alert -->|"是"| Slack[🚨 Slack 告警]
Alert -->|"否"| Log[✅ 记录日志]
end
style Compare fill:#8b5cf6,stroke:#7c3aed,color:#fff
style Alert fill:#f59e0b,stroke:#d97706// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// LLM-as-Judge 评分 Prompt
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
const judgePrompt = `
你是一个 RAG 质量评估专家。请对以下检索结果进行评分。
## 标准问题
${testQuestion}
## 标准答案
${expectedAnswer}
## RAG 实际回答
${ragAnswer}
## 评分维度 (每项 1-5 分)
1. 事实准确性: RAG 回答的内容是否与标准答案一致?
2. 完整性: 是否覆盖了标准答案的所有关键点?
3. 无幻觉: 是否存在编造的、标准答案中没有的信息?
请以 JSON 格式输出:
{"accuracy": N, "completeness": N, "no_hallucination": N, "comment": "..."}
`;
4. 幻觉检测工作流
graph TB
RAGAnswer[🤖 RAG Agent 回答] --> Extract[提取 Agent 引用的事实声明]
Extract --> Verify["🔍 逐条验证
在 Qdrant 中搜索每条声明"]
Verify --> Check{声明是否有文档支撑?}
Check -->|"✅ 有支撑"| Safe[标记: 可信]
Check -->|"❌ 无支撑"| Flag["⚠️ 标记: 可能幻觉"]
Flag --> Notify["📧 通知管理员审核"]
style Flag fill:#ef4444,stroke:#dc2626,color:#fff模块四总结
mindmap
root((模块四: 企业级 RAG))
Ep 16 RAG 原理
Embedding 机制
分块策略
向量数据库选型
Ep 17 索引管道
Qdrant Docker 部署
文档加载 → 分块 → 嵌入 → 存储
元数据标记
Ep 18 RAG Agent
Vector Store Tool
检索 + 生成时序
System Prompt for RAG
Ep 19 高级优化
Hybrid Search
Re-Ranking
Multi-Query
Ep 20 知识库运维
增量更新管道
过期清理
质量监控 + 幻觉检测下一步
模块五将进入 MCP (Model Context Protocol) 生态系统——学习如何通过标准化协议让 Agent 连接任何外部服务,打开"无限工具箱"。