Skip to main content
Version: Next

使用 LlamaIndex 构建 RAG

LlamaIndex 将 RAG 流程抽象为多个层次:

Document → Node → Index → Retriever → QueryEngine → LLM
  • Document:从原始文件解析出的文档对象。
  • Node:切分后的最小语义单元,包含文本、元数据和可选的向量。
  • Index:组织 Node 并支持检索的数据结构。
  • Retriever:根据问题返回相关 Node。
  • QueryEngine:将检索与回答合成为完整查询流程。

创建索引​

下面的示例使用目录读取器加载文档,并使用 Embedding 模型建立向量索引。实际项目中应通过环境变量或密钥管理服务提供配置,不要把密钥写入代码。

import os

from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
from llama_index.llms.openai_like import OpenAILike
from llama_index.embeddings.dashscope import DashScopeEmbedding

documents = SimpleDirectoryReader("./docs").load_data()

embed_model = DashScopeEmbedding(
model_name=os.environ["MODEL_NAME_EMBEDDING"],
api_key=os.environ["MODEL_API_KEY"],
)

index = VectorStoreIndex.from_documents(
documents,
embed_model=embed_model,
)

VectorStoreIndex.from_documents() 会完成文档切分、Embedding 计算和向量存储等步骤。需要更精细地控制切分时,可以先显式创建 Node:

from llama_index.core.node_parser import SentenceSplitter

splitter = SentenceSplitter(
chunk_size=1024,
chunk_overlap=200,
)
nodes = splitter.get_nodes_from_documents(documents)
index = VectorStoreIndex(nodes, embed_model=embed_model)

创建查询引擎​

llm = OpenAILike(
model=os.environ["MODEL_NAME_LLM"],
api_base=os.environ["MODEL_URL_LLM"],
api_key=os.environ["MODEL_API_KEY"],
is_chat_model=True,
)

query_engine = index.as_query_engine(
similarity_top_k=3,
streaming=True,
llm=llm,
)

response = query_engine.query("学院的定位是什么?")
response.print_response_stream()

similarity_top_k 控制召回的片段数量。它不是越大越好:过小可能遗漏信息,过大则会引入无关上下文。应结合评测结果和问题类型调节。

查看召回内容​

调试 RAG 时,不要只观察最终答案,还要检查检索阶段的输出:

response = query_engine.query("学院的定位是什么?")

for i, source_node in enumerate(response.source_nodes, start=1):
print(f"结果 {i}")
print("来源:", source_node.node.metadata.get("file_name"))
print("相似度:", source_node.score)
print(source_node.get_content())

如果召回的片段本身与问题无关,问题出在检索链路,而不是回答模型。

持久化与加载​

索引创建可能涉及大量文件解析和向量计算,生产使用时应持久化,避免每次启动都重新构建:

index.storage_context.persist("./knowledge_base/test")

加载已有索引:

from llama_index.core import StorageContext, load_index_from_storage

storage_context = StorageContext.from_defaults(
persist_dir="./knowledge_base/test"
)
index = load_index_from_storage(
storage_context,
embed_model=embed_model,
)

加载索引时应使用与建库阶段兼容的 Embedding 模型,否则可能出现向量维度或语义空间不一致的问题。

自定义 OpenAI 兼容 Embedding 服务​

如果 Embedding 服务只提供 OpenAI 兼容的 HTTP 接口,可以实现 LlamaIndex 的 BaseEmbedding,在 _get_embedding() 中发送请求并返回 data[0].embedding。请求失败时应保留 HTTP 错误,便于定位服务或配置问题;不要用空向量静默兜底。