基于 LlamaIndex 构建企业知识库问答系统
·
基于 LlamaIndex 构建企业知识库问答系统
前言
企业内部的规章制度、操作手册、FAQ 等文档往往散落在各个系统中,员工遇到问题时难以快速找到准确答案。传统的关键词搜索只能匹配字面,无法理解语义;而大语言模型虽然能理解语义,却无法直接访问企业私有数据。
RAG(检索增强生成) 是解决这一问题的标准方案:先将文档切块并构建向量索引,查询时先检索相关片段,再交给 LLM 生成答案。本文基于 LlamaIndex 框架,用不到 40 行代码实现一个企业休假制度问答系统。
1. 整体架构
1.1 系统全景

1.2 核心组件
| 组件 | 作用 | LlamaIndex 实现 |
|---|---|---|
| 文档加载器 | 读取多种格式文件 | SimpleDirectoryReader |
| 文本切分器 | 将文档切为语义块 | 默认 SentenceSplitter |
| Embedding 模型 | 文本转向量 | DashScopeEmbedding |
| 向量索引 | 存储和检索向量 | VectorStoreIndex |
| 查询引擎 | 检索 + 生成 | as_query_engine() |
| LLM | 生成最终答案 | OpenAILike |
1.3 技术栈
- LlamaIndex:RAG 框架,提供文档加载、索引、检索一体化能力
- DashScope(通义千问):LLM 和 Embedding 接口
- qwen-plus:生成答案的大语言模型
- text-embedding-v3:文本向量化的 Embedding 模型
2. 代码实现
2.1 环境配置
from dotenv import load_dotenv
load_dotenv()
import os
import dashscope
from llama_index.core import Settings
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.llms.openai_like import OpenAILike
from llama_index.embeddings.dashscope import DashScopeEmbedding, DashScopeTextEmbeddingModels
# dashscope SDK 需要显式设置 api_key
dashscope.api_key = os.getenv("DASHCOPE_KEY")
踩坑记录:
DashScopeEmbedding底层使用dashscopeSDK,该 SDK 需要DASHSCOPE_API_KEY环境变量。如果.env中变量名不同(如DASHCOPE_KEY),必须通过dashscope.api_key = ...显式设置。
2.2 全局配置
Settings.llm = OpenAILike(
model="qwen-plus",
api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
api_key=os.getenv("DASHCOPE_KEY"),
is_chat_model=True
)
Settings.embed_model = DashScopeEmbedding(
model_name=DashScopeTextEmbeddingModels.TEXT_EMBEDDING_V3,
embed_batch_size=6,
embed_input_length=8192
)
Settings 是 LlamaIndex 的全局配置对象,设置后所有组件自动使用:
| 参数 | 含义 | 本例取值 |
|---|---|---|
model |
LLM 模型名 | qwen-plus |
api_base |
兼容 OpenAI 协议的接口地址 | DashScope |
is_chat_model |
是否为对话模型 | True |
model_name |
Embedding 模型名 | text-embedding-v3 |
embed_batch_size |
批量 embedding 数量 | 6(DashScope 限制) |
embed_input_length |
单条文本最大长度 | 8192 |
2.3 三步构建问答系统
# 第1步:加载文档
documents = SimpleDirectoryReader("data").load_data()
# 第2步:构建向量索引
index = VectorStoreIndex.from_documents(documents)
# 第3步:创建查询引擎并提问
query_engine = index.as_query_engine()
response = query_engine.query("怎么休事假?")
print(response)
仅 3 行核心代码,就完成了文档加载 → 索引构建 → 语义问答的完整流程。
3. 运行效果
以《公司员工休假福利管理制度》为知识库:
Q: 怎么休事假?
A: 员工因私事必须本人处理的,可申请事假。需提前向直属主管提出申请并获得批准;
如遇紧急情况,可事后补办手续。事假为无薪假,按日扣除相应工资。
每月事假原则上不超过3天,全年累计不得超过15天。
Q: 元旦休假几天?
A: 元旦休假1天。
Q: 春节休假几天?
A: 春节休假3天。
4. LlamaIndex 核心机制详解
4.1 文档加载
SimpleDirectoryReader 支持多种文件格式:
# 基础用法:读取目录下所有支持的文件
documents = SimpleDirectoryReader("data").load_data()
# 进阶用法:指定扩展名、递归子目录、排除隐藏文件
documents = SimpleDirectoryReader(
"data",
required_exts=[".txt", ".pdf"], # 只读取特定格式
recursive=True, # 递归子目录
exclude_hidden=True # 排除隐藏文件
).load_data()
4.2 文本切分
文档加载后,LlamaIndex 自动使用默认的 SentenceSplitter 将文档切分为 Node:
原始文档 → 按句子边界切分 → 生成多个 Node(每个 Node 包含文本 + 元数据)
from llama_index.core.node_parser import SentenceSplitter
# 自定义切分策略
parser = SentenceSplitter(
chunk_size=512, # 每块目标字符数
chunk_overlap=50, # 块间重叠
separator=" ", # 句子分隔符
)
nodes = parser.get_nodes_from_documents(documents)
4.3 向量索引
# 构建索引(自动调用 Embedding 模型)
index = VectorStoreIndex.from_documents(documents)
# 持久化保存(避免每次重新构建)
index.storage_context.persist(persist_dir="./storage")
# 加载已保存的索引
from llama_index.core import StorageContext, load_index_from_storage
storage_context = StorageContext.from_defaults(persist_dir="./storage")
index = load_index_from_storage(storage_context)
4.4 查询引擎
# 基础查询
query_engine = index.as_query_engine()
response = query_engine.query("怎么休事假?")
# 流式查询(实时输出)
streaming_engine = index.as_query_engine(streaming=True)
response = streaming_engine.query("怎么休事假?")
response.print_response_stream()
# 对话引擎(支持多轮问答)
from llama_index.core import ChatEngine
chat_engine = index.as_chat_engine()
response = chat_engine.chat("我想请事假,需要什么流程?")

5. 思考题:LlamaIndex 框架能力解答
5.1 数据层
| 问题 | LlamaIndex 支持情况 |
|---|---|
| 多种数据源统一接入 | ✅ 支持本地文件、云存储、数据库、API 等多种 Reader |
| 多种文件类型自动识别 | ✅ 支持 PDF、DOCX、CSV、PPT、HTML 等常见格式 |
| 容错能力 | ️ 部分支持,需自定义异常处理 |
| 动态指定目录路径 | ✅ SimpleDirectoryReader(path) 支持任意路径 |
| 递归读取子目录 | ✅ recursive=True |
| 自定义解析逻辑 | ✅ 继承 BaseReader 实现自定义解析器 |
5.2 索引层
| 问题 | LlamaIndex 支持情况 |
|---|---|
| 向量存储后端灵活切换 | ✅ 支持 FAISS、Chroma、Pinecone、Milvus 等 |
| 文档切分策略可配置 | ✅ SentenceSplitter、TokenTextSplitter 等 |
| 元数据嵌入索引用于过滤 | ✅ Node 支持 metadata 字段 |
| 索引持久化保存 | ✅ storage_context.persist() |
| 增量索引更新 | ✅ index.insert_nodes() |
| 混合搜索 | ✅ BM25Retriever + VectorIndexRetriever |
5.3 查询层
| 问题 | LlamaIndex 支持情况 |
|---|---|
| 流式输出 | ✅ streaming=True |
| 多轮问答和上下文理解 | ✅ ChatEngine 支持对话历史 |
| 路由到不同查询引擎 | ✅ RouterQueryEngine |
| 意图识别 | ⚠️ 需结合 Tool 或自定义逻辑实现 |
| 查询重写或澄清提问 | ✅ SubQuestionQueryEngine 支持查询分解 |
5.4 输出层
| 问题 | LlamaIndex 支持情况 |
|---|---|
| 转换为标准 JSON | ✅ response.get_response() |
| 附带引用来源 | ✅ response.source_nodes 获取引用节点 |
| 序列化跨网络传输 | ✅ 支持 JSON 序列化 |
| 结构化输出 | ✅ PydanticOutputParser |
| 安全检查 | ⚠️ 需外部介入,框架本身不提供 |
5.5 业务层
| 问题 | LlamaIndex 支持情况 |
|---|---|
| 适配具体业务场景 | ✅ 可通过自定义 Prompt 和 Tool 适配 |
| 不同用户角色看到不同结果 | ️ 需外部逻辑实现权限控制 |
| 业务规则与检索结果融合 | ✅ 可通过 Prompt 注入业务规则 |
| 反馈机制收集问题 | ⚠️ 需外部逻辑实现 |
| 高频未命中问题记录 | ⚠️ 需外部日志系统实现 |
5.6 工程层
| 问题 | LlamaIndex 支持情况 |
|---|---|
| 异常捕获和处理 | ✅ 标准 Python 异常机制 |
| 高并发和异步处理 | ✅ 支持异步加载和查询 |
| 关键日志记录 | ✅ 标准 logging |
| 监控指标 | ⚠️ token 消耗可通过回调获取 |
| CI/CD 集成 | ✅ 组件可编程组装 |
5.7 安全层
| 问题 | LlamaIndex 支持情况 |
|---|---|
| 敏感信息权限控制 | ⚠️ 需应用层实现 |
| 隐私内容保护 | ⚠️ 需外部脱敏机制 |
| 敏感字段自动脱敏 | ️ 需自定义预处理 |
| 合规性校验 | ⚠️ 需外部内容过滤 |
| 安全审计 | ⚠️ 需外部系统实现 |
5.8 扩展层
| 问题 | LlamaIndex 支持情况 |
|---|---|
| 自定义数据连接器 | ✅ 继承 BaseReader |
| 多模态内容理解 | ✅ 支持图像、表格等(需对应模型) |
| 自由替换 LLM | ✅ 支持 HuggingFace、Ollama、本地模型 |
| 开放接口或 SDK | ✅ 提供 Python SDK |
| 扩展新数据源/索引类型 | ✅ 高度可扩展的插件架构 |
6. 总结
核心优势
- 极简 API:3 行核心代码完成 RAG 全流程
- 开箱即用:文档加载、切分、索引、检索一体化
- 高度可扩展:支持自定义 Reader、Parser、Retriever、LLM
- 生产就绪:支持持久化、流式输出、多轮对话
适用场景
| 场景 | 说明 |
|---|---|
| 企业知识库问答 | 规章制度、操作手册、FAQ |
| 文档智能检索 | 合同、论文、报告检索 |
| 客服机器人 | 产品咨询、技术支持 |
| 个人知识管理 | 笔记、书签、收藏整理 |
与 LangGraph 的对比
| 维度 | LlamaIndex | LangGraph |
|---|---|---|
| 核心定位 | RAG 框架 | 工作流编排框架 |
| 文档处理 | 内置加载、切分、索引 | 需手动实现 |
| 向量检索 | 一体化 | 需集成 FAISS 等 |
| 复杂流程 | 支持但非核心 | 核心能力(条件分支、并行) |
| 学习曲线 | 较平缓 | 较陡峭 |
更多推荐
所有评论(0)