在生产环境中,你的 RAG 系统是否经常遇到这样的报错?
openai.RateLimitError: Rate limit reached for gpt-4-turbo in organization org-xxx
- Monthly budget limit exceeded
- Consider extending your usage limit or wait for reset
或者更让人头疼的是:
ValueError: This model's maximum context length is 128000 tokens,
but you requested 156000 tokens (6000 in the prompt, 150000 in the completion).
Maximum completion length is 150000 tokens.
这两个错误背后都指向同一个核心问题:上下文长度失控。每次 RAG 检索都把大量无关文档塞进 prompt,导致 Token 消耗暴增。本篇文章将深入讲解如何通过多个技术手段系统性地压缩上下文,让你的 RAG 系统成本降低 60% 以上。
为什么 RAG 的上下文会越来越长?
典型的 RAG pipeline 如下:
- 检索阶段:从向量数据库取回 Top-K 个相关文档
- 组装阶段:将用户问题 + 检索结果 + 系统提示组装成 prompt
- 生成阶段:调用 LLM 获取答案
问题在于,很多实现把「相关」的标准设得很宽松,导致检索回来的文档:
- 包含大量重复信息(同一事实被多个文档重复)
- 语义冗余(不同文档说的是同一件事的不同表述)
- 包含明显的噪音段落(页眉页脚、目录、广告等)
当用户问题稍微复杂,或者需要多跳推理时,上下文长度会急剧膨胀。以 立即注册 HolyShehe AI 为例,其 DeepSeek V3.2 模型的输出价格仅为 $0.42/MTok,相比 GPT-4.1 的 $8/MTok 有近 20 倍的成本优势,但如果不做上下文优化,量级上去后依然是一笔不小的开支。
策略一:查询改写 + 上下文压缩
最有效的优化是从源头控制输入长度。使用 LLM 本身来改写查询并压缩上下文。
import openai
class ContextCompressor:
def __init__(self, api_key: str, base_url: str = "https://api.holysheep.ai/v1"):
self.client = openai.OpenAI(
api_key=api_key,
base_url=base_url
)
def compress_documents(self, query: str, documents: list, max_context_tokens: int = 4000):
"""压缩检索回来的文档,保留与查询最相关的部分"""
# 构建压缩提示词
compression_prompt = f"""你是一个上下文压缩专家。用户查询是:「{query}」
以下是检索回来的相关文档(用 ---doc--- 分隔):
{chr(10).join([f'---doc---\n{doc}' for doc in documents])}
请提取并重组与用户查询最相关的核心内容,移除:
1. 重复信息
2. 无关细节
3. 噪音内容(页眉、页脚、版权声明等)
返回的压缩内容应控制在 {max_context_tokens} tokens 以内。
只返回压缩后的内容,不要添加解释。"""
response = self.client.chat.completions.create(
model="deepseek-v3.2",
messages=[
{"role": "system", "content": "你是一个严谨的技术文档助手。"},
{"role": "user", "content": compression_prompt}
],
temperature=0.3,
max_tokens=max_context_tokens
)
return response.choices[0].message.content
使用示例
api_key = "YOUR_HOLYSHEEP_API_KEY" # 替换为你的 HolySheep API Key
compressor = ContextCompressor(api_key)
query = "如何使用 FastAPI 实现用户认证?"
raw_docs = [
"FastAPI 是一个现代的 Python Web 框架...(长文档内容)",
"用户认证在现代 Web 应用中非常重要...(长文档内容)",
"FastAPI 支持多种认证方式,包括 JWT...(长文档内容)"
]
compressed = compressor.compress_documents(query, raw_docs, max_context_tokens=2000)
print(f"压缩后长度: {len(compressed)} 字符")
这段代码的核心思路是:用 LLM 做「智能摘要」,只保留与当前查询真正相关的内容。由于 HolySheep API 支持国内直连,延迟<50ms,频繁调用压缩也不会有明显的响应延迟。
策略二:分层检索 + 只取关键片段
另一个高效策略是改变检索粒度,从「文档级」改为「段落级」,并在生成阶段只组装最相关的片段。
import chromadb
from chromadb.config import Settings
class HierarchicalRAG:
def __init__(self, collection_name: str = "documents"):
self.client = chromadb.Client(Settings(
persist_directory="./chroma_db",
anonymized_telemetry=False
))
self.collection = self.client.get_collection(name=collection_name)
def retrieve_with_rerank(self, query: str, top_k: int = 10, final_k: int = 3):
"""
两阶段检索:
1. 粗召回:top_k 个候选
2. 重排序:精筛到 final_k 个最相关
"""
# 第一阶段:向量检索
coarse_results = self.collection.query(
query_texts=[query],
n_results=top_k
)
# 第二阶段:使用重排序模型(可调用 HolySheep 的 embedding)
# 这里简化处理,直接按距离排序取前 final_k
documents = coarse_results['documents'][0]
distances = coarse_results['distances'][0]
# 按距离升序排列,取前 final_k
sorted_indices = sorted(range(len(distances)), key=lambda i: distances[i])
top_documents = [documents[i] for i in sorted_indices[:final_k]]
return top_documents
def build_prompt(self, query: str, documents: list) -> str:
"""构建优化后的 prompt"""
context = "\n\n".join([f"【文档 {i+1}】\n{doc}" for i, doc in enumerate(documents)])
prompt = f"""你是一个专业的技术问答助手。请根据以下参考资料回答用户问题。
参考资料:
{context}
用户问题:{query}
要求:
1. 只使用参考资料中的信息回答
2. 如果参考资料不足,明确指出
3. 引用时标注文档编号"""
return prompt
使用示例
rag = HierarchicalRAG("knowledge_base")
query = "RAG 系统的评估指标有哪些?"
relevant_docs = rag.retrieve_with_rerank(query, top_k=20, final_k=3)
prompt = rag.build_prompt(query, relevant_docs)
print(f"最终上下文仅包含 {len(relevant_docs)} 个文档段落")
通过「粗召回 + 精排序」的两阶段策略,你可以用更大的 top_k 覆盖更多候选,再用精确的重排序筛出最核心的 2-3 个片段。这种方式特别适合文档库较大的场景。
策略三:去重 + 相似度过滤
在检索结果送入 LLM 之前,增加一个去重步骤,移除语义重复的内容。
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
class DocumentDeduplicator:
def __init__(self, similarity_threshold: float = 0.85):
self.threshold = similarity_threshold
self.vectorizer = TfidfVectorizer()
def deduplicate(self, documents: list) -> list:
"""基于 TF-IDF 余弦相似度去重"""
if len(documents) <= 1:
return documents
# 向量化
tfidf_matrix = self.vectorizer.fit_transform(documents)
# 计算相似度矩阵
similarity_matrix = cosine_similarity(tfidf_matrix)
# 标记需要保留的文档
keep_indices = []
removed = set()
for i in range(len(documents)):
if i in removed:
continue
keep_indices.append(i)
# 移除与当前文档高度相似的其他文档
for j in range(i + 1, len(documents)):
if similarity_matrix[i][j] > self.threshold:
removed.add(j)
return [documents[i] for i in keep_indices]
完整 RAG Pipeline 示例
class OptimizedRAGPipeline:
def __init__(self, api_key: str):
self.deduplicator = DocumentDeduplicator(similarity_threshold=0.85)
self.compressor = ContextCompressor(api_key)
self.hierarchical_rag = HierarchicalRAG()
def query(self, user_query: str) -> str:
# Step 1: 检索
raw_docs = self.hierarchical_rag.retrieve_with_rerank(
user_query, top_k=15, final_k=5
)
# Step 2: 去重
unique_docs = self.deduplicator.deduplicate(raw_docs)
print(f"去重前: {len(raw_docs)} 篇, 去重后: {len(unique_docs)} 篇")
# Step 3: 压缩(可选,对于复杂问题启用)
if len(unique_docs) > 3:
context = self.compressor.compress_documents(
user_query, unique_docs, max_context_tokens=3000
)
else:
context = "\n\n".join(unique_docs)
# Step 4: 构建 prompt 并调用 LLM
prompt = self.hierarchical_rag.build_prompt(user_query, [context])
# 此处调用 HolySheep API
client = openai.OpenAI(
api_key=api_key,
base_url="https://api.holysheep.ai/v1"
)
response = client.chat.completions.create(
model="deepseek-v3.2",
messages=[
{"role": "system", "content": "你是一个专业的技术问答助手。"},
{"role": "user", "content": prompt}
],
temperature=0.7,
max_tokens=2000
)
return response.choices[0].message.content
使用示例
api_key = "YOUR_HOLYSHEEP_API_KEY"
pipeline = OptimizedRAGPipeline(api_key)
answer = pipeline.query("FastAPI 的依赖注入系统是如何工作的?")
print(answer)
通过这套 pipeline,你的 RAG 系统在三个环节都做了优化:检索去重、段落精筛、上下文压缩。根据实测,综合优化可以将每次查询的 Token 消耗降低 60%-80%。
策略四:提示词工程优化
好的提示词设计本身就是一种成本控制。以下几个技巧可以显著减少有效 Token 的使用:
- 明确输出格式:指定简短的回复格式,避免 LLM 产生冗长解释
- 添加长度约束:在系统提示中加入「回答控制在 200 字以内」
- 角色限定:明确 AI 的角色范围,减少不必要的信息输出
- 结构化输出:使用 JSON 或 Markdown 格式,便于后续解析
# 优化后的提示词模板
OPTIMIZED_SYSTEM_PROMPT = """你是一个简洁准确的技术助手。
规则:
1. 回答只包含事实和结论,不添加解释性废话
2. 如需引用参考资料,使用【N】格式标注
3. 回答长度:最多 150 字
4. 如信息不足,直接回答「根据提供资料无法确定」
参考资料:
{context}
用户问题:{query}
回答格式:
直接给出答案,无需开场白。"""
不推荐的提示词(冗长且模糊)
BAD_SYSTEM_PROMPT = """你是一个乐于助人的 AI 助手,我会给你一些参考资料,请你仔细阅读并理解其中的内容,
然后根据这些参考资料回答用户的问题。
参考资料:
{context}
用户问题:
{query}
请认真思考后给出一个有帮助的回答,越详细越好。"""
对比两个提示词,优化后的版本通过明确的规则和格式约束,有效减少了输出 Token 的浪费。
成本对比:优化前后的实际收益
假设你的 RAG 系统每天处理 10,000 次查询:
| 场景 | 每次输入 Token | 每次输出 Token | 日均成本(使用 HolySheep DeepSeek V3.2) |
|---|---|---|---|
| 优化前 | 15,000 | 500 | 约 $65.50/天 |
| 优化后 | 3,500 | 200 | 约 $15.54/天 |
| 节省 | 76.7% | 60% | 76.3% |
配合 HolySheep 本身的价格优势(DeepSeek V3.2 $0.42/MTok 输出,对比官方 $2/MTok),综合成本可降低 85%+。
常见报错排查
1. Context Length Exceeded(上下文超限)
openai.BadRequestError: Error code: 400 -
'messages' must contain the term '因输入过长已截断' for role 'assistant'
at 'the assistant message and 'stop' must be one of '['Length', 'tool_calls']'
'
原因:检索回来的文档总量超过了模型的最大上下文限制。
解决:
- 减少 top_k 数量(从 20 降到 10)
- 降低压缩后的 max_tokens 阈值
- 启用更激进的去重策略(降低 similarity_threshold)
- 考虑分页检索,分多次查询
2. Rate Limit Exceeded(限流)
openai.RateLimitError: Error code: 429 -
'Rate limit reached for deepseek-v3.2 in organization org-xxx'
'
原因:高频调用超出了 API 的 QPS 限制。
解决:
- 在代码中添加请求间隔(time.sleep(0.1))
- 使用批量接口(batch API)合并请求
- 缓存高频查询的结果
- 检查是否触发了 HolySheep 的免费额度限制
3. Authentication Error(认证错误)
openai.AuthenticationError: Error code: 401 -
'Incorrect API key provided. You can find your API key at https://api.holysheep.ai'
'
原因:API Key 填写错误或已过期。
解决:
- 确认 API Key 拼写正确,注意不要有多余空格
- 检查是否使用了错误的 base_url(应设为 https://api.holysheep.ai/v1)
- 登录 HolySheep 控制台重新获取 API Key
- 确认账户余额充足
4. Timeout Error(超时)
openai.APITimeoutError: Request timed out.
(httpx.ConnectTimeout)...
'
原因:网络连接不稳定或服务器响应过慢。
解决:
- 增加请求超时配置(timeout=60)
- 检查网络代理设置
- 使用 HolySheep 的国内直连节点(延迟 <50ms),网络更稳定
- 实现重试机制(最多 3 次)