基于 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 底层使用 dashscope SDK,该 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 等
文档切分策略可配置 SentenceSplitterTokenTextSplitter
元数据嵌入索引用于过滤 ✅ 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. 总结

核心优势

  1. 极简 API:3 行核心代码完成 RAG 全流程
  2. 开箱即用:文档加载、切分、索引、检索一体化
  3. 高度可扩展:支持自定义 Reader、Parser、Retriever、LLM
  4. 生产就绪:支持持久化、流式输出、多轮对话

适用场景

场景 说明
企业知识库问答 规章制度、操作手册、FAQ
文档智能检索 合同、论文、报告检索
客服机器人 产品咨询、技术支持
个人知识管理 笔记、书签、收藏整理

与 LangGraph 的对比

维度 LlamaIndex LangGraph
核心定位 RAG 框架 工作流编排框架
文档处理 内置加载、切分、索引 需手动实现
向量检索 一体化 需集成 FAISS 等
复杂流程 支持但非核心 核心能力(条件分支、并行)
学习曲线 较平缓 较陡峭

更多推荐