RAG 从入门到实战:文本切分、向量检索、多模态,一篇文章打通全流程

RAG 从入门到实战:文本切分、向量检索、多模态,一篇文章打通全流程

导语

如果你正在搭建一个知识库问答系统、客服机器人,或者让大模型「学会」你的内部文档,那 RAG(Retrieval-Augmented Generation)是你绕不开的技术栈。过去一年里,RAG 从一个研究概念变成了落地标配——2025 年的行业调研数据显示,超过 70% 的 LLM 应用在生产环境中采用了 RAG 架构。这篇文章从最基础的概念讲起,一路走到多模态 RAG 和线上部署,包含可以直接运行的代码。

这篇文章适合谁看

有 Python 基础、了解基本的大模型 API 调用,想从零搭建一个自己的 RAG 系统。

读完这篇文章你能做到的:

理解 RAG 的完整工作流程——从用户提问到答案返回,每一步在做什么、为什么这么做

掌握 5 个核心组件的选型逻辑——文本切分用多细、向量模型用哪个、数据库选什么、检索怎么召回、大模型选哪个

拿到一份可以直接运行的代码——基于 LangChain + Chroma + DeepSeek/Qwen,覆盖文档加载、切分、向量化、检索、生成的完整链路

了解多模态 RAG 的落地方式——图片搜索、图文联合检索、视觉问答等进阶玩法

看完这篇文章你仍然不会熟悉的:分布式 RAG 系统调优、大规模(千万级)向量集群运维、RAG 评估框架的具体搭建。这些话题每个都可以单独写一篇,本文先把单机可跑的全流程打通。

RAG 解决了什么问题

大模型有两个天生的短板:一是知识截止于训练数据的时间点,二是遇到不知道的事情会「编造」答案(幻觉)。RAG 的思路很直接——不给模型凭空发挥的机会。每次用户提问时,先从外部知识库检索相关信息,把这些信息作为上下文注入到提示词里,再让模型基于这些材料回答。

一个经典的比喻:RAG 就像给大模型开卷考试。模型不需要把所有知识背下来,只需要知道去哪里找答案、怎么组织找到的材料。

过去三年 RAG 的演进其实反映了整个行业对 LLM 应用的理解变化:

2023 — 朴素 RAG:文档切碎、向量化、相似度检索、拼进 Prompt。能用,但很容易搜到不相关的内容,答案质量随缘。

2024 — 模块化 RAG:加了查询改写、重排序、Hybrid 检索、多轮对话管理。每一步都可以独立优化,效果稳定很多。

2025 — 多模态 + Agentic RAG:支持图片、表格、代码等非文本数据的检索和生成。RAG 不再只是「文本搜文本」,而是多模态信息的一个路由层。

RAG 核心流程拆解

整个 RAG 流程可以拆成两条线:

索引线(离线):文档 → 切分 Chunks → 向量化 Embedding → 存入向量数据库。这条线只在首次搭建或文档更新时跑一次。

查询线(在线):用户提问 → 向量检索 → 召回结果重排序 → 组装 Prompt → 大模型生成回答。这条线每次用户提问都会走一遍。

两条线分开看,每条线上的组件都可以独立选型和优化。下面从索引线开始,逐个拆解。

文本切分——RAG 的第一道关卡

文本怎么切是 RAG 系统里最容易忽视、但影响最大的环节。切得太碎,语义不完整;切得太粗,一条 Chunk 包含太多无关信息,检索噪音大。

实践中常用的几种切分策略:

固定长度切分:按字符或 Token 数硬切,比如每 512 个字符一段。简单直接,但会在句子中间断开,破坏语义完整性。通常设 10%-15% 的重叠(Overlap)来缓解断句问题。

递归字符切分:按\n\n\n→ 句号 → 分号的优先级逐级回退。这是 LangChain 默认的切分方式,能在大部分场景下保持段落和句子的完整性。推荐 Chunk Size 设为 500-1000,Overlap 100-200。

语义切分:通过嵌入向量的相似度变化来判断话题边界。当连续两个句子的向量夹角超过某个阈值时,认为话题切换了。这种方式更智能,但需要额外的模型推理开销。

Late Chunking(延迟切分):先对整个文档做向量化,再切分,让每个 Chunk 保留全局上下文信息。这种方法在 2024 年底的 Cohere 论文中被提出,实测在长文档检索上有明显提升,缺点是推理成本更高。

选型上没有银弹。技术类文档(代码、API 文档)建议用 500-800 字符的递归切分,自然语言文档(报告、文章)建议用 800-1200 字符的语义切分。如果文档格式统一(PDF、Markdown),优先按标题层级结构切分,效果通常比纯文本切分好一个档次。

向量模型选型——谁把文字变成了坐标

选向量模型的核心指标有两个:检索质量和推理性能。不同语言的模型差异很大,中文场景不要直接套英文模型。

当前主流方案:

BGE(BAAI):BAAI 出品的系列模型,中文场景首选。BGE-large-zh-v1.5 在 MTEB(中文)上长期占据前排,768 维,支持 512 Token 输入,推理速度适中。适合绝大多数中文 RAG 场景。

BCE(maidalun1020):专门针对中文和代码场景优化的 BERT 类模型。在中文检索任务上对 BGE 系列有一定优势,参数量更小,推理更快。如果文档以代码和技术文档为主,BCE 是值得优先试的选项。

text-embedding-3-small(OpenAI):1536 维,API 调用,不需要本地 GPU。缺点是每次检索都要走网络、有 API 成本,但嵌入质量很稳定。适合英文或双语场景,中文不如 BGE/BCE。

GTE(Alibaba):阿里出品的多语言 Embedding 模型,GTE-Qwen2 在 C-MTEB 上表现很好。与通义系列模型配合使用有加成。

模型中文质量向量维度输入长度推荐场景
BGE-large-zh-v1.5⭐⭐⭐⭐⭐768512通用中文 RAG
BCE-embedding-base_v1⭐⭐⭐⭐⭐768512中文 + 代码
text-embedding-3-small⭐⭐⭐⭐512-15368192双语/纯英文
GTE-Qwen2⭐⭐⭐⭐⭐768-20488192多语言长文档

选型建议:中文项目默认从 BGE-large-zh-v1.5 起步。如果文档以代码为主,换成 BCE。如果预算允许且需要处理超长文档(超过 512 Token),GTE-Qwen2 支持 8192 Token 输入是杀手级特性。

向量数据库选型——检索背后的基础设施

向量数据库存储 Embedding 向量并提供近似最近邻(ANN)检索。不同的库在部署复杂度、性能、成本上差异很大。

方案部署方式适合规模Filter 支持推荐场景
Chroma嵌入式≤ 100 万基础开发原型、个人项目
MilvusDocker 集群亿级丰富生产环境、大规模
QdrantDocker 单机/集群千万级丰富中小型生产、Rust 高性能
PineconeSaaS亿级丰富不想运维、预算充足的团队
PGVectorPostgreSQL 插件≤ 50 万原生 SQL已有 PG、数据结构化

选型建议:刚开始做原型用 Chroma,零配置、零运维,pip install 就能跑。进入生产阶段,数据量在百万级以内且团队熟悉 Docker,上 Qdrant;数据量大(千万级以上),上 Milvus。不想管运维,Pinecone。如果团队已经重度使用 PostgreSQL,PGVector 是最省事的选择。

检索召回策略——如何找到最相关的内容

把文档切碎、向量化、存进数据库之后,最关键的问题来了:用户问一个问题,怎么从成千上万条 Chunks 里找到最相关的那几条?

纯向量检索(Dense Retrieval):把用户问题用同样的向量模型编码,去向量数据库里做 ANN 搜索。最常用,但依赖向量模型的质量,对语义相近但表达方式不同的 Query 容易漏检。

稀疏检索(Sparse Retrieval):用 BM25 之类的关键词匹配算法检索。优点是精确匹配强,对专有名词、缩写、产品名效果好。缺点是语义理解为零。好消息是稀疏检索和向量检索可以互补。

Hybrid 检索:把向量检索和 BM25 的结果合并,用加权平均或 RRF(Reciprocal Rank Fusion)做融合。权重分配上,技术文档场景建议 BM25 权重高一些(0.4-0.5),因为专有名词匹配很重要;开放域问答场景向量检索权重高一些(0.6-0.7)。

重排序(Reranking):Hybrid 检索可能召回 20-50 条结果,但大模型的上下文窗口放不下这么多。重排序是用一个专门的 Cross-Encoder 模型对这几十条结果逐一打分,选出最相关的 top-K 条交给大模型。这是 RAG 系统中性价比最高的优化——加一个 Reranker 通常能把答案准确率提升 5-15 个百分点,而推理成本只增加几毫秒。

推荐方案:BGE-reranker-v2-m3(中文)、Cohere Rerank 3(英文)、BCE-reranker-base_v1(中文+代码)。

查询改写(Query Rewriting):用户的问题通常很简短,像「报销流程是什么」「怎么部署」,直接拿去检索效果不好。查询改写在把原始问题交给检索系统之前,先让大模型做一次扩展——把问题补充完整、拆成多个子问题、或者用同义词扩展。这是 Multi-Step RAG 的核心套路之一。

大模型选型——生成质量的最后一道关

RAG 的生成质量取决于两个因素:检索到的内容是否相关,以及大模型是否能基于这些内容正确生成。

用闭源模型还是开源模型,可以从三个维度权衡:

上下文长度:长上下文的模型能接受更多的检索结果。Claude(200K)、GPT-4o(128K)、DeepSeek-V3(128K)都支持一次塞入大量资料。开源的 Qwen2.5-72B(128K)和 GLM-4-9B(128K)也追上了。建议选 128K+ 的模型,这样 Reranker 之后可以放心地保留 15-20 条 Chunks。

指令遵循能力:RAG 场景下模型需要严格「只看提供的材料,不要自己编」。指令遵循能力弱的模型容易无视检索结果,自己发挥。Claude Sonnet 和 GPT-4o 在这方面的表现最好,开源的 DeepSeek-V3 和 Qwen2.5-72B 紧随其后。

中文能力:中文场景下 DeepSeek 和通义千问系列是最稳妥的选择。DeepSeek-V3 在中文知识问答上甚至能和 GPT-4o 打平,API 价格低一个数量级。

选型建议:个人/小团队做 RAG 原型,用 DeepSeek API(便宜、中文好、128K 上下文)。生产环境且预算充足,Claude 或 GPT-4o。需要私有化部署,Qwen2.5-72B 或 DeepSeek-V3 本地跑。

从零搭建 RAG 系统——完整代码实战

下面用 Python 跑通一个完整的 RAG 流水线:文档加载 → 文本切分 → 向量化 → 存入 Chroma → 检索 → 生成回答。

项目结构:

text

rag-demo/├── .env # API Key 配置├── ingest.py # 索引线:文档处理 + 入库├── query.py # 查询线:检索 + 生成├── requirements.txt # 依赖└── data/ # 源文档目录

安装依赖

bash

pip install langchain langchain-community langchain-chroma chromadb sentence-transformers python-dotenv

配置 .env

text

# 选用的 Embedding 模型,默认用 BGEEMBEDDING_MODEL=BAAI/bge-large-zh-v1.5# LLM API 配置(用 DeepSeek 示例)LLM_API_KEY=your_deepseek_api_keyLLM_BASE_URL=https://api.deepseek.comLLM_MODEL=deepseek-chat

索引线:文档处理与入库

python

# ingest.pyimport osfrom dotenv import load_dotenvfrom langchain_community.document_loaders import DirectoryLoader, TextLoaderfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom langchain_community.embeddings import HuggingFaceBgeEmbeddingsfrom langchain_chroma import Chromaload_dotenv()# 1. 加载文档loader = DirectoryLoader( "./data", glob="**/*.md", loader_cls=TextLoader, loader_kwargs={"encoding": "utf-8"})docs = loader.load()print(f"加载了 {len(docs)} 个文档")# 2. 文本切分text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=100, separators=["\n\n", "\n", "。", ";", ",", " ", ""], length_function=len)chunks = text_splitter.split_documents(docs)print(f"切分为 {len(chunks)} 个 Chunks")# 3. 初始化 Embedding 模型model_name = os.getenv("EMBEDDING_MODEL", "BAAI/bge-large-zh-v1.5")embeddings = HuggingFaceBgeEmbeddings( model_name=model_name, model_kwargs={"device": "cpu"}, encode_kwargs={"normalize_embeddings": True})# 4. 存入 Chromapersist_dir = "./chroma_db"vector_store = Chroma.from_documents( documents=chunks, embedding=embeddings, persist_directory=persist_dir)print(f"向量库已持久化到 {persist_dir}")

查询线:检索与生成

python

# query.pyimport osfrom dotenv import load_dotenvfrom langchain_community.embeddings import HuggingFaceBgeEmbeddingsfrom langchain_chroma import Chromafrom openai import OpenAIload_dotenv()# 加载向量库model_name = os.getenv("EMBEDDING_MODEL", "BAAI/bge-large-zh-v1.5")embeddings = HuggingFaceBgeEmbeddings( model_name=model_name, model_kwargs={"device": "cpu"}, encode_kwargs={"normalize_embeddings": True})vector_store = Chroma( persist_directory="./chroma_db", embedding_function=embeddings)# 初始化 LLMclient = OpenAI( api_key=os.getenv("LLM_API_KEY"), base_url=os.getenv("LLM_BASE_URL"))def rag_query(question: str, k: int = 5) -> str: # 检索 results = vector_store.similarity_search(question, k=k) contexts = "\n\n".join([doc.page_content for doc in results]) # 组装 Prompt prompt = f"""你是一个知识库问答助手。请基于以下资料回答问题。如果资料中没有相关信息,请直接说不知道。资料:{contexts}问题:{question}请基于以上资料回答:""" # 生成 response = client.chat.completions.create( model=os.getenv("LLM_MODEL", "deepseek-chat"), messages=[{"role": "user", "content": prompt}], temperature=0.3, max_tokens=2048 ) return response.choices[0].message.contentif __name__ == "__main__": while True: q = input("\n请输入问题(输入 q 退出):") if q.lower() == "q": break answer = rag_query(q) print(f"\n回答:\n{answer}")

大功告成。把文档放进data/目录,跑一次python ingest.py建库,然后python query.py就能开始问答了。

加入 Hybrid 检索和 Reranker

基础版跑通之后,加 Hybrid 和 Reranker 是投入产出比最高的升级。

bash

pip install rank-bm25

python

# 在 query.py 中添加 Hybrid 检索 + Rerankerfrom typing import Listfrom langchain_chroma import Chromafrom rank_bm25 import BM25Okapiimport jiebadef hybrid_search(question: str, k: int = 20) -> List[str]: # Dense 检索 dense_results = vector_store.similarity_search(question, k=k) dense_texts = [doc.page_content for doc in dense_results] # Sparse 检索(BM25) tokenized_docs = [list(jieba.cut(doc.page_content)) for doc in dense_results] bm25 = BM25Okapi(tokenized_docs) tokenized_query = list(jieba.cut(question)) bm25_scores = bm25.get_scores(tokenized_query) sparse_indices = sorted( range(len(bm25_scores)), key=lambda i: bm25_scores[i], reverse=True )[:k] sparse_texts = [dense_texts[i] for i in sparse_indices] # RRF 融合 all_texts = list(dict.fromkeys(dense_texts + sparse_texts)) return all_texts[:k]# 用 Cross-Encoder 重排序from sentence_transformers import CrossEncoderreranker = CrossEncoder("BAAI/bge-reranker-v2-m3")def rerank(query: str, candidates: List[str], top_k: int = 5) -> List[str]: pairs = [[query, doc] for doc in candidates] scores = reranker.predict(pairs) ranked = sorted(zip(candidates, scores), key=lambda x: x[1], reverse=True) return [doc for doc, _ in ranked[:top_k]]

把这段加入后,rag_query函数里的检索替换为rerank(question, hybrid_search(question, k=20), top_k=5),答案质量会有明显提升。

⚠️ **Reranker 显存占用** Cross-Encoder 模型推理比 Bi-Encoder 慢,而且显存消耗随候选文档数量线性增长。如果 CPU 推理,建议候选数不超过 30 条,单条不超过 512 Token。有 GPU 的话,BGE-reranker-v2-m3 在 FP16 下显存占用不到 2GB。

进阶:多模态 RAG

文本 RAG 跑通之后,下一个方向是让系统理解图片、表格、甚至是音视频。

两种实现路径

路径一:图文统一嵌入。用多模态 Embedding 模型(如 CLIP、SigLIP、Nomic Embed Vision)把图片和文本映射到同一个向量空间。检索时用户的文本 Query 可以直接匹配图片。适用于「按语义搜图片」的场景。

路径二:先提取后检索。用 VLM(视觉语言模型,如 GPT-4o、Qwen-VL、CogVLM2)把图片转成文字描述,然后走标准文本 RAG 流程。适用于「基于图文混合文档做问答」的场景,比如产品手册中既有文字说明又有示意图。

两种路径的实际结合方案在 2025 年逐渐成熟——先用多模态 Embedding 做粗筛,再用 VLM 做细读。比如用户问「这张架构图里的数据库层用了什么技术」,粗筛找出相关图片,细读让 VLM 仔细解读图片内容。

python

# 多模态 RAG:图片转文字后检索from openai import OpenAIimport base64client = OpenAI(api_key="...")def image_to_text(image_path: str) -> str: with open(image_path, "rb") as f: img_b64 = base64.b64encode(f.read()).decode() response = client.chat.completions.create( model="gpt-4o", messages=[{ "role": "user", "content": [ {"type": "text", "text": "请详细描述这张图片的内容,列出所有关键文字元素"}, {"type": "image_url", "image_url": { "url": f"data:image/png;base64,{img_b64}" }} ] }] ) return response.choices[0].message.content# 对每张图片生成文字描述,与文本 Chunks 一起索引# 检索时同时搜文本和图片描述,流程不变

部署上线

把 RAG 系统包装成一个可调用的 API 服务,用 FastAPI 最直接。

python

# api.pyfrom fastapi import FastAPI, Queryfrom pydantic import BaseModelfrom query import rag_queryapp = FastAPI(title="RAG API")class QueryRequest(BaseModel): question: str top_k: int = 5class QueryResponse(BaseModel): question: str answer: str@app.post("/rag", response_model=QueryResponse)async def ask(request: QueryRequest): answer = rag_query(request.question, k=request.top_k) return QueryResponse(question=request.question, answer=answer)@app.get("/health")async def health(): return {"status": "ok"}

启动服务:

bash

pip install fastapi uvicornuvicorn api:app --host 0.0.0.0 --port 8000

调用方式:

bash

curl -X POST http://localhost:8000/rag \ -H "Content-Type: application/json" \ -d '{"question": "报销流程是什么", "top_k": 5}'

Docker 部署

dockerfile

FROM python:3.11-slimWORKDIR /appCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txtCOPY . .# Chroma 持久化目录、模型缓存需要持久卷VOLUME ["/app/chroma_db", "/root/.cache"]CMD ["uvicorn", "api:app", "--host", "0.0.0.0", "--port", "8000"]

bash

docker build -t rag-demo .docker run -d -p 8000:8000 -v ./chroma_db:/app/chroma_db rag-demo

⚠️ **模型加载时间** HuggingFace 模型首次加载会下载权重,镜像启动后可能需要 1-3 分钟才能响应第一个请求。建议用VOLUME持久化/root/.cache/目录,避免每次重启都重新下载。

避坑指南

⚠️ **Chunk Size 过大或过小** Chunk Size 设到 2000+,一条 Chunk 包含三四段内容,检索命中率看起来高,但送入 LLM 的上下文噪声太大,答案反而变差。Chunk Size 小于 200,语义碎片化严重,LLM 接不上上下文。500-800 字符是不容易出错的安全区间。

⚠️ **中文场景用英文 Embedding 模型** 用text-embedding-ada-002all-MiniLM-L6-v2做中文 RAG,中文检索准确率会掉 10-20 个百分点。中文文本先做分词再送入 BGE 或 BCE,效果比直接送入 OpenAI 的英文 Embedding 好很多。

⚠️ **只有 Dense 检索,没有 Reranker** 向量检索召回 top-10 的结果里,排第三的可能比排第五的更适合。Reranker 可以用 Cross-Encoder 做更精确的语义匹配,把真正相关的结果顶到前面。不加 Reranker,生成质量完全取决于向量模型的排序能力,没有纠错机制。

⚠️ **检索结果直接拼入 Prompt,不做筛选** 如果一条 Chunks 和问题完全无关,但被召回了,LLM 可能会被「带偏」。用 Reranker 设一个置信度阈值,低于阈值的 Chunks 直接丢弃。如果最终有效上下文不足,让 LLM 回答"资料中没有相关信息",而不是强行编造。

⚠️ **上下文窗口塞满 Chunks** 模型有 128K 上下文,不代表要把 128K 都用完。实测经验:将 top-5 到 top-10 条精排后的 Chunks 送入模型,质量标准控制在 4000-6000 Token 以内,生成效果最稳定。上下文塞得越满,模型越容易在无关细节中迷失。

总结

两句话:RAG 不是把文档切碎塞进向量库就完事了。文本怎么切、向量模型选哪个、检索出来怎么重排、最终怎么组装 Prompt,每一层的选择都会影响最终效果。从 BGE + Chroma + 500 字 Chunk 起步,加上 Hybrid 检索和 Reranker,这套组合能覆盖绝大多数知识库问答场景。多模态 RAG 的门槛正在快速降低,图文统一检索的方向值得持续关注。

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费