RAG(检索增强生成)是解决大模型知识时效性、领域专业性问题的核心方案,LangChain 擅长流程编排、LlamaIndex 专精数据索引与检索,二者结合能高效构建企业级 RAG 知识库。本文从环境搭建、数据加载、索引构建、检索增强到生成回答,完整讲解落地流程。

一、核心概念与技术栈说明
第一安装核心依赖包,提议使用Python 3.9 + 版本:
# 核心依赖
pip install langchain langchain-community langchain-openai llama-index chromadb python-dotenv
# 文档解析依赖(按需安装)
pip install pypdf python-docx markdown2 # 支持PDF/Word/Markdown
# 可选:中文分词增强(针对中文场景)
pip install jieba
二、基础配置(密钥与模型初始化)
创建.env文件配置敏感信息,避免硬编码:
# OpenAI密钥(替换为自己的)
OPENAI_API_KEY=your-openai-api-key
# 可选:如果使用国内代理(如OpenAI接口代理)
OPENAI_BASE_URL=https://api.openai-proxy.com/v1
初始化大模型、Embedding模型(向量编码):
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from llama_index.core import Settings
# 加载环境变量
load_dotenv()
# 1. 配置LangChain大模型
llm_langchain = ChatOpenAI(
model_name="gpt-3.5-turbo",
temperature=0.1, # 越低回答越精准
api_key=os.getenv("OPENAI_API_KEY"),
base_url=os.getenv("OPENAI_BASE_URL")
)
# 2. 配置LlamaIndex全局设置(复用LangChain的Embedding/LLM)
Settings.llm = llm_langchain
Settings.embed_model = OpenAIEmbeddings(
api_key=os.getenv("OPENAI_API_KEY"),
base_url=os.getenv("OPENAI_BASE_URL")
)
Settings.chunk_size = 512 # 文本分块大小(中文提议512-1024)
Settings.chunk_overlap = 50 # 分块重叠长度(避免上下文断裂)

三、数据加载与预处理(LlamaIndex核心)
LlamaIndex提供丰富的Reader类,支持本地文档、网页、数据库等数据源,这里以本地文档(PDF/Word/Markdown)为例:
1. 加载多类型文档
from llama_index.core import SimpleDirectoryReader
from llama_index.core.node_parser import SentenceSplitter
# 1. 加载指定目录下的所有文档(自动识别PDF/Word/MD等)
# 文档存放路径:./docs(需提前创建,放入测试文档)
reader = SimpleDirectoryReader(
input_dir="./docs",
recursive=True, # 递归读取子目录
required_exts=[".pdf", ".docx", ".md"], # 仅加载指定格式
)
documents = reader.load_data()
print(f"加载文档数量:{len(documents)}")
# 2. 文本分块(核心步骤:解决大模型上下文限制)
parser = SentenceSplitter(
chunk_size=Settings.chunk_size,
chunk_overlap=Settings.chunk_overlap,
# 中文分词增强(可选)
separator="。!?;,
",
)
# 将文档切分为Node(LlamaIndex的基础数据单元)
nodes = parser.get_nodes_from_documents(documents)
print(f"文档分块数量:{len(nodes)}")
2. 自定义数据加载(可选)
如果需要加载非标准格式数据(如数据库、API),可自定义Document:
from llama_index.core import Document
# 自定义文本数据
custom_text = "LangChain与LlamaIndex结合构建RAG的核心是检索精准性..."
custom_doc = Document(
text=custom_text,
metadata={"source": "自定义文档", "date": "2026-01-04"} # 元数据增强检索
)
nodes.extend(parser.get_nodes_from_documents([custom_doc]))
四、构建向量索引(LlamaIndex + Chroma)
LlamaIndex支持多种索引类型,VectorStoreIndex(向量索引)是RAG的核心,结合Chroma向量数据库实现持久化存储:
1. 构建并保存索引
from llama_index.core import VectorStoreIndex
from llama_index.vector_stores.chroma import ChromaVectorStore
from chromadb.config import Settings as ChromaSettings
import chromadb
# 1. 初始化Chroma客户端(持久化存储到本地)
chroma_client = chromadb.PersistentClient(
path="./chroma_db", # 向量库存储路径
settings=ChromaSettings(
anonymized_telemetry=False, # 关闭遥测
is_persistent=True
)
)
# 2. 创建/获取Chroma集合
chroma_collection = chroma_client.get_or_create_collection("rag_knowledge_base")
# 3. 将LlamaIndex与Chroma绑定
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
# 4. 构建向量索引(将Node转为向量并存储)
index = VectorStoreIndex(
nodes=nodes,
vector_store=vector_store,
embed_model=Settings.embed_model
)
# 5. 保存索引(可选,Chroma已自动持久化)
index.storage_context.persist(persist_dir="./llama_index_storage")
2. 加载已保存的索引(后续使用)
无需重复构建索引时,直接加载:
from llama_index.core import StorageContext, load_index_from_storage
# 加载Chroma向量库
chroma_client = chromadb.PersistentClient(path="./chroma_db")
chroma_collection = chroma_client.get_collection("rag_knowledge_base")
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
# 加载LlamaIndex存储上下文
storage_context = StorageContext.from_defaults(
vector_store=vector_store,
persist_dir="./llama_index_storage"
)
# 加载索引
index = load_index_from_storage(storage_context=storage_context)

五、构建RAG检索链(LangChain + LlamaIndex)
结合LangChain的流程编排能力与LlamaIndex的精准检索,实现“检索→格式化→生成”的完整RAG 流程:
1. LlamaIndex检索器接入LangChain
from langchain_core.retrievers import BaseRetriever
from langchain_core.callbacks import CallbackManagerForRetrieverRun
from typing import List
from llama_index.core.query_engine import RetrieverQueryEngine
# 1. 将LlamaIndex索引转为LangChain兼容的检索器
class LlamaIndexRetriever(BaseRetriever):
def __init__(self, index: VectorStoreIndex, top_k: int = 3):
self.index = index
self.top_k = top_k
# 创建LlamaIndex检索器
self.llama_retriever = index.as_retriever(similarity_top_k=top_k)
def _get_relevant_documents(
self, query: str, *, run_manager: CallbackManagerForRetrieverRun
) -> List:
# 调用LlamaIndex检索,转换为LangChain Document格式
nodes = self.llama_retriever.retrieve(query)
langchain_docs = []
for node in nodes:
langchain_docs.append(
{
"page_content": node.text,
"metadata": node.metadata
}
)
return langchain_docs
# 初始化检索器(返回Top3相关文档)
retriever = LlamaIndexRetriever(index=index, top_k=3)
2. 构建LangChain RAG链
使用create_retrieval_chain实现 “检索→格式化提示词→生成回答” 的标准化流程:
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnablePassthrough
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
# 1. 定义Prompt模板(核心:引导大模型基于检索结果回答)
prompt = ChatPromptTemplate.from_messages([
("system", """你是专业的知识库问答助手,仅基于提供的参考文档回答问题。
参考文档:
{context}
如果参考文档中没有相关信息,请明确说明“未找到相关答案”,不要编造内容。"""),
MessagesPlaceholder(variable_name="chat_history"), # 支持多轮对话
("user", "{input}"),
])
# 2. 创建文档合并链(将检索结果填入Prompt)
combine_docs_chain = create_stuff_documents_chain(llm_langchain, prompt)
# 3. 创建完整RAG链
rag_chain = create_retrieval_chain(
retriever,
combine_docs_chain
)
六、RAG问答调用与多轮对话
1. 单次问答调用
# 提问(替换为你的知识库问题)
question = "LangChain与LlamaIndex结合构建RAG的核心步骤是什么?"
# 调用RAG链
response = rag_chain.invoke({
"input": question,
"chat_history": [] # 首次对话无历史
})
# 输出结果
print("=== 回答 ===")
print(response["answer"])
print("
=== 参考文档 ===")
for i, doc in enumerate(response["context"], 1):
print(f"
【参考{i}】")
print(f"内容:{doc['page_content'][:200]}...") # 截断显示
print(f"来源:{doc['metadata'].get('source', '未知')}")
2. 多轮对话支持
基于chat_history维护对话上下文,实现多轮交互:
# 初始化对话历史
chat_history = []
# 第一轮对话
q1 = "RAG中的向量索引有什么作用?"
r1 = rag_chain.invoke({"input": q1, "chat_history": chat_history})
print(f"Q1: {q1}
A1: {r1['answer']}
")
# 更新对话历史
chat_history.extend([
("user", q1),
("assistant", r1["answer"])
])
# 第二轮对话(基于历史上下文)
q2 = "如何优化向量索引的检索精准性?"
r2 = rag_chain.invoke({"input": q2, "chat_history": chat_history})
print(f"Q2: {q2}
A2: {r2['answer']}")
七、进阶优化策略
1. 检索增强
混合检索:结合关键词检索(BM25)+ 向量检索,提升召回率
from llama_index.core.retrievers import BM25Retriever
from llama_index.core.retrievers import QueryFusionRetriever
# 构建BM25检索器
bm25_retriever = BM25Retriever.from_defaults(
nodes=nodes,
similarity_top_k=3
)
# 融合向量检索与BM25检索
fusion_retriever = QueryFusionRetriever(
[retriever.llama_retriever, bm25_retriever],
similarity_top_k=3,
num_queries=1 # 生成1个扩展查询
)
元数据过滤:基于文档来源、日期等元数据缩小检索范围
# 仅检索2026年的文档
retriever.llama_retriever = index.as_retriever(
similarity_top_k=3,
filters={"date": ["2026-01-04"]}
)
2. 中文优化
- 使用中文Embedding模型(如智谱 AI、百度文心)替换OpenAI Embedding
- 优化中文分词:自定义SentenceSplitter的分隔符,结合jieba分词
3. 大模型替换
如需使用国产大模型(如通义千问、文心一言),只需替换LangChain的LLM:
# 示例:替换为通义千问
from langchain_community.chat_models import ChatTongyi
llm_langchain = ChatTongyi(
model_name="qwen-turbo",
temperature=0.1,
api_key="your-tongyi-api-key"
)
Settings.llm = llm_langchain # 更新LlamaIndex全局LLM
八、部署与运维
1. 索引更新
当知识库文档新增/修改时,重新加载文档并更新索引:
# 加载新文档
new_docs = SimpleDirectoryReader(input_dir="./new_docs").load_data()
new_nodes = parser.get_nodes_from_documents(new_docs)
# 向现有索引添加新节点
index.insert_nodes(new_nodes)
2. 性能优化
- 调整chunk_size:中文提议 512-1024,过大会降低检索精准性,过小会丢失上下文
- 向量库优化:Chroma可配置持久化/分片/生产环境可替换为Milvus/Pinecone
- 缓存:对高频查询结果缓存,减少大模型调用次数
九、常见问题解决
- 检索结果为空:检查文档分块是否合理、Embedding模型是否匹配、查询词是否与文档相关
- 回答偏离知识库:优化Prompt分词模板,增加 “仅基于参考文档回答” 的强约束
- 中文检索效果差:替换为中文Embedding模型,优化分词规则
- 索引构建慢:批量处理文档,或使用GPU加速Embedding 计算
总结
基于LangChain(流程编排)+ LlamaIndex(数据索引)构建完整的RAG知识库,核心流程为:数据加载→分块→向量索引构建→检索→Prompt 格式化→大模型生成。该方案可适配本地文档、多模态数据、国产大模型,满足企业级知识库的核心需求。如需进一步扩展,可结合 API 封装、前端界面、权限控制等模块,形成完整的知识库问答系统。





