ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

LlamaIndex

LlamaIndex 一、为什么需要 RAG大模型虽然能力强大但存在三个核心短板问题表现知识截止模型训练数据有截止日期无法回答最新政策幻觉问题面对不熟悉的领域模型会一本正经地胡说八道私有知识缺失银行内部政策、考核标准等文档模型从未见过RAGRetrieval-Augmented Generation检索增强生成的思路很简单用户提问 → 先从知识库中检索相关文档片段 → 将片段作为上下文喂给大模型 → 大模型基于上下文生成回答这样模型回答的每句话都有据可查大幅降低幻觉风险。二、技术栈一览组件选型作用框架LlamaIndexRAG 流程编排提供文档加载、切块、索引、检索的完整链路向量数据库ChromaDB存储文档向量支持持久化到本地磁盘Embedding 模型通义千问 text-embedding将文本转为高维向量LLM构建索引用qwen-plus索引构建阶段使用的语言模型LLM问答用DeepSeek查询阶段使用的语言模型API 网关阿里云百炼 DashScope提供 OpenAI 兼容接口三、环境准备3.1 安装依赖pip install llama-index llama-index-vector-stores-chroma pip install chromadb llama-index-embeddings-openai llama-index-llms-openai pip install llama-index-llms-deepseek四、索引构建build_index.pyimport os import chromadb from llama_index.core import ( SimpleDirectoryReader, VectorStoreIndex, Settings, StorageContext ) from llama_index.core.node_parser import SentenceSplitter from llama_index.vector_stores.chroma import ChromaVectorStore from llama_index.embeddings.openai import OpenAIEmbedding from llama_index.llms.openai import OpenAI DASHSCOPE_API_KEY os.environ.get(DASHSCOPE_API_KEY) if DASHSCOPE_API_KEY is None: raise ValueError(DASHSCOPE_API_KEY not set) BASE_URL https://ws-f057okn6tche3m0w.cn-beijing.maas.aliyuncs.com/compatible-mode/v1 # 设置向量模型 Settings.embed_model OpenAIEmbedding( modesimilarity, modeltext-embedding-ada-002, model_nameqwen3.7-text-embedding, api_keyDASHSCOPE_API_KEY, api_baseBASE_URL, max_retries3, timeout60, ) # 设置 LLM 模型 Settings.llm OpenAI( modelqwen-plus, api_keyDASHSCOPE_API_KEY, api_baseBASE_URL, max_retries3, timeout60, ) # 设置文本分割器 Settings.text_splitter SentenceSplitter(chunk_size500, chunk_overlap50) def load_documents(data_dir./data): reader SimpleDirectoryReader( data_dir, recursiveTrue, file_metadatalambda filename: {source: os.path.basename(filename)} ) documents reader.load_data() print(f✅ 加载了 {len(documents)} 个文档片段) return documents def build_and_save_index(documents, persist_dir./storage): # 连接 ChromaDB chroma_client chromadb.PersistentClient(pathpersist_dir) chroma_collection chroma_client.get_or_create_collection( namebank_policy_collection, ) vector_store ChromaVectorStore(chroma_collectionchroma_collection) storage_context StorageContext.from_defaults(vector_storevector_store) index VectorStoreIndex.from_documents( documents, storage_contextstorage_context, show_progressTrue ) index.storage_context.persist(persist_dir) vector_count chroma_collection.count() print(f✅ 索引向量数: {vector_count}) return index if __name__ __main__: docs load_documents(./data) print(docs) index build_and_save_index(docs, ./storage) print(\n 索引构建完成运行 query.py 进行问答。)4.2 代码逐行解析4.2.1 全局配置SettingsLlamaIndex 的Settings是全局配置对象只需设置一次后续所有组件自动继承Settings.embed_model OpenAIEmbedding(...) # 向量化模型 Settings.llm OpenAI(...) # 语言模型 Settings.text_splitter SentenceSplitter(...) # 文本切块器4.2.2 文本切块器SentenceSplitterSettings.text_splitter SentenceSplitter(chunk_size500, chunk_overlap50)这是 RAG 中最容易被忽略、但影响最大的参数参数值含义chunk_size500每块约 500 个 token。太大→检索精度下降太小→上下文不足chunk_overlap50相邻块重叠约 50 个 token防止关键句子被从中间切断举例一段 1000 token 的文档大致切为块1: [0 — 500] 块2: [450 — 950] ← 与块1重叠50 块3: [900 — 1000] ← 与块2重叠50踩坑提示SentenceSplitter是基于token而非字符切分的。中文一个字通常约 2 个 token所以 500 token ≈ 250 个中文字符左右。4.2.3 文档加载SimpleDirectoryReaderreader SimpleDirectoryReader( data_dir, recursiveTrue, # 递归读取子目录 file_metadatalambda filename: {source: os.path.basename(filename)} )recursiveTrue递归扫描子目录支持多层级文档管理file_metadata为每个文档附加source元数据这是溯源的关键——检索到答案后可以告诉用户这个回答来自哪个文件SimpleDirectoryReader支持.pdf、.docx、.txt、.md、.csv等多种格式开箱即用。4.2.4 ChromaDB 持久化chroma_client chromadb.PersistentClient(pathpersist_dir) chroma_collection chroma_client.get_or_create_collection( namebank_policy_collection, ) vector_store ChromaVectorStore(chroma_collectionchroma_collection) storage_context StorageContext.from_defaults(vector_storevector_store)关键概念PersistentClient数据持久化到磁盘重启后不丢失Collection类似数据库中的表一个 collection 存储同类文档的向量VectorStore StorageContextLlamaIndex 的适配层把 ChromaDB 包装成统一的向量存储接口4.2.5 构建索引index VectorStoreIndex.from_documents( documents, storage_contextstorage_context, show_progressTrue )这一步内部做了三件事将文档按SentenceSplitter切成小块node对每个小块调用 embedding 模型生成向量将向量 原文 元数据写入 ChromaDBshow_progressTrue会在终端显示进度条构建大量文档时非常有用。五、问答检索query.pyimport os import chromadb from llama_index.core import Settings, StorageContext, load_index_from_storage from llama_index.vector_stores.chroma import ChromaVectorStore from llama_index.embeddings.openai import OpenAIEmbedding from llama_index.llms.openai import OpenAI from llama_index.llms.deepseek import DeepSeek DASHSCOPE_API_KEY os.environ.get(DASHSCOPE_API_KEY) if not DASHSCOPE_API_KEY: raise Exception(DASHSCOPE_API_KEY not set) BASE_URL https://ws-f057okn6tche3m0w.cn-beijing.maas.aliyuncs.com/compatible-mode/v1 Settings.embed_model OpenAIEmbedding( modesimilarity, modeltext-embedding-ada-002, model_nameqwen3.7-text-embedding, api_keyDASHSCOPE_API_KEY, api_baseBASE_URL, ) Settings.llm DeepSeek( modeldeepseek-chat, api_keyos.getenv(DEEPSEEK_API_KEY) ) def load_index(persist_dir./storage): chroma_client chromadb.PersistentClient(pathpersist_dir) chroma_collection chroma_client.get_collection(bank_policy_collection) vector_store ChromaVectorStore(chroma_collectionchroma_collection) storage_context StorageContext.from_defaults( vector_storevector_store, persist_dirpersist_dir ) index load_index_from_storage(storage_context) print(f✅ 索引加载成功向量数: {chroma_collection.count()}) return index def query_policy(index, user_query, top_k3): query_engine index.as_query_engine(similarity_top_ktop_k) response query_engine.query(user_query) print(\n 检索到的相关片段RAG 依据:) for i, node in enumerate(response.response_nodes, 1): score node.score if node.score else 0 print(f [{i}] 相似度: {score:.4f} | 来源: {node.metadata.get(source, 未知)}) preview node.text.replace(\n, )[:100] ... print(f 预览: {preview}) return response if __name__ __main__: index load_index(./storage) questions [ 个金客户经理的准入条件是什么, 客户经理的业绩考核包括哪些具体指标, 资深客户经理的储蓄业务准入标准是多少, 工作质量考核中服务质量扣分有哪些具体规定, ] for q in questions: print(\n * 60) print(f❓ 问题: {q}) response query_policy(index, q, top_k3) print(f\n 答案:\n{response})5.2 代码解析5.2.1 加载已有索引chroma_collection chroma_client.get_collection(bank_policy_collection)注意与构建时的区别构建阶段get_or_create_collection不存在则创建查询阶段get_collection必须已存在否则报错index load_index_from_storage(storage_context)load_index_from_storage从磁盘恢复索引对象无需重新构建秒级加载。5.2.2 查询引擎query_engine index.as_query_engine(similarity_top_ktop_k) response query_engine.query(user_query)similarity_top_k3检索相似度最高的 3 个文档片段查询流程用户问题 → embedding → ChromaDB 向量检索 → 取 top-3 → 拼接为上下文 → LLM 生成回答5.2.3 检索结果溯源response.response_nofor i, node in enumerate(response.response_nodes, 1): print(f [{i}] 相似度: {node.score:.4f} | 来源: {node.metadata.get(source, 未知)})des包含了检索到的原始文档片段每个 node 携带node.score相似度分数0~1越高越相关node.metadata构建时附加的元数据这里是我们存入的source文件名node.text原始文本内容chunk_size 怎么选场景推荐 chunk_size理由FAQ 问答200-300问题短精准匹配政策制度文档400-600条款通常较长需完整上下文长篇报告600-1000保持段落完整性similarity_top_k 怎么选k1~2追求精准适合 FAQk3~5通用场景的推荐值k5上下文过多可能引入噪声反而降低回答质量Embedding 和 LLM 可以用不同模型吗可以本项目中索引构建用qwen-plus通义千问问答生成用deepseek-chatDeepSeek两者完全独立。Embedding 模型在两个阶段必须保持一致同一模型同一维度但 LLM 可以随意切换。总结本文完整介绍了基于 LlamaIndex ChromaDB 的银行政策 RAG 问答系统搭建流程文档加载SimpleDirectoryReader支持多格式、递归读取、元数据溯源文本切块SentenceSplitter按 token 切分overlap 保证语义连续性向量存储ChromaDB 持久化重启不丢数据检索问答similarity_top_k控制召回数量response_nodes提供溯源信息
返回列表