Appearance
RAG(检索增强生成)通过在生成前检索相关文档来减少幻觉、保持知识更新,无需微调。OpenRouter 通过单一 API 提供 RAG 管道所需的三个构建块:/api/v1/embeddings(向量化)、/api/v1/rerank(重排序)、/api/v1/chat/completions(生成)。本文包含完整的四步 Python 实现:索引→检索→重排→生成,以及 chunking 策略、何时用 rerank、生产最佳实践。
RAG(Retrieval-Augmented Generation,检索增强生成)将 LLM 的回答锚定在你自己的数据上——在生成答案前先检索相关文档,从而减少幻觉、保持内容时效性,而无需微调。
OpenRouter 通过单一 API 提供 RAG 管道的三个核心组件:
- Embeddings — 将文档和查询转换为向量,用于语义搜索
- Rerank — 对检索到的候选文档重新评分,提升精准度
- Chat Completions — 利用检索到的上下文生成最终答案
RAG 工作原理
典型 RAG 管道分为四步:
- 索引(Index) — 将文档分块并为每块生成 embedding,存入向量数据库
- 检索(Retrieve) — 将用户查询向量化,找到最相似的文档块
- 重排(Rerank,可选) — 用交叉编码器对候选结果精排,提升召回精度
- 生成(Generate) — 将排名靠前的文档作为上下文传给 LLM 生成有依据的答案
第一步:索引文档
将文档切块,批量生成 embedding,存入向量数据库(此处用内存演示):
python
import requests
OPENROUTER_API_KEY = "YOUR_API_KEY"
chunks = [
"OpenRouter is a unified API gateway for LLMs.",
"RAG stands for Retrieval-Augmented Generation.",
"Embeddings convert text into numerical vectors.",
"Reranking uses a cross-encoder to re-score documents.",
"Vector databases like Pinecone, Weaviate, Qdrant store embeddings.",
]
response = requests.post(
"https://openrouter.ai/api/v1/embeddings",
headers={"Authorization": f"Bearer {OPENROUTER_API_KEY}"},
json={"model": "your-embedding-model", "input": chunks},
)
data = response.json()
document_embeddings = [
{"text": chunks[item["index"]], "embedding": item["embedding"]}
for item in data["data"]
]生产环境中,使用向量数据库(Pinecone、Weaviate、Qdrant、pgvector 等)存储 embedding。
第二步:检索相关文档
将用户查询向量化,通过余弦相似度找到最相似的文档块:
python
import numpy as np
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
def retrieve(query, document_embeddings, top_n=5):
response = requests.post(
"https://openrouter.ai/api/v1/embeddings",
headers={"Authorization": f"Bearer {OPENROUTER_API_KEY}"},
json={"model": "your-embedding-model", "input": query},
)
query_embedding = np.array(response.json()["data"][0]["embedding"])
scored = [
{"text": doc["text"], "score": cosine_similarity(query_embedding, np.array(doc["embedding"]))}
for doc in document_embeddings
]
scored.sort(key=lambda x: x["score"], reverse=True)
return scored[:top_n]第三步:Rerank 精排(可选)
基于 embedding 的检索速度快但精度有限。Rerank 模型用交叉编码器将每个文档直接与查询比较,产生更准确的相关性评分——特别适合检索量大(20 个候选)但只需精选少数(3 个)的场景:
python
def rerank(query, documents, top_n=3):
response = requests.post(
"https://openrouter.ai/api/v1/rerank",
headers={"Authorization": f"Bearer {OPENROUTER_API_KEY}"},
json={"model": "your-rerank-model", "query": query, "documents": documents, "top_n": top_n},
)
return response.json()["results"]
retrieved_texts = [r["text"] for r in results]
reranked = rerank(query, retrieved_texts, top_n=3)第四步:生成有依据的答案
将排名靠前的文档作为上下文传给 chat 模型:
python
def generate_answer(query, context_docs):
context = "\n\n".join(
f"[{i+1}] {doc['document']['text']}"
for i, doc in enumerate(context_docs)
)
response = requests.post(
"https://openrouter.ai/api/v1/chat/completions",
headers={"Authorization": f"Bearer {OPENROUTER_API_KEY}"},
json={
"model": "your-chat-model",
"messages": [
{"role": "system", "content": "Answer based on the provided context. Cite source numbers in brackets. If context is insufficient, say so."},
{"role": "user", "content": f"Context:\n{context}\n\nQuestion: {query}"},
],
},
)
return response.json()["choices"][0]["message"]["content"]何时使用 Rerank
适合使用 rerank:
- 知识库较大(数百到数千个文档块),embedding 检索结果噪声较多
- 精度比延迟更重要(如面向用户的 Q&A、法律医疗文档)
- 检索大量候选(如 top 20)并需要精选最优的几个
可以跳过 rerank:
- 知识库较小,embedding 检索精度已足够
- 需要最低延迟(rerank 增加一次额外 API 调用)
- 构建原型,保持管道简单
文档分块策略
分块方式对检索质量影响显著:
- 按段落/章节分块 — 保持语义完整性,适合结构化文档
- 固定大小 + 重叠 — 每块 200-500 token,~50 token 重叠,避免边界截断
- 按语义边界 — 使用标题、节分隔符或句子边界创建自然分块
较小分块(200-300 token)检索更精准但可能丢失上下文;较大分块(500-1000 token)保留更多上下文但可能稀释相关性。
最佳实践
- 索引和查询使用同一 embedding 模型 — 混用不同模型会产生不兼容的向量空间
- 批量发送 embedding 请求 — 一次 API 调用传入多个文本,降低延迟和成本
- 缓存 embedding — 相同文本的 embedding 是确定性的,存入数据库避免重复计算
- 多检索少用,配合 rerank 精选 — 常见模式是先取 10-20 个候选,rerank 精选到 3-5 个
- 在 prompt 中包含元数据 — 附上文档标题、来源 URL 等,让 LLM 能生成准确引用
- 设置相关性阈值 — Rerank 后过滤掉低于最低相关分的文档,避免注入干扰上下文
常见问题
Q: 必须用 Rerank 吗?
A: 不是必须的。对于中小型知识库,embedding 相似度检索的精度通常已足够。Rerank 主要价值在于大规模知识库或对精度要求极高的场景。先不用 rerank 测试你的 RAG 效果,精度不满意再引入。
Q: 如何选择 chunk 大小?
A: 没有通用答案,取决于你的数据特点。一个实用起点是 400 token + 50 token 重叠。如果检索到的上下文太碎(LLM 回答缺乏连贯性),增大 chunk;如果太泛(检索结果噪声多),减小 chunk。
Q: Embeddings API 支持哪些模型?
A: 通过 https://openrouter.ai/api/v1/embeddings 可访问所有支持 embedding 的模型。详见 Embeddings API 文档,可按支持类型筛选。