很多人聊 RAG(Retrieval-Augmented Generation),一上来就是各种 fancy 架构、向量数据库对比、评测体系……最后一个 demo 都跑不起来。

这篇只干一件事:
👉 用最少的技术栈,搭一个“能用”的 RAG MVP。


一、整体架构

(先把全局搞清楚)

RAG MVP 本质就 4 步:

数据 → 向量索引 → 检索 → 大模型生成

请求流程:

用户问题 → 向量检索 → 找到相关文档 → 拼 Prompt → LLM 生成答案


二、数据准备与清洗

(决定上限的环节)

👉 MVP 原则:不要贪多,先保证“干净 + 可控”

1. 数据来源(选一个就够)

你可以选最简单的一种:

  • Markdown 文档(推荐)
  • FAQ(问答对)
  • 产品说明文档
  • txt / pdf

👉 MVP建议:用 Markdown + FAQ


2. 数据清洗(必须做)

目标:让模型“更容易理解 + 更容易切块”

必做操作:

  • 去掉无用内容(页眉页脚、广告)
  • 统一格式(标题层级)
  • 删除重复段落
  • 修正乱码

3. 文本切分(Chunking)

这是 RAG 成败关键点之一。

推荐方案:

from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
chunk_size=500,
chunk_overlap=100
)

docs = splitter.split_text(text)

参数建议:

  • chunk_size:300~800
  • overlap:50~150

👉 原则:

  • 太小 → 信息碎
  • 太大 → 检索不准

三、索引构建

(核心基础设施)

1. 向量模型(Embedding)

👉 MVP 直接选一个成熟的:

可选方案:

  • OpenAI embedding(稳定)
  • 本地模型:
    • bge-small
    • bge-base
    • e5-small

👉 推荐(性价比):

  • bge-base-zh(中文)
  • bge-small-en(英文)

2. 向量数据库(不要复杂)

MVP别上来就搞分布式。

推荐三选一:

✅ 最简单:

  • FAISS(本地文件)

from langchain.vectorstores import FAISS

✅ 稍微正规:

  • Chroma(轻量)
  • Milvus(进阶)

👉 MVP推荐:FAISS


3. 构建索引(代码示例)

from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS

embedding = HuggingFaceEmbeddings(model_name="BAAI/bge-base-zh")

db = FAISS.from_texts(docs, embedding)
db.save_local("faiss_index")


四、检索策略优化

(RAG的灵魂)

很多人卡在这里。

👉 MVP 不需要 fancy,但必须做 3 件事:


1. Top-K 检索

docs = db.similarity_search(query, k=5)

👉 建议:

  • k=3~5:精准
  • k=5~10:信息更全

2. 加一个简单 rerank(强烈建议)

否则容易“看起来相关但没用”。

方案:

  • bge-reranker
  • cross-encoder

简单思路:

# 对召回结果重新排序
reranked_docs = reranker.rank(query, docs)

👉 如果不想加模型:

👉 直接用“最长文本优先”也比没有强


3. 加关键词兜底(Hybrid Search)

纯向量检索会翻车。

👉 MVP补救方案:

  • 同时做关键词匹配(BM25)
  • 两边结果合并

简单版本:

if len(vector_results) < 3:
results += keyword_search(query)


五、生成与提示工程

决定“像不像人话”

1. Prompt 模板(必须写死)

不要裸问模型。

推荐模板:

你是一个专业助手,请基于提供的上下文回答问题。

【上下文】
{context}

【问题】
{question}

要求:
1. 只基于上下文回答
2. 如果不知道,请说“不确定”
3. 回答要简洁清晰


2. 拼接上下文

context = "\n\n".join([doc.page_content for doc in docs])

👉 控制长度:

  • 不超过模型 token 限制
  • 一般 2000~4000 tokens

3. 选择模型

MVP 推荐:

  • API:
    • GPT-4o-mini
    • Claude Haiku
  • 本地:
    • Qwen2-7B
    • Llama3-8B

👉 原则:

👉 先用API验证,再考虑本地化


六、完整最小流程代码(核心骨架)

def rag_pipeline(query):
# 1. 检索
docs = db.similarity_search(query, k=5)

# 2. 拼上下文
context = "\n".join([d.page_content for d in docs])

# 3. 构建prompt
prompt = f"""
你是一个专业助手,请基于提供的上下文回答问题。

上下文:
{context}

问题:
{query}
"""

# 4. 调用LLM
response = llm(prompt)

return response


最后上Demo

不讲概念,直接给一个一键能跑的最小 RAG Demo(本地 + Python + FAISS + 开源 embedding + OpenAI 生成)。

1. 项目结构(直接照抄)


rag-mvp/
├── main.py
├── data.txt
└── requirements.txt

2. 准备数据(data.txt)

随便写点内容(先跑通再说):

RAG 是一种结合检索和生成的技术,可以提升大模型的准确性。
FAISS 是一个向量检索库,适合做本地向量搜索。
Chunk 切分是 RAG 的关键步骤之一,会影响检索效果。

3.依赖(requirements.txt)

langchain
faiss-cpu
sentence-transformers
openai
tqdm

安装:

pip install -r requirements.txt

4. 核心代码(main.py)

直接复制运行👇

import os
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import FAISS
from langchain.embeddings import HuggingFaceEmbeddings
from openai import OpenAI

# ========= 1. 配置 =========
os.environ["OPENAI_API_KEY"] = "你的API_KEY"
client = OpenAI()

# ========= 2. 读取数据 =========
with open("data.txt", "r", encoding="utf-8") as f:
text = f.read()

# ========= 3. 切分 =========
splitter = RecursiveCharacterTextSplitter(
chunk_size=300,
chunk_overlap=50
)
docs = splitter.split_text(text)

# ========= 4. 向量化 =========
embedding = HuggingFaceEmbeddings(
model_name="BAAI/bge-small-zh"
)

# ========= 5. 建库 =========
db = FAISS.from_texts(docs, embedding)

# ========= 6. RAG函数 =========
def ask(query):
# 检索
results = db.similarity_search(query, k=3)

# 拼上下文
context = "\n".join([r.page_content for r in results])

# Prompt
prompt = f"""
你是一个专业助手,请基于上下文回答问题。

上下文:
{context}

问题:
{query}

要求:
- 只基于上下文回答
- 不要编造
"""

# 调用大模型
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": prompt}
]
)

return response.choices[0].message.content


# ========= 7. 交互 =========
if __name__ == "__main__":
while True:
q = input("\n请输入问题:")
print("\n回答:", ask(q))

5.运行

python main.py

输入:

RAG 是什么?

你会得到一个基于你 data.txt 的回答。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐