使用 LlamaIndex + 阿里云百炼实现知识库

阿里云百炼准备工作

获取 API 密钥

阿里云百炼 API 密钥:从 阿里云控制台 获取。

模型

使用 链接 中的向量模型

目前,最新的模型:

  • 处理文本推荐 通用文本向量-v4

  • 处理文本+图片,推荐 通用多模态向量

LlamaIndex 安装依赖

pip install llama-index
pip install llama-index-llms-dashscope  # 阿里云百炼适配
pip install llama-index-embeddings-dashscope
pip install pypdf python-docx # 处理PDF文档、word文档

下载 NLTK stopwords 停用词

默认使用 NLTK 分词,首次执行代码时,会自动从 github.com 下载 停用词,如果不能访问 github.com,执行代码会报错下载失败

手动下载语料库

访问 stopwords 语料库的 GitHub 下载链接:

https://raw.githubusercontent.com/nltk/nltk_data/gh-pages/packages/corpora/stopwords.zip

解压到指定目录

  • 找到 nltk_data 的默认存储路径:
    Windows 系统通常为 C:\Users\你的用户名\AppData\Roaming\nltk_data(AppData 是隐藏文件夹,需开启“显示隐藏文件”)。
  • 在该路径下创建 corpora 文件夹(若不存在),将下载的 stopwords.zip 解压到 corpora 中,最终目录结构为:
    C:\Users\你的用户名\AppData\Roaming\nltk_data\corpora\stopwords\(解压后内部应有 english、chinese 等子文件夹)。

验证是否生效

运行以下代码,若不报错则配置成功:

import nltk
from nltk.corpus import stopwords
# 查看英文停用词(测试是否能加载)
print(stopwords.words('english')[:5])  # 输出前5个英文停用词

下载 NLTK punkt_tab 文本拆分

punkt_tab 是 LlamaIndex 文本拆分(尤其是句子级拆分)的核心依赖

首次执行代码时,会自动从 github.com 下载 punkt_tab.zip(用于文本分词的核心语料库),如果不能访问 github.com,执行代码会报错下载失败

手动下载 punkt_tab 语料库

直接访问 punkt_tab 的 GitHub 下载链接:

https://raw.githubusercontent.com/nltk/nltk_data/gh-pages/packages/tokenizers/punkt_tab.zip

解压到 nltk_data 指定目录

  • 找到 nltk_data 路径:
    Windows 系统默认路径为 C:\Users\你的用户名\AppData\Roaming\nltk_data(AppData 是隐藏文件夹,需开启“显示隐藏文件”)。
  • 创建目录结构:
    在 nltk_data 下新建 tokenizers 文件夹(若不存在),将下载的 punkt_tab.zip 解压到 tokenizers 中,最终目录为:
    C:\Users\你的用户名\AppData\Roaming\nltk_data\tokenizers\punkt_tab\
    (解压后内部应有 english.pickle、chinese.pickle 等分词模型文件)。

验证是否生效

运行以下代码,无报错则配置成功:

import nltk
from nltk.tokenize import sent_tokenize  # 依赖 punkt_tab 进行句子分割
# 测试句子分词
text = "这是第一个句子。这是第二个句子。"
print(sent_tokenize(text))  # 正常输出:['这是第一个句子。', '这是第二个句子。']

代码

import os
from llama_index.core import VectorStoreIndex,SimpleDirectoryReader,ServiceContext,PromptTemplate,Settings,StorageContext,load_index_from_storage
from llama_index.llms.dashscope import DashScope  # 阿里云百炼LLM适配
from llama_index.embeddings.dashscope import DashScopeEmbedding  # 阿里云百炼Embedding适配
from llama_index.core.node_parser import SentenceSplitter

import nltk

# 创建一个新的路径列表,将新路径添加到列表中
print("nltk.data.path:",nltk.data.path)
new_path = ['./nltk_data']
nltk.data.path += new_path
print("nltk.data.path:",nltk.data.path)


# --------------------------
# 配置阿里云百炼API密钥
# --------------------------
os.environ["DASHSCOPE_API_KEY"] = "sk-xxxx"  # 替换为实际API密钥

# --------------------------
# 初始化模型(LLM和Embedding)
# --------------------------
# 配置大语言模型(通义千问)
llm = DashScope(
    model_name="qwen-plus",  # 可选模型:qwen-plus/qwen-max/qwen-turbo等
    temperature=0.1,  # 控制回答随机性(0-1,越低越确定)
    api_key=os.getenv("DASHSCOPE_API_KEY"),  # 使用环境变量中的 API Key
)

# 配置Embedding模型(用于文本向量化)
embed_model = DashScopeEmbedding(
    model_name="text-embedding-v4",  # 使用阿里百炼 通用文本向量-v4
    dimension=1536,  # 模型输出维度(固定为1536)
    embed_batch_size=10  # 关键:设置批量处理大小为10(模型最大限制),否则请模型发请求会报400错误
)

# --------------------------
# 配置 SentenceSplitter,拆分token,防止文本多长,超过模型token限制
# --------------------------
node_parser = SentenceSplitter(
    chunk_size=1024,  # 单个节点1024 token
    chunk_overlap=50,  # 重叠50 token
)

# --------------------------
# 配置全局参数
# --------------------------

Settings.llm = llm
Settings.embed_model = embed_model
Settings.num_output = 512
Settings.context_window = 3900
Settings.node_parser = node_parser  # 应用SentenceSplitter

# --------------------------
# 加载与处理文档,加载当前目录下 docs 文件夹下的文档
# --------------------------
def load_documents(doc_dir="docs"):
    """加载指定文件夹中的所有文档(支持PDF、TXT、DOCX等)"""
    # 自动识别并加载文件夹中的所有文档
    loader = SimpleDirectoryReader(
        input_dir=doc_dir,
        recursive=True  # 递归加载子文件夹文档
    )
    return loader.load_data()

# --------------------------
# 构建或加载索引
# persist_dir:向量索引的保存路径
# --------------------------
def get_index(documents, persist_dir="./text_index"):
    """构建新索引或加载已保存的索引"""
    if not os.path.exists(persist_dir):
        # 首次运行:构建索引并保存到本地
        index = VectorStoreIndex.from_documents(
            documents
        )
        # 持久化索引(避免重复构建)
        index.storage_context.persist(persist_dir=persist_dir)
        print(f"索引构建完成,已保存至 {persist_dir}")
    else:
        # 后续运行:加载已有索引
        storage_context = StorageContext.from_defaults(persist_dir=persist_dir)
        index = load_index_from_storage(
            storage_context
        )
        print(f"已加载现有索引:{persist_dir}")
    return index

# --------------------------
# 构建问答引擎并交互
# --------------------------
if __name__ == "__main__":
    # 加载文档(确保"docs"文件夹中存在你的知识库文档)
    documents = load_documents(doc_dir="文档")
    print(f"成功加载 {len(documents)} 个文档")

    # 获取索引
    index = get_index(documents)

    # 创建查询引擎(配置检索参数)
    query_engine = index.as_query_engine(
        similarity_top_k=3  # 检索最相关的3个文档片段
    )

    # 交互式问答
    print("\n===== 知识库问答系统 =====")
    while True:
        question = input("\n请输入问题(输入'q'退出):")
        if question.lower() == "q":
            break
        # 调用查询引擎获取回答
        response = query_engine.query(question)
        print("\n回答:")
        print(response)
        # 可选:打印参考的文档来源
        print("\n参考文档片段:")
        for i, node in enumerate(response.source_nodes, 1):
            print(f"\n片段{i}(相关性:{node.score:.2f}):")
            print(node.text[:200] + "...")  # 显示前200字符

创建文档

在当前工程目录下创建 文档 目录,该目录下存放要学习的文档

运行程序

执行程序后,生成 text_index 目录,该目录是存放向量的数据