2
0
0

基于 LlamaIndex 的 RAG 文档问答实现

2026-09-19
2026-09-19
基于 LlamaIndex 的 RAG 文档问答实现
文章摘要
|

基于 LlamaIndex 的 RAG 文档问答实现

本文使用 LlamaIndex 构建一个面向本地 Markdown 文档的 RAG 问答应用。最小可行系统采用初始化设置、文档加载、索引构建、查询引擎创建和查询验证五步。下面就采用这个最小系统实现基于 LlamaIndex 的 RAG 应用。

一、初始化设置

这一步要完成环境变量加载、LLM 配置和嵌入模型配置。RAG 应用同时依赖生成模型与向量模型,因此需要先通过 LlamaIndex 的 Settings 设置全局默认组件,后续索引构建和查询引擎会自动复用这些配置。

import os
# os.environ['HF_ENDPOINT'] = 'https://hf-mirror.com'
from dotenv import load_dotenv
from llama_index.core import Settings
from llama_index.llms.openai_like import OpenAILike
from llama_index.embeddings.huggingface import HuggingFaceEmbedding

load_dotenv()

Settings.llm = OpenAILike(
    model=os.getenv("DEEPSEEK_API_MODEL"),
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    api_base=os.getenv("DEEPSEEK_API_BASE"),
    is_chat_model=True
)
Settings.embed_model = HuggingFaceEmbedding("BAAI/bge-small-zh-v1.5")

这里使用 load_dotenv().env 文件加载环境变量,避免在代码中硬编码密钥。OpenAILike 用于兼容 OpenAI 接口的模型服务,其中 model 指定模型名称,api_key 从环境变量读取,api_base 指定服务地址,is_chat_model=True 表示按聊天模型方式调用。

嵌入模型使用 BAAI/bge-small-zh-v1.5。该模型体积较小,适合中文检索场景,并且可以在 CPU 环境中运行。这里使用其默认参数进行文本嵌入。如果模型下载受限,可以取消 HF_ENDPOINT 的注释,使用镜像地址。

使用 Settings 而不是在每个组件中重复传入模型,主要是为了让索引构建和查询引擎共享同一套 LLM 与嵌入配置。

二、加载本地文档

这一步需要将本地 Markdown 文档读取为 LlamaIndex 的 Document 对象。RAG 的第一步是数据准备,只有先将原始文档加载进内存,后续才能进行切分、嵌入和检索。

from llama_index.core import SimpleDirectoryReader

documents = SimpleDirectoryReader(
    input_files=["./text.md"]
).load_data()

SimpleDirectoryReader 是 LlamaIndex 中常用的文档加载器。这里通过 input_files 指定单个 Markdown 文件,load_data() 会返回一个 Document 列表。相对于直接读取目录,指定 input_files 可以精确控制输入文档,避免加载无关文件。

当不指定参数初始化 SimpleDirectoryReader 时,其默认行为旨在读取目录中的支持文件;这里使用 input_files 是为了让示例更聚焦于单篇文档。

三、构建向量索引

这一步要将加载后的文档转换为可检索的向量索引。LlamaIndex 会先对文档进行切分,再调用嵌入模型生成向量,最后写入默认的向量存储中。

from llama_index.core import VectorStoreIndex

index = VectorStoreIndex.from_documents(documents)

VectorStoreIndex.from_documents() 是高层 API,内部会完成节点切分、嵌入计算和索引构建。它默认使用 Settings.embed_model,也就是上一步配置的 HuggingFaceEmbedding。在不指定向量数据库时,索引通常保存在内存中,适合最小可行示例。

使用 VectorStoreIndex.from_documents() 而不是手动切分和写入,主要是为了以最小代码完成索引构建;后续需要优化时,可以替换切分器、向量存储或嵌入模型。

四、创建查询引擎

这一步要将索引封装为查询引擎。查询引擎负责接收用户问题,先检索相关文档片段,再将这些片段与问题一起交给 LLM,生成最终答案。

query_engine = index.as_query_engine()

print(query_engine.get_prompts())

index.as_query_engine() 会返回一个查询引擎。在不指定参数时,它会采用默认的检索与响应合成策略,例如默认检索一定数量的相关节点,并使用默认响应模式组织上下文。get_prompts() 用于查看当前查询引擎使用的提示词模板,便于调试检索增强生成中的上下文注入方式。

使用查询引擎而不是手动调用检索器和 LLM,主要是为了复用 LlamaIndex 的响应合成逻辑,包括上下文拼接、提示词模板和答案生成。

五、执行查询与验证

最后一步是输入问题并验证端到端流程。查询引擎会自动完成检索、上下文构造和大模型生成,因此这里只需要调用 query() 并打印结果。

question = "文中举了哪些例子?"
answer = query_engine.query(question)
print(answer)

query() 返回的是 Response 对象,直接 print 可以查看生成的答案文本。这里的问题与参考文档内容相关,用于验证文档是否被正确加载、索引是否建立成功,以及 LLM 是否能基于检索到的上下文作答。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

评论