核心理论知识
在线查询阶段(Online Phase)流程
用户提问 → Top-K 检索 → Prompt 设计 → Token 控制 → LLM 生成 → 回答
关键步骤:
- Top-K 检索:从向量数据库召回最相关的 K 个文档片段
- Prompt 设计:将检索结果与问题组合成合适的提示词
- Token 控制:管理上下文窗口,优化成本和性能
- LLM 生成:基于上下文生成精准答案
Token 预算控制(重点!)
为什么要控制 Token 预算?
| 原因 | 说明 |
|---|---|
| 模型限制 | 所有 LLM 都有上下文窗口上限(如 GPT-4: 128K tokens) |
| 成本控制 | API 按 token 收费,过多 token = 高昂成本 |
| 性能优化 | Token 越多 = 响应越慢 |
| 回答质量 | 过多无关信息会分散注意力,降低质量 |
Token 预算分配公式
\text{max\_tokens} = \text{检索到的知识} + \text{用户问题} + \text{LLM 回答}
示例分配(max_tokens=3000):
- 检索到的知识:~2000 tokens(70%)
- 用户问题:~200 tokens
- LLM 回答:~800 tokens(30%)
实际代码实现
class RAGSystem:
def __init__(self, max_tokens=3000):
self.max_tokens = max_tokens
self.context_budget = int(max_tokens * 0.7) # 70% 给检索内容
self.response_budget = int(max_tokens * 0.3) # 30% 给回答
def search_and_generate(self, query):
# 动态调整 top_k,确保不超过 context_budget
chunks = []
total_tokens = 0
for chunk in vector_store.search(query, top_k=10):
chunk_tokens = count_tokens(chunk.text)
if total_tokens + chunk_tokens <= self.context_budget:
chunks.append(chunk)
total_tokens += chunk_tokens
else:
break # 达到预算,停止检索
# 构建 prompt 并调用 LLM
response = llm.generate(prompt, max_tokens=self.response_budget)
return response
关键技术要点总结
FAISS/ChromaDB 检索细节
当 top_k > index.ntotal 时:
- 多余的返回位置填充 -1
- 必须过滤掉 -1,否则会导致索引错误
# 需要过滤掉 -1
valid_results = [idx for idx in indices if idx != -1]
热更新机制
后端使用 Uvicorn 的 --reload 参数实现热更新:
python -m uvicorn app.main:app --reload --port 8000
工作原理:
- 父进程监控文件变化
- 子进程运行应用
- 检测到 .py 文件变化时自动重启子进程
注意事项:
- 生产环境禁用热更新
- 有轻微性能开销
文章评论