用 DeepSeek + Kimi 搭一套生产级 RAG 系统:国产大模型 RAG 实战(2026 完整代码)

0 阅读4分钟

为什么要写这篇

RAG(Retrieval-Augmented Generation)从 2023 年炒到现在,能写"教程"的文章满网都是,但真要做生产环境,绕不开几个硬问题:

  • Embedding 用国产还是 OpenAI?
  • 向量库选哪个,为啥别人用 Milvus 你用 Chroma 就崩?
  • 检索召回率上不去怎么办?
  • LLM 生成阶段用 GPT 太贵,国产能不能扛?
  • 整套链路的延迟和成本怎么算账?

这篇把过去三个月在生产环境跑过的 RAG 方案整理出来,全部用国产大模型 + 国产 Embedding 做,附完整可跑代码。

数据采集 / 代码验证时间:2026 年 4 月 23 日


一、整体架构:一张图看懂 RAG

                          ┌─────────────────┐
                          │  用户问题 Query  │
                          └────────┬────────┘
                                   │
                          ┌────────▼────────┐
                          │ Embedding 向量化 │
                          │  (bge-m3 等)    │
                          └────────┬────────┘
                                   │
                          ┌────────▼────────┐
                          │  向量库相似检索  │
                          │  (Milvus/Qdrant)│
                          └────────┬────────┘
                                   │
                          ┌────────▼────────┐
                          │  Rerank 精排    │
                          │  (bge-reranker) │
                          └────────┬────────┘
                                   │
                          ┌────────▼────────┐
                          │  Prompt 拼接    │
                          │  + LLM 生成     │
                          │  (Kimi/DeepSeek)│
                          └────────┬────────┘
                                   │
                          ┌────────▼────────┐
                          │   返回回答 + 引用 │
                          └─────────────────┘

每一层都有选型决策。下面逐层拆。


二、Embedding 选型:国产已经够用

2024 年大家还在用 OpenAI text-embedding-3-small,2026 年没必要了。国产 Embedding 在中文 + 跨语言场景已经超过 OpenAI

模型维度中文 MTEB多语言价格推荐场景
bge-m3102470.3✅ 多语言开源免费通用首选
bge-large-zh-v1.5102468.5❌ 仅中文开源免费纯中文场景
text-embedding-v3(阿里)1024/153669.8$0.07 / M tokens不想自部署
m3e-large102465.2⚠️ 弱开源免费老项目
OpenAI text-embedding-3-large307264.6$0.13 / M tokens已无优势

实战建议:

  • 自己部署:选 bge-m3(开源 + 多语言 + MTEB 中文 70.3 第一)
  • 不想运维:选阿里 text-embedding-v3(OpenAI 兼容接口,$0.07/M 比 OpenAI 便宜)

自部署 bge-m3 代码

from FlagEmbedding import BGEM3FlagModel
​
model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=True)
​
texts = ["RAG 是什么?", "向量库怎么选?", "Kimi K2.6 跑分如何?"]
embeddings = model.encode(texts, batch_size=12, max_length=8192)['dense_vecs']
​
print(embeddings.shape)  # (3, 1024)

用阿里 DashScope 兼容接口

from openai import OpenAI
​
client = OpenAI(
    api_key="sk-your-dashscope-key",
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
​
resp = client.embeddings.create(
    model="text-embedding-v3",
    input=["RAG 是什么?", "向量库怎么选?"],
    dimensions=1024,  # 可选 1536
)
​
vecs = [d.embedding for d in resp.data]

三、向量库选型:别再无脑 Chroma 了

向量库适用规模性能部署复杂度推荐场景
Milvus千万 ~ 十亿级极强生产首选
Qdrant百万 ~ 千万级低(Rust 单二进制)中等规模生产
pgvector十万 ~ 百万级低(PostgreSQL 扩展)已有 PG 的项目
Chroma< 十万级极低原型 / Demo
Weaviate百万级需要混合搜索

关键判断:

  • 如果你的语料 < 10 万条,Chroma 够用,但别用到生产——它的并发和持久化都是玩具级
  • 10 万 ~ 百万:Qdrant 是甜蜜点(Rust 单二进制,部署简单,性能稳)
  • 百万以上:上 Milvus,没的选

Qdrant 完整代码

from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
​
client = QdrantClient(url="http://localhost:6333")
​
# 创建 collection(一次)
client.create_collection(
    collection_name="docs",
    vectors_config=VectorParams(size=1024, distance=Distance.COSINE),
)
​
# 插入向量
points = [
    PointStruct(
        id=i,
        vector=embeddings[i].tolist(),
        payload={"text": texts[i], "source": f"doc_{i}.md"},
    )
    for i in range(len(texts))
]
client.upsert(collection_name="docs", points=points)
​
# 检索
query_vec = model.encode(["如何选向量库?"])['dense_vecs'][0]
results = client.search(
    collection_name="docs",
    query_vector=query_vec.tolist(),
    limit=5,
)
for r in results:
    print(r.score, r.payload["text"])

四、Rerank 精排:召回率从 70% 提到 92%

很多人 RAG 效果差就是漏了 Rerank。Embedding 召回是粗排,精度上限大概 70% 。加一层 Rerank 模型(cross-encoder 架构),实测召回率能提到 90%+。

国产 bge-reranker-v2-m3 是当前最强开源 reranker:

from FlagEmbedding import FlagReranker
​
reranker = FlagReranker('BAAI/bge-reranker-v2-m3', use_fp16=True)
​
query = "如何选向量库?"
candidates = [r.payload["text"] for r in results]  # 上一步召回的 Top 5# 计算 query 和每个候选的相关性分
pairs = [[query, c] for c in candidates]
scores = reranker.compute_score(pairs, normalize=True)
​
# 按分数排序
ranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True)
top3 = [c for c, _ in ranked[:3]]

实测对比(10 万条中文知识库):

方案Top-3 召回率平均延迟
仅 bge-m3 召回71.4%35 ms
bge-m3 + bge-reranker-v292.6%95 ms

延迟从 35ms 涨到 95ms,但准确率提了 21 个百分点——生产环境基本必加。


五、Generation:用 Kimi K2.6 还是 DeepSeek V3.2?

LLM 生成阶段是 RAG 成本大头(Embedding 一次性,生成每次都要算)。国产首选两家:

维度Kimi K2.6DeepSeek V3.2
上下文256K128K
输入价 ($/M)$0.60$0.14
输出价 ($/M)$2.50$0.28
Cache hit ($/M)$0.16$0.07
中文质量AA
长上下文表现A(256K 内稳)B+(128K 内稳)

结论:

  • 一般 RAG 上下文 < 128K → 选 DeepSeek V3.2,便宜且质量足够
  • 检索回的文档量大、上下文经常 > 128K → 选 Kimi K2.6
  • 想省钱到极致 → DeepSeek + Cache hit,长 system prompt 命中率高时单次调用 < $0.001

Generation 代码(DeepSeek + 流式)

from openai import OpenAI
​
llm = OpenAI(
    api_key="sk-your-deepseek-key",
    base_url="https://api.deepseek.com/v1",
)
​
def generate_with_context(query, context_docs):
    context = "\n\n".join([f"[文档 {i+1}]\n{doc}" for i, doc in enumerate(context_docs)])
​
    messages = [
        {
            "role": "system",
            "content": "你是企业知识库助手。根据下面的文档回答问题,只用文档内信息,"
                       "如果文档没说就回复'文档中未找到相关信息'。回答末尾标注引用的 [文档 X]。",
        },
        {
            "role": "user",
            "content": f"# 参考文档\n\n{context}\n\n# 问题\n{query}",
        },
    ]
​
    stream = llm.chat.completions.create(
        model="deepseek-chat",
        messages=messages,
        stream=True,
        temperature=0.1,
    )
​
    for chunk in stream:
        if chunk.choices[0].delta.content:
            yield chunk.choices[0].delta.content

六、完整 RAG Pipeline(端到端代码)

把上面所有组件串起来:

from openai import OpenAI
from FlagEmbedding import BGEM3FlagModel, FlagReranker
from qdrant_client import QdrantClient
​
# === 初始化 ===
embedder = BGEM3FlagModel('BAAI/bge-m3', use_fp16=True)
reranker = FlagReranker('BAAI/bge-reranker-v2-m3', use_fp16=True)
vdb = QdrantClient(url="http://localhost:6333")
llm = OpenAI(api_key="sk-...", base_url="https://api.deepseek.com/v1")
​
​
def rag_query(question: str, top_k_recall: int = 20, top_k_final: int = 3) -> str:
    # 1. Embedding
    q_vec = embedder.encode([question])['dense_vecs'][0]
​
    # 2. 向量库召回
    candidates = vdb.search(
        collection_name="docs",
        query_vector=q_vec.tolist(),
        limit=top_k_recall,
    )
    candidate_texts = [c.payload["text"] for c in candidates]
​
    # 3. Rerank 精排
    pairs = [[question, t] for t in candidate_texts]
    scores = reranker.compute_score(pairs, normalize=True)
    ranked = sorted(zip(candidate_texts, scores), key=lambda x: x[1], reverse=True)
    final_docs = [t for t, _ in ranked[:top_k_final]]
​
    # 4. LLM 生成
    context = "\n\n".join([f"[文档 {i+1}]\n{d}" for i, d in enumerate(final_docs)])
    messages = [
        {"role": "system", "content": "根据文档回答,标注引用 [文档 X]。"},
        {"role": "user", "content": f"# 文档\n{context}\n\n# 问题\n{question}"},
    ]
    resp = llm.chat.completions.create(
        model="deepseek-chat",
        messages=messages,
        temperature=0.1,
    )
    return resp.choices[0].message.content
​
​
# 用法
print(rag_query("公司今年 Q2 营收增长率是多少?"))

七、性能优化的四个杠杆

跑通 demo 之后,生产环境要继续优化这四个方向:

7.1 Embedding 批处理

单条向量化太慢,批量处理能把吞吐提 5-10 倍:

# 慢
for text in texts:
    vec = embedder.encode([text])['dense_vecs']
​
# 快
vecs = embedder.encode(texts, batch_size=32)['dense_vecs']

7.2 Cache hit:长 system prompt 必启用

DeepSeek 和 Kimi 都支持自动 prompt caching,关键是 system prompt 必须放在 messages 第一条且内容不变

SYSTEM_PROMPT = """你是企业知识库助手。规则:
1. 只用提供的文档回答
2. 文档没说就回复"未找到相关信息"
3. 答案末尾标注 [文档 X]
... (这里是几千字的详细规则)
"""# 每次调用都用同一个 SYSTEM_PROMPT,cache 自动命中
messages = [
    {"role": "system", "content": SYSTEM_PROMPT},  # 这部分会 cache
    {"role": "user", "content": user_input},
]

实测 DeepSeek cache hit 后输入价从 0.14降到0.14 降到 0.07,4000 tokens 长 system prompt 月省 60-70%

7.3 Hybrid Search:向量 + BM25

纯向量检索对实体名 / 错别字 / 行业术语召回弱。Qdrant 1.10+ 支持 hybrid,向量 + 关键词融合:

from qdrant_client.models import SparseVector, NamedVector, Prefetch, Fusion, FusionQuery
​
results = vdb.query_points(
    collection_name="docs",
    prefetch=[
        Prefetch(query=q_vec.tolist(), using="dense", limit=20),
        Prefetch(query=SparseVector(indices=[...], values=[...]), using="bm25", limit=20),
    ],
    query=FusionQuery(fusion=Fusion.RRF),
    limit=5,
)

7.4 流式输出 + 异步并发

RAG 一次完整请求 = Embedding(50ms) + 检索(30ms) + Rerank(60ms) + 生成(2-5s)。生成是大头,必须流式:

import asyncio
from openai import AsyncOpenAI
​
async_llm = AsyncOpenAI(api_key="...", base_url="https://api.deepseek.com/v1")
​
async def stream_rag(question):
    # ... 前三步用同步即可,最后生成用 async
    stream = await async_llm.chat.completions.create(
        model="deepseek-chat",
        messages=[...],
        stream=True,
    )
    async for chunk in stream:
        if chunk.choices[0].delta.content:
            yield chunk.choices[0].delta.content

八、踩过的坑

坑一:bge-m3 在 Apple Silicon 上很慢

M 系列芯片 + bge-m3 + MPS backend,性能比 NVIDIA T4 还差。生产环境就老老实实用 GPU 服务器。

坑二:Qdrant 内存吃得比想象大

百万级向量 + 1024 维 + payload 大,单实例内存可能跑到 16GB+。配置 on_disk: true 把向量落盘可省 60% 内存。

坑三:DeepSeek context length 实际只有 64K 是稳的

虽然官方说 128K,但实测超过 64K 后 needle-in-haystack 准确率明显下降。RAG 上下文超长时换 Kimi K2.6(256K,180K 内都稳)。

坑四:Rerank 模型本地跑慢,但又不想 GPU 服务器

可以用阿里 / 智谱的 rerank 在线 API 替代——但 RAG 系统又多一个外部依赖。我们的做法是 reranker 单独部署在低配 GPU 节点(T4 即可),通过内部 RPC 调用。

坑五:检索回的文档塞太多 → LLM 性能反而下降

俗称 "lost in the middle"。Top-K 不是越大越好,实测 K=3 ~ 5 准确率最高,K=10+ 反而下降。


九、成本估算(每千次查询)

组件成本 / 千次备注
Embedding (bge-m3 自部署)~$0.5算 GPU 折旧
向量检索 (Qdrant)~$0.1单机集群分摊
Rerank (bge-reranker 自部署)~$0.8T4 GPU 折旧
LLM 生成 (DeepSeek + cache)~$0.7平均 5K 输入 + 500 输出
合计~$2.1单查询 ~$0.002

对比纯 OpenAI 方案(GPT-4o + text-embedding-3):

  • OpenAI 同样规模约 $25 / 千次

国产方案成本是 OpenAI 的 1/12 左右。 这是 RAG 这个高频调用场景下国产模型最大的吸引力。


十、FAQ

Q1:bge-m3 和 OpenAI embedding 怎么选?

A:中文 / 多语言场景 bge-m3 全面胜出。纯英文且不在意成本可以保留 OpenAI。混合语言生产环境直接 bge-m3。

Q2:能用 LangChain / LlamaIndex 吗?

A:可以,上面的代码本质和 LangChain 的 chain 是一回事。框架的好处是组件标准化,缺点是抽象层多、debug 难。生产环境我们倾向直接用底层 SDK + 自己的封装

Q3:RAG 和 fine-tuning 怎么选?

A:知识更新频繁 / 强可解释性 / 需要引用来源 → RAG。固定能力增强(特定文风、行业术语)→ fine-tuning。两者可以结合:fine-tune LLM 学到风格,RAG 注入实时知识。

Q4:向量库要不要 GPU?

A:检索阶段不需要(Qdrant / Milvus 都是 CPU 索引)。Embedding 和 Rerank 阶段建议 GPU,否则吞吐拉胯。

Q5:怎么评估 RAG 效果?

A:用 RAGAS、TruLens 等框架。核心指标三个:Faithfulness(答案是否忠于文档)、Answer Relevance(答案是否切题)、Context Precision(召回文档是否相关)。

Q6:LLM 生成怎么避免幻觉?

A:Prompt 里强制要求"只用文档信息,没有就回复未找到"+ 温度调到 0.1 + 答案末尾要求标注引用 [文档 X]。这套组合实测能把幻觉率从 ~15% 降到 ~3%。


十一、总结

国产大模型在 2026 Q2 这一波,把 RAG 这个高频调用场景的成本打到了一个新水位:

  • Embedding:bge-m3 是首选,免费且效果好
  • 向量库:百万级以下 Qdrant,再大上 Milvus
  • Rerank:bge-reranker-v2 一定要加,召回率从 70% → 92%
  • 生成:日常用 DeepSeek V3.2,长上下文用 Kimi K2.6
  • 成本:千次查询 ~$2,比纯 OpenAI 方案省 12 倍

这套组合我们已经在生产跑了三个月,单系统日均 50 万查询稳定。下一篇会写RAG 评估 + 持续优化的工程实践,包括 RAGAS 接入、A/B 测试、Bad Case 自动收集,敬请期待。


参考资料


作者:TokenMix 研究院 · 长期追踪大模型技术与价格变动

如果这篇对你有用,点赞 + 收藏 + 关注。下次更新国产 RAG 评估实战。