一、LlamaIndex-RAG
- 使用 LlamaIndex 实现 RAG 的一些常见操作案例
1、PDF解析-MD
- 把 PDF 解析为 MD 格式,使用 LlamaParse 实现
- 前提:
- 注册 LlamaCloud 账号并且配置环境变量 LLAMA_CLOUD_API_KEY
- LlamaCloud 一个月的免费额度为 10000 点
import os
from llama_parse import LlamaParse
# 从环境变量读取 API Key
api_key = os.getenv("LLAMA_CLOUD_API_KEY")
if not api_key:
raise ValueError("请设置环境变量 LLAMA_CLOUD_API_KEY")
# 初始化 LlamaParse 解析器
parser = LlamaParse(
api_key=api_key,
result_type="markdown", # 输出格式: markdown / text / json
num_workers=4, # 并行 worker 数
verbose=True, # 打印详细日志
language="ch_sim", # 文档语言: 简体中文
# 自定义解析指令(可选)
system_prompt="""
这是一篇关于 RAG 评估框架 Ragas 的中文技术文档。
请保留所有表格结构、代码块和层级标题。
对于数学公式,请尽量保留原始格式。
""",
)
# 指定要解析的 PDF 文件路径
pdf_path = os.path.join(os.path.dirname(__file__), "19.Ragas评估.pdf")
print(f"正在解析 PDF: {pdf_path}")
print("=" * 60)
# 方式1: load_data() — 直接返回 Document 对象列表
# documents = parser.load_data(pdf_path)
# for i, doc in enumerate(documents):
# print(f"文档片段 {i}: {doc.text[:200]}...")
# 获取 Markdown 格式的完整结果
json_result = parser.get_json_result(pdf_path)
if not json_result:
raise RuntimeError("PDF 解析失败,返回结果为空。请检查 API Key 是否有效、PDF 文件是否损坏。")
# json_result 结构: [{"pages": [{"page": 1, "md": "...", "text": "..."}, ...], ...}]
# 拼接所有页面的 Markdown 内容
pages = json_result[0]["pages"]
md_text = "\n\n".join(page["md"] for page in pages)
# 保存解析结果到 Markdown 文件
output_path = pdf_path.replace(".pdf", "_解析结果.md")
with open(output_path, "w", encoding="utf-8") as f:
f.write(md_text)
print(f"解析完成! 结果已保存到: {output_path}")
print("=" * 60)
print(f"解析内容预览(前 500 字符):\n{md_text[:500]}")
2、PDF 解析后构建索引存储-内存
import os
from llama_parse import LlamaParse
from llama_index.core import Settings
from llama_index.embeddings.dashscope import DashScopeEmbedding
from llama_index.llms.openai_like import OpenAILike
from llama_index.core import VectorStoreIndex
from llama_index.core.node_parser import MarkdownElementNodeParser
# 配置 Embedding 模型(用 DashScope)
Settings.embed_model = DashScopeEmbedding(
model_name="qwen3.7-text-embedding",
api_key=os.getenv("DASHSCOPE_API_KEY"),
embed_batch_size=10, # DashScope embedding 单次最大 25,设小一点避免超限
)
# 配置 LLM(用 DashScope 兼容模式)
Settings.llm = OpenAILike(
model="qwen3.7-flash",
api_key=os.getenv("DASHSCOPE_API_KEY"),
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
is_chat_model=True,
)
# Step 1: 解析文档
api_key = os.getenv("LLAMA_CLOUD_API_KEY")
if not api_key:
raise ValueError("请设置环境变量 LLAMA_CLOUD_API_KEY")
parser = LlamaParse(
api_key=api_key,
result_type="markdown", # 输出格式: markdown / text / json
num_workers=4, # 并行 worker 数
verbose=True, # 打印详细日志
language="ch_sim", # 文档语言: 简体中文
# 自定义解析指令(可选)
system_prompt="""
这是一篇关于 RAG 评估框架 Ragas 的中文技术文档。
请保留所有表格结构、代码块和层级标题。
对于数学公式,请尽量保留原始格式。
""",
)
pdf_path = os.path.join(os.path.dirname(__file__), "19.Ragas评估.pdf")
documents = parser.load_data(pdf_path)
# Step 2: 构建节点解析器(保留 Markdown 结构)
node_parser = MarkdownElementNodeParser()
nodes = node_parser.get_nodes_from_documents(documents)
# Step 3: 创建索引
index = VectorStoreIndex(nodes)
# Step 4: 创建查询引擎
query_engine = index.as_query_engine(
similarity_top_k=3, # 返回最相关的 3 个片段
verbose=True,
)
# Step 5: 提问
response = query_engine.query("Ragas评估体系概述")
print(f"回答: {response}")
3、PDF解析后构建索引存储-chromadb
import os
import chromadb
from llama_parse import LlamaParse
from llama_index.core import Settings, VectorStoreIndex, StorageContext
from llama_index.core.node_parser import MarkdownElementNodeParser
from llama_index.embeddings.dashscope import DashScopeEmbedding
from llama_index.llms.openai_like import OpenAILike
from llama_index.vector_stores.chroma import ChromaVectorStore
# 1. 配置 Embedding 模型
Settings.embed_model = DashScopeEmbedding(
model_name="qwen3.7-text-embedding",
api_key=os.getenv("DASHSCOPE_API_KEY"),
embed_batch_size=10,
)
# 2. 配置 LLM
Settings.llm = OpenAILike(
model="qwen3.7-flash",
api_key=os.getenv("DASHSCOPE_API_KEY"),
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
is_chat_model=True,
)
# 3. 初始化 Chroma
# Chroma 数据持久化目录
chroma_client = chromadb.PersistentClient(
path="./chroma_db"
)
# 创建 / 获取 collection
chroma_collection = chroma_client.get_or_create_collection(
name="ragas_docs"
)
# 将 Chroma collection 包装成 LlamaIndex VectorStore
vector_store = ChromaVectorStore(
chroma_collection=chroma_collection
)
# 创建 StorageContext
storage_context = StorageContext.from_defaults(
vector_store=vector_store
)
# 4. 解析 PDF
llama_cloud_api_key = os.getenv("LLAMA_CLOUD_API_KEY")
if not llama_cloud_api_key:
raise ValueError(
"请设置环境变量 LLAMA_CLOUD_API_KEY"
)
parser = LlamaParse(
api_key=llama_cloud_api_key,
result_type="markdown",
num_workers=4,
verbose=True,
language="ch_sim",
system_prompt="""
这是一篇关于 RAG 评估框架 Ragas 的中文技术文档。
请保留所有表格结构、代码块和层级标题。
对于数学公式,请尽量保留原始格式。
""",
)
pdf_path = os.path.join(
os.path.dirname(__file__),
"19.Ragas评估.pdf"
)
documents = parser.load_data(pdf_path)
# 5. Markdown → Nodes
node_parser = MarkdownElementNodeParser()
nodes = node_parser.get_nodes_from_documents(
documents
)
# 6. 创建 Chroma 向量索引
index = VectorStoreIndex(
nodes,
storage_context=storage_context,
)
# 7. 创建 Query Engine
query_engine = index.as_query_engine(
similarity_top_k=3,
verbose=True,
)
# 8. 查询
response = query_engine.query(
"Ragas是什么?"
)
print(f"回答: {response}")
4、读取Charomadb数据回答
import os
import chromadb
from llama_index.core import VectorStoreIndex, StorageContext, Settings
from llama_index.embeddings.dashscope import DashScopeEmbedding
from llama_index.llms.openai_like import OpenAILike
from llama_index.vector_stores.chroma import ChromaVectorStore
# 1. 模型配置
Settings.embed_model = DashScopeEmbedding(
model_name="qwen3.7-text-embedding",
api_key=os.getenv("DASHSCOPE_API_KEY"),
embed_batch_size=10,
)
Settings.llm = OpenAILike(
model="qwen3.7-flash",
api_key=os.getenv("DASHSCOPE_API_KEY"),
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
is_chat_model=True,
)
# 2. Chroma配置
CHROMA_PATH = "./chroma_db"
COLLECTION_NAME = "ragas_docs"
chroma_client = chromadb.PersistentClient(
path=CHROMA_PATH
)
collection = chroma_client.get_or_create_collection(
COLLECTION_NAME
)
vector_store = ChromaVectorStore(
chroma_collection=collection
)
storage_context = StorageContext.from_defaults(
vector_store=vector_store
)
# 3. 加载已有知识库
index = VectorStoreIndex.from_vector_store(
vector_store
)
# 4. 查询
question = "什么是忠诚度?"
query_engine = index.as_query_engine(
similarity_top_k=3,
verbose=True
)
response = query_engine.query(
question
)
print(response)
5、使用本地向量化模型-存储
import os
import chromadb
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_parse import LlamaParse
from llama_index.core import Settings, StorageContext
from llama_index.llms.openai_like import OpenAILike
from llama_index.core import VectorStoreIndex
from llama_index.core.node_parser import MarkdownElementNodeParser
# 1. 配置 Embedding 模型
Settings.embed_model = HuggingFaceEmbedding(
model_name=r"G:\models\bge-base-zh-v1.5",
model_kwargs={
"local_files_only": True,
},
)
# 2. 配置 LLM
Settings.llm = OpenAILike(
model="qwen3.7-flash",
api_key=os.getenv("DASHSCOPE_API_KEY"),
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
is_chat_model=True,
)
# 3. 初始化 Chroma
# Chroma 数据持久化目录
chroma_client = chromadb.PersistentClient(
path="./chroma_db"
)
# 创建 / 获取 collection
chroma_collection = chroma_client.get_or_create_collection(
name="dldh_docs"
)
# 将 Chroma collection 包装成 LlamaIndex VectorStore
vector_store = ChromaVectorStore(
chroma_collection=chroma_collection
)
# 创建 StorageContext
storage_context = StorageContext.from_defaults(
vector_store=vector_store
)
# 4. 解析 PDF
llama_cloud_api_key = os.getenv("LLAMA_CLOUD_API_KEY")
if not llama_cloud_api_key:
raise ValueError(
"请设置环境变量 LLAMA_CLOUD_API_KEY"
)
parser = LlamaParse(
api_key=llama_cloud_api_key,
result_type="markdown",
num_workers=4,
verbose=True,
language="ch_sim",
system_prompt="""
这是一篇关于 RAG 评估框架 Ragas 的中文技术文档。
请保留所有表格结构、代码块和层级标题。
对于数学公式,请尽量保留原始格式。
""",
)
pdf_path = os.path.join(
os.path.dirname(__file__),
"11.多轮对话.pdf"
)
documents = parser.load_data(pdf_path)
# 5. Markdown → Nodes
node_parser = MarkdownElementNodeParser()
nodes = node_parser.get_nodes_from_documents(
documents
)
# 6. 创建 Chroma 向量索引
index = VectorStoreIndex(
nodes,
storage_context=storage_context,
)
# 7. 创建 Query Engine
query_engine = index.as_query_engine(
similarity_top_k=3,
verbose=True,
)
# 8. 查询
response = query_engine.query(
"KV缓存指的是什么?"
)
print(f"回答: {response}")
6、使用本地向量化模型-推理+自定义提示词+检索内容打印
import os
from llama_index.core.prompts import ChatPromptTemplate
import chromadb
from llama_index.core import VectorStoreIndex, StorageContext, Settings
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.openai_like import OpenAILike
from llama_index.vector_stores.chroma import ChromaVectorStore
# 1. 模型配置
Settings.embed_model = HuggingFaceEmbedding(
model_name=r"G:\models\bge-base-zh-v1.5",
model_kwargs={
"local_files_only": True,
},
)
Settings.llm = OpenAILike(
model="qwen3.7-flash",
api_key=os.getenv("DASHSCOPE_API_KEY"),
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
is_chat_model=True,
)
# 2. Chroma配置
CHROMA_PATH = "./chroma_db"
COLLECTION_NAME = "dldh_docs"
chroma_client = chromadb.PersistentClient(
path=CHROMA_PATH
)
collection = chroma_client.get_or_create_collection(
COLLECTION_NAME
)
vector_store = ChromaVectorStore(
chroma_collection=collection
)
storage_context = StorageContext.from_defaults(
vector_store=vector_store
)
# 3. 加载已有知识库
index = VectorStoreIndex.from_vector_store(
vector_store
)
# 4. 查询
question = "短期记忆是什么?"
# 自定义提示词模板
CUSTOM_QA_PROMPT = ChatPromptTemplate.from_messages([
(
"system",
"""
你是一个知识渊博的助手,请根据以下上下文信息回答问题。
上下文信息:
{context_str}
规则:
1. 仅根据上下文信息回答,不要编造内容
2. 如果上下文不足以回答问题,请明确说"根据现有资料无法回答"
3. 回答要简洁、准确,使用中文
""",
),
("user", "问题:{query_str}"),
])
# 方式1: 通过 text_qa_template 传入自定义提示词
query_engine = index.as_query_engine(
similarity_top_k=3,
text_qa_template=CUSTOM_QA_PROMPT, # 自定义 QA 提示词
verbose=True,
)
# 5. 查询(一次检索 + 生成,通过 response.source_nodes 查看检索结果)
response = query_engine.query(question)
print("=" * 60)
print("检索到的文档片段:")
print("=" * 60)
for i, node in enumerate(response.source_nodes):
print(f"\n--- 片段 {i + 1} (相关性: {node.score:.4f}) ---")
print(f"来源: {node.metadata}")
print(f"内容:\n{node.text[:500]}...")
print("-" * 40)
print("\n" + "=" * 60)
print("生成回答:")
print("=" * 60)
print(f"回答: {response}")
7、使用本地向量化模型-自定义提示词赋值
import os
from llama_index.core.prompts import ChatPromptTemplate
import chromadb
from llama_index.core import VectorStoreIndex, StorageContext, Settings
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.openai_like import OpenAILike
from llama_index.vector_stores.chroma import ChromaVectorStore
# 1. 模型配置
Settings.embed_model = HuggingFaceEmbedding(
model_name=r"G:\models\bge-base-zh-v1.5",
model_kwargs={
"local_files_only": True,
},
)
Settings.llm = OpenAILike(
model="qwen3.7-flash",
api_key=os.getenv("DASHSCOPE_API_KEY"),
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
is_chat_model=True,
)
# 2. Chroma配置
CHROMA_PATH = "./chroma_db"
COLLECTION_NAME = "dldh_docs"
chroma_client = chromadb.PersistentClient(
path=CHROMA_PATH
)
collection = chroma_client.get_or_create_collection(
COLLECTION_NAME
)
vector_store = ChromaVectorStore(
chroma_collection=collection
)
storage_context = StorageContext.from_defaults(
vector_store=vector_store
)
# 3. 加载已有知识库
index = VectorStoreIndex.from_vector_store(
vector_store
)
# 4. 模拟对话历史记录
chat_history = [
{"role": "user", "content": "我的名字叫cc,今年29岁"},
{"role": "assistant", "content": "你好cc,很高兴认识你"},
{"role": "user", "content": "我是一名华清远见成都中心的AI讲师"},
{"role": "assistant", "content": "好滴"},
]
# 将历史记录转为文本
history_text = "\n".join(
[f"{msg['role']}: {msg['content']}" for msg in chat_history]
)
# 5. 自定义提示词模板(含 {history} 占位符)
CUSTOM_QA_PROMPT = ChatPromptTemplate.from_messages([
(
"system",
"""
你是一个知识渊博的助手,请根据以下上下文信息回答问题。
上下文信息:
{context_str}
对话历史:
{history}
规则:
1. 仅根据上下文信息回答,不要编造内容
2. 如果上下文不足以回答问题,请明确说"根据现有资料无法回答"
3. 回答要简洁、准确,使用中文
""",
),
("user", "问题:{query_str}"),
])
# 6. 主动为 {history} 赋值,{context_str} 和 {query_str} 由引擎自动填充
prompt_with_history = CUSTOM_QA_PROMPT.partial_format(history=history_text)
# 7. 创建查询引擎,传入已赋值的提示词
query_engine = index.as_query_engine(
similarity_top_k=3,
text_qa_template=prompt_with_history,
verbose=True,
)
# 8. 当前问题
question = "cc是谁?"
print(f"当前问题: {question}")
print(f"历史记录数: {len(chat_history)} 条")
print("=" * 60)
# 5. 查询(一次检索 + 生成,通过 response.source_nodes 查看检索结果)
response = query_engine.query(question)
print("=" * 60)
print("检索到的文档片段:")
print("=" * 60)
for i, node in enumerate(response.source_nodes):
print(f"\n--- 片段 {i + 1} (相关性: {node.score:.4f}) ---")
print(f"来源: {node.metadata}")
print(f"内容:\n{node.text[:500]}...")
print("-" * 40)
print("\n" + "=" * 60)
print("生成回答:")
print("=" * 60)
print(f"回答: {response}")
8、使用本地向量化模型-重排序
import os
from llama_index.core.prompts import ChatPromptTemplate
import chromadb
from llama_index.core import VectorStoreIndex, StorageContext, Settings, get_response_synthesizer
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.openai_like import OpenAILike
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.postprocessor.flag_embedding_reranker import FlagEmbeddingReranker
# 1. 模型配置
Settings.embed_model = HuggingFaceEmbedding(
model_name=r"G:\models\bge-base-zh-v1.5",
model_kwargs={
"local_files_only": True,
},
)
Settings.llm = OpenAILike(
model="qwen3.7-flash",
api_key=os.getenv("DASHSCOPE_API_KEY"),
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
is_chat_model=True,
)
# 2. Chroma配置
CHROMA_PATH = "./chroma_db"
COLLECTION_NAME = "dldh_docs"
chroma_client = chromadb.PersistentClient(
path=CHROMA_PATH
)
collection = chroma_client.get_or_create_collection(
COLLECTION_NAME
)
vector_store = ChromaVectorStore(
chroma_collection=collection
)
storage_context = StorageContext.from_defaults(
vector_store=vector_store
)
# 3. 加载已有知识库
index = VectorStoreIndex.from_vector_store(
vector_store
)
# 4. 模拟对话历史记录
chat_history = [
{"role": "user", "content": "我的名字叫cc,今年29岁"},
{"role": "assistant", "content": "你好cc,很高兴认识你"},
{"role": "user", "content": "我是一名华清远见成都中心的AI讲师"},
{"role": "assistant", "content": "好滴"},
]
# 将历史记录转为文本z
history_text = "\n".join(
[f"{msg['role']}: {msg['content']}" for msg in chat_history]
)
# 5. 自定义提示词模板(含 {history} 占位符)
CUSTOM_QA_PROMPT = ChatPromptTemplate.from_messages([
(
"system",
"""
你是一个知识渊博的助手,请根据以下上下文信息回答问题。
上下文信息:
{context_str}
对话历史:
{history}
规则:
1. 仅根据上下文信息回答,不要编造内容
2. 如果上下文不足以回答问题,请明确说"根据现有资料无法回答"
3. 回答要简洁、准确,使用中文
""",
),
("user", "问题:{query_str}"),
])
# 6. 创建 Retriever
retriever = index.as_retriever(
similarity_top_k=15
)
# 7. 配置重排序模型(Cross-Encoder,比向量检索更精准)
reranker = FlagEmbeddingReranker(
model="G:\\models\\bge-reranker-large_v1", # 中文重排序模型,首次运行自动下载
top_n=3, # 从候选集中精选出最相关的 3 条
use_fp16=True,
)
# 8. 主动为 {history} 赋值,{context_str} 和 {query_str} 由引擎自动填充
prompt_with_history = CUSTOM_QA_PROMPT.partial_format(history=history_text)
# 9. 创建查询引擎(检索 + 重排序 + 生成)
query_engine = index.as_query_engine(
similarity_top_k=15, # 第一阶段:向量检索召回 15 条候选
text_qa_template=prompt_with_history,
node_postprocessors=[reranker], # 第二阶段:重排序精选 top_n=3 条
verbose=True,
)
# 10. 当前问题
question = "长期记忆是什么?"
print(f"当前问题: {question}")
print(f"历史记录数: {len(chat_history)} 条")
print("=" * 60)
# 10. 向量召回
retrieved_nodes = retriever.retrieve(question)
print("=" * 60)
print("第一阶段:向量数据库召回")
print("=" * 60)
print(f"召回数量:{len(retrieved_nodes)}")
for i, node in enumerate(retrieved_nodes, 1):
print(f"\n--- 召回结果 {i} ---")
print(f"向量相似度:{node.score}")
print(f"Node ID:{node.node.node_id}")
print(f"Metadata:{node.metadata}")
print(f"内容:\n{node.text}")
print("-" * 60)
# 11. Reranker 重排序 -- 它接收的就是上面 retrieved_nodes
reranked_nodes = reranker.postprocess_nodes(
retrieved_nodes,
query_str=question,
)
print("\n")
print("=" * 60)
print("第二阶段:Reranker 重排序")
print("=" * 60)
print(f"重排序后数量:{len(reranked_nodes)}")
for i, node in enumerate(reranked_nodes, 1):
print(f"\n--- 重排序结果 {i} ---")
print(f"Reranker 分数:{node.score}")
print(f"Node ID:{node.node.node_id}")
print(f"Metadata:{node.metadata}")
print(f"内容:\n{node.text}")
print("-" * 60)
# 12. 创建 Response Synthesizer
response_synthesizer = get_response_synthesizer(
text_qa_template=prompt_with_history,
llm=Settings.llm,
)
# 13. 直接使用重排序后的 Node 生成回答
response = response_synthesizer.synthesize(
question,
nodes=reranked_nodes,
)
print("\n" + "=" * 60)
print("生成回答:")
print("=" * 60)
print(f"回答: {response}")
9、使用本地向量化模型-BM25检索
import os
from llama_index.core.prompts import ChatPromptTemplate
import chromadb
from llama_index.core import VectorStoreIndex, StorageContext, Settings, get_response_synthesizer
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.openai_like import OpenAILike
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.postprocessor.flag_embedding_reranker import FlagEmbeddingReranker
from llama_index.retrievers.bm25 import BM25Retriever
# 1. 模型配置
Settings.embed_model = HuggingFaceEmbedding(
model_name=r"G:\models\bge-base-zh-v1.5",
model_kwargs={
"local_files_only": True,
},
)
Settings.llm = OpenAILike(
model="qwen3.7-flash",
api_key=os.getenv("DASHSCOPE_API_KEY"),
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
is_chat_model=True,
)
# 2. Chroma配置
CHROMA_PATH = "./chroma_db"
COLLECTION_NAME = "dldh_docs"
chroma_client = chromadb.PersistentClient(
path=CHROMA_PATH
)
collection = chroma_client.get_or_create_collection(
COLLECTION_NAME
)
vector_store = ChromaVectorStore(
chroma_collection=collection
)
storage_context = StorageContext.from_defaults(
vector_store=vector_store
)
# 3. 加载已有知识库
index = VectorStoreIndex.from_vector_store(
vector_store
)
# 4. 模拟对话历史记录
chat_history = [
{"role": "user", "content": "我的名字叫cc,今年29岁"},
{"role": "assistant", "content": "你好cc,很高兴认识你"},
{"role": "user", "content": "我是一名华清远见成都中心的AI讲师"},
{"role": "assistant", "content": "好滴"},
]
# 将历史记录转为文本z
history_text = "\n".join(
[f"{msg['role']}: {msg['content']}" for msg in chat_history]
)
# 5. 自定义提示词模板(含 {history} 占位符)
CUSTOM_QA_PROMPT = ChatPromptTemplate.from_messages([
(
"system",
"""
你是一个知识渊博的助手,请根据以下上下文信息回答问题。
上下文信息:
{context_str}
对话历史:
{history}
规则:
1. 仅根据上下文信息回答,不要编造内容
2. 如果上下文不足以回答问题,请明确说"根据现有资料无法回答"
3. 回答要简洁、准确,使用中文
""",
),
("user", "问题:{query_str}"),
])
# 6. 从 ChromaDB 获取所有已存储的节点,构建 BM25 索引
# ChromaDB 中存储了文档内容和元数据,提取出来构建 BM25
from llama_index.core.schema import TextNode
# 获取 ChromaDB 中所有文档
all_docs = collection.get()
nodes = []
for i, (doc_id, doc_text, doc_meta) in enumerate(
zip(all_docs["ids"], all_docs["documents"], all_docs["metadatas"])
):
if doc_text: # 跳过空文档
nodes.append(TextNode(
id_=doc_id,
text=doc_text,
metadata=doc_meta if doc_meta else {},
))
print(f"ChromaDB 中共有 {len(nodes)} 条文档,已加载到 BM25 索引")
# 创建 BM25 检索器(关键词匹配,无需 embedding)
retriever = BM25Retriever(
nodes=nodes,
similarity_top_k=15, # 召回 15 条候选
language="chinese", # 中文分词
)
# 7. 配置重排序模型(Cross-Encoder,比向量检索更精准)
reranker = FlagEmbeddingReranker(
model="G:\\models\\bge-reranker-large_v1", # 中文重排序模型,首次运行自动下载
top_n=3, # 从候选集中精选出最相关的 3 条
use_fp16=True,
)
# 8. 主动为 {history} 赋值,{context_str} 和 {query_str} 由引擎自动填充
prompt_with_history = CUSTOM_QA_PROMPT.partial_format(history=history_text)
# 9. 当前问题
question = "长期记忆是什么?"
print(f"当前问题: {question}")
print(f"历史记录数: {len(chat_history)} 条")
print("=" * 60)
# 10. BM25召回
retrieved_nodes = retriever.retrieve(question)
print("=" * 60)
print("第一阶段:BM25 关键词召回")
print("=" * 60)
print(f"召回数量:{len(retrieved_nodes)}")
for i, node in enumerate(retrieved_nodes, 1):
print(f"\n--- 召回结果 {i} ---")
print(f"BM25 分数:{node.score}")
print(f"Node ID:{node.node.node_id}")
print(f"Metadata:{node.metadata}")
print(f"内容:\n{node.text}")
print("-" * 60)
# 11. Reranker 重排序 -- 它接收的就是上面 retrieved_nodes
reranked_nodes = reranker.postprocess_nodes(
retrieved_nodes,
query_str=question,
)
print("\n")
print("=" * 60)
print("第二阶段:Reranker 重排序")
print("=" * 60)
print(f"重排序后数量:{len(reranked_nodes)}")
for i, node in enumerate(reranked_nodes, 1):
print(f"\n--- 重排序结果 {i} ---")
print(f"Reranker 分数:{node.score}")
print(f"Node ID:{node.node.node_id}")
print(f"Metadata:{node.metadata}")
print(f"内容:\n{node.text}")
print("-" * 60)
# 12. 创建 Response Synthesizer
response_synthesizer = get_response_synthesizer(
text_qa_template=prompt_with_history,
llm=Settings.llm,
)
# 13. 直接使用重排序后的 Node 生成回答
response = response_synthesizer.synthesize(
question,
nodes=reranked_nodes,
)
print("\n" + "=" * 60)
print("生成回答:")
print("=" * 60)
print(f"回答: {response}")
10、使用本地向量化模型-混合检索
import os
from llama_index.core.prompts import ChatPromptTemplate
import chromadb
from llama_index.core import VectorStoreIndex, StorageContext, Settings, get_response_synthesizer
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.openai_like import OpenAILike
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.postprocessor.flag_embedding_reranker import FlagEmbeddingReranker
from llama_index.retrievers.bm25 import BM25Retriever
from llama_index.core.retrievers import QueryFusionRetriever
from llama_index.core.retrievers.fusion_retriever import FUSION_MODES
from llama_index.core.schema import TextNode
# 1. 模型配置
Settings.embed_model = HuggingFaceEmbedding(
model_name=r"G:\models\bge-base-zh-v1.5",
model_kwargs={
"local_files_only": True,
},
)
Settings.llm = OpenAILike(
model="qwen3.7-flash",
api_key=os.getenv("DASHSCOPE_API_KEY"),
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
is_chat_model=True,
)
# 2. Chroma配置
CHROMA_PATH = "./chroma_db"
COLLECTION_NAME = "dldh_docs"
chroma_client = chromadb.PersistentClient(
path=CHROMA_PATH
)
collection = chroma_client.get_or_create_collection(
COLLECTION_NAME
)
vector_store = ChromaVectorStore(
chroma_collection=collection
)
storage_context = StorageContext.from_defaults(
vector_store=vector_store
)
# 3. 加载已有知识库
index = VectorStoreIndex.from_vector_store(
vector_store
)
# 4. 模拟对话历史记录
chat_history = [
{"role": "user", "content": "我的名字叫cc,今年29岁"},
{"role": "assistant", "content": "你好cc,很高兴认识你"},
{"role": "user", "content": "我是一名华清远见成都中心的AI讲师"},
{"role": "assistant", "content": "好滴"},
]
# 将历史记录转为文本z
history_text = "\n".join(
[f"{msg['role']}: {msg['content']}" for msg in chat_history]
)
# 5. 自定义提示词模板(含 {history} 占位符)
CUSTOM_QA_PROMPT = ChatPromptTemplate.from_messages([
(
"system",
"""
你是一个知识渊博的助手,请根据以下上下文信息回答问题。
上下文信息:
{context_str}
对话历史:
{history}
规则:
1. 仅根据上下文信息回答,不要编造内容
2. 如果上下文不足以回答问题,请明确说"根据现有资料无法回答"
3. 回答要简洁、准确,使用中文
""",
),
("user", "问题:{query_str}"),
])
# 6. 构建两个检索器:向量检索 + BM25 关键词检索
# 6a. 向量检索器(语义匹配)
vector_retriever = index.as_retriever(similarity_top_k=15)
# 6b. BM25 检索器(关键词匹配)
all_docs = collection.get()
bm25_nodes = []
for doc_id, doc_text, doc_meta in zip(
all_docs["ids"], all_docs["documents"], all_docs["metadatas"]
):
if doc_text:
bm25_nodes.append(TextNode(
id_=doc_id,
text=doc_text,
metadata=doc_meta if doc_meta else {},
))
bm25_retriever = BM25Retriever(
nodes=bm25_nodes,
similarity_top_k=15,
language="chinese",
)
print(f"ChromaDB 中共有 {len(bm25_nodes)} 条文档")
# 6c. 混合检索器:RRF 融合向量检索 + BM25 检索
# RRF (Reciprocal Rank Fusion):对两个检索器的排名取倒数求和,无需调权重
hybrid_retriever = QueryFusionRetriever(
retrievers=[vector_retriever, bm25_retriever],
mode=FUSION_MODES.RECIPROCAL_RANK, # RRF 融合算法
similarity_top_k=15, # 融合后返回 15 条
)
# 7. 配置重排序模型(Cross-Encoder,比向量检索更精准)
reranker = FlagEmbeddingReranker(
model="G:\\models\\bge-reranker-large_v1", # 中文重排序模型,首次运行自动下载
top_n=3, # 从候选集中精选出最相关的 3 条
use_fp16=True,
)
# 8. 主动为 {history} 赋值,{context_str} 和 {query_str} 由引擎自动填充
prompt_with_history = CUSTOM_QA_PROMPT.partial_format(history=history_text)
# 9. 当前问题
question = "长期记忆是什么?"
print(f"当前问题: {question}")
print(f"历史记录数: {len(chat_history)} 条")
print("=" * 60)
# 10. 混合检索
retrieved_nodes = hybrid_retriever.retrieve(question)
print("=" * 60)
print("第一阶段:混合检索(向量 + BM25,RRF 融合)")
print("=" * 60)
print(f"召回数量:{len(retrieved_nodes)}")
for i, node in enumerate(retrieved_nodes, 1):
print(f"\n--- 召回结果 {i} ---")
print(f"RRF 融合分数:{node.score:.4f}")
print(f"Node ID:{node.node.node_id}")
print(f"Metadata:{node.metadata}")
print(f"内容:\n{node.text[:200]}...")
print("-" * 60)
# 11. Reranker 重排序 -- 它接收的就是上面 retrieved_nodes
reranked_nodes = reranker.postprocess_nodes(
retrieved_nodes,
query_str=question,
)
print("\n")
print("=" * 60)
print("第二阶段:Reranker 重排序")
print("=" * 60)
print(f"重排序后数量:{len(reranked_nodes)}")
for i, node in enumerate(reranked_nodes, 1):
print(f"\n--- 重排序结果 {i} ---")
print(f"Reranker 分数:{node.score}")
print(f"Node ID:{node.node.node_id}")
print(f"Metadata:{node.metadata}")
print(f"内容:\n{node.text}")
print("-" * 60)
# 12. 创建 Response Synthesizer
response_synthesizer = get_response_synthesizer(
text_qa_template=prompt_with_history,
llm=Settings.llm,
)
# 13. 直接使用重排序后的 Node 生成回答
response = response_synthesizer.synthesize(
question,
nodes=reranked_nodes,
)
print("\n" + "=" * 60)
print("生成回答:")
print("=" * 60)
print(f"回答: {response}")