
大模型在生成信息时可能出现幻觉问题,生成看似合理但实际错误或不存在的内容,同时,模型存在知识边界限制,其知识受限于训练数据的时间截点和覆盖范围,无法获取实时信息或特定领域深度知识。为解决这些问题,通常采用检索增强生成(RAG)技术,结合外部知识库实时检索来修正和补充模型知识;通过提示工程明确约束生成范围;建立事实核查和置信度评估机制。
这些方法显著提升了生成内容的准确性和可靠性,扩展了模型的实际应用边界,而 LlamaIndex 与 LangChain 作为 RAG 生态的两大核心工具,前者擅长文档索引与语义检索,后者强于 LLM 工作流编排与提示工程。传统 RAG 实践多依赖 OpenAI 等云端模型,存在数据安全风险与 API 成本问题;今天我们还是以本地化 Qwen1.5-1.8B-Chat 模型为基座,通过两个递进式示例,深度解析 LlamaIndex 与 LangChain 的集成逻辑,从极简版 “功能验证” 到生产级 “工程化落地”,揭示这两个框架如何各司其职、协同增效,构建全本地化、高可控的智能文档问答系统。

LlamaIndex:
LangChain:
LlamaIndex 与 LangChain 的集成遵循 “分工协作” 原则:
两者通过 “检索结果(上下文文本)” 完成数据流转,形成 RAG 闭环。
我们结合两个示例,由浅入深、循序渐进的差异化讲解设计逻辑和价值体现
1.1 基础定位

本地化 RAG 实现,聚焦 “快速验证核心流程”,剥离所有工程化冗余,仅保留 RAG 的核心闭环:文档加载→索引构建→上下文检索→LLM 生成回答。
1.2 核心功能
1.3 示例特点
2.1 基础定位

可落地的工程化版本,在示例 1 的基础上补充工程化能力,聚焦 “实用性、可复用性、稳定性”,适配真实场景下的 RAG 系统需求。
2.2 核心功能
2.3 示例特点
核心目标:
索引管理:
代码结构:
LlamaIndex 配置:
LangChain 能力:
交互方式:
扩展能力:
# 核心代码段
local_model_path = snapshot_download(MODEL_NAME, cache_dir=CACHE_DIR)
tokenizer = AutoTokenizer.from_pretrained(local_model_path, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
local_model_path, trust_remote_code=True, device_map="auto"
)关键分析:
# 配置本地Embedding(中文优化)
Settings.embed_model = HuggingFaceEmbedding(
model_name="D:/modelscope/hub/models/sentence-transformers/paraphrase-MiniLM-L6-v2",
model_kwargs={"device": "cpu"},
embed_batch_size=16
)3.1 简单版
# 索引构建(无持久化)
documents = SimpleDirectoryReader(input_dir="./docs").load_data()
index = VectorStoreIndex.from_documents(documents)
# 检索函数
def get_context(query):
retriever = index.as_retriever(similarity_top_k=3)
nodes = retriever.retrieve(query)
return "\n\n".join([node.text for node in nodes])特点:
3.2 升级版
# 索引管理函数(核心升级)
def build_or_load_index(doc_dir: str = "./docs", index_dir: str = "./storage"):
if not os.path.exists(index_dir):
documents = SimpleDirectoryReader(input_dir=doc_dir, recursive=True).load_data()
index = VectorStoreIndex.from_documents(documents)
index.storage_context.persist(persist_dir=index_dir) # 持久化
else:
storage_context = StorageContext.from_defaults(persist_dir=index_dir)
index = load_index_from_storage(storage_context) # 加载本地索引
return index
# 检索器优化
def get_optimized_retriever(index, top_k: int = 3):
retriever = VectorIndexRetriever(
index=index, similarity_top_k=top_k
# 可扩展:元数据过滤、相似度阈值等
)
return retriever特点:
4.1 简单版-手动拼接
# 提示模板
prompt = ChatPromptTemplate.from_messages([
("system", "仅根据上下文回答问题...上下文:{context}"),
("human", "{question}")
])
# 问答逻辑(手动调用)
def answer_question(question):
context = get_context(question)
final_prompt = prompt.format(context=context, question=question)
response = llm.invoke(final_prompt)
return response特点:
4.2 升级版-声明式链
# RAG链构建(核心升级)
def build_rag_chain(retriever):
def retrieve_context(query: str) -> str:
nodes = retriever.retrieve(query)
return "\n\n".join([node.text for node in nodes])
prompt = ChatPromptTemplate.from_messages([...]) # 增强指令约束
rag_chain = (
{"context": RunnablePassthrough() | retrieve_context, "question": RunnablePassthrough()}
| prompt
| langchain_llm
| StrOutputParser() # 输出解析为纯文本
)
return rag_chain特点:
升级版新增Settings.llm = HuggingFaceLLM(...),实现 LlamaIndex 直接调用本地 Qwen 模型,而非仅依赖 LangChain 的 LLM 封装,核心价值:
import os
from modelscope.hub.snapshot_download import snapshot_download
# LlamaIndex核心模块
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.core import Settings
# LangChain核心模块
from langchain_community.llms.huggingface_pipeline import HuggingFacePipeline
from langchain_core.prompts import ChatPromptTemplate
# HuggingFace模型加载
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
# ===================== 1. 本地Qwen模型配置(核心改造) =====================
# 模型信息
MODEL_NAME = "qwen/Qwen1.5-1.8B-Chat"
CACHE_DIR = "D:\\modelscope\\hub" # 模型下载/缓存目录
# 下载模型(首次运行自动下载,后续跳过)
print("正在加载/下载Qwen模型...")
local_model_path = snapshot_download(MODEL_NAME, cache_dir=CACHE_DIR)
# 加载Tokenizer和Model(适配Qwen1.5)
tokenizer = AutoTokenizer.from_pretrained(
local_model_path,
trust_remote_code=True,
cache_dir=CACHE_DIR
)
model = AutoModelForCausalLM.from_pretrained(
local_model_path,
trust_remote_code=True,
cache_dir=CACHE_DIR,
device_map="auto", # 自动分配GPU/CPU
torch_dtype="auto"
)
# 配置LlamaIndex本地Embedding(替代OpenAI Embedding)
Settings.embed_model = HuggingFaceEmbedding(
model_name="D:/modelscope/hub/models/sentence-transformers/paraphrase-MiniLM-L6-v2", # 中文轻量Embedding
model_kwargs={"device": "cpu"}
)
# ===================== 2. LlamaIndex:加载文档+构建索引 =====================
# 加载单个PDF/TXT文档(放入./docs目录)
documents = SimpleDirectoryReader(input_dir="./docs").load_data()
# 构建向量索引(自动分块+本地向量化)
index = VectorStoreIndex.from_documents(documents)
# ===================== 3. LlamaIndex:检索相关上下文 =====================
def get_context(query):
# 检索相似度前3的文档片段
retriever = index.as_retriever(similarity_top_k=3)
nodes = retriever.retrieve(query)
# 拼接上下文
return "\n\n".join([node.text for node in nodes])
# ===================== 4. LangChain:本地Qwen模型+提示模板 =====================
# 构建HF Pipeline(适配LangChain)
qwen_pipeline = pipeline(
"text-generation",
model=model,
tokenizer=tokenizer,
max_new_tokens=512, # 最大生成token数
temperature=0.1, # 生成随机性
top_p=0.95,
repetition_penalty=1.15,
device_map="auto"
)
# 封装为LangChain兼容的LLM
llm = HuggingFacePipeline(pipeline=qwen_pipeline)
# 提示模板(适配Qwen的指令格式)
prompt = ChatPromptTemplate.from_messages([
("system", "仅根据上下文回答问题,无相关信息则说“无法回答”。上下文:{context}"),
("human", "{question}")
])
# ===================== 5. 问答逻辑 =====================
def answer_question(question):
context = get_context(question)
# 组装提示并调用本地Qwen模型
final_prompt = prompt.format(context=context, question=question)
response = llm.invoke(final_prompt)
return response
# ===================== 6. 测试 =====================
if __name__ == "__main__":
query = "文档中提到的RAG核心步骤有哪些?"
print("问题:", query)
print("回答:", answer_question(query))import os
from dotenv import load_dotenv
from modelscope.hub.snapshot_download import snapshot_download
# LlamaIndex核心模块
from llama_index.core import (
SimpleDirectoryReader, VectorStoreIndex, StorageContext,
load_index_from_storage, Settings
)
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.llms.huggingface import HuggingFaceLLM # LlamaIndex适配HF模型
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
# LangChain核心模块
from langchain_community.llms.huggingface_pipeline import HuggingFacePipeline
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser
# HuggingFace模型加载
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
# ===================== 1. 本地模型配置(核心改造) =====================
# 模型信息
MODEL_NAME = "qwen/Qwen1.5-1.8B-Chat"
CACHE_DIR = "D:\\modelscope\\hub" # 模型下载目录
# 下载模型(首次运行自动下载,后续跳过)
print("开始下载/加载模型...")
local_model_path = snapshot_download(MODEL_NAME, cache_dir=CACHE_DIR)
print(f"模型本地路径:{local_model_path}")
# 加载Tokenizer和Model(适配Qwen1.5)
tokenizer = AutoTokenizer.from_pretrained(
local_model_path,
trust_remote_code=True,
cache_dir=CACHE_DIR
)
model = AutoModelForCausalLM.from_pretrained(
local_model_path,
trust_remote_code=True,
cache_dir=CACHE_DIR,
device_map="auto", # 自动分配GPU/CPU
torch_dtype="auto"
)
# ===================== 2. 全局配置 =====================
# LlamaIndex全局配置
Settings.chunk_size = 512 # 文档分块大小
Settings.chunk_overlap = 50 # 分块重叠
# 配置LlamaIndex的LLM为本地Qwen
Settings.llm = HuggingFaceLLM(
model=model,
tokenizer=tokenizer,
context_window=4096, # Qwen1.5-1.8B上下文窗口
max_new_tokens=512, # 最大生成token数
generate_kwargs={"temperature": 0.1}, # 生成参数
model_kwargs={"device_map": "auto"}
)
# 配置本地Embedding(中文优化)
Settings.embed_model = HuggingFaceEmbedding(
model_name="D:/modelscope/hub/models/sentence-transformers/paraphrase-MiniLM-L6-v2",
model_kwargs={"device": "cpu"},
embed_batch_size=16
)
# LangChain配置:将本地Qwen封装为LangChain LLM
# 构建HF Pipeline
qwen_pipeline = pipeline(
"text-generation",
model=model,
tokenizer=tokenizer,
max_new_tokens=512,
temperature=0.1,
top_p=0.95,
repetition_penalty=1.15,
device_map="auto"
)
# 封装为LangChain LLM
langchain_llm = HuggingFacePipeline(pipeline=qwen_pipeline)
# ===================== 3. 索引管理 =====================
def build_or_load_index(doc_dir: str = "./docs", index_dir: str = "./storage"):
"""构建或加载向量索引(避免重复构建)"""
if not os.path.exists(index_dir):
# 加载文档(支持PDF/TXT,递归读取)
reader = SimpleDirectoryReader(
input_dir=doc_dir,
required_exts=[".pdf", ".txt"],
recursive=True
)
documents = reader.load_data()
print(f"加载文档数量:{len(documents)}")
# 构建向量索引
index = VectorStoreIndex.from_documents(documents)
# 持久化索引到本地
index.storage_context.persist(persist_dir=index_dir)
print("索引构建并保存完成")
else:
# 加载本地索引
storage_context = StorageContext.from_defaults(persist_dir=index_dir)
index = load_index_from_storage(storage_context)
print("加载本地索引完成")
return index
# ===================== 4. 检索器配置 =====================
def get_optimized_retriever(index, top_k: int = 3):
"""获取优化的向量检索器"""
retriever = VectorIndexRetriever(
index=index,
similarity_top_k=top_k,
# 可选:元数据过滤(如只检索指定文档)
# filters=[MetadataFilter(key="source", value="example.pdf")]
)
return retriever
# ===================== 5. LangChain RAG链构建 =====================
def build_rag_chain(retriever):
"""构建本地化RAG链"""
# 检索上下文函数
def retrieve_context(query: str) -> str:
nodes = retriever.retrieve(query)
return "\n\n".join([node.text for node in nodes])
# 提示模板(适配Qwen的指令格式)
prompt = ChatPromptTemplate.from_messages([
("system", """
你是智能文档问答助手,严格遵循以下规则:
1. 仅使用提供的上下文回答用户问题;
2. 如果上下文没有相关信息,明确说明“无法从文档中找到相关答案”;
3. 回答简洁、准确,使用中文表述。
上下文:{context}
"""),
("human", "{question}")
])
# 构建RAG链
rag_chain = (
{"context": RunnablePassthrough() | retrieve_context, "question": RunnablePassthrough()}
| prompt
| langchain_llm
| StrOutputParser()
)
return rag_chain
# ===================== 6. 主函数(交互式问答) =====================
def main():
# 步骤1:构建/加载索引
index = build_or_load_index(doc_dir="./docs", index_dir="./storage")
# 步骤2:初始化检索器
retriever = get_optimized_retriever(index, top_k=3)
# 步骤3:构建RAG链
rag_chain = build_rag_chain(retriever)
# 步骤4:交互式问答
print("\n===== 本地化RAG问答系统(Qwen1.5-1.8B-Chat) =====")
print("输入 'exit' 退出问答")
while True:
query = input("\n请输入问题:")
if query.lower() == "exit":
print("退出系统...")
break
# 调用RAG链生成回答
try:
response = rag_chain.invoke(query)
print(f"\n回答:\n{response}")
except Exception as e:
print(f"回答生成失败:{str(e)}")
if __name__ == "__main__":
main()LlamaIndex 与 LangChain的深度集成,本质是专业工具做专业事的应用化实践:LlamaIndex 解决了 RAG 的数据处理与检索的痛点,LangChain 解决了LLM 调用与流程编排的痛点。今天我们通过两个递进式示例,从极简验证到生产级落地,完整展现了双工具集成的核心逻辑与本地化改造路径,既保留了 RAG 的核心价值解决 LLM 幻觉,又实现了全流程的本地化可控,为RAG 系统的落地提供了构建的思路,也可进行针对性的自定义优化以达到更精确的效果。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。