首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >构建高可用 RAG 大模型系统:从基础检索到上下文增强的实战指南

构建高可用 RAG 大模型系统:从基础检索到上下文增强的实战指南

原创
作者头像
资源大佬 jzit-top
发布2026-08-04 13:56:01
发布2026-08-04 13:56:01
1570
举报

构建高可用 RAG 大模型系统:从基础检索到上下文增强的实战指南

1. 引言:RAG 系统的工程挑战

检索增强生成(Retrieval-Augmented Generation, RAG)已成为大模型落地企业知识库、客服机器人等场景的标配架构。然而,从 Demo 到生产环境,开发者常面临以下痛点:

  • 检索精度不足:简单的向量相似度难以处理同义词、多义性问题,导致召回结果偏离用户意图。
  • 上下文融合困难:检索到的多个文档片段如何组织成有效的 LLM 输入,既不丢失关键信息又不超出上下文窗口。
  • 性能与成本平衡:向量数据库的 QPS 瓶颈、Embedding 模型的计算开销、LLM 的 Token 消耗。

本文从工程视角出发,结合实际代码,构建一个可扩展、可评估的 RAG 系统。我们将依次讨论 文档分块与索引优化检索策略(含重排序)上下文增强与 Prompt 设计离线评估与线上监控,每个环节均提供可复现的实现方案。


2. 系统架构概览

核心组件:

  • 索引层:处理文档分块、向量化、存储(本文使用 Qdrant)。
  • 检索层:混合检索(向量 + 关键词)及重排序(Cross-Encoder)。
  • 生成层:上下文组装与 LLM 调用(OpenAI / 开源模型)。
  • 评估层:使用 RAGAS 或自定义指标离线迭代。

3. 文档分块与索引优化

3.1 分块策略对比

策略

描述

适用场景

固定大小(Fixed-size)

按 Token 数或字符数切分,可设置重叠

通用文档,实现简单

递归字符分割(RecursiveCharacterTextSplitter)

按段落、句子、词语层级递归切割,尽量保持语义边界

非结构化长文档(如 Markdown、HTML)

语义分割(Semantic Splitter)

基于句子向量相似度决定断点

需要保持主题一致性的文档

推荐:使用 LangChain 的 RecursiveCharacterTextSplitter,设置 chunk_size=512chunk_overlap=50(Token 级),平衡粒度与上下文连续性。

代码语言:javascript
复制
from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=50,
    separators=["\n\n", "\n", "。", " ", ""],
    length_function=len,
)
chunks = splitter.split_documents(docs)

3.2 元数据附加

为每个 chunk 附加元数据(来源文件、标题、章节、时间戳),便于后续过滤和引用溯源。

代码语言:javascript
复制
for chunk in chunks:
    chunk.metadata["source"] = file_path
    chunk.metadata["section"] = extract_section(chunk.page_content)

3.3 Embedding 模型选型

模型

维度

语言

成本($/1M tokens)

备注

text-embedding-3-small

1536

多语言

0.02

OpenAI,性能均衡

text-embedding-3-large

3072

多语言

0.13

更高精度

BAAI/bge-large-zh-v1.5

1024

中文

免费(本地)

开源 SOTA

intfloat/multilingual-e5-large

1024

多语言

免费(本地)

需加 query: / passage: 前缀

建议:若预算充足且需多语言,选 text-embedding-3-small;若部署私有化,选 bge-largee5,使用 sentence-transformers 加载。

代码语言:javascript
复制
from sentence_transformers import SentenceTransformer

model = SentenceTransformer("BAAI/bge-large-zh-v1.5")
embeddings = model.encode(chunk_text, normalize_embeddings=True)  # L2归一化

3.4 向量数据库选择(生产级)

数据库

类型

特点

Qdrant

开源向量数据库

支持过滤、多向量、高 QPS

Milvus

开源向量数据库

分布式,适合海量数据

Pinecone

云服务

全托管,简便

Elasticsearch

全文+向量混合

支持混合检索原生

本文选用 Qdrant(Docker 部署):

代码语言:javascript
复制
# docker-compose.yml
services:
  qdrant:
    image: qdrant/qdrant:latest
    ports:
      - "6333:6333"
    volumes:
      - ./qdrant_storage:/qdrant/storage

创建 Collection 并索引:

代码语言:javascript
复制
from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance

client = QdrantClient(host="localhost", port=6333)
client.recreate_collection(
    collection_name="knowledge_base",
    vectors_config=VectorParams(
        size=1024,  # 与 embedding 维度一致
        distance=Distance.COSINE,
    ),
)

4. 检索策略:向量 + 关键词混合,配合重排序

4.1 混合检索(Hybrid Search)

纯向量检索可能遗漏低频关键词匹配。引入 BM25 关键词检索,将两者得分加权融合(RRF 或加权求和)。

方案:使用 Qdrant 自带的 hybrid 查询(需全文索引支持),或使用 Elasticsearch。此处以 Qdrant + rank_fusion 为例:

代码语言:javascript
复制
from qdrant_client.models import Filter, SearchRequest

# 向量检索
vector_results = client.search(
    collection_name="knowledge_base",
    query_vector=query_embedding,
    limit=10,
)

# 关键词检索(需 Qdrant 开启全文索引)
keyword_results = client.search(
    collection_name="knowledge_base",
    query_filter=Filter(must=[...]),
    query="用户输入关键词",
    limit=10,
    with_payload=True,
)

# RRF 融合
def reciprocal_rank_fusion(results_list, k=60):
    scores = {}
    for results in results_list:
        for rank, hit in enumerate(results):
            id = hit.id
            score = 1.0 / (k + rank + 1)
            scores[id] = scores.get(id, 0) + score
    return sorted(scores.items(), key=lambda x: x[1], reverse=True)

4.2 重排序(Reranking)

初召回结果(Top-20)通过 Cross-Encoder 模型重新评分,提升排序准确性。Cross-Encoder 将查询和文档拼接输入,输出相关性分数(0~1),效果优于双塔向量。

模型BAAI/bge-reranker-v2-m3(多语言)或 cross-encoder/ms-marco-MiniLM-L-6-v2(英文)。

代码语言:javascript
复制
from transformers import AutoModelForSequenceClassification, AutoTokenizer
import torch

tokenizer = AutoTokenizer.from_pretrained("BAAI/bge-reranker-v2-m3")
model = AutoModelForSequenceClassification.from_pretrained("BAAI/bge-reranker-v2-m3")

def rerank(query, passages, top_k=5):
    pairs = [[query, p] for p in passages]
    inputs = tokenizer(pairs, padding=True, truncation=True, return_tensors="pt", max_length=512)
    with torch.no_grad():
        scores = model(**inputs).logits.squeeze().tolist()
    scored = sorted(zip(passages, scores), key=lambda x: x[1], reverse=True)
    return [p for p, s in scored[:top_k]]

将重排序后的 Top-5 文档送入 LLM,可显著提升事实准确性。


5. 上下文增强与 Prompt 设计

5.1 上下文组装策略

检索到的文档片段可能内容冗余或顺序混乱。我们需要构建一个结构化的上下文:

  • 策略一:按文档分段,直接拼接(简单,可能超长)。
  • 策略二:按相关性排序,并添加标题/来源
  • 策略三:压缩与摘要,对过长片段调用 LLM 进行摘要(增加成本)。

推荐:采用策略二,并限制总 Token 数(如 4000 tokens),超出则截断低分内容。

代码语言:javascript
复制
def build_context(docs, max_tokens=4000):
    context_parts = []
    total_tokens = 0
    for idx, (content, score) in enumerate(docs):
        prefix = f"[{idx+1}] {content[:100]}... (来源: {metadata.get('source')})\n"
        part = f"{prefix}{content}\n"
        tokens = len(part) // 3   # 粗略估算
        if total_tokens + tokens > max_tokens:
            break
        context_parts.append(part)
        total_tokens += tokens
    return "\n".join(context_parts), total_tokens

5.2 Prompt 模板(含角色、约束、引用)

代码语言:javascript
复制
SYSTEM_PROMPT = """你是一个基于知识库的问答助手。你必须严格按照以下规则回答:
1. 只使用下方提供的上下文信息,不要添加任何外部知识。
2. 如果上下文不足以回答问题,请明确回答“根据当前知识库,无法回答此问题”。
3. 在回答末尾,用[1][2]等标注所引用的文档编号。
4. 回答应简洁、条理清晰,不超过200字。
"""

USER_PROMPT_TEMPLATE = """
上下文:
{context}

问题:{question}
回答:
"""

5.3 LLM 调用(支持流式与重试)

使用 OpenAI Python SDK:

代码语言:javascript
复制
from openai import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def generate_answer(context, question):
    messages = [
        {"role": "system", "content": SYSTEM_PROMPT},
        {"role": "user", "content": USER_PROMPT_TEMPLATE.format(context=context, question=question)}
    ]
    response = client.chat.completions.create(
        model="gpt-4-turbo",
        messages=messages,
        temperature=0.1,
        max_tokens=500,
        stream=False
    )
    return response.choices[0].message.content

若使用开源模型(如 Qwen-2.5-7B),可用 vLLM 或 TGI 部署,兼容 OpenAI API 格式。


6. 评估与监控

6.1 离线评估指标(RAGAS 框架)

RAGAS 提供四个核心指标:

  • Faithfulness(忠实度):生成内容是否与检索到的上下文矛盾(使用 NLI 模型)。
  • Answer Relevancy(答案相关性):生成回答与问题的相关性(使用 LLM 计算)。
  • Context Relevancy(上下文相关性):检索到的内容是否切题。
  • Context Recall:检索到的内容是否覆盖了参考答案的关键点。

安装 ragas 并评估:

代码语言:javascript
复制
pip install ragas
代码语言:javascript
复制
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_relevancy

dataset = {
    "question": [...],
    "answer": [...],
    "contexts": [[...], ...],
    "ground_truth": [...]  # 可选
}

result = evaluate(dataset, metrics=[faithfulness, answer_relevancy, context_relevancy])
print(result)

建议设定每日自动化任务,使用历史对话数据计算上述指标,并记录到监控面板(如 Grafana)。

6.2 线上监控指标

  • 检索延迟:从查询到返回 top-k 文档的耗时(P50、P99)。
  • LLM 首 Token 延迟:影响用户体验。
  • 引用率:用户点击文档引用链接的比例(需前端埋点)。
  • 负反馈率:用户点击“不相关”、“重新生成”等按钮的比例。

6.3 自动超参调优(Optuna)

对分块大小、重叠长度、检索权重(向量 vs 关键词)、重排序阈值等参数,使用 Optuna 结合离线评估指标(如 Faithfulness)进行贝叶斯优化:

代码语言:javascript
复制
import optuna

def objective(trial):
    chunk_size = trial.suggest_int("chunk_size", 256, 1024, step=128)
    overlap = trial.suggest_int("overlap", 20, 100, step=10)
    weight_vector = trial.suggest_float("weight_vector", 0.3, 0.7)
    # 重新运行索引和评估,返回 faithfulness
    return -faithfulness_score  # 最小化负值

study = optuna.create_study()
study.optimize(objective, n_trials=30)

7. 总结与最佳实践

7.1 常见陷阱与对策

陷阱

对策

检索结果噪声大

引入重排序,提高 Top-5 准确率;添加过滤条件(如时间范围)

上下文过长被截断

采用摘要压缩,或选择更长窗口的 LLM(如 Gemini 1.5)

生成幻觉严重

强化 Prompt 约束(强制引用);使用 Faithfulness 指标把关

向量数据库更新延迟

实现增量索引;使用 CDC(Change Data Capture)触发重建

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 构建高可用 RAG 大模型系统:从基础检索到上下文增强的实战指南
    • 1. 引言:RAG 系统的工程挑战
    • 2. 系统架构概览
    • 3. 文档分块与索引优化
      • 3.1 分块策略对比
      • 3.2 元数据附加
      • 3.3 Embedding 模型选型
      • 3.4 向量数据库选择(生产级)
    • 4. 检索策略:向量 + 关键词混合,配合重排序
      • 4.1 混合检索(Hybrid Search)
      • 4.2 重排序(Reranking)
    • 5. 上下文增强与 Prompt 设计
      • 5.1 上下文组装策略
      • 5.2 Prompt 模板(含角色、约束、引用)
      • 5.3 LLM 调用(支持流式与重试)
    • 6. 评估与监控
      • 6.1 离线评估指标(RAGAS 框架)
      • 6.2 线上监控指标
      • 6.3 自动超参调优(Optuna)
    • 7. 总结与最佳实践
      • 7.1 常见陷阱与对策
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档