LangChain与Llama-Index联动:解锁多重检索RAG新技能
LangChain与Llama-Index联动:解锁多重检索RAG新技能
在RAG(Retrieval-Augmented Generation)架构中,如何同时利用多种检索方式,提升生成质量和检索覆盖面,是一个前沿话题。LangChain 作为引领 LLM 应用开发的框架,提供了丰富的链式调用和检索器适配;而 Llama-Index(又名 GPT Index)则专注于构建灵活、高效的索引结构,支持多种检索后端。本文将带你从原理到实战,讲解如何将 LangChain 与 Llama-Index 联动,打造一个“多重检索”RAG 系统,并配以代码示例、Mermaid 流程图和详细说明,帮助你快速上手。
目录
1. 背景与目标
在大规模文本库中,仅依赖单一的向量检索或全文检索,往往难以同时兼顾召回率与精确度。多重检索(Multi-Retrieval)通过将多种检索策略(如向量近邻检索+关键词匹配+实体索引等)组合起来,可以在兼顾语义召回的同时,也保证对准确性或时效性要求较高的场景表现更好。
场景示例
- 技术文档库:向量检索可召回相关度高的章节,全文检索可精准匹配关键代码片段。
- 常见问答库:向量检索能处理自然语言模糊查询,全文检索能保证针对“特定术语/编号”的定位。
- 知识库搜人:向量检索基于简介文本检索,全文检索则命中具体姓名或 ID。
目标:
- 使用 Llama-Index 构建多种索引(例如向量索引与树形索引、全文索引)。
- 在 LangChain 中同时引入这些检索器,通过融合策略获取多路检索结果。
- 将多路检索结果统一传给 LLM,提升 RAG 生成的准确度与丰富度。
2. 核心组件概览
2.1 LangChain 简介
LangChain 是目前最活跃的 LLM 应用框架之一,具备以下特点:
- 链式调用(Chain):将检索、LLM 生成、后处理等步骤用“链”串联起来。
- 丰富的检索器适配:内置对 OpenAI、Milvus、Weaviate、Chroma 等向量库的支持,也能对接自定义检索接口。
- 工具流程(Tool):可以把检索、问答、计算等功能做成“工具”,由 LLM 调度。
- Prompt 管理与记忆模块:支持将历史对话、检索结果等信息拼接到 Prompt 中。
简言之,LangChain 为我们提供了一个“可组合、可扩展”的 RAG 架构蓝图。
2.2 Llama-Index 简介
Llama-Index(又名 GPT Index)侧重于灵活索引结构的构建,并分离了“索引”与“查询”两大核心。其特色包括:
- 索引多样性:支持
GPTSimpleVectorIndex
(向量索引)、GPTTreeIndex
(树形索引)、GPTKeywordTableIndex
(关键词索引)、GPTListIndex
(列表索引)等。 - 抽象数据流:从原始文档 → 文本分割 → 索引构建 → 查询调用,每一步都对用户开放定制。
- 与向量数据库集成:可以将向量索引结果同步到 Milvus/ElasticSearch/FAISS 等。
- 可选全文检索插件:可以结合 ElasticSearch、Weaviate 等外部全文检索引擎。
Llama-Index 的定位是“让文档索引与查询变得一行代码可调用”,非常适合做复杂索引结构的快速搭建与实验。
3. 多重检索RAG架构
3.1 架构原理
我们要实现的多重检索RAG,大致包含以下步骤:
- 文档预处理:将文档切分成适合 Llama-Index 的
Document
单元。 构建多种索引:
- 向量索引:利用 Llama-Index 的
GPTSimpleVectorIndex
,并存储到向量数据库(如 Milvus)。 - 关键词或树形索引:用
GPTKeywordTableIndex
或GPTTreeIndex
建立一种“主题+节点”索引,支持按目录层级或关键词进行检索。 - 全文检索(可选):结合 ElasticSearch,通过 Llama-Index 插件把每个 Chunk 同步到 ES。
- 向量索引:利用 Llama-Index 的
LangChain 检索器配置:在 LangChain 中,构造多个检索器对象:
- 向量检索器(调用 Llama-Index 向量索引后的
query
)。 - 关键词检索器(调用 Llama-Index 关键词索引后的
query
)。 - 全文检索器(调用 ES API 或 Llama-Index ES 插件)。
- 向量检索器(调用 Llama-Index 向量索引后的
- 融合策略:将多个检索器的 Top-K 结果进行去重、打分或简单合并,得到最终的上下文片段列表。
- LLM 生成:将融合后的上下文片段拼接到 Prompt 中,调用 LLM(如 OpenAI GPT-4)生成答案。
这样的好处在于:
- 兼顾召回率与精确性:向量检索善于“语义召回”,关键词/全文检索擅长“精准定位”。
- 多样化结果补充:不同检索器返回的结果类型互补,能丰富上下文。
- 灵活可扩展:未来可继续增加新的检索器,比如基于知识图谱的检索。
3.2 Mermaid 流程图
flowchart TB
subgraph 索引构建阶段
A1[原始文档集合] --> A2[文本分割与清洗]
A2 --> A3a[向量索引构建 (GPTSimpleVectorIndex)]
A2 --> A3b[关键词/树形索引构建 (GPTKeywordTableIndex/GPTTreeIndex)]
A2 --> A3c[同步到 ElasticSearch (可选)]
end
subgraph 多重检索阶段
B1[用户输入 Query] --> B2a[LangChain 向量检索器]
B1 --> B2b[LangChain 关键词检索器]
B1 --> B2c[LangChain 全文检索器 (ES)]
B2a --> C[结果融合与去重]
B2b --> C
B2c --> C
C --> D[拼接上下文 + Prompt 构建]
D --> E[LLM 生成答案]
E --> F[返回给用户]
end
上图分为两个阶段:索引构建阶段(左侧)和多重检索阶段(右侧)。在实际系统运行时,索引构建通常是离线或定时任务,而多重检索阶段则是在线请求流程。
4. 环境准备与依赖安装
以下以 Python 3.9+ 为例,示范如何安装所需依赖。
# 1. 创建并激活虚拟环境(推荐)
python3 -m venv langchain_llamaenv
source langchain_llamaenv/bin/activate
# 2. 安装基础依赖
pip install --upgrade pip setuptools
# 3. 安装 LangChain
pip install langchain
# 4. 安装 Llama-Index(GPT Index)
pip install llama-index
# 5. 安装 OpenAI SDK(用于 LLM 调用)
pip install openai
# 6. 安装可选向量数据库依赖(以 Milvus 为例)
pip install pymilvus
# 7. 安装可选 ElasticSearch 客户端
pip install elasticsearch
# 8. 安装额外工具(可视化、数据处理)
pip install pandas numpy tqdm
# 9. 确保 API Key 环境变量已配置
export OPENAI_API_KEY="你的_OpenAI_Key"
如果你只想先在本地完成小规模实验,也可跳过 Milvus 或 ElasticSearch 部分,直接使用 Llama-Index 内置的 storage_context
存储向量索引。
5. 构建数据源与索引
5.1 文本数据准备
假设我们有一批技术文档,格式为多个 Markdown 文件或 TXT 文本,存放于 ./docs/
目录。示例文件结构:
docs/
├─ doc1.md
├─ doc2.txt
├─ subfolder/
│ ├─ doc3.md
│ └─ ...
我们要将所有文本读入并做基本清洗,包括:
- 去除空行、特殊符号
- 按 “段落” 或 “固定字符数” 将文件切分成
text_chunks
下面给出一个简单的文本加载与切分函数示例:
import os
from typing import List
from llama_index import Document
def load_and_split_documents(data_dir: str, chunk_size: int = 1000, overlap: int = 200) -> List[Document]:
"""
加载 data_dir 下的所有文本文件,按 chunk_size 切分,重叠 overlap 个字符。
返回 Llama-Index 需要的 Document 列表。
"""
documents = []
for root, _, files in os.walk(data_dir):
for file in files:
if not file.endswith((".md", ".txt")):
continue
file_path = os.path.join(root, file)
with open(file_path, "r", encoding="utf-8") as f:
text = f.read()
# 简单去除多余空白
text = "\n".join([line.strip() for line in text.splitlines() if line.strip()])
# 切分
start = 0
length = len(text)
while start < length:
end = start + chunk_size
chunk_text = text[start:end]
doc = Document(text=chunk_text, metadata={"source": file_path})
documents.append(doc)
start = end - overlap # 保持 overlap 重叠
return documents
# 示例调用
docs = load_and_split_documents("./docs", chunk_size=1000, overlap=200)
print(f"已生成 {len(docs)} 个文本块 (Documents).")
- Document 对象:Llama-Index 中的基本单位,包含
text
和metadata
(如来源文件路径、文档 ID 等)字段。
5.2 向量索引与全文检索索引
5.2.1 构建向量索引(GPTSimpleVectorIndex)
向量索引可直接存储到本地的 storage_context
中,或同步到外部数据库。以下示例先使用本地简单索引,再演示如何将索引传给 Milvus。
from llama_index import SimpleDirectoryReader, GPTSimpleVectorIndex, StorageContext, load_index_from_storage
# 如果你已经生成好了 Document 列表 (docs),则直接用 Document 构建索引:
from llama_index import VectorStoreIndex
from llama_index.vector_stores import FAISSVectorStore
# 方法 A: 使用本地 FAISS 存储
def build_local_vector_index(documents):
# 创建 FAISS 向量存储
vector_store = FAISSVectorStore.from_documents(documents)
# 用向量存储构建索引
index = VectorStoreIndex(documents, vector_store=vector_store)
index.storage_context.persist("./index_storage")
return index
index = build_local_vector_index(docs)
print("向量索引已构建并保存到 ./index_storage")
# 方法 B: 将向量索引写入 Milvus(假设 Milvus 已启动)
from llama_index.vector_stores import MilvusVectorStore
def build_milvus_vector_index(documents, milvus_collection_name="langchain_collection"):
# 初始化 Milvus 向量存储
vector_store = MilvusVectorStore.from_documents(
documents,
collection_name=milvus_collection_name,
index_args={"index_type": "IVF_FLAT", "metric_type": "IP", "params": {"nlist": 128}},
connection_args={"host": "127.0.0.1", "port": "19530"},
)
# 构建索引
index = VectorStoreIndex(documents, vector_store=vector_store)
index.storage_context.persist("./index_storage_milvus")
return index
milvus_index = build_milvus_vector_index(docs)
print("向量索引已构建并保存到 ./index_storage_milvus (Milvus).")
VectorStoreIndex
:Llama-Index 2.0 中新引入的类,替换了老版本中的GPTSimpleVectorIndex
,但使用思路相同。FAISSVectorStore
:使用 FAISS 在本地进行向量索引。MilvusVectorStore
:将索引写入 Milvus,以便多实例或分布式部署。
5.2.2 构建关键词/树形索引(GPTKeywordTableIndex / GPTTreeIndex)
假设我们想在文档中按“章节标题”或“关键字表”做一种快速导航式检索,可以使用 GPTKeywordTableIndex
:
from llama_index import GPTKeywordTableIndex, LLMPredictor, PromptHelper, ServiceContext
# 1. 先定义一个简单的 LLM Predictor,供索引在构建时使用(可使用 OpenAI)
from openai import OpenAI
llm = OpenAI(model="gpt-3.5-turbo", temperature=0)
# 2. 构造服务上下文
prompt_helper = PromptHelper(
max_input_size=4096,
num_output=512,
max_chunk_overlap=200
)
service_context = ServiceContext.from_defaults(
llm_predictor=LLMPredictor(llm=llm),
prompt_helper=prompt_helper
)
def build_keyword_index(documents):
index = GPTKeywordTableIndex.from_documents(
documents,
service_context=service_context,
index_structure_kwargs={"threshold": 1, "num_children": 3}
)
index.storage_context.persist("./keyword_index")
return index
keyword_index = build_keyword_index(docs)
print("关键词索引已构建并保存到 ./keyword_index")
GPTKeywordTableIndex
:自动生成“关键字→文档块”映射表,供后续按关键字快速检索。GPTTreeIndex
:则会将文档切分为树状层级索引,适合章节式分布的文档。构建用法类似。
小提示:关键词索引更适合“区分度较高的术语检索”;树形索引更适合“文档已划分章节”的场景。
5.2.3 构建全文检索索引(ElasticSearch)
如果你想在多重检索中加入“全文检索”的能力,可将文本同步到 ElasticSearch:
from llama_index import ElasticsearchReader, GPTListIndex
# 1. 首先需要确保 Elasticsearch 服务已启动 (默认端口 9200)
# 2. 使用 Reader 将本地 documents 导入 ES
def sync_to_elasticsearch(documents, index_name="langchain_es_index"):
es_client = ElasticsearchReader(
hosts=["http://127.0.0.1:9200"],
index_name=index_name
)
# 将每个 Document 存到 ES,ESReader 会自动创建索引并写入
for doc in documents:
es_client.add_document(doc)
return es_client
es_reader = sync_to_elasticsearch(docs)
print("全文检索索引已同步到 ElasticSearch (index: langchain_es_index)")
ElasticsearchReader.add_document
会将Document.text
写入 ES 并生成倒排索引。- 后续可在 LangChain 中使用 ES 的 API 或 Llama-Index 的 ES 查询适配器完成检索。
6. LangChain 中的检索器配置
完成索引构建后,我们需要在 LangChain 中创建多个检索器(Retriever),并按需求组合。
from langchain.retrievers import VectorRetriever, ElasticSearchRetriever, BaseRetriever
# 1. 加载已持久化的 Llama-Index index
from llama_index import load_index_from_storage, StorageContext
# 加载向量索引
storage_context = StorageContext.from_defaults(persist_dir="./index_storage")
vector_index = load_index_from_storage(storage_context).as_retriever()
# 加载关键词索引
kw_storage = StorageContext.from_defaults(persist_dir="./keyword_index")
keyword_index = load_index_from_storage(kw_storage).as_retriever()
# 2. 构建 LangChain Retriever
# (1)向量检索器
vector_retriever = VectorRetriever(
index=vector_index,
embeddings_model="openai-ada" # 如果使用 OpenAI 嵌入
)
# (2)关键词检索器(内部其实调用 keyword_index.query)
class LlamaKeywordRetriever(BaseRetriever):
def __init__(self, llama_retriever):
self.llama_retriever = llama_retriever
async def get_relevant_documents(self, query: str):
# llama_retriever.query 返回 Document 列表
results = self.llama_retriever.retrieve(query, top_k=5)
# 转换为 LangChain Document 类型
from langchain.schema import Document as LCDocument
return [LCDocument(page_content=doc.text, metadata=doc.metadata) for doc in results]
keyword_retriever = LlamaKeywordRetriever(keyword_index)
# (3)全文检索器(ElasticSearch)
class ESDocumentRetriever(BaseRetriever):
def __init__(self, index_name="langchain_es_index", host="http://127.0.0.1:9200"):
from elasticsearch import Elasticsearch
self.es = Elasticsearch([host])
self.index_name = index_name
async def get_relevant_documents(self, query: str):
body = {
"query": {
"multi_match": {
"query": query,
"fields": ["text"]
}
}
}
res = self.es.search(index=self.index_name, body=body, size=5)
docs = []
for hit in res["hits"]["hits"]:
docs.append(
Document(
text=hit["_source"]["text"],
metadata={"score": hit["_score"], "source": hit["_source"].get("source", "")}
)
)
# 转换为 LangChain Document
from langchain.schema import Document as LCDocument
return [LCDocument(page_content=d.text, metadata=d.metadata) for d in docs]
es_retriever = ESDocumentRetriever()
VectorRetriever
:LangChain 自带的向量检索器,可以接受一个 Llama-Index 返回的向量检索接口。- 自定义
LlamaKeywordRetriever
:利用 Llama-Index 对关键词索引的retrieve
方法,将结果包装成 LangChain 文档。 - 自定义
ESDocumentRetriever
:通过 ElasticSearch 原生 API 对 ES 索引做多字段检索,并返回 LangChain 格式的文档列表。
Tip:LangChain 所有检索器最终都需要实现get_relevant_documents(query)
方法,输出一列表 LangChainDocument
对象。
7. Llama-Index 中的索引构建与查询
虽然我们已经在第 5 节展示了索引构建示例,这里进一步补充几种常用的 Llama-Index 索引类型与查询方法。
7.1 节点索引(GPTSimpleVectorIndex)
注意:在 Llama-Index v0.6+ 中,GPTSimpleVectorIndex
被整合到VectorStoreIndex
中。
构建完成后,进行查询很简洁:
# 加载向量索引
from llama_index import load_index_from_storage, StorageContext
storage_context = StorageContext.from_defaults(persist_dir="./index_storage")
vector_index = load_index_from_storage(storage_context)
# 查询
query_text = "如何在 Python 中使用多线程?"
response = vector_index.as_query_engine().query(query_text)
print("向量检索结果:", response.response)
as_query_engine()
:以默认的参数包装一个“查询引擎”,方便直接调用query()
获得一个Response
对象,包含response
(文本)和source_nodes
(对应文档块元信息)。
7.2 树形索引(GPTTreeIndex)
如果你想按层级结构检索文档,可以使用树形索引:
from llama_index import GPTTreeIndex
# 构建
tree_index = GPTTreeIndex.from_documents(
docs,
service_context=service_context,
index_struct_kwargs={"num_children": 4}
)
tree_index.storage_context.persist("./tree_index")
# 查询
storage_context = StorageContext.from_defaults(persist_dir="./tree_index")
loaded_tree = load_index_from_storage(storage_context)
response = loaded_tree.as_query_engine().query("请列出所有关于日志记录的章节内容。")
print("树形检索结果:", response.response)
- 树形索引会自动根据语义或层次将文档分成多级节点,查询时模型会逐级下钻以确定最相关的节点。
7.3 结合全文搜索引擎(如 ElasticSearch)
如果使用 ES 同步方式,Llama-Index 也能封装 ES 作为 QueryEngine
:
from llama_index import ElasticSearchReader, ElasticsearchQueryEngine
# 构建 ES 查询引擎
es_query_engine = ElasticsearchQueryEngine(
es_reader=es_reader, # 前面已经构建好的 ES Reader
service_context=service_context
)
# 查询
result = es_query_engine.query("如何处理数据库死锁?")
print("全文检索结果:", result.response)
- 通过
ElasticsearchQueryEngine
,Llama-Index 会将 ES 返回的文本包装为 Response,并可选地在生成时结合 LLm 做进一步指引。
8. 多重检索管道示例
8.1 设计思路
我们希望在 LangChain 中同时调用以上三种检索器,形成一个多路并行检索 → 融合 → LLM 生成的完整管道。具体思路:
- 定义多个检索器:
vector_retriever
、keyword_retriever
、es_retriever
。 - 并行调用:在收到用户 Query 后,同时调用三条检索管道,获取各自 Top-K 文档。
- 结果融合:对三路检索结果做去重和打分。简单示例:将相同文本块合并,将各自的相关度分数归一化后求平均。
- 拼接 Prompt:将融合后的前 N 条文档内容,按照优先级(一般向量检索优先级高)拼接到 LLM Prompt 中。
- 生成答案:调用 LLM 生成最终回答并返回。
下面给出一个完整的 LangChain + Llama-Index 多重检索管道示例。
8.2 代码示例:整合 LangChain & Llama-Index
import asyncio
from typing import List, Dict, Any
from langchain import OpenAI
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
from langchain.schema import Document as LCDocument
# 假设前面已经创建好以下检索器
# vector_retriever: VectorRetriever
# keyword_retriever: LlamaKeywordRetriever
# es_retriever: ESDocumentRetriever
# 1. 定义一个并行调用检索器的函数
async def multi_retrieve(query: str, top_k: int = 5) -> List[LCDocument]:
"""
并行调用向量、关键词、全文检索器,返回融合后的前 top_k 文档列表。
"""
# 并发执行
results = await asyncio.gather(
vector_retriever.get_relevant_documents(query),
keyword_retriever.get_relevant_documents(query),
es_retriever.get_relevant_documents(query),
)
# results = [list_vector_docs, list_keyword_docs, list_es_docs]
all_docs = []
seen_texts = set()
# 简单去重与合并:按照来源优先级遍历
for source_docs in results:
for doc in source_docs:
txt = doc.page_content.strip()
if txt not in seen_texts:
seen_texts.add(txt)
all_docs.append(doc)
if len(all_docs) >= top_k:
break
if len(all_docs) >= top_k:
break
return all_docs
# 2. 定义 Prompt 模板
prompt_template = """
你是一个知识问答助手。以下是从不同检索器获取到的上下文片段,请根据它们回答用户的问题。
=== 上下文开始 ===
{context}
=== 上下文结束 ===
问题:{question}
"""
prompt = PromptTemplate(
template=prompt_template,
input_variables=["context", "question"]
)
# 3. 初始化 LLMChain
llm = OpenAI(temperature=0.0, model_name="gpt-3.5-turbo")
chain = LLMChain(llm=llm, prompt=prompt)
# 4. 将检索与生成串联
async def run_multiretrieval_qa(query: str):
# 多重检索
docs = await multi_retrieve(query, top_k=5)
# 将文档拼接成一个长上下文
context = "\n\n".join([f"- 文档来源:{doc.metadata.get('source', 'unknown')}\n{doc.page_content}" for doc in docs])
# 构造输入
inputs = {"context": context, "question": query}
# 调用 LLM
response = chain.run(inputs)
return response
# 示例运行
if __name__ == "__main__":
query = "如何在 Python 中实现并发文件下载?"
ans = asyncio.run(run_multiretrieval_qa(query))
print("最终回答:\n", ans)
代码说明
multi\_retrieve:
- 使用
asyncio.gather
并行调用三路检索器的get_relevant_documents(query)
。 - 结果分别为三条 Doc 列表,内部逐一合并、去重,并按顺序取前
top_k
条。 - 简易去重策略:根据文档文本
page_content
是否重复剔除。
- 使用
PromptTemplate:
- 将多重检索得到的上下文片段拼接并传给 LLM,使用明确的标识区分不同来源。
LLMChain:
- 调用 OpenAI LLM(如 GPT-3.5 或 GPT-4)生成答案。
- 你可以自定义 Prompt 模板,以加入更多如“使用 Markdown 输出”或“回答要点列举”等要求。
异步运行:
- 使用
asyncio
并行加速检索,避免串行导致的延迟。 - 最终使用
asyncio.run
在主程序中同步获取结果。
- 使用
整个示例展现出如何把多路检索与LLM 生成无缝集成在一起,实现一个端到端的“多重检索RAG”流水线。
9. 完整流程演示
为了让你更清晰地理解上述各组件如何串联,下面再一次以流程图形式重现“用户 Query → 多重检索 → 融合 → 生成 → 返回”全过程。
flowchart LR
U[用户输入 Query] -->|async| R1[调用向量检索器]
U -->|async| R2[调用关键词检索器]
U -->|async| R3[调用全文检索器]
subgraph 并行检索
R1 --> MR[结果收集]
R2 --> MR
R3 --> MR
end
MR -->|去重&融合| Ctx[生成统一上下文块]
Ctx -->|拼接 Prompt| PromptHai[构造 Prompt]
PromptHai --> LLM[LLMChain 调用 OpenAI]
LLM -->|返回答案| Ans[输出给用户]
- 并行检索:向量、关键词、全文检索同时触发。
- 结果收集与融合:在本地合并不同检索源的结果,去除重复文本,并可自定义更复杂的打分策略。
- Prompt 拼接:将多个文档片段统一拼接到 Prompt 中,传给 LLM。
- 生成与返回:LLM 给出最终答案输出。
10. 调优与注意事项
10.1 检索器权重与融合策略
简单去重 vs 权重融合
- 上述示例只做了按顺序去重与合并。若想保留每种检索器的“置信度”或“相关度分数”,可以给每个文档打分(如向量检索使用相似度得分,关键词检索使用出现次数,全文检索使用 ES 得分),然后归一化后做加权平均,再取 Top-K。
动态权重
- 可以根据 Query 类型动态调整权重,例如当 Query 包含专业术语时,降低向量检索权重;当 Query 简单常见时,优先全文检索。
10.2 索引更新与数据刷新
增量更新
如果文档库在运行过程中不断更新,需支持对向量索引与关键词索引的增量更新。Llama-Index 支持新 Document 追加:
new_docs = load_and_split_documents("./new_docs") vector_index.insert_documents(new_docs) keyword_index.insert_documents(new_docs)
- 对 ES 同步则可直接调用
es_retriever.add_document
写入新索引。
定期重建
- 当文档变化较大时,建议定期重建索引以保证检索质量。尤其是关键词索引和树形索引,可能在分层方式上发生重大变化时,需要全量重建。
10.3 并行检索与性能优化
异步 vs 线程池
- LangChain 的检索器方法是异步的(
async get_relevant_documents
),可以使用asyncio
并发,也可将其包装到ThreadPoolExecutor
在同步代码中并行调用。
- LangChain 的检索器方法是异步的(
批量查询
- 如果系统需要处理高并发请求,可考虑批量化查询或预热常见 Query,缓存 Top-K 结果,减少后端检索压力。
检索器超时与降级
- 对于 ES 等外部服务,需设置RPC/HTTP 超时时间。一旦检索器超时,可主动降级为“只使用本地向量检索”,保证系统可用性。
10.4 对话上下文与缓存
对话历史纳入检索
- 在对话型 RAG 场景中,可以将之前的用户问题和答案也记入上下文,然后再触发多重检索。LangChain 提供了
ConversationBufferMemory
,可以将历史对话自动拼接到 Prompt 中。
- 在对话型 RAG 场景中,可以将之前的用户问题和答案也记入上下文,然后再触发多重检索。LangChain 提供了
检索结果缓存
- 对于相同的 Query,缓存
multi_retrieve(query)
的结果,避免重复调用多个检索器。可使用 Redis 或内存缓存进行缓存管理。
- 对于相同的 Query,缓存
11. 小结
本文系统地介绍了如何将 LangChain 与 Llama-Index 联动,打造一个“多重检索 RAG”系统。核心流程包括:
索引构建
- 利用 Llama-Index 构建向量索引、关键词/树形索引,甚至同步到 ElasticSearch。
LangChain 检索器配置
- 将 Llama-Index 索引封装为 LangChain 可以调用的检索器:向量检索器、关键词检索器、全文检索器等。
多重检索与融合
- 异步并行调用多路检索器,聚合去重后形成统一上下文。
Prompt 拼接与 LLM 生成
- 将融合后的上下文块传给 LLM(如 GPT-4),生成高质量、覆盖面更广的答案。
通过示例代码与 Mermaid 流程图,我们展示了从数据准备、索引构建到检索—生成的完整端到端流程。你可以根据实际业务需求,灵活调整:
- 检索器的种类与权重
- 索引刷新策略与增量更新方式
- 对话上下文与缓存技术
- 并行化与降级机制
多重检索能显著提升 RAG 系统在“召回率+精确度”上的平衡,适用于技术文档库、问答知识库、客户支持中心等场景。
评论已关闭