项目结构llamaindex-rag-example/├── data/ # 存放待处理的原始文档（如PDF/TXT/Markdown等）├── storage_exp/ # 持久化存储向量索引的目录（自动生成）├── 01_build.py # 构建并持久化向量索引的脚本└── 02_query.py # 加载索引并进行问答查询的脚本PDF文件转Markdown#如果直接用 pdf版解析会很差，可以用mineru转化为md文件，但是测试 api 速度也不快， 可以直接在官网将文档转化下载，时间最快，还可以进行调整 官网：https://mineru.net/ 01_build.py 构建索引import os import time import torch from pathlib import Path from llama_index.core import VectorStoreIndex, Settings, Document from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.core.node_parser import SimpleNodeParser # 配置 device = "cpu" #如果直接用 pdf版解析会很差，可以用mineru转化为md文件，但是测试 api 速度也不快， 可以直接在官网将文档转化下载，时间最快，还可以进行调整https://mineru.net/ markdown_path = "./data/test_manual.md" persist_dir = "./storage_exp" # 创建目录 os.makedirs(persist_dir, exist_ok=True) os.makedirs("./models", exist_ok=True) # 2. 配置全局 Embedding（本地 Qwen3 模型） EMBEDDING_PATH = "/Users/t-mac/.cache/huggingface/hub/models--Qwen--Qwen3-Embedding-0.6B/snapshots/c54f2e6e80b2d7b7de06f51cec4959f6b3e03418" Settings.embed_model = HuggingFaceEmbedding( model_name=EMBEDDING_PATH, trust_remote_code=True ) # 读取 Markdown 文件 print(f"读取 Markdown: {markdown_path}") with open(markdown_path, "r", encoding="utf-8") as f: markdown_content = f.read() print(f"文档长度: {len(markdown_content)} 字符") # 创建 Document doc = Document( text=markdown_content, metadata={ "source": Path(markdown_path).name, "file_path": str(Path(markdown_path).absolute()), } ) # 切分文档 print("切分文档...") parser = SimpleNodeParser(chunk_size=512, chunk_overlap=50) nodes = parser.get_nodes_from_documents([doc]) print(f"生成 {len(nodes)} 个节点") # 构建索引 print("构建索引...") start_time = time.time() index = VectorStoreIndex(nodes) build_time = time.time() - start_time print(f"索引构建完成，耗时 {build_time:.2f} 秒") # 保存索引 print(f"保存索引到 {persist_dir}...") index.storage_context.persist(persist_dir=persist_dir) # 统计 index_size = 0 for root, dirs, files in os.walk(persist_dir): for file in files: index_size += os.path.getsize(os.path.join(root, file)) print("\n" + "="*50) print("构建完成!") print("="*50) print(f"文档长度: {len(markdown_content):,} 字符") print(f"节点数量: {len(nodes)}") print(f"索引大小: {index_size / 1024:.1f} KB") print(f"总耗时: {build_time:.2f} 秒") print("="*50) 02_query.pyimport os import sys import time from llama_index.core import StorageContext, load_index_from_storage, Settings from llama_index.llms.openai import OpenAI from llama_index.llms.openai_like import OpenAILike from llama_index.core.prompts import PromptTemplate from llama_index.core.postprocessor import SentenceTransformerRerank from llama_index.retrievers.bm25 import BM25Retriever # 导入依赖 from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings from llama_index.embeddings.huggingface import HuggingFaceEmbedding import os from dotenv import load_dotenv # 加载环境变量 load_dotenv() QIANWEN_KEY = os.getenv("QIANWEN_API_KEY") os.environ["TOKENIZERS_PARALLELISM"] = "false" # 配置 device = "mps" persist_dir = "./storage_exp" lm_studio_url = "http://localhost:1234/v1" # 2. 配置全局 Embedding（本地 Qwen3 模型） EMBEDDING_PATH = "/Users/t-mac/.cache/huggingface/hub/models--Qwen--Qwen3-Embedding-0.6B/snapshots/c54f2e6e80b2d7b7de06f51cec4959f6b3e03418" Settings.embed_model = HuggingFaceEmbedding( model_name=EMBEDDING_PATH, trust_remote_code=True ) # 1. 配置全局 LLM（通义千问） Settings.llm = OpenAILike( model="qwen3.5-flash", api_base="https://dashscope.aliyuncs.com/compatible-mode/v1", api_key=QIANWEN_KEY, is_chat_model=True, temperature=0.1 ) # 重排序器 # 中文专用重排模型 # reranker = SentenceTransformerRerank( # model="BAAI/bge-reranker-base", # top_n=5 # ) # 提示词模板 PROMPT = PromptTemplate( """你是一个专业的 HR 助手，请基于以下员工手册内容回答问题。 {context_str} 问题：{query_str} 回答：""" ) # 加载索引 print("加载索引...") storage_context = StorageContext.from_defaults(persist_dir=persist_dir) index = load_index_from_storage(storage_context) print(f"索引加载成功，共 {len(index.docstore.docs)} 个节点") def hybrid_search(query, top_k=5): """混合检索""" # 向量检索 vector_retriever = index.as_retriever(similarity_top_k=10) vector_nodes = vector_retriever.retrieve(query) # BM25 检索 all_nodes = [] for doc_id in index.docstore.docs.keys(): doc = index.docstore.get_document(doc_id) if hasattr(doc, 'nodes'): all_nodes.extend(doc.nodes) else: all_nodes.append(doc) bm25_retriever = BM25Retriever.from_defaults( nodes=all_nodes, similarity_top_k=10, ) bm25_nodes = bm25_retriever.retrieve(query) # 合并去重 seen = set() merged = [] for node in vector_nodes + bm25_nodes: if node.node.node_id not in seen: seen.add(node.node.node_id) merged.append(node) return merged[:top_k] # # 重排序 # reranked = reranker.postprocess_nodes(merged, query_str=query) # return reranked[:top_k] def generate_answer(query, nodes): """生成回答""" from llama_index.core import get_response_synthesizer synthesizer = get_response_synthesizer(text_qa_template=PROMPT) return synthesizer.synthesize(query, nodes=nodes) def query(question): """执行查询""" nodes = hybrid_search(question) response = generate_answer(question, nodes) return response.response if __name__ == "__main__": question = "员工违约的条件有哪些？" print(f"\n问题: {question}") print("-" * 40) start = time.time() answer = query(question) elapsed = time.time() - start print(f"回答: {answer}") print("-" * 40) print(f"耗时: {elapsed:.2f} 秒") 测试结果/opt/miniconda3/envs/langchain-dev/bin/python /Users/t-mac/workspace/Python/python_code/24-LlamaIndex/projects/llamaindex-rag-example/02_query.py W0522 23:40:21.752000 33319 site-packages/torch/distributed/elastic/multiprocessing/redirects.py:35] NOTE: Redirects are currently not supported in MacOs. W0522 23:40:21.774000 33319 site-packages/torch/utils/_pytree.py:630] <enum 'KernelPreference'> is an Enum subclass and is now natively supported by torch.compile as an opaque value type. Calling register_constant() on Enum subclasses is deprecated and will be an error in a future release. W0522 23:40:21.793000 33319 site-packages/torch/utils/_pytree.py:630] <enum 'ScaleCalculationMode'> is an Enum subclass and is now natively supported by torch.compile as an opaque value type. Calling register_constant() on Enum subclasses is deprecated and will be an error in a future release. Loading weights: 100%|██████████| 310/310 [00:00<00:00, 8048.99it/s] 加载索引... 索引加载成功，共 98 个节点 问题: 员工违约的条件有哪些？ ---------------------------------------- 回答: 你好！我是你的专业 HR 助手。根据提供的《员工手册》内容，虽然手册中主要使用“违纪”、“严重违纪”及“解除劳动合同”等术语，但以下情况均属于员工违反公司规章制度或劳动合同约定的条件（即通常理解的“违约”情形）。 以下是基于文档整理的员工违纪及违规的具体条件分类： ### 1. 考勤与出勤违规 * **迟到早退：** 连续 30 天内迟到或早退三次及以上（10.1.1）；试用期内迟到早退累计达三次或以上（4.5）。 * **旷工：** * 未经请假或请假未获批准擅自不到岗（3.1）。 * 请假期满未续假或续假未批逾期不归（3.3.2）。 * 特殊原因未在当日上班 1 小时内请假，或事后 3 个工作日内未补办手续（3.3.3）。 * 不服从工作调动、工时制度调整拒不执行导致未正常出勤（3.3.4）。 * **后果阈值：** 连续旷工 2 天及以上，或一年内累计旷工 3 天及以上（10.1.2）；连续旷工 3 天及以上，或全年累计旷工 7 天及以上（3.2）。 * **打卡异常：** 委托他人打卡或替他人打卡（10.1.3）；连续 30 天累计 6 次以上未打卡且无法说明原因或提供证明（1.4 / 10.1.4）。 * **试用期出勤率：** 试用期实际出勤日/应出勤日低于 85%（4.5）。 ### 2. 诚信与入职信息违规 * **虚假信息：** 伪造学历、工作经历、证书，简历、入职登记信息、健康状况等与真实情况不符（4.6）。 * **隐瞒欺骗：** 有欺骗、隐瞒行为（4.6）。 * **价值观问题：** 诚信等价值观存在问题，无论服务年限长短，均可能导致立即解除劳动合同（1.3）。 * **竞业限制：** 入职本公司将违反竞业限制义务（4.15）。 ### 3. 行为规范与安全违规 * **扰乱秩序：** 发起、参与离岗、怠工、罢工、示威，或鼓动他人参与（10.2.1）。 * **骚扰行为：** 侮辱、诽谤、辱骂、造谣、威胁、恐吓他人（10.2.2）。 * **现场管理：** 将无关人员带入工作现场，情节严重或造成损害（10.2.3）。 * **安全隐患：** 在库房等高风险区域内吸烟，情节严重或造成损害（10.2.4）。 * **资产损害：** 损坏或遗失公司财物，浪费公司资产，情节严重或造成损害（10.2.5 / 10.2.6）。 ### 4. 法律、健康与个人资质违规 * **刑事犯罪：** 被判处有期徒刑尚在服刑（4.8）；通缉在案（4.10）；实施违反国家法律法规的行为（如加入邪教、恐怖组织、酗酒、吸毒、赌博、嫖娼等）（4.14）。 * **权利状态：** 被剥夺公民权利者（4.9）。 * **年龄与健康：** 未满 16 周岁（4.11）；传染性疾病病原携带者或患有其他严重疾病（4.12）；患有精神病（4.13）。 * **债务问题：** 拖欠他人重大债务或进入法院执行程序未偿还债务者（4.16）。 * **过往记录：** 曾经被公司辞退或未经批准擅自离职者（4.7）。 ### 5. 试用期特殊解除条件 * **处分记录：** 试用期期间受记过及以上处分者（4）。 * **综合表现：** 上述考勤、诚信、法律等条款在试用期内触犯者（4.5 - 4.16）。 ### 6. 管理与连带责任 * **监管不力：** 管理者对员工违纪行为存在监管不力、失察、包庇、纵容或教唆等情形的，主管也将受到处罚（9.6）。 * **兜底条款：** 其他任何与前述违纪行为严重性相当的行为，或违反部门规定的行为，情节较重或造成一般损害的（5）。 **总结：** 根据手册第 10 条，若员工出现上述**严重违纪行为**，公司将对其进行**辞退（解除劳动合同）**。其中涉及诚信价值观问题、刑事犯罪、严重旷工等行为，公司有权立即解除合同且不支付经济补偿。 希望以上整理能帮助您准确理解员工手册中的相关规定。如有具体案例需要分析，欢迎随时提问。 ---------------------------------------- 耗时: 37.51 秒
LlamaIndex 学习笔记git地址https://github.com/zxliucn/LlamaIndex-Learning目录文档加载 (DataLoader)节点解析器 (NodeParser)嵌入模型 (Embedding Model)索引与存储 (Index)检索器 (Retriever)索引、向量数据与数据库的关系一、文档加载 (DataLoader)文档加载是 LlamaIndex 构建 RAG 应用的第一步，也是最基础的一步。本文将全面介绍 LlamaIndex 中文档加载的各种方式、核心概念以及高级自定义技巧。1.1 核心概念：Document在 LlamaIndex 中，Document（文档）是对原始数据源的标准化封装，是整个 RAG 流程的数据入口。它不仅仅指传统的文本文档，而是涵盖所有可被加载的结构化/非结构化数据的抽象载体。Document 的核心属性属性类型说明textstr核心属性，存储文档的原始文本内容metadatadict元数据字典，记录文档的上下文信息（文件名、路径、创建时间等）id_ / doc_idstr唯一标识符，用于区分不同 DocumentDocument 的关键特性多源适配性：LlamaIndex 提供 100+ 内置 Data Loader，可将不同数据源统一为 Document 对象不可变性：原始 Document 加载后内容不会被修改（分割操作会生成新的 Node）编码保障：加载中文文档时需通过 encoding="utf-8" 指定编码1.2 文档加载的三种方式方式一：使用 SimpleDirectoryReader（最常用）SimpleDirectoryReader 是最简单易用的加载器，可以将指定目录中的文件批量加载为 Document 对象：from llama_index.core import SimpleDirectoryReader # 基本用法：加载目录下所有文件 documents = SimpleDirectoryReader("./data").load_data() # 指定编码（处理中文文档） documents = SimpleDirectoryReader("./data", encoding="utf-8").load_data() # 查看加载结果 print(f"加载文档数量：{len(documents)}") print(f"第一个文档内容长度：{len(documents[0].text)}字符") print(f"文档元数据：{documents[0].metadata}")支持的文件格式：Markdown、PDF、Word 文档、PowerPoint 演示文稿、图像、音频和视频等。方式二：使用 LlamaHub 的数据加载器LlamaHub 是 LlamaIndex 的数据连接器注册表，提供了数百种连接器，支持从各种数据源加载数据：from llama_index.core import download_loader from llama_index.readers.database import DatabaseReader # 示例：从 SQL 数据库加载数据 reader = DatabaseReader( scheme="postgresql", host="localhost", port=5432, user="myuser", password="mypassword", dbname="mydb", ) query = "SELECT * FROM users" documents = reader.load_data(query=query)方式三：手动构造 Documentfrom llama_index.core import Document # 从文本列表创建 text_list = ["文本1内容", "文本2内容", "文本3内容"] documents = [Document(text=t) for t in text_list] # 创建单个文档 document = Document(text="这是文档的原始文本内容") # 快速创建示例文档（用于原型开发） example_doc = Document.example()1.3 元数据（Metadata）管理元数据是 Document 的重要组成部分，用于记录文档的上下文信息，对回答溯源和多文档管理至关重要。设置元数据方式一：在构造函数中设置document = Document( text="文档内容", metadata={ "filename": "important_doc.pdf", "category": "技术文档", "author": "张三", "creation_date": "2024-01-15" } )方式二：创建后设置document = Document(text="文档内容") document.metadata = {"filename": "doc.txt", "category": "指南"}方式三：使用 SimpleDirectoryReader 自动设置from llama_index.core import SimpleDirectoryReader # 定义元数据生成函数 filename_fn = lambda filename: {"file_name": filename, "source": "local"} documents = SimpleDirectoryReader( "./data", file_metadata=filename_fn ).load_data()自定义文档 ID# 自动将文件路径作为 ID documents = SimpleDirectoryReader("./data", filename_as_id=True).load_data() # 手动设置 ID document.doc_id = "my_custom_document_id"高级元数据自定义from llama_index.core import Document from llama_index.core.schema import MetadataMode document = Document( text="这是一个需要处理的文档", metadata={ "file_name": "secret_document.txt", "category": "finance", "author": "LlamaIndex" }, excluded_llm_metadata_keys=["file_name"], excluded_embed_metadata_keys=["file_name"], ) # 查看 LLM 实际看到的内容 print(document.get_content(metadata_mode=MetadataMode.LLM)) # 查看 Embedding 模型实际看到的内容 print(document.get_content(metadata_mode=MetadataMode.EMBED))自定义元数据格式document = Document( text="文档内容", metadata={"key1": "value1", "key2": "value2"}, metadata_seperator=" | ", # 键值对之间的分隔符 metadata_template="{key}: {value}", # 每个键值对的格式 text_template="元数据：{metadata_str}\n---\n内容：{content}" )1.4 批量加载与高级用法批量加载目录from llama_index.core import SimpleDirectoryReader documents = SimpleDirectoryReader( input_dir="./docs", recursive=True, # 递归读取子目录 required_exts=[".pdf", ".txt"], # 只加载特定扩展名 exclude=["temp", "draft"] # 排除特定目录 ).load_data()使用 DocStore 管理多个索引from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, SummaryIndex from llama_index.core.storage.docstore import SimpleDocumentStore from llama_index.core import StorageContext from llama_index.core.node_parser import SentenceSplitter documents = SimpleDirectoryReader("./data").load_data() nodes = SentenceSplitter().get_nodes_from_documents(documents) docstore = SimpleDocumentStore() docstore.add_documents(nodes) storage_context = StorageContext.from_defaults(docstore=docstore) # 多个索引共享同一个文档存储 vector_index = VectorStoreIndex(nodes, storage_context=storage_context) summary_index = SummaryIndex(nodes, storage_context=storage_context)1.5 完整示例：从加载到索引from llama_index.core import ( SimpleDirectoryReader, VectorStoreIndex, Settings ) from llama_index.core.node_parser import SentenceSplitter from llama_index.llms.openai import OpenAI # 1. 配置 LLM Settings.llm = OpenAI(model="gpt-3.5-turbo", temperature=0) # 2. 加载文档 documents = SimpleDirectoryReader( "./data", encoding="utf-8", filename_as_id=True ).load_data() # 3. 设置文本分割 Settings.chunk_size = 512 Settings.chunk_overlap = 20 # 4. 构建索引 index = VectorStoreIndex.from_documents(documents) # 5. 查询测试 query_engine = index.as_query_engine() response = query_engine.query("你的问题在这里") print(response)1.6 常见问题与最佳实践问题建议中文编码务必指定 encoding="utf-8"元数据保留文件路径和文件名，便于溯源；敏感信息用 excluded_llm_metadata_keys 排除性能大文档集设置合理 chunk_size（512-1024）；避免不必要的深层遍历文档刷新设置 filename_as_id=True 方便检测变化并刷新索引二、节点解析器 (NodeParser)2.1 核心概念：Document vs NodeDocument：原始文档对象，可以是一整个文件或一段文本Node：文档切分后的"块"，包含文本内容、元数据以及节点间的关系信息（如前后节点、父节点引用）from llama_index.core.schema import TextNode, NodeRelationship, RelatedNodeInfo node1 = TextNode(text="这是第一个文本块", id_="node_1") node2 = TextNode(text="这是第二个文本块", id_="node_2") node1.relationships[NodeRelationship.NEXT] = RelatedNodeInfo(node_id=node2.node_id) node2.relationships[NodeRelationship.PREVIOUS] = RelatedNodeInfo(node_id=node1.node_id)2.2 什么数据需要切分？什么时候不需要？需要切分的数据类型数据类型切分必要性推荐切分器📄 纯文本文档✅ 必须切分SentenceSplitter📝 Markdown文档✅ 必须切分MarkdownNodeParser🌐 HTML网页✅ 必须切分MarkdownNodeParser（先转Markdown）💻 代码文件✅ 必须切分CodeSplitter📑 长文本日志✅ 必须切分SentenceSplitter不需要切分的数据类型数据类型原子单位LlamaIndex 推荐方式🗄️ SQL数据库行/记录SQLTableRetriever + 文本到SQL📋 JSON/XML字段/路径字段路径访问 + Jsonalyzer📊 CSV表格行PandasQueryEngine🕸️ 知识图谱三元组/节点KnowledgeGraphIndex半结构化数据：混合处理策略# 表格部分：保留原结构，不走切分 # 文本部分：切分后建向量索引 from llama_index.core.node_parser import SentenceSplitter text_nodes = SentenceSplitter().get_nodes_from_documents(text_docs) vector_index = VectorStoreIndex(text_nodes) sql_query_engine = NLSQLTableQueryEngine(sql_database)核心原则原则说明原子性优先如果数据本身具有原子单位，直接使用该单位检索破坏结构不切切分会破坏数据关系时不切分超限才切只有当单个单位超过LLM上下文窗口时才切分混合分别处理半结构化数据中的表格和文字分开处理2.3 自动切分 vs 手动切分VectorStoreIndex 的自动切分from llama_index.core import VectorStoreIndex, SimpleDirectoryReader documents = SimpleDirectoryReader("./data/").load_data() index = VectorStoreIndex.from_documents(documents) # 自动完成切分！控制自动切分：from llama_index.core import Settings from llama_index.core.node_parser import SentenceSplitter # 方式一：通过全局 Settings 配置 Settings.text_splitter = SentenceSplitter(chunk_size=512, chunk_overlap=50) index = VectorStoreIndex.from_documents(documents) # 方式二：通过 transformations 参数 text_splitter = SentenceSplitter(chunk_size=500, chunk_overlap=50) index = VectorStoreIndex.from_documents(documents, transformations=[text_splitter])手动切分的优势能力自动切分手动切分快速上手✅ 一行代码❌ 需要写代码自定义元数据❌ 只能文档级别✅ 节点级别精细控制节点关系（父子/前后）❌ 扁平结构✅ 任意关系内容过滤/清洗❌ 无法干预✅ 完全控制完整性保证⚠️ 可能切断关键内容✅ 可保证多模态支持❌ 有限✅ 灵活渐进式优化建议# 阶段一：快速验证（自动切分） index = VectorStoreIndex.from_documents(documents) # 阶段二：发现问题后切换手动切分 parser = SentenceSplitter(chunk_size=512, chunk_overlap=50) nodes = parser.get_nodes_from_documents(documents) # 阶段三：手动增强元数据 for i, node in enumerate(nodes): node.metadata["chunk_index"] = i node.metadata["source_file"] = documents[0].metadata.get("file_name") if "summary" in node.text.lower(): node.metadata["is_summary"] = True index = VectorStoreIndex(nodes)2.4 最常用的切分方式：SentenceSplitterfrom llama_index.core.node_parser import SentenceSplitter # 创建切分器 parser = SentenceSplitter(chunk_size=512, chunk_overlap=20) # 执行切分 nodes = parser.get_nodes_from_documents(documents) # 全局配置 from llama_index.core import Settings Settings.chunk_size = 512 Settings.chunk_overlap = 202.5 进阶切分器MarkdownNodeParser - 保留 Markdown 结构from llama_index.core.node_parser import MarkdownNodeParser parser = MarkdownNodeParser() nodes = parser.get_nodes_from_documents(documents)CodeSplitter - 代码专用切分from llama_index.core.node_parser import CodeSplitter parser = CodeSplitter( language="python", chunk_lines=40, chunk_lines_overlap=15, max_chars=1500, ) nodes = parser.get_nodes_from_documents(documents)SemanticSplitterNodeParser - 语义切分from llama_index.core.node_parser import SemanticSplitterNodeParser from llama_index.embeddings.openai import OpenAIEmbedding embed_model = OpenAIEmbedding() parser = SemanticSplitterNodeParser( embed_model=embed_model, buffer_size=1, breakpoint_percentile_threshold=95, ) nodes = parser.get_nodes_from_documents(documents)参数说明buffer_size分组评估语义相似度时的句子数量breakpoint_percentile_threshold余弦相似度百分位数阈值，值越小切分越细embed_model用于计算语义相似度的嵌入模型（必填）2.6 使用 IngestionPipelinefrom llama_index.core.ingestion import IngestionPipeline from llama_index.core.node_parser import SentenceSplitter from llama_index.core.extractors import TitleExtractor pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_size=512, chunk_overlap=20), TitleExtractor(), ] ) nodes = pipeline.run(documents=documents, show_progress=True)2.7 第三方切分器DashScopeJsonNodeParser（阿里通义）from llama_index.node_parser.dashscope import DashScopeJsonNodeParser node_parser = DashScopeJsonNodeParser( chunk_size=100, overlap_size=0, separator=" |,|，|。|？|！|\n|\?|\!", language="cn" )2.8 切分策略总结文档类型推荐切分器是否需要切分普通文本文档SentenceSplitter✅Markdown文档MarkdownNodeParser✅代码文件CodeSplitter✅长文档/书籍SemanticSplitterNodeParser✅SQL数据库不切分❌JSON/XML不切分❌CSV小表不切分❌中文文档DashScopeJsonNodeParser✅💡 核心提示：当你发现检索结果不够好时，手动切分往往是第一个需要优化的地方。三、嵌入模型 (Embedding Model)Embedding 模型将文本转换为向量表示，直接影响检索质量。3.1 安装与基础配置pip install llama-index-embeddings-openai # OpenAI pip install llama-index-embeddings-huggingface # Hugging Face pip install llama-index-embeddings-ollama # Ollama pip install BCEmbedding # 中文推荐全局配置from llama_index.core import Settings from llama_index.embeddings.openai import OpenAIEmbedding Settings.embed_model = OpenAIEmbedding()3.2 各主要来源 Embedding 模型OpenAI Embeddingfrom llama_index.embeddings.openai import OpenAIEmbedding embed_model = OpenAIEmbedding( model="text-embedding-3-small", # 或 text-embedding-3-large embed_batch_size=10, )Hugging Face 本地模型from llama_index.embeddings.huggingface import HuggingFaceEmbedding # 轻量级 embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-en-v1.5") # 高性能 embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-large-en-v1.5")模型特点维度BAAI/bge-small-en-v1.5轻量快速384BAAI/bge-base-en-v1.5平衡768BAAI/bge-large-en-v1.5高性能1024Ollama 本地部署from llama_index.embeddings.ollama import OllamaEmbedding embed_model = OllamaEmbedding( model_name="nomic-embed-text", base_url="http://localhost:11434", query_instruction="Represent the question for retrieving supporting documents:", text_instruction="Represent the document for retrieval:", )ONNX 加速from llama_index.embeddings.huggingface_optimum import OptimumEmbedding OptimumEmbedding.create_and_save_optimum_model("BAAI/bge-small-en-v1.5", "./bge_onnx") Settings.embed_model = OptimumEmbedding(folder_name="./bge_onnx")3.3 中文 Embedding 模型推荐模型核心特点向量维度适用场景BGE-M3100+语言，8192 tokens，混合检索1024跨语言长文档bce-embedding-base_v1中英双语优化，RAG SOTA768双语RAGQwen3-VL-2B多模态，跨语言检索强2048图文混合检索M3E-Turbo中文轻量，本地部署—本地知识库jina-embeddings-v2-base-zh中英双语，8192上下文768中文长文档重点推荐：BCEmbeddingfrom llama_index.embeddings.huggingface import HuggingFaceEmbedding embed_model = HuggingFaceEmbedding( model_name="maidalun1020/bce-embedding-base_v1", max_length=512, embed_batch_size=32, device="cuda" )配合 Reranker（强烈推荐）：from BCEmbedding.tools.llama_index import BCERerank reranker = BCERerank( model="maidalun1020/bce-reranker-base_v1", top_n=5, device="cuda" ) query_engine = index.as_query_engine(node_postprocessors=[reranker])中文场景决策树纯中文 + 本地部署 → M3E-Turbo 纯中文 + 高精度 → xiaobu-embedding-v2 中英双语 + RAG → bce-embedding-base_v1（首选） 多语言/长文档 → BGE-M3 图像+文本混合 → Qwen3-VL-2B3.4 模型选择与性能评测评测指标Hit Rate（命中率）：正确答案出现在 top-k 检索结果中的查询比例MRR（平均倒数排名）：第一个相关文档排名倒数的平均值各模型性能对比Embedding 模型搭配 RerankerHit RateMRRJinaAI-Basebge-reranker-large0.9380.869OpenAICohereRerank0.9270.866bge-largeCohereRerank0.8760.823关键结论：Reranker 几乎总是能显著提升效果。3.5 完整代码示例基础 RAG Pipelinefrom llama_index.core import SimpleDirectoryReader, VectorStoreIndex, Settings from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.core.node_parser import SentenceSplitter Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-large-en-v1.5") Settings.text_splitter = SentenceSplitter(chunk_size=512, chunk_overlap=50) documents = SimpleDirectoryReader("./data").load_data() index = VectorStoreIndex.from_documents(documents, show_progress=True) index.storage_context.persist(persist_dir="./storage") query_engine = index.as_query_engine() response = query_engine.query("你的问题")中文 RAG 完整示例from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, Settings from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.core.node_parser import SentenceSplitter from BCEmbedding.tools.llama_index import BCERerank Settings.embed_model = HuggingFaceEmbedding( model_name="maidalun1020/bce-embedding-base_v1", device="cuda" ) Settings.text_splitter = SentenceSplitter(chunk_size=512, chunk_overlap=50) documents = SimpleDirectoryReader("./chinese_docs").load_data() index = VectorStoreIndex.from_documents(documents, show_progress=True) reranker = BCERerank(model="maidalun1020/bce-reranker-base_v1", top_n=3, device="cuda") query_engine = index.as_query_engine( similarity_top_k=10, node_postprocessors=[reranker], ) response = query_engine.query("《长安的荔枝》的主角是谁？")四、索引与存储 (Index)4.1 索引概述索引（Index） 是核心数据结构，将原始 Document 对象组织起来，以便 LLM 高效查询。构建索引包括将文档解析、分块为 Node 对象。4.2 核心索引类型索引类型核心机制最佳适用场景检索策略VectorStoreIndex向量嵌入存储语义相似度匹配，RAG 最常用ANN 近似最近邻SummaryIndex顺序列表生成文档摘要全量遍历TreeIndex分层树状结构长文档摘要、逐级下钻逐层遍历KeywordTableIndex关键词→Node映射基于关键词的精确检索倒排索引4.3 存储机制核心存储组件组件存储内容查询频率DocStore原始文本、Node对象中VectorStore向量数组、映射关系极高IndexStore索引元数据低GraphStore知识图谱低ChatStoreAgent对话历史中方案一：本地磁盘持久化from llama_index.core import VectorStoreIndex, StorageContext, load_index_from_storage # 持久化 index.storage_context.persist(persist_dir="./my_storage") # 加载 if os.path.exists("./my_storage"): storage_context = StorageContext.from_defaults(persist_dir="./my_storage") index = load_index_from_storage(storage_context) else: index = VectorStoreIndex.from_documents(documents) index.storage_context.persist(persist_dir="./my_storage")方案二：向量数据库存储（生产环境首选）import chromadb from llama_index.vector_stores.chroma import ChromaVectorStore db = chromadb.PersistentClient(path="./chroma_db") chroma_collection = db.get_or_create_collection("my_documents") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) storage_context = StorageContext.from_defaults(vector_store=vector_store) index = VectorStoreIndex.from_documents(documents, storage_context=storage_context) # 重启后直接加载（无需重新嵌入） loaded_index = VectorStoreIndex.from_vector_store(vector_store)动态更新索引new_documents = SimpleDirectoryReader("new_data").load_data() for doc in new_documents: index.insert(doc)4.4 Agent 记忆存储短期记忆：SQLite 存储，维护当前会话上下文长期记忆：三种记忆块：StaticMemoryBlock：静态信息（姓名、偏好）FactExtractionMemoryBlock：LLM 驱动自动提取事实VectorMemoryBlock：历史对话嵌入向量数据库4.5 最佳实践场景推荐方案数据量小/原型验证本地磁盘 + VectorStoreIndex生产环境/大规模向量数据库 + VectorStoreIndex关键词搜索KeywordTableIndex长文档摘要TreeIndex对话式 AgentChatStore + 长期记忆块五、检索器 (Retriever)5.1 Retriever 是什么？Retriever（检索器） 负责根据用户查询获取最相关的上下文内容，是连接索引和查询引擎的核心桥梁。组件职责类比Retriever从索引中检索相关节点图书管理员找书Response Synthesizer将检索到的节点合成答案阅读并总结资料Query Engine整合上述两者前台查询服务窗口用户查询 → Retriever → Response Synthesizer → 返回响应5.2 快速上手from llama_index.core import VectorStoreIndex index = VectorStoreIndex.from_documents(documents) # 获取检索器 retriever = index.as_retriever(similarity_top_k=5) # 执行检索 nodes = retriever.retrieve("Who is Paul Graham?")5.3 索引与 Retriever 的关系索引类型检索器模式适用场景VectorStoreIndex向量相似度检索语义搜索SummaryIndex列表式/LLM检索摘要生成KeywordTableIndex关键词匹配精确查询5.4 高阶检索技术递归检索器（Recursive Retriever）解耦检索与合成，通过文档代理实现复杂操作：from llama_index.core.schema import IndexNode from llama_index.agent.openai import OpenAIAgent # 为每个文档构建代理 for wiki_title in wiki_titles: vector_index = VectorStoreIndex.from_documents(docs) summary_index = SummaryIndex.from_documents(docs) tools = [ QueryEngineTool(query_engine=vector_index.as_query_engine(), metadata=ToolMetadata(name="vector_tool", description="搜索具体事实")), QueryEngineTool(query_engine=summary_index.as_query_engine(), metadata=ToolMetadata(name="summary_tool", description="总结内容")), ] agent = OpenAIAgent.from_tools(tools) # 构建顶层检索器，查询会自动路由到正确的文档代理混合检索结合关键词匹配（BM25）和语义向量搜索：class HybridRetriever(BaseRetriever): def __init__(self, vector_retriever, keyword_retriever, mode="AND"): self.vector_retriever = vector_retriever self.keyword_retriever = keyword_retriever self.mode = mode def _retrieve(self, query_bundle): vector_nodes = self.vector_retriever.retrieve(query_bundle) keyword_nodes = self.keyword_retriever.retrieve(query_bundle) vector_ids = {n.node.node_id for n in vector_nodes} keyword_ids = {n.node.node_id for n in keyword_nodes} combined = {n.node.node_id: n for n in vector_nodes} combined.update({n.node.node_id: n for n in keyword_nodes}) if self.mode == "AND": result_ids = vector_ids.intersection(keyword_ids) else: result_ids = vector_ids.union(keyword_ids) return [combined[rid] for rid in result_ids]检索器路由（Retriever Router）通过向量检索动态选择最相关的查询引擎：from llama_index.core.query_engine import ToolRetrieverRouterQueryEngine router_query_engine = ToolRetrieverRouterQueryEngine(obj_index.as_retriever()) response = router_query_engine.query("What did the author do at Y Combinator?")5.5 RetrieverQueryEnginefrom llama_index.core.query_engine import RetrieverQueryEngine query_engine = RetrieverQueryEngine.from_args( retriever=my_retriever, response_mode="compact", node_postprocessors=[reranker], )支持的后处理组件后处理器功能SimilarityPostprocessor按相似度分数过滤KeywordNodePostprocessor按关键词过滤CohereRerankCohere 重排序5.6 性能优化参数推荐值说明similarity_top_k5-10检索返回节点数量chunk_size512-1024文档分块大小response_modecompact / tree_summarize合成策略场景选型场景推荐方案中小型知识库LlamaIndex 开箱即用高精度检索（法律/医疗）混合检索 + 重排序多文档复杂推理递归检索 + 文档代理快速原型验证index.as_query_engine()5.7 设计哲学：渐进式复杂度简单：index.as_retriever() → 一行代码 ↓ 进阶：配置 similarity_top_k、retriever_mode ↓ 高级：自定义 Retriever 类、混合检索 ↓ 专业：递归检索、检索器路由、多 Agent 协作六、索引、向量数据与数据库的关系6.1 概念澄清组件本质存储内容比喻向量数值化后的文本特征浮点数数组文档的"DNA编码"索引(Index)高效检索向量的数据结构向量 + ID映射"目录+分类卡片"数据库持久化存储系统向量+文本+元数据"书架系统"关键理解：向量是数据本身索引是数据结构（帮助快速检索）数据库是载体（持久化存储向量+索引+元数据）6.2 LlamaIndex 的三层存储架构from llama_index.core import StorageContext storage_context = StorageContext.from_defaults( docstore=... # 文档存储：存原始文本和节点 vector_store=... # 向量存储：存向量嵌入 index_store=... # 索引存储：存索引元数据 )组件存储内容数据量级查询频率DocStore原始文本、Node较大中VectorStore向量数组、映射极大极高IndexStore索引元数据极小低6.3 不同存储方式对比本地文件系统（SimpleVectorStore）./storage/ ├── docstore.json # 所有原始文本 ├── vector_store.json # 所有向量数据（JSON格式，效率低） └── index_store.json # 索引元数据适合小规模数据（<1万条文档）专业向量数据库（Chroma）chroma_db/ ├── chroma.sqlite3 # 元数据、文档ID └── data_level0.bin # HNSW索引 + 向量数据向量、索引、元数据分离但关联存储6.4 数据流向构建索引阶段： 文档 → 文本分块 + 嵌入模型 → VectorStore(存向量+NodeID) + DocStore(存文本+NodeID) 查询阶段： 查询文本 → 查询向量 → VectorStore(相似度搜索) → 返回NodeID列表 → DocStore(根据NodeID获取原始文本) → 返回结果6.5 常见误区误区纠正"索引就是数据库"索引=检索算法的数据结构，数据库=持久化存储系统"向量数据库不存储向量"向量数据库专门为存储和检索向量设计"索引在内存中就不需要数据库"仍需持久化，否则程序退出后索引消失6.6 选择决策指南数据量推荐方案< 1万条本地文件系统（JSON）1万-10万Chroma/Qdrant10万-100万Milvus/Pinecone> 100万自建HNSW+对象存储总结概念一句话定义向量文本的数学表示，用于计算相似度索引加速向量检索的数据结构数据库持久化存储向量+索引+元数据的系统最佳实践：小项目：用 LlamaIndex 本地文件系统生产环境：用专业向量数据库（Chroma/Milvus/Qdrant）超大规模：向量存对象存储，索引存 Redis 缓存
一、Retriever 是什么？在 LlamaIndex 的架构中，Retriever（检索器） 负责根据用户查询（或聊天消息）获取最相关的上下文内容。它是连接索引（Index）和查询引擎（Query Engine）的核心桥梁。整个查询流程包含三个核心组件：组件职责类比Retriever从索引中检索相关节点图书管理员在书架上找书Response Synthesizer将检索到的节点合成答案阅读并总结找到的资料Query Engine整合上述两者，提供统一接口前台的查询服务窗口用户查询 → Retriever（检索相关节点）→ Response Synthesizer（合成答案）→ 返回响应二、快速上手：基础用法2.1 最简单的使用方式from llama_index.core import VectorStoreIndex from llama_index.core import SimpleDirectoryReader # 加载文档 documents = SimpleDirectoryReader("data").load_data() # 构建索引 index = VectorStoreIndex.from_documents(documents) # 获取检索器（最简形式） retriever = index.as_retriever() # 执行检索 nodes = retriever.retrieve("Who is Paul Graham?")💡 as_retriever() 是从索引获取检索器的快捷方式。每个索引类型都有自己默认的检索器实现。2.2 配置检索参数# 配置返回节点数量（Top-K） retriever = index.as_retriever(similarity_top_k=5) # VectorStoreIndex 还支持向量搜索相关参数 retriever = vector_index.as_retriever( similarity_top_k=3, # 返回最相似的3个节点 vector_store_query_mode="default", )三、核心概念深入3.1 Index（索引）与 Retriever 的关系Index（索引） 是存储在文档对象之上的数据结构，旨在支持 LLM 进行查询。不同类型的索引对应不同的检索策略：索引类型检索器模式适用场景VectorStoreIndex向量相似度检索语义搜索、事实查询SummaryIndex列表式检索/LLM检索摘要生成、全文遍历KeywordTableIndex关键词匹配检索精确关键词查询from llama_index.core import SummaryIndex, VectorStoreIndex # 不同索引的不同检索器配置 summary_index = SummaryIndex(nodes) vector_index = VectorStoreIndex(nodes) # SummaryIndex 支持多种检索模式 list_retriever = summary_index.as_retriever( retriever_mode="llm", # 使用 LLM 选择 choice_batch_size=5, # 批处理大小 ) # 低阶 API：直接实例化检索器类 from llama_index.core.indices.list import SummaryIndexLLMRetriever retriever = SummaryIndexLLMRetriever( index=summary_index, choice_batch_size=5, )3.2 检索器在 RAG 流程中的位置┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ Load │ -> │ Index │ -> │ Retriever │ -> │ Synthesize │ │ 加载文档 │ │ 构建索引 │ │ 检索节点 │ │ 生成答案 │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ ↑ 用户查询进入四、高阶检索技术4.1 递归检索器（Recursive Retriever）递归检索解决了两个核心痛点：解耦检索与合成：有时通过摘要获取文档比直接搜索原始块更有效文档内动态任务：在单个文档内可能需要超越事实问答的复杂操作from llama_index.core import VectorStoreIndex, SummaryIndex from llama_index.core.schema import IndexNode from llama_index.core.tools import QueryEngineTool from llama_index.agent.openai import OpenAIAgent # 为每个文档构建文档代理（Document Agent） agents = {} for wiki_title in wiki_titles: # 向量索引：用于语义搜索 vector_index = VectorStoreIndex.from_documents(docs) # 摘要索引：用于总结 summary_index = SummaryIndex.from_documents(docs) # 创建两个查询引擎工具 tools = [ QueryEngineTool( query_engine=vector_index.as_query_engine(), metadata=ToolMetadata( name="vector_tool", description=f"搜索 {wiki_title} 中的具体事实", ), ), QueryEngineTool( query_engine=summary_index.as_query_engine(), metadata=ToolMetadata( name="summary_tool", description=f"总结 {wiki_title} 的内容", ), ), ] # 文档代理：可动态选择使用向量搜索还是摘要 agent = OpenAIAgent.from_tools(tools) agents[wiki_title] = agent # 构建顶层检索器 objects = [] for title, agent in agents.items(): node = IndexNode( text=f"关于 {title} 的维基百科内容", index_id=title, obj=agent, ) objects.append(node) top_index = VectorStoreIndex(objects=objects) query_engine = top_index.as_query_engine(similarity_top_k=1) # 查询会自动路由到正确的文档代理 response = query_engine.query("Tell me about sports teams in Boston")4.2 混合检索：自定义检索器混合检索结合关键词匹配（BM25）和语义向量搜索，提升检索精度：from typing import List from llama_index.core import QueryBundle from llama_index.core.retrievers import BaseRetriever, VectorIndexRetriever from llama_index.core.retrievers import KeywordTableSimpleRetriever from llama_index.core.schema import NodeWithScore class HybridRetriever(BaseRetriever): """实现 AND/OR 逻辑的混合检索器""" def __init__( self, vector_retriever: VectorIndexRetriever, keyword_retriever: KeywordTableSimpleRetriever, mode: str = "AND", # "AND" 取交集，"OR" 取并集 ): self.vector_retriever = vector_retriever self.keyword_retriever = keyword_retriever self.mode = mode super().__init__() def _retrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]: # 分别执行两种检索 vector_nodes = self.vector_retriever.retrieve(query_bundle) keyword_nodes = self.keyword_retriever.retrieve(query_bundle) vector_ids = {n.node.node_id for n in vector_nodes} keyword_ids = {n.node.node_id for n in keyword_nodes} # 合并结果字典 combined = {n.node.node_id: n for n in vector_nodes} combined.update({n.node.node_id: n for n in keyword_nodes}) # 根据模式取交集或并集 if self.mode == "AND": result_ids = vector_ids.intersection(keyword_ids) else: result_ids = vector_ids.union(keyword_ids) return [combined[rid] for rid in result_ids] # 使用自定义检索器 vector_retriever = VectorIndexRetriever(index=vector_index, similarity_top_k=3) keyword_retriever = KeywordTableSimpleRetriever(index=keyword_index) hybrid_retriever = HybridRetriever( vector_retriever, keyword_retriever, mode="AND" ) # 接入查询引擎 from llama_index.core.query_engine import RetrieverQueryEngine query_engine = RetrieverQueryEngine( retriever=hybrid_retriever, response_synthesizer=get_response_synthesizer(), )4.3 检索器路由（Retriever Router）当工具/索引数量较多时，传统路由器会受限于 Prompt 长度。检索器路由通过向量检索动态选择最相关的查询引擎：from llama_index.core.objects import ObjectIndex, SimpleToolNodeMapping from llama_index.core.query_engine import ToolRetrieverRouterQueryEngine # 创建多个查询引擎工具 list_tool = QueryEngineTool.from_defaults( query_engine=list_query_engine, description="用于作者传记类问题", ) vector_tool = QueryEngineTool.from_defaults( query_engine=vector_query_engine, description="用于检索作者生平的具体片段，如大学经历、YC经历等", ) # 构建对象索引 tool_mapping = SimpleToolNodeMapping.from_objects([list_tool, vector_tool]) obj_index = ObjectIndex.from_objects( [list_tool, vector_tool], tool_mapping, VectorStoreIndex, ) # 路由检索器：动态选择工具 router_query_engine = ToolRetrieverRouterQueryEngine(obj_index.as_retriever()) # 路由会自动选择 vector_tool response = router_query_engine.query("What did the author do at Y Combinator?")五、RetrieverQueryEngine 详解RetrieverQueryEngine 是将检索器与响应合成器组合的标准方式：from llama_index.core.query_engine import RetrieverQueryEngine from llama_index.core import get_response_synthesizer # 方式一：从检索器构建 query_engine = RetrieverQueryEngine.from_args( retriever=my_retriever, response_mode="compact", # 响应合成模式 text_qa_template=my_qa_template, # 自定义 Prompt node_postprocessors=[...], # 节点后处理器 ) # 方式二：直接构造 response_synthesizer = get_response_synthesizer(response_mode="tree_summarize") query_engine = RetrieverQueryEngine( retriever=my_retriever, response_synthesizer=response_synthesizer, ) # 执行查询 response = query_engine.query("What is the main topic?") print(response)支持的后处理组件后处理器功能SimilarityPostprocessor按相似度分数过滤KeywordNodePostprocessor按关键词过滤PrevNextNodePostprocessor获取相邻节点CohereRerank使用 Cohere 重排序六、性能优化与最佳实践6.1 检索参数调优参数推荐值说明similarity_top_k5-10检索返回的节点数量chunk_size512-1024文档分块大小response_modecompact / tree_summarize合成策略6.2 索引优化策略# 1. 设置合适的 chunk_size Settings.chunk_size = 512 Settings.chunk_overlap = 20 # 2. 使用高性能 embedding from llama_index.embeddings.openai import OpenAIEmbedding Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small") # 3. 启用节点后处理（重排序提升准确率） from llama_index.postprocessor.cohere import CohereRerank rerank = CohereRerank(top_k=3) query_engine = RetrieverQueryEngine( retriever=retriever, node_postprocessors=[rerank], )6.3 场景选型建议场景推荐方案中小型知识库（<10万文档）LlamaIndex 开箱即用高精度检索需求（法律/医疗）混合检索 + 重排序多文档复杂推理递归检索 + 文档代理快速原型验证index.as_query_engine() 一键搭建七、总结：Retriever 设计哲学LlamaIndex 遵循 渐进式复杂度揭示（Progressive Disclosure of Complexity）的设计理念：简单场景：index.as_retriever() → 一行代码搞定 ↓ 进阶场景：配置 similarity_top_k、retriever_mode ↓ 高级场景：自定义 Retriever 类、实现混合检索 ↓ 专业场景：递归检索、检索器路由、多 Agent 协作💡 核心要点：从最简单的需求出发，当默认行为无法满足时，逐层深入使用更底层的 API。这种设计让初学者能够快速上手，同时为专家提供足够的灵活性。
LlamaIndex 索引与存储完全指南1. 索引概述：从数据到查询的桥梁在 LlamaIndex 中，索引（Index） 是一个核心的数据结构，它将原始的 Document 对象组织起来，以便大语言模型（LLM）能够高效地查询和理解。构建索引的过程通常包括将文档解析、分块为更精细的 Node 对象，每个 Node 对应文档中的一段文本。这样做解决了直接将海量私有数据喂给 LLM 时遇到的知识断层和上下文窗口限制问题。2. LlamaIndex 核心索引类型深度解析LlamaIndex 提供了多种索引类型，每种都针对特定的查询场景进行了优化。下表总结了四种最核心的索引结构：索引类型核心机制与数据结构最佳适用场景检索策略向量存储索引 (VectorStoreIndex)将每个 Node 及其对应的 Embedding（向量嵌入）存储在向量数据库中。语义相似度匹配，是 RAG 最常用的索引。适用于问答系统、推荐系统、跨文档主题查找等。将查询语句转为向量，通过 ANN（近似最近邻）算法（如 FAISS、HNSW）查找最相似的 Top-K 个 Node。摘要索引 (Summary Index)简单地将所有 Node 存储为一个顺序列表。生成文档整体摘要，或在需要针对非常少量的节点进行全量、顺序遍历时使用。加载列表中的全部或大部分 Node 至响应合成模块，让 LLM 查看所有文本后生成答案。树状索引 (Tree Index)从 Node 集合构建一个分层的树状结构，每个父节点是其子节点的摘要。需要对长文档进行摘要总结或逐级下钻的查询场景。适合从宏观到微观的层次化信息检索。从根节点开始，逐层遍历（如每次选择相关性最高的 top-k 子节点），最终到达叶子节点获取详细上下文。关键词表索引 (Keyword Table Index)从每个 Node 中提取关键词，构建一个从关键词到 Node 的映射表（类似倒排索引）。基于特定关键词的精确检索，如文档管理系统、传统搜索引擎风格的查询。解析查询语句中的关键词，通过映射表快速定位包含这些关键词的 Node。3. 存储机制：持久化与后端集成默认情况下，LlamaIndex 将索引数据存储在内存中，这意味着程序退出后数据就会丢失。为了实现数据持久化，LlamaIndex 设计了灵活的存储抽象层（Storage Abstractions）。3.1 核心存储组件文档存储 (Document Stores)：存储 ingested 后的文档和 Node 对象。索引存储 (Index Stores)：存储索引的元数据（如映射关系、树结构）。向量存储 (Vector Stores)：专门存储向量嵌入及其对应的文本数据。这是最关键的组件，因为许多向量数据库（除 FAISS 外）会同时存储数据和索引，因此可能不再需要单独的文档或索引存储。图存储 (Graph Stores)：为知识图谱索引（KnowledgeGraphIndex）专门设计。聊天存储 (Chat Stores)：用于存储 Agent 的对话历史。3.2 持久化实践指南方案一：本地磁盘持久化最简单的方式，适用于开发和测试环境。通过 storage_context 的 persist() 方法将数据写入磁盘，或通过 from_defaults 加载。from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, StorageContext, load_index_from_storage import os # 1. 构建索引并持久化 documents = SimpleDirectoryReader("data").load_data() index = VectorStoreIndex.from_documents(documents) # 持久化到本地目录 (默认为 ./storage) index.storage_context.persist(persist_dir="./my_storage") # 2. 从磁盘加载索引 if not os.path.exists("./my_storage"): # 如果不存在，走构建流程 index = VectorStoreIndex.from_documents(documents) index.storage_context.persist(persist_dir="./my_storage") else: # 重建存储上下文并加载 storage_context = StorageContext.from_defaults(persist_dir="./my_storage") index = load_index_from_storage(storage_context)方案二：向量数据库存储生产环境的首选。LlamaIndex 支持超过 160+ 种数据源和向量数据库。以下是使用开源数据库 Chroma 的示例：import chromadb from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, StorageContext from llama_index.vector_stores.chroma import ChromaVectorStore # 1. 初始化 Chroma 客户端 db = chromadb.PersistentClient(path="./chroma_db") # 数据持久化到磁盘 chroma_collection = db.get_or_create_collection("my_documents") # 2. 构建存储上下文 vector_store = ChromaVectorStore(chroma_collection=chroma_collection) storage_context = StorageContext.from_defaults(vector_store=vector_store) # 3. 加载文档并创建索引（向量会自动存入 Chroma） documents = SimpleDirectoryReader("./data").load_data() index = VectorStoreIndex.from_documents(documents, storage_context=storage_context) # 4. 重启后直接加载索引（无需重新嵌入） # 直接通过已有的向量存储加载 loaded_index = VectorStoreIndex.from_vector_store(vector_store, storage_context=storage_context)高级配置：云端存储LlamaIndex 通过 fsspec 协议支持 S3、Cloudflare R2 等云存储，只需传递相应的文件系统对象即可。3.3 动态更新索引索引构建完成后，如果需要补充新数据，无需重建整个索引。可以使用 insert 方法动态添加文档。# 假设已存在 index new_documents = SimpleDirectoryReader("new_data").load_data() for doc in new_documents: index.insert(doc)4. 进阶话题：Agent 记忆存储在构建复杂的 Agent（智能体）应用时，LlamaIndex 提供了专门的 Memory（记忆） 组件，它也是存储系统的一部分。短期记忆（Short-Term Memory）：默认存储在 SQLite 数据库中（内存模式或文件模式），用于维护当前会话的上下文，解决“那个地方是哪里”这类指代不明的问题。长期记忆（Long-Term Memory）：当短期记忆达到 Token 限制时，会冲刷到以下三种“记忆块”中：静态记忆块（StaticMemoryBlock）：存储用户姓名、偏好等静态信息。事实提取记忆块（FactExtractionMemoryBlock）：由 LLM 驱动，自动从对话中提取结构化事实（如“用户 29 岁”）。向量记忆块（VectorMemoryBlock）：将历史对话嵌入到向量数据库中，实现基于语义的历史对话检索。5. 总结：索引与存储的最佳实践考虑维度推荐方案说明数据量小/原型验证本地磁盘 + SummaryIndex 或 VectorStoreIndex利用 persist_dir 简单保存，成本低。生产环境/大规模数据向量数据库 + VectorStoreIndex消除重新嵌入的时间和费用，支持分布式和横向扩展。关键词搜索场景KeywordTableIndex构建倒排索引，响应速度极快。长文档摘要TreeIndex避免简单的 Top-K 检索丢失全局上下文。对话式 AgentChatStore + 长期记忆块分离短期对话缓冲区和长期向量/事实存储，提升用户体验。掌握 LlamaIndex 的索引和存储机制，是从“能用”到“用好” RAG 技术的关键一步。正确的索引选择能显著提升检索准确率，而合理的存储配置则能大幅节省计算成本并加速响应速度。
LlamaIndex Embedding Model 完全指南在 LlamaIndex 中，Embedding 模型是将文本转换为向量表示的核心组件，直接影响检索质量。本文将系统地介绍如何使用、配置和评估 Embedding 模型，并特别加入针对中文场景的详细推荐。目录概念与核心作用安装与基础配置各主要来源 Embedding 模型详解中文 Embedding 模型详解与推荐高级配置参数模型选择与性能评测完整代码示例常见问题与最佳实践一、概念与核心作用Embedding 模型将文本作为输入，输出一个浮点数列表（向量），用于捕捉文本的语义信息。这些向量使得语义相似的文本在向量空间中彼此靠近，从而支持搜索、RAG 等应用。在 LlamaIndex 中，Embedding 模型有两个关键使用场景：索引阶段：将文档切分后的 Node 转换为向量，存入向量数据库查询阶段：将用户查询转换为向量，用于与索引中的向量进行相似度计算默认情况下，LlamaIndex 使用 OpenAI 的 text-embedding-ada-002 模型，相似度计算采用余弦相似度。二、安装与基础配置2.1 安装对应包不同 Embedding 提供商需要安装不同的包：# OpenAI pip install llama-index-embeddings-openai # Hugging Face 本地模型 pip install llama-index-embeddings-huggingface # Ollama 本地模型 pip install llama-index-embeddings-ollama # LangChain 集成 pip install llama-index-embeddings-langchain # ONNX 加速 pip install llama-index-embeddings-huggingface-optimum transformers optimum[exporters] # Jina AI pip install llama-index-embeddings-jinaai # BCEmbedding（中文推荐） pip install BCEmbedding2.2 全局配置方式最常用的配置方式是通过 Settings 对象全局设置 Embedding 模型：from llama_index.core import Settings from llama_index.embeddings.openai import OpenAIEmbedding # 全局设置 Settings.embed_model = OpenAIEmbedding() # 之后构建的 index 和 query engine 会自动使用该模型也可以在创建 Index 时单独指定：index = VectorStoreIndex.from_documents( documents, embed_model=embed_model )三、各主要来源 Embedding 模型详解3.1 OpenAI EmbeddingOpenAI 的 Embedding 模型在多项评测中表现优异，特别是与 reranker 配合使用时。from llama_index.embeddings.openai import OpenAIEmbedding from llama_index.core import Settings # 基础配置 Settings.embed_model = OpenAIEmbedding() # 自定义配置 embed_model = OpenAIEmbedding( model="text-embedding-3-small", # 或 "text-embedding-3-large", "text-embedding-ada-002" embed_batch_size=10, # 批处理大小，默认 10 api_key="your-api-key", # 可选，也可通过环境变量设置 )根据 LlamaIndex 官方评测，OpenAI Embedding 与 CohereRerank 搭配时，Hit Rate 可达 0.926966，MRR 达 0.86573。3.2 Hugging Face 本地模型使用本地模型可以避免 API 调用成本，适合需要离线运行或数据隐私敏感的场景。基础用法：from llama_index.embeddings.huggingface import HuggingFaceEmbedding # 使用轻量级模型（速度快） embed_model = HuggingFaceEmbedding( model_name="BAAI/bge-small-en-v1.5" ) # 使用高性能模型 embed_model = HuggingFaceEmbedding( model_name="BAAI/bge-large-en-v1.5" )带缓存的配置：embed_model = HuggingFaceEmbedding( cache_folder="./models", # 模型缓存目录 model_name="BAAI/bge-large-en-v1.5" ) Settings.embed_model = embed_model常用 Hugging Face Embedding 模型：模型特点维度BAAI/bge-small-en-v1.5轻量快速，适合开发测试384BAAI/bge-base-en-v1.5平衡性能与速度768BAAI/bge-large-en-v1.5高性能，适合生产环境1024sentence-transformers/all-mpnet-base-v2通用性较好7683.3 Ollama 本地部署Ollama 允许在本地运行 LLM 和 Embedding 模型，提供隐私保护和离线能力。前置步骤：# 1. 安装 Ollama（访问 ollama.ai） # 2. 启动 Ollama 服务（默认 localhost:11434） # 3. 拉取 embedding 模型 ollama pull nomic-embed-text # 或 ollama pull embeddinggemma代码使用：from llama_index.embeddings.ollama import OllamaEmbedding from llama_index.core import Settings embed_model = OllamaEmbedding( model_name="nomic-embed-text", # 必需：Ollama 模型名称 base_url="http://localhost:11434", # Ollama 服务地址 embed_batch_size=10, # 批处理大小 keep_alive="5m", # 模型在内存中的保持时间 query_instruction=None, # 查询前置指令 text_instruction=None, # 文本前置指令 ) Settings.embed_model = embed_model带指令的配置（可提升检索质量）：embed_model = OllamaEmbedding( model_name="nomic-embed-text", query_instruction="Represent the question for retrieving supporting documents:", text_instruction="Represent the document for retrieval:", )异步使用：import asyncio async def generate_embeddings(): embedding = await embed_model.aget_text_embedding("Hello, world!") embeddings = await embed_model.aget_text_embeddings(["text1", "text2"]) asyncio.run(generate_embeddings())Ollama 可用的 Embedding 模型：nomic-embed-text：通用型embeddinggemma：Google Gemma 系列mxbai-embed-large：大型模型，质量更高3.4 LangChain 集成如需使用 LangChain 中的 Embedding 模型：from langchain.embeddings.huggingface import HuggingFaceBgeEmbeddings from llama_index.core import Settings from llama_index.embeddings.langchain import LangchainEmbedding embed_model = LangchainEmbedding( HuggingFaceBgeEmbeddings(model_name="BAAI/bge-base-en") ) Settings.embed_model = embed_model3.5 ONNX 加速模型使用 ONNX 可显著提升推理速度：from llama_index.embeddings.huggingface_optimum import OptimumEmbedding # 首次运行：创建并保存 ONNX 模型 OptimumEmbedding.create_and_save_optimum_model( "BAAI/bge-small-en-v1.5", "./bge_onnx" ) # 后续使用 Settings.embed_model = OptimumEmbedding(folder_name="./bge_onnx")3.6 自定义 Embedding 模型可以通过继承 BaseEmbedding 类实现自定义模型：from typing import List from llama_index.core.embeddings import BaseEmbedding class CustomEmbedding(BaseEmbedding): def __init__(self, **kwargs): super().__init__(**kwargs) # 初始化你的模型 def _get_query_embedding(self, query: str) -> List[float]: # 生成查询向量 pass def _get_text_embedding(self, text: str) -> List[float]: # 生成文本向量 pass def _get_text_embeddings(self, texts: List[str]) -> List[List[float]]: # 批量生成（可选，用于优化性能） pass四、中文 Embedding 模型详解与推荐4.1 中文模型选型总览根据不同的使用场景，下表汇总了当前主流的中文 Embedding 模型：模型名称开发者核心特点向量维度适用场景BGE-M3智源研究院支持100+语言，输入8192 tokens，密集/稀疏/多向量混合检索1024跨语言长文档检索、多语言知识库bce-embedding-base_v1网易有道中英双语优化，RAG场景SOTA表现，无需指令前缀768双语RAG、语义搜索Qwen3-VL-2B阿里巴巴多模态支持，跨语言检索能力强，开源2048图文混合检索、跨语言场景SEA-LION-E5-Embedding-600MAISG东南亚+中英文优化，CMTEB得分60.79未明确东南亚语言+中文场景xiaobu-embedding-v2国内团队专为中文语义深度优化未明确通用中文检索、电商搜索stella-mrl-large-zh-v3.5国内团队大规模中文数据处理能力强1792中文复杂语义、新闻舆情分析M3E-Turbo国内团队中文轻量模型，支持本地私有化部署未明确本地知识库、专业领域检索jina-embeddings-v2-base-zhJina AI中英双语，8192上下文768中文长文档检索4.2 重点推荐模型详解🔥 网易有道 BCEmbedding (bce-embedding-base_v1)网易有道推出的双语 Embedding 模型，在生产环境（QAnything）中得到验证。from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.core import Settings # 配置 BCEmbedding embed_model = HuggingFaceEmbedding( model_name="maidalun1020/bce-embedding-base_v1", max_length=512, embed_batch_size=32, device="cuda" # 或 "cpu" ) Settings.embed_model = embed_model核心优势：无需指令：不像很多模型需要添加 "Represent this sentence: " 等前缀，开箱即用RAG 优化：专门针对检索增强生成场景调优双语 SOTA：在 LlamaIndex 官方 RAG 评测中，bce-embedding-base_v1 + bce-reranker-base_v1 组合达到 SOTA生产验证：已被网易有道多个产品（速读、翻译）采用配合 Reranker 使用（强烈推荐）：from BCEmbedding.tools.llama_index import BCERerank # 配置 Reranker reranker = BCERerank( model="maidalun1020/bce-reranker-base_v1", top_n=5, device="cuda" ) # 在 Query Engine 中使用 query_engine = index.as_query_engine(node_postprocessors=[reranker])🔥 BGE-M3（智源研究院）智源发布的 M3（Multi-Function, Multi-Lingual, Multi-Granularity）Embedding 模型，是处理多语言和长文档的首选。from llama_index.embeddings.huggingface import HuggingFaceEmbedding embed_model = HuggingFaceEmbedding( model_name="BAAI/bge-m3", trust_remote_code=True, # BGE-M3 需要 )核心优势：超长上下文：8192 tokens，可处理整篇文章或长文档100+ 语言支持：中文、英文及众多小语种混合检索：支持密集向量、稀疏向量（类似 BM25）、多向量三种检索方式CMTEB 高分：在中文 MTEB 评测中表现优异适用场景：跨语言知识库、多语言 RAG 系统、处理超长文档的企业应用。🔥 Qwen3-VL-2B（阿里巴巴）阿里云 Qwen 团队最新推出的多模态 Embedding 模型，在跨语言检索评测中表现优异。# 需要从 Qwen 官方仓库加载 from transformers import AutoModel from llama_index.core.embeddings import BaseEmbedding # 注意：该模型可能需要自定义封装 # 详见 Qwen 官方文档核心优势：跨语言能力：中英跨语言检索得分 0.988，仅次于 Gemini多模态支持：同时支持文本和图像输入开源免费：2B 参数，可本地部署Jina AI v2/v3 系列Jina AI 提供了专门的中文版本 jina-embeddings-v2-base-zh，支持 8192 上下文。from llama_index.embeddings.jinaai import JinaEmbedding # 使用中文专用版本 embed_model = JinaEmbedding( model="jina-embeddings-v2-base-zh", # 中文专用 api_key="your-jina-api-key", ) # 或使用最新的 v3 多语言模型（推荐） embed_model = JinaEmbedding( model="jina-embeddings-v3", task="retrieval.passage", # 可指定任务类型 )Jina v3 任务适配器：retrieval.query：查询编码retrieval.passage：文档编码（索引时使用）classification：文本分类text-matching：相似度匹配中文轻量模型：M3E-Turbo 与 xiaobu-embedding-v2对于资源受限或纯中文场景，可考虑以下国产轻量模型：# M3E-Turbo（本地部署优先） embed_model = HuggingFaceEmbedding( model_name="moka-ai/m3e-turbo", # 或 "m3e-base", "m3e-small" ) # xiaobu-embedding-v2（通用中文场景） embed_model = HuggingFaceEmbedding( model_name="xiaobu/xiaobu-embedding-v2", )模型适用场景特点M3E-Turbo本地私有部署、法律/医疗专业检索轻量、易部署xiaobu-embedding-v2电商搜索、客服知识库中文语义理解精度高4.3 跨语言检索性能对比根据 2026 年最新的 CCKM 评测基准，各模型在中英跨语言检索任务中的表现如下：模型跨语言得分 (R@1)中文成语理解 (Hard Tier)Gemini Embedding 20.9971.000Qwen3-VL-2B0.9880.969Jina Embeddings v40.9850.969Voyage Multimodal 3.50.9820.938OpenAI text-embedding-3-large0.9670.906BGE-M30.9400.844nomic-embed-text0.1540.031关键结论：在需要处理中文成语、俗语等复杂语义的场景下，BGE-M3、Qwen3-VL-2B 等专门优化的模型明显优于通用英文模型。4.4 CMTEB 中文评测基准表现SEA-LION 项目发布的最新评测数据（CMTEB 中文基准）：模型参数量CMTEB 得分Qwen-8B-Embedding8B75.00Qwen-0.6B-Embedding0.6B67.45SEA-LION-E5-Embedding-600M0.6B60.79BGE-M30.6B60.47text-embedding-3-small (OpenAI)—处理失败4.5 中文场景决策树根据业务需求，按以下步骤选择最合适的模型：第一步：确定语言需求 ├── 纯中文 + 资源受限/本地部署 → M3E-Turbo ├── 纯中文 + 云端部署/高精度 → xiaobu-embedding-v2 或 stella-mrl-large-zh ├── 中英双语 + RAG 场景 → bce-embedding-base_v1（首选） ├── 多语言（>10种）/长文档 → BGE-M3 ├── 多语言 + 高精度（愿意付费） → Gemini Embedding 2 └── 需要图像+文本混合检索 → Qwen3-VL-2B 第二步：是否配合 Reranker？ ├── 是 → bce-reranker-base_v1（与 BCEmbedding 最佳搭配） │ 或 BGE-reranker-large └── 否 → 考虑提升 top_k 值补偿召回4.6 中文场景特别注意事项文本分块优化：中文建议使用 SpacyTextSplitter + zh_core_web_sm 模型，比默认的 SentenceSplitter 更适合中文：from langchain.text_splitter import SpacyTextSplitter from llama_index.core.node_parser import LangchainNodeParser parser = LangchainNodeParser( SpacyTextSplitter( pipeline="zh_core_web_sm", chunk_size=512, chunk_overlap=50, ) )中文标题增强：可参考 QAnything 的实现，对文档标题进行标记，提升检索完整性模型大小选择：轻量级（< 0.5B）：BGE-small-zh、M3E-Turbo中量级（0.5B-1B）：bce-embedding-base_v1、BGE-M3、jina-embedding-v2-zh重量级（> 2B）：Qwen3-VL-2B、stella-large-zh获取最新评测数据：建议关注 MTEB 中文榜单 和 LlamaIndex 官方博客的持续更新。五、高级配置参数5.1 批处理大小（Batch Size）默认批处理大小为 10，可根据需求调整：# 增大批处理可以提高吞吐量，但可能触发速率限制 embed_model = OpenAIEmbedding(embed_batch_size=42)5.2 分块策略配合Embedding 的质量与文本分块策略密切相关：from llama_index.core.node_parser import SentenceSplitter text_splitter = SentenceSplitter( chunk_size=500, # 每块大小 chunk_overlap=50, # 块之间重叠 ) index = VectorStoreIndex.from_documents( documents, transformations=[text_splitter] )5.3 混合使用不同模型可以在索引和查询阶段使用不同的 Embedding 模型，或使用不同模型进行检索和 LLM 生成：from llama_index.core import ServiceContext from llama_index.llms.openai import OpenAI # 索引阶段使用本地 embedding embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-large-en-v1.5") # 查询阶段使用 OpenAI LLM llm = OpenAI(model="gpt-3.5-turbo") service_context = ServiceContext.from_defaults( embed_model=embed_model, llm=llm ) index = VectorStoreIndex.from_documents(documents, service_context=service_context)六、模型选择与性能评测6.1 评测指标LlamaIndex 使用两个主要指标评估检索性能：Hit Rate（命中率）：正确答案出现在 top-k 检索结果中的查询比例MRR（Mean Reciprocal Rank，平均倒数排名）：第一个相关文档排名倒数的平均值6.2 各模型性能对比根据 LlamaIndex 官方评测（特定数据集）：Embedding 模型搭配 RerankerHit RateMRRJinaAI-Basebge-reranker-large0.9382020.868539JinaAI-BaseCohereRerank0.9325840.873689OpenAICohereRerank0.9269660.865730OpenAIbge-reranker-large0.9101120.855805VoyageCohereRerank0.9157300.851217Google-PaLMCohereRerank0.9101120.855712Cohere v3.0CohereRerank0.8876400.836049bge-largeCohereRerank0.8764040.8227536.3 关键结论Reranker 的重要性：几乎所有 Embedding 模型在搭配 Reranker 后都有显著提升，CohereRerank 和 bge-reranker-large 表现最为突出最佳组合：OpenAI/JinaAI-Base + CohereRerank/bge-reranker-large 是目前表现最好的组合本地模型的选择：追求质量：BAAI/bge-large-en-v1.5平衡速度和效果：BAAI/bge-base-en-v1.5轻量快速：BAAI/bge-small-en-v1.5基础模型是关键：即使是最好的 Reranker，也无法弥补基础 Embedding 模型质量不足的问题七、完整代码示例7.1 基础 RAG Pipelinefrom llama_index.core import ( SimpleDirectoryReader, VectorStoreIndex, Settings, ) from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.core.node_parser import SentenceSplitter # 1. 配置 Embedding 模型 Settings.embed_model = HuggingFaceEmbedding( model_name="BAAI/bge-large-en-v1.5", cache_folder="./models" ) # 2. 配置文本分块 Settings.text_splitter = SentenceSplitter( chunk_size=512, chunk_overlap=50, ) # 3. 加载文档并建立索引 documents = SimpleDirectoryReader("./data").load_data() index = VectorStoreIndex.from_documents( documents, show_progress=True, ) # 4. 持久化 index.storage_context.persist(persist_dir="./storage") # 5. 查询 query_engine = index.as_query_engine() response = query_engine.query("你的问题") print(response)7.2 带 Reranker 的完整 Pipelinefrom llama_index.core import VectorStoreIndex, Settings from llama_index.core.retrievers import VectorIndexRetriever from llama_index.core.query_engine import RetrieverQueryEngine from llama_index.core.postprocessor import SentenceTransformerRerank # 配置 Embedding Settings.embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-large-en-v1.5") # 构建索引 index = VectorStoreIndex.from_documents(documents) # 配置 Retriever（获取更多候选） retriever = VectorIndexRetriever( index=index, similarity_top_k=10, # 获取 top-10 ) # 配置 Reranker（重排序取 top-5） reranker = SentenceTransformerRerank( model="BAAI/bge-reranker-large", top_n=5, ) # 构建 Query Engine query_engine = RetrieverQueryEngine.from_args( retriever=retriever, node_postprocessors=[reranker], ) response = query_engine.query("你的问题")7.3 使用 Ollama 本地模型from llama_index.embeddings.ollama import OllamaEmbedding from llama_index.llms.ollama import Ollama from llama_index.core import Settings # 设置 Embedding 模型 Settings.embed_model = OllamaEmbedding( model_name="nomic-embed-text", base_url="http://localhost:11434", ) # 设置 LLM（也可用 Ollama） Settings.llm = Ollama( model="llama3.1", base_url="http://localhost:11434", ) # 正常使用 index = VectorStoreIndex.from_documents(documents) query_engine = index.as_query_engine()7.4 中文 RAG 完整示例from llama_index.core import ( SimpleDirectoryReader, VectorStoreIndex, Settings, ) from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.core.node_parser import SentenceSplitter from BCEmbedding.tools.llama_index import BCERerank # 1. 配置中文优化的 Embedding 模型 Settings.embed_model = HuggingFaceEmbedding( model_name="maidalun1020/bce-embedding-base_v1", device="cuda", embed_batch_size=32, ) # 2. 配置文本分块（中文建议 512-1024） Settings.text_splitter = SentenceSplitter( chunk_size=512, chunk_overlap=50, ) # 3. 加载中文文档 documents = SimpleDirectoryReader("./chinese_docs").load_data() # 4. 建立索引 index = VectorStoreIndex.from_documents( documents, show_progress=True, ) # 5. 配置 Reranker（可选，但强烈推荐） reranker = BCERerank( model="maidalun1020/bce-reranker-base_v1", top_n=3, device="cuda", ) # 6. 构建 Query Engine query_engine = index.as_query_engine( similarity_top_k=10, # 先召回更多，让 reranker 精排 node_postprocessors=[reranker] if reranker else [], ) # 7. 中文查询测试 response = query_engine.query("《长安的荔枝》的主角是谁？") print(response)八、常见问题与最佳实践8.1 如何选择合适的模型？考虑约束条件：有预算、需要最佳效果 → OpenAI + CohereRerank数据隐私要求高 → 本地模型（BGE 系列）+ 本地 Reranker需要离线运行 → Ollama + nomic-embed-text中文场景 → bce-embedding-base_v1 + bce-reranker-base_v1小规模测试：使用 LlamaIndex 的 RetrieverEvaluator 在你自己的数据上测试8.2 Embedding 维度不匹配？确保查询和索引使用同一个 Embedding 模型。不同模型的向量维度不同，无法直接比较。8.3 如何提升检索质量？调整分块策略：根据文档类型调整 chunk_size 和 chunk_overlap添加 Reranker：可显著提升 MRR，尤其对于长尾查询使用指令型模型：如 Instructor、Nomic-embed-text 支持前置指令8.4 性能优化建议使用批处理：get_text_embeddings() 比循环调用 get_text_embedding() 高效开启异步：使用 aget_text_embedding() 提升并发能力ONNX 加速：对 Hugging Face 模型使用 Optimum 导出8.5 中文场景特别建议首选组合：对于中英双语 RAG 场景，强烈推荐 bce-embedding-base_v1 + bce-reranker-base_v1长文档处理：使用 BGE-M3（8192 上下文）预算有限：使用轻量模型 M3E-Turbo 或 xiaobu-embedding-v2持续关注：定期查看 MTEB 中文榜单获取最新评测数据参考资料LlamaIndex Ollama Embeddings IntegrationLlamaIndex Embeddings 官方文档LlamaIndex RAG 评测：选择最佳 Embedding 和 RerankerBCEmbedding 评测工具文档Stack Overflow 社区实践经验MTEB 中文榜单 (Hugging Face)网易有道 QAnything 项目文档智源研究院 BGE 系列模型文档
LlamaIndex 文档切分 Node 教程（完整版）一、核心概念：Document vs NodeDocument：原始文档对象，可以是一整个文件或一段文本Node：文档切分后的"块"，包含文本内容、元数据以及节点间的关系信息（如前后节点、父节点引用）from llama_index.core.schema import TextNode, NodeRelationship, RelatedNodeInfo # 手动创建 Node 并设置关系 node1 = TextNode(text="这是第一个文本块", id_="node_1") node2 = TextNode(text="这是第二个文本块", id_="node_2") # 设置节点间的前后关系 node1.relationships[NodeRelationship.NEXT] = RelatedNodeInfo(node_id=node2.node_id) node2.relationships[NodeRelationship.PREVIOUS] = RelatedNodeInfo(node_id=node1.node_id)四、最常用的切分方式：SentenceSplitterSentenceSplitter 是 LlamaIndex 默认的 Node Parser，它会按句子边界进行切分，避免在句子中间切断。4.1 基本用法from llama_index.core import SimpleDirectoryReader from llama_index.core.node_parser import SentenceSplitter # 1. 加载文档 documents = SimpleDirectoryReader("./data/").load_data() # 2. 创建切分器 parser = SentenceSplitter(chunk_size=512, chunk_overlap=20) # 3. 执行切分，得到 Nodes nodes = parser.get_nodes_from_documents(documents) print(f"原始文档数量: {len(documents)}") print(f"切分后节点数量: {len(nodes)}")4.2 全局配置方式如果你希望在整个应用中统一使用相同的切分配置，可以通过 Settings 对象设置：from llama_index.core import Settings from llama_index.core.node_parser import SentenceSplitter # 方式一：设置完整的 Node Parser Settings.text_splitter = SentenceSplitter(chunk_size=1024, chunk_overlap=20) # 方式二：只修改默认的 chunk 参数 Settings.chunk_size = 512 Settings.chunk_overlap = 20 # 之后所有的操作都会自动应用这个切分设置五、进阶切分器详解5.1 MarkdownNodeParser - 保留 Markdown 结构适用于处理 Markdown 格式的文档，能识别标题、代码块、列表等结构：from llama_index.core.node_parser import MarkdownNodeParser parser = MarkdownNodeParser() nodes = parser.get_nodes_from_documents(documents) # 输出的 node 会保留标题层级等结构信息5.2 CodeSplitter - 代码专用切分用于切分代码文件，它会按抽象语法树（AST）节点进行分割，保证每个 Node 包含完整的函数或类定义：from llama_index.core.node_parser import CodeSplitter # 指定代码语言和块大小 parser = CodeSplitter( language="python", chunk_lines=40, # 每个块的最大行数 chunk_lines_overlap=15, # 块之间的重叠行数 max_chars=1500, # 每个块的最大字符数 ) nodes = parser.get_nodes_from_documents(documents)5.3 SemanticSplitterNodeParser - 语义切分这是更高级的切分方式：根据句子间的语义相似度来决定在哪里切分，而不是机械地按字符数切割。from llama_index.core.node_parser import SemanticSplitterNodeParser from llama_index.embeddings.openai import OpenAIEmbedding # 需要提供嵌入模型来计算语义相似度 embed_model = OpenAIEmbedding() parser = SemanticSplitterNodeParser( embed_model=embed_model, buffer_size=1, # 每次比较的句子数量 breakpoint_percentile_threshold=95, # 相似度阈值 ) nodes = parser.get_nodes_from_documents(documents)参数说明：参数说明buffer_size分组评估语义相似度时的句子数量，设为1则逐句比较breakpoint_percentile_threshold余弦相似度百分位数阈值，值越小切分越细embed_model用于计算语义相似度的嵌入模型（必填）六、使用 IngestionPipeline 进行切分IngestionPipeline 可以将切分与其他数据转换步骤（如元数据提取、嵌入生成）组合在一起：from llama_index.core.ingestion import IngestionPipeline from llama_index.core.node_parser import SentenceSplitter from llama_index.core.extractors import TitleExtractor pipeline = IngestionPipeline( transformations=[ SentenceSplitter(chunk_size=512, chunk_overlap=20), TitleExtractor(), # 自动提取每个节点的标题 ] ) # 执行管道 nodes = pipeline.run(documents=documents, show_progress=True)七、第三方切分器集成7.1 DashScopeJsonNodeParser（阿里通义）使用阿里巴巴通义实验室开发的文本切分模型，特别适合中文文档：from llama_index.node_parser.dashscope import DashScopeJsonNodeParser from llama_index.core.ingestion import IngestionPipeline os.environ["DASHSCOPE_API_KEY"] = "your_api_key" node_parser = DashScopeJsonNodeParser( chunk_size=100, overlap_size=0, separator=" |,|，|。|？|！|\n|\?|\!", language="cn" # 中文模式 ) pipeline = IngestionPipeline(transformations=[node_parser]) nodes = pipeline.run(documents=documents)7.2 Preprocess API使用外部 API 服务进行智能切分，能识别文档的布局和语义结构：from llama_index.readers.preprocess import PreprocessReader loader = PreprocessReader( api_key="your-api-key", filepath="document.pdf" ) nodes = loader.get_nodes() # 直接获取切分好的 nodes八、Node 的后续使用切分完成后，最典型的用途是构建向量索引：from llama_index.core import VectorStoreIndex # 使用 nodes 构建索引 index = VectorStoreIndex(nodes) # 创建查询引擎 query_engine = index.as_query_engine() # 执行查询 response = query_engine.query("你的问题") print(response)二、什么数据需要切分？什么时候不需要？这是实际应用中最常见的问题。并非所有数据都需要切分，选择错误的处理方式会严重影响系统效果。2.1 需要切分的数据类型以下数据类型必须进行切分，否则无法有效检索：数据类型切分必要性推荐切分器📄 纯文本文档✅ 必须切分SentenceSplitter📝 Markdown文档✅ 必须切分MarkdownNodeParser🌐 HTML网页✅ 必须切分MarkdownNodeParser（先转Markdown）💻 代码文件✅ 必须切分CodeSplitter📑 长文本日志✅ 必须切分SentenceSplitter2.2 不需要切分的数据类型以下结构化数据天然具有原子单位，直接检索即可，切分反而会破坏其结构：数据类型原子单位LlamaIndex 推荐方式🗄️ SQL数据库行/记录SQLTableRetriever + 文本到SQL📋 JSON/XML字段/路径字段路径访问 + Jsonalyzer📊 CSV表格行（如果行级语义完整）PandasQueryEngine🕸️ 知识图谱三元组/节点KnowledgeGraphIndex📈 时间序列时间点/时段TimeIndex🔢 纯数值数组元素直接数学计算# SQL 数据示例 - 不需要切分 from llama_index.core.query_engine import NLSQLTableQueryEngine query_engine = NLSQLTableQueryEngine( sql_database=sql_database, tables=["users", "orders"], ) response = query_engine.query("查询过去30天订单金额前10的用户") # JSON 数据示例 - 不需要切分 import json data = json.load(open("data.json")) # 直接按路径访问即可，不需要切分 value = data["users"][0]["address"]["city"]2.3 半结构化数据：混合处理策略实际数据常常是表格 + 自然语言描述的混合体，需要分别处理：# 产品手册（半结构化示例） ## 规格参数（表格形式） | 型号 | 价格 | 重量 | 库存 | |------|------|------|------| | A100 | $10000 | 30kg | 50台 | | V100 | $8000 | 25kg | 30台 | 详细说明：A100适用于大规模AI训练，支持FP64精度...混合处理方案：from llama_index.core.node_parser import SentenceSplitter from llama_index.core.extractors import TableExtractor # 方案1：表格转文本 + 正常切分 table_text = "型号A100价格10000美元重量30kg库存50台。型号V100价格8000美元重量25kg库存30台。" nodes = SentenceSplitter(chunk_size=512).get_nodes_from_documents([table_text]) # 方案2：使用专门的TableNodeParser from llama_index.core.node_parser import TableNodeParser table_nodes = TableNodeParser().get_nodes_from_documents(table_documents) # 方案3：混合索引 - 表格走结构化查询，文本走向量检索 from llama_index.core import VectorStoreIndex, SQLTableNodeMapping # 文本部分：切分后建向量索引 text_nodes = SentenceSplitter().get_nodes_from_documents(text_docs) vector_index = VectorStoreIndex(text_nodes) # 表格部分：保留原结构，不走切分 sql_query_engine = NLSQLTableQueryEngine(sql_database)2.4 判断流程图def decide_chunking_strategy(data): """ 判断数据类型应采用切分还是直接检索 """ # 1. 是否为纯文本/半文本 if is_free_text(data): return "USE_CHUNKING", "SentenceSplitter" # 2. 是否有明确的原子单位（行、字段、记录） if has_clear_atomic_unit(data): # 如：SQL行、JSON字段 return "NO_CHUNKING", "Direct query / Path access" # 3. 单个记录是否超过token限制 if estimate_tokens(data) > 8192: # LLM上下文窗口 return "USE_CHUNKING", "SentenceSplitter (large chunk)" # 4. 数据结构是否严格层级化 if is_strictly_hierarchical(data): # 如：深度嵌套JSON return "NO_CHUNKING", "Jsonalyzer" return "USE_CHUNKING", "SentenceSplitter (default)"2.5 核心原则总结原则说明示例原子性优先如果数据本身具有原子单位（行、记录、字段），直接使用该单位检索SQL行、JSON字段破坏结构不切切分会破坏数据关系（如父-子引用、外键约束）时，不切分树形JSON、XML超限才切只有当单个单位超过LLM上下文窗口时，才考虑切分超长文本字段混合分别处理半结构化数据中的表格和文字分开处理，使用不同策略产品规格表 + 描述文字三、自动切分 vs 手动切分3.1 VectorStoreIndex 的自动切分VectorStoreIndex 在构建索引时会自动完成文档的切分：from llama_index.core import VectorStoreIndex, SimpleDirectoryReader # 加载文档 documents = SimpleDirectoryReader("./data/").load_data() # 构建索引 —— 这里会自动完成切分！ index = VectorStoreIndex.from_documents(documents)自动完成的操作：将每个 Document 切分成更小的 Node 对象（文本块）为每个 Node 生成向量嵌入（embedding）将向量存储到索引中，准备检索控制自动切分的方式：from llama_index.core import Settings from llama_index.core.node_parser import SentenceSplitter # 方式一：通过全局 Settings 配置 Settings.text_splitter = SentenceSplitter(chunk_size=512, chunk_overlap=50) index = VectorStoreIndex.from_documents(documents) # 方式二：通过 transformations 参数直接传入 text_splitter = SentenceSplitter(chunk_size=500, chunk_overlap=50) index = VectorStoreIndex.from_documents( documents, transformations=[text_splitter] )3.2 为什么需要手动切分？既然 VectorStoreIndex 会自动切分，为什么还要手动操作？因为手动切分给你精细控制权。自动切分是"一键傻瓜式"操作，适合快速原型开发；而生产环境中，你往往需要以下手动控制能力。优势一：自定义元数据（最关键）每个 Node 可以附带不同的元数据，这对检索质量影响巨大：from llama_index.core.schema import TextNode # 手动创建节点，为每个块添加特定元数据 nodes = [ TextNode( text="A100 显卡支持 FP64 高精度计算", metadata={ "page": 5, "section": "技术规格", "product": "A100", "importance": "high", "price_range": "$10000+" } ), TextNode( text="安装 A100 需要 300W 电源和 PCIe 4.0 插槽", metadata={ "page": 12, "section": "安装指南", "product": "A100", "importance": "medium" } ) ] # 自动切分做不到这种细粒度的元数据 index = VectorStoreIndex(nodes)优势二：自定义节点关系可以手动建立节点间的引用关系，实现更精准的检索：from llama_index.core.schema import TextNode, NodeRelationship, RelatedNodeInfo # 创建父子节点关系 parent_node = TextNode(text="第一章：AI 芯片概述", id_="parent_1") child_node_1 = TextNode( text="1.1 GPU 架构详解...", id_="child_1", relationships={ NodeRelationship.PARENT: RelatedNodeInfo(node_id="parent_1") } ) child_node_2 = TextNode( text="1.2 TPU 对比分析...", id_="child_2", relationships={ NodeRelationship.PARENT: RelatedNodeInfo(node_id="parent_1") } ) # 检索时可以获得层级上下文自动切分生成的节点是扁平的、无关系的。优势三：过滤和预处理在切分阶段可以做很多自动切分做不到的事：# 手动切分前可以进行智能过滤 documents = load_documents() filtered_nodes = [] for doc in documents: # 1. 移除噪音内容 if "[广告]" in doc.text: continue # 2. 合并太短的块 if len(doc.text) < 50: # 合并到上一个节点 pass # 3. 根据内容决定切分策略 if "表格" in doc.metadata.get("type", ""): # 表格用特殊方式处理 nodes = table_parser.parse(doc) else: nodes = text_parser.parse(doc) filtered_nodes.extend(nodes)优势四：保证完整性约束某些内容绝对不能被切分，自动切分无法保证：# 代码示例：函数定义必须完整 # 自动切分可能在函数中间切断 def complex_function(a, b, c): # 100 行代码... if a > b: # 自动切分可能在这里切断！导致语法错误 pass # 手动切分：按 AST 节点切分，保证函数完整 from llama_index.core.node_parser import CodeSplitter code_parser = CodeSplitter(language="python", chunk_lines=50) nodes = code_parser.get_nodes_from_documents(code_docs)优势五：多模态和复杂数据结构# 混合内容：图片 + 文字 nodes = [ TextNode( text="图 1 显示了 A100 的核心架构", metadata={"image_path": "a100_diagram.png", "image_id": "fig1"} ), TextNode( text="该架构包含 6192 个 CUDA 核心...", metadata={"references": ["fig1"]} ) ] # 或者预先生成的 embedding from llama_index.core.embeddings import OpenAIEmbedding embed_model = OpenAIEmbedding() node = TextNode(text="重要内容") node.embedding = embed_model.get_text_embedding("重要内容") # 预计算3.3 自动切分 vs 手动切分 对比总结能力自动切分手动切分快速上手✅ 一行代码❌ 需要写代码自定义元数据❌ 只能文档级别✅ 节点级别精细控制节点关系（父子/前后）❌ 扁平结构✅ 任意关系内容过滤/清洗❌ 无法干预✅ 完全控制完整性保证⚠️ 可能切断关键内容✅ 可保证多模态支持❌ 有限✅ 灵活性能优化（如预计算 embedding）⚠️ 批量计算✅ 精细控制3.4 实践建议：渐进式优化# 阶段一：快速验证（用自动切分） index = VectorStoreIndex.from_documents(documents) # 测试效果... # 阶段二：发现问题后，切换到手动切分 # 例如：检索结果缺失某些关键信息、上下文不连贯 # 阶段三：针对性优化 from llama_index.core.node_parser import SentenceSplitter # 先用解析器生成基础 nodes parser = SentenceSplitter(chunk_size=512, chunk_overlap=50) nodes = parser.get_nodes_from_documents(documents) # 再手动增强 for i, node in enumerate(nodes): # 添加缺失的元数据 node.metadata["chunk_index"] = i node.metadata["source_file"] = documents[0].metadata.get("file_name") # 标记重要节点 if "summary" in node.text.lower(): node.metadata["is_summary"] = True index = VectorStoreIndex(nodes)3.5 一句话总结方式适用场景自动切分快且省事，适合探索和简单场景手动切分可控且精准，适合生产和复杂场景💡 核心提示：当你发现检索结果不够好时，手动切分往往是第一个需要优化的地方。九、切分策略总结与建议9.1 按文档类型选择策略文档类型推荐切分器chunk_size / 说明是否需要切分普通文本文档SentenceSplitter512-1024✅ 必须Markdown文档MarkdownNodeParser保留标题结构✅ 必须代码文件CodeSplitter按AST节点切分✅ 必须长文档/书籍SemanticSplitterNodeParser按语义边界切分✅ 必须SQL数据库不切分使用NLSQLTableQueryEngine❌ 不需要JSON/XML不切分路径直接访问❌ 不需要CSV小表不切分使用PandasQueryEngine❌ 不需要半结构化混合表格不切分 + 文本切分混合策略⚠️ 视情况中文文档DashScopeJsonNodeParser专门优化中文分词✅ 必须9.2 关键提示chunk_size：越小检索越精准但可能丢失上下文；越大上下文更完整但检索噪音增加chunk_overlap：通常设置为 chunk_size 的 10%-20%，用于保持相邻块之间的信息连续性结构化数据优先不切：SQL、JSON等有原子单位的数据，直接检索即可半结构化混合处理：表格部分走结构化查询，文本部分走向量检索自动切分 vs 手动切分：快速验证用自动，生产环境根据需求选择手动实验验证：不同的切分方式对 RAG 效果影响显著，建议在实际任务中进行实验对比9.3 快速决策表# 你的数据是...？ data_type = input("数据类型: ") if data_type in ["PDF", "TXT", "MD", "HTML", "代码"]: print("→ 使用 SentenceSplitter 或 MarkdownNodeParser 切分") elif data_type in ["SQL", "数据库", "表格(结构化)"]: print("→ 不需要切分，使用 NLSQLTableQueryEngine") elif data_type in ["JSON", "XML", "API响应"]: print("→ 不需要切分，直接路径访问") elif data_type == "半结构化(表格+文字)": print("→ 混合策略：表格保留结构，文字切分") else: print("→ 默认使用 SentenceSplitter") # 你想控制到什么程度？ control_level = input("控制程度（快速/精细）: ") if control_level == "快速": print("→ 使用 VectorStoreIndex.from_documents() 自动切分") else: print("→ 手动创建 Nodes，自定义元数据、关系和预处理逻辑")这个完整版教程现在涵盖了：✅ 核心概念（Document vs Node）✅ 什么数据需要/不需要切分✅ 自动切分 vs 手动切分的对比和选择✅ 各种切分器的详细使用✅ 进阶功能和第三方集成✅ 实践建议和决策指南
LlamaIndex 文档加载完全指南文档加载是 LlamaIndex 构建 RAG 应用的第一步，也是最基础的一步。本文将全面介绍 LlamaIndex 中文档加载的各种方式、核心概念以及高级自定义技巧。一、核心概念：Document在 LlamaIndex 中，Document（文档）是对原始数据源的标准化封装，是整个 RAG 流程的数据入口。它不仅仅指传统的文本文档，而是涵盖所有可被加载的结构化/非结构化数据的抽象载体。1. Document 的核心属性每个 Document 对象包含以下关键属性：属性类型说明textstr核心属性，存储文档的原始文本内容metadatadict元数据字典，记录文档的上下文信息（文件名、路径、创建时间等）id_ / doc_idstr唯一标识符，用于区分不同 Document2. Document 的关键特性多源适配性：LlamaIndex 提供 100+ 内置 Data Loader，可将不同数据源统一为 Document 对象不可变性：原始 Document 加载后内容不会被修改（分割操作会生成新的 Node）编码保障：加载中文文档时需通过 encoding="utf-8" 指定编码二、文档加载的三种方式方式一：使用 SimpleDirectoryReader（最常用）SimpleDirectoryReader 是最简单易用的加载器，可以将指定目录中的文件批量加载为 Document 对象：from llama_index.core import SimpleDirectoryReader # 基本用法：加载目录下所有文件 documents = SimpleDirectoryReader("./data").load_data() # 指定编码（处理中文文档） documents = SimpleDirectoryReader("./data", encoding="utf-8").load_data() # 查看加载结果 print(f"加载文档数量：{len(documents)}") print(f"第一个文档内容长度：{len(documents[0].text)}字符") print(f"文档元数据：{documents[0].metadata}")支持的文件格式：Markdown、PDF、Word 文档、PowerPoint 演示文稿、图像、音频和视频等。方式二：使用 LlamaHub 的数据加载器LlamaHub 是 LlamaIndex 的数据连接器注册表，提供了数百种连接器，支持从各种数据源加载数据：from llama_index.core import download_loader from llama_index.readers.database import DatabaseReader # 示例：从 SQL 数据库加载数据 reader = DatabaseReader( scheme="postgresql", host="localhost", port=5432, user="myuser", password="mypassword", dbname="mydb", ) query = "SELECT * FROM users" documents = reader.load_data(query=query)方式三：手动构造 Document你也可以手动创建 Document 对象：from llama_index.core import Document # 从文本列表创建 text_list = ["文本1内容", "文本2内容", "文本3内容"] documents = [Document(text=t) for t in text_list] # 创建单个文档 document = Document(text="这是文档的原始文本内容") # 快速创建示例文档（用于原型开发） example_doc = Document.example()三、元数据（Metadata）管理元数据是 Document 的重要组成部分，用于记录文档的上下文信息，对回答溯源和多文档管理至关重要。1. 设置元数据方式一：在构造函数中设置document = Document( text="文档内容", metadata={ "filename": "important_doc.pdf", "category": "技术文档", "author": "张三", "creation_date": "2024-01-15" } )方式二：创建后设置document = Document(text="文档内容") document.metadata = {"filename": "doc.txt", "category": "指南"}方式三：使用 SimpleDirectoryReader 自动设置from llama_index.core import SimpleDirectoryReader # 定义元数据生成函数 filename_fn = lambda filename: {"file_name": filename, "source": "local"} documents = SimpleDirectoryReader( "./data", file_metadata=filename_fn ).load_data()2. 自定义文档 ID文档 ID 用于在索引中高效管理和刷新文档：# 自动将文件路径作为 ID documents = SimpleDirectoryReader("./data", filename_as_id=True).load_data() # 手动设置 ID document.doc_id = "my_custom_document_id"3. 高级元数据自定义默认情况下，元数据会被同时注入到 Embedding 模型和 LLM 中。但你可以分别控制：from llama_index.core import Document from llama_index.core.schema import MetadataMode document = Document( text="这是一个需要处理的文档", metadata={ "file_name": "secret_document.txt", # 文件名可能包含敏感信息 "category": "finance", "author": "LlamaIndex" }, # 排除 LLM 可见的元数据字段 excluded_llm_metadata_keys=["file_name"], # 排除 Embedding 可见的元数据字段 excluded_embed_metadata_keys=["file_name"], ) # 查看 LLM 实际看到的内容 print("LLM 看到的内容：") print(document.get_content(metadata_mode=MetadataMode.LLM)) # 查看 Embedding 模型实际看到的内容 print("Embedding 模型看到的内容：") print(document.get_content(metadata_mode=MetadataMode.EMBED))4. 自定义元数据格式你可以控制元数据在文本中的呈现格式：document = Document( text="文档内容", metadata={"key1": "value1", "key2": "value2"}, metadata_seperator=" | ", # 键值对之间的分隔符，默认为 "\n" metadata_template="{key}: {value}", # 每个键值对的格式，默认为 "{key}: {value}" text_template="元数据：{metadata_str}\n---\n内容：{content}" # 最终模板 )四、批量加载与高级用法1. 批量加载目录from llama_index.core import SimpleDirectoryReader # 加载整个目录 documents = SimpleDirectoryReader( input_dir="./docs", recursive=True, # 递归读取子目录 required_exts=[".pdf", ".txt"], # 只加载特定扩展名 exclude=["temp", "draft"] # 排除特定目录 ).load_data()2. 处理大文档对于大型文档，建议在加载时进行流式处理或设置合适的 chunk 大小：from llama_index.core import Settings from llama_index.core.node_parser import SentenceSplitter # 全局设置 chunk 大小 Settings.chunk_size = 512 # 或使用自定义解析器 documents = SimpleDirectoryReader("./data").load_data() parser = SentenceSplitter(chunk_size=512, chunk_overlap=20) nodes = parser.get_nodes_from_documents(documents)3. 使用 DocStore 管理多个索引你可以将文档存储在 Document Store 中，供多个索引重用，避免数据重复：from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, SummaryIndex from llama_index.core.storage.docstore import SimpleDocumentStore from llama_index.core import StorageContext from llama_index.core.node_parser import SentenceSplitter # 加载并解析文档 documents = SimpleDirectoryReader("./data").load_data() nodes = SentenceSplitter().get_nodes_from_documents(documents) # 创建文档存储 docstore = SimpleDocumentStore() docstore.add_documents(nodes) storage_context = StorageContext.from_defaults(docstore=docstore) # 多个索引共享同一个文档存储 vector_index = VectorStoreIndex(nodes, storage_context=storage_context) summary_index = SummaryIndex(nodes, storage_context=storage_context) # 验证：两个索引使用相同的底层节点 print(f"文档存储中的节点数：{len(storage_context.docstore.docs)}")五、完整示例：从加载到索引以下是一个完整的文档加载到索引构建的示例：from llama_index.core import ( SimpleDirectoryReader, VectorStoreIndex, Settings ) from llama_index.core.node_parser import SentenceSplitter from llama_index.llms.openai import OpenAI # 1. 配置 LLM（可选） Settings.llm = OpenAI(model="gpt-3.5-turbo", temperature=0) # 2. 加载文档 documents = SimpleDirectoryReader( "./data", encoding="utf-8", filename_as_id=True # 使用文件名作为文档 ID ).load_data() print(f"成功加载 {len(documents)} 个文档") # 3. 查看文档信息 for doc in documents[:3]: # 显示前3个 print(f"文档ID: {doc.doc_id}") print(f"文件名: {doc.metadata.get('file_name', 'Unknown')}") print(f"内容长度: {len(doc.text)} 字符") print("-" * 50) # 4. 设置文本分割 Settings.chunk_size = 512 Settings.chunk_overlap = 20 # 5. 构建索引 index = VectorStoreIndex.from_documents(documents) # 6. 查询测试 query_engine = index.as_query_engine() response = query_engine.query("你的问题在这里") print(response)六、常见问题与最佳实践1. 中文编码问题加载中文文档时，务必指定 encoding="utf-8"，否则可能导致乱码：documents = SimpleDirectoryReader("./chinese_docs", encoding="utf-8").load_data()2. 元数据最佳实践保留文件路径和文件名，便于溯源对敏感元数据使用 excluded_llm_metadata_keys 排除保持元数据值类型简单（str、float、int），以便向量数据库兼容3. 性能优化对于大型文档集，合理设置 chunk_size（通常 512-1024）使用 recursive=False 避免不必要的深层遍历考虑使用 SimpleDirectoryReader 的 file_metadata 回调函数批量添加元数据4. 文档刷新策略通过设置 filename_as_id=True，可以方便地检测文档变化并刷新索引：# 设置文件名作为 ID，便于检测变化 documents = SimpleDirectoryReader("./data", filename_as_id=True).load_data() # 后续可以使用索引的 refresh() 方法更新总结LlamaIndex 的文档加载机制灵活而强大，核心要点包括：Document 是核心抽象：统一表示各种数据源的标准化容器SimpleDirectoryReader 是主力工具：覆盖大部分本地文件加载需求元数据是关键：合理设置元数据可大幅提升 RAG 效果LlamaHub 提供扩展：数百种数据连接器满足各种场景需求DocStore 支持多索引共享：避免数据冗余，提升效率掌握这些文档加载技巧，将为后续的索引构建和智能问答打下坚实基础。
索引、向量数据与数据库的关系这是一个非常核心的问题。理解三者的关系，对于设计RAG应用的存储架构至关重要。一、概念澄清1.1 各角色定义组件本质存储内容比喻向量数值化后的文本特征浮点数数组（如[0.12, -0.34, 0.56...]）文档的"DNA编码"索引(Index)高效检索向量的数据结构向量 + 对应的ID映射关系图书的"目录+分类卡片"数据库持久化存储系统向量数据 + 原始文本 + 元数据图书馆的"书架系统"1.2 三者的层级关系graph TD A[数据库 Database] --> B[向量存储 Vector Store] A --> C[文档存储 Document Store] A --> D[索引存储 Index Store] B --> E[向量数据 Vector Data] C --> F[原始文本+节点] D --> G[索引元数据 Index Metadata] style A fill:#f9f,stroke:#333,stroke-width:4px关键理解：向量是数据本身（一种特殊的数据类型）索引是数据结构（帮助快速检索这些数据）数据库是载体（持久化存储向量+索引+元数据）二、LlamaIndex 的三层存储架构LlamaIndex 将存储拆分为三个独立的组件，它们共同构成完整的索引系统：2.1 存储组件详解from llama_index.core import StorageContext storage_context = StorageContext.from_defaults( docstore=... # 文档存储：存原始文本和节点 vector_store=... # 向量存储：存向量嵌入 index_store=... # 索引存储：存索引元数据 )组件存储内容数据量级查询频率DocStore原始文本、Node对象、文本分块较大中（返回结果时读取）VectorStore向量数组、向量与Node的映射极大（取决于维度）极高（每次查询）IndexStore索引ID、索引类型、构建参数极小低（加载时读取）2.2 实际数据示例假设你有一篇文章："LlamaIndex是一个强大的RAG框架"# 1. 原始文本 → 存入 DocStore { "node_id": "node_001", "text": "LlamaIndex是一个强大的RAG框架", "metadata": {"source": "article.pdf", "page": 1} } # 2. 文本转化为向量 → 存入 VectorStore { "node_id": "node_001", "embedding": [0.123, -0.456, 0.789, ...], # 768维或1536维向量 } # 3. 索引元数据 → 存入 IndexStore { "index_id": "my_vector_index", "index_type": "VectorStoreIndex", "embedding_model": "text-embedding-ada-002", "node_count": 1500 }三、不同存储方式的差异3.1 本地文件系统（SimpleVectorStore）storage_context = StorageContext.from_defaults(persist_dir="./storage")存储结构：./storage/ ├── docstore.json # 所有原始文本 ├── vector_store.json # 所有向量数据（JSON格式，效率低） └── index_store.json # 索引元数据特点：向量和索引耦合在同一个JSON文件中适合小规模数据（<1万条文档）每次加载需反序列化整个文件3.2 专业向量数据库（如Chroma）vector_store = ChromaVectorStore(chroma_collection=collection) storage_context = StorageContext.from_defaults(vector_store=vector_store)存储结构（Chroma内部）：chroma_db/ ├── chroma.sqlite3 # 存储元数据、文档ID、集合信息 └── data_level0.bin # 存储HNSW索引 + 向量数据关系说明：SQLite表：存储文档ID、元数据、向量与文件的映射二进制文件：存储HNSW图索引结构 + 实际向量数组向量、索引、元数据分离但关联存储3.3 分布式系统（Redis + S3）# 向量存储在S3，索引元数据在Redis vector_store = S3VectorStore(bucket="my-bucket") index_store = RedisIndexStore(host="localhost") storage_context = StorageContext.from_defaults( vector_store=vector_store, index_store=index_store )数据分布：数据存储位置原因向量文件S3数据量大，需要低成本持久化索引缓存Redis需要快速访问，支持高并发原始文本PostgreSQL需要结构化查询和事务支持四、核心关系图解4.1 数据流向sequenceDiagram participant User participant Index participant VectorStore participant DocStore Note over User,DocStore: 构建索引阶段 User->>Index: 1. 提供文档 Index->>Index: 2. 文本分块 + 调用嵌入模型 Index->>VectorStore: 3. 存储向量 + NodeID Index->>DocStore: 4. 存储原始文本 + NodeID Note over User,DocStore: 查询阶段 User->>Index: 5. 输入查询文本 Index->>Index: 6. 查询文本 → 查询向量 Index->>VectorStore: 7. 相似度搜索（返回NodeID列表） VectorStore-->>Index: 8. [node_001, node_045, ...] Index->>DocStore: 9. 根据NodeID获取原始文本 DocStore-->>Index: 10. 返回完整文本内容 Index-->>User: 11. 返回检索结果4.2 查询执行细节# 当你执行 query_engine.query("什么是RAG？") 时： # 步骤1：查询文本转向量 query_vector = embed_model.encode("什么是RAG？") # 步骤2：在VectorStore中搜索最相似的向量 results = vector_store.similarity_search(query_vector, top_k=5) # 返回: [(node_id="node_001", score=0.95), (node_id="node_045", score=0.87)] # 步骤3：从DocStore中获取原始文本 documents = [docstore.get_document(node_id) for node_id, _ in results] # 步骤4：返回结果 return documents五、常见误区澄清误区1："索引就是数据库"纠正：索引 = 检索算法的数据结构（如HNSW图、IVF倒排索引）数据库 = 持久化存储系统正确关系：数据库可以存储索引和向量误区2："向量数据库不存储向量"纠正：向量数据库专门为存储和检索向量设计内部集成了索引结构（如HNSW、IVF）来加速向量检索例如Pinecone、Milvus、Qdrant都是存储向量+索引误区3："索引在内存中就不需要数据库"纠正：# 即使索引在内存中，仍需持久化 index = VectorStoreIndex.from_documents(documents) # 在内存中 # 如果不持久化，程序退出后索引消失 index.storage_context.persist(persist_dir="./storage") # 保存到数据库/文件六、选择决策指南6.1 数据规模决定存储方式数据量向量数量推荐方案索引存储位置< 1万条< 100万向量本地文件系统JSON文件1万-10万< 1000万向量Chroma/Qdrant本地磁盘+内存缓存10万-100万< 1亿向量Milvus/Pinecone分布式存储+SSD> 100万> 1亿向量自建HNSW+对象存储S3+Redis缓存6.2 性能考虑# 影响性能的关键因素： # 1. 向量维度：768维 vs 1536维 → 存储空间差2倍，检索速度差2倍 # 2. 索引类型：暴力搜索 vs HNSW → 速度差100倍，内存占用差10倍 # 3. 存储介质：内存 vs SSD vs HDD → 延迟差1000倍七、代码验证# 完整示例：展示三者的实际内容 from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, StorageContext import json # 构建索引 documents = SimpleDirectoryReader("./data").load_data() index = VectorStoreIndex.from_documents(documents) index.storage_context.persist(persist_dir="./storage_demo") # 查看实际存储内容 import os # DocStore内容 with open("./storage_demo/docstore.json", "r") as f: docstore = json.load(f) print(f"DocStore中的文档数量: {len(docstore['docstore/data'])}") first_node_id = list(docstore['docstore/data'].keys())[0] print(f"第一个文档内容预览: {docstore['docstore/data'][first_node_id]['text'][:100]}...") # VectorStore内容 with open("./storage_demo/vector_store.json", "r") as f: vector_store = json.load(f) first_vector = list(vector_store['vector_store/data'].values())[0] print(f"向量维度: {len(first_vector)}") print(f"向量前5个值: {first_vector[:5]}") # IndexStore内容 with open("./storage_demo/index_store.json", "r") as f: index_store = json.load(f) print(f"索引信息: {index_store}")输出示例：DocStore中的文档数量: 145 第一个文档内容预览: LlamaIndex是一个构建RAG应用的框架，它提供了数据连接、索引构建和查询引擎等功能... 向量维度: 1536 向量前5个值: [0.023, -0.456, 0.789, -0.123, 0.567] 索引信息: {"index_store/data": {"my_vector_index": {"index_id": "my_vector_index", "type": "vector"}}}总结概念一句话定义向量文本的数学表示，用于计算相似度索引加速向量检索的数据结构数据库持久化存储向量+索引+元数据的系统最佳实践：小项目：用LlamaIndex本地文件系统（简单）生产环境：用专业向量数据库（Chroma/Milvus/Qdrant）超大规模：向量存对象存储，索引存Redis缓存
LlamaIndex + Qwen RAG 实战学习文档版本适配: LlamaIndex v0.14.x (2026年最新稳定版) 目标读者: 大模型应用程序员 核心模型: 千问 (Qwen2.5 / Qwen3 / DashScope API) 文档定位: 从环境搭建到生产级 RAG 系统的完整实践指南目录框架概览与版本说明环境准备与安装核心概念速览基础 RAG：五步走通全流程千问模型集成详解数据加载与文档解析索引构建与向量存储检索策略与查询引擎高级 RAG 技巧生产化部署要点完整可运行代码汇总1. 框架概览与版本说明1.1 LlamaIndex 是什么？LlamaIndex 是一个专为 RAG（检索增强生成） 设计的 Python 框架，其核心理念是：数据索引化：将任意格式的非结构化数据（PDF、网页、数据库）转化为 LLM 可消费的索引结构检索即服务：提供从简单向量检索到多跳推理的完整检索抽象层与模型无关：通过 Settings 全局配置，可无缝切换 OpenAI、Claude、千问等不同模型1.2 版本演进（关键 Breaking Changes）版本关键变化影响0.9.x 之前单体式包结构from llama_index import ...0.10+模块化重构核心包 + 独立集成包，必须分开安装0.11+Settings 全局配置统一通过 Settings.llm = ... 配置0.14.x当前最新API 稳定，支持异步流式、Agent 编排⚠️ 重要: 0.10+ 版本后，llama-index 核心包不再包含模型集成代码。使用 HuggingFace 模型或特定 API 时，必须安装对应的子包。2. 环境准备与安装2.1 基础依赖安装# 核心框架（必须） pip install llama-index # 千问本地部署（HuggingFace 方式） pip install llama-index-llms-huggingface pip install llama-index-embeddings-huggingface # 千问 API 方式（DashScope / 阿里云百炼） pip install llama-index-llms-openai-like # 文档解析增强 pip install llama-index-readers-web # 网页读取 pip install llama-index-readers-file # 文件读取（PDF、Word 等） # 向量数据库（生产环境必需） pip install llama-index-vector-stores-chroma # ChromaDB pip install llama-index-vector-stores-qdrant # Qdrant # 其他工具 pip install transformers>=4.37.0 pip install torch pip install sentence-transformers2.2 环境变量配置# 方式一：本地 HuggingFace 模型（需提前下载） export HF_ENDPOINT=https://hf-mirror.com # 国内镜像加速 export CUDA_VISIBLE_DEVICES=0 # 方式二：DashScope API（推荐，无需本地 GPU） export DASHSCOPE_API_KEY="sk-xxxxxxxxxxxxxxxx" # 方式三：阿里云百炼 export ALIBABA_API_KEY="sk-xxxxxxxxxxxxxxxx"3. 核心概念速览在写代码前，必须理解 LlamaIndex 的 5 个核心抽象：┌─────────────────────────────────────────────────────────────┐ │ LlamaIndex 核心抽象层 │ ├─────────────────────────────────────────────────────────────┤ │ Document → 原始文档对象（text + metadata） │ │ ↓ │ │ Node → 文档切片（chunk），检索的最小单元 │ │ ↓ │ │ Index → 索引结构（VectorStoreIndex / TreeIndex） │ │ ↓ │ │ Retriever → 检索器（从 Index 中召回相关 Nodes） │ │ ↓ │ │ QueryEngine → 查询引擎（Retriever + LLM 合成答案） │ └─────────────────────────────────────────────────────────────┘关键理解: QueryEngine = Retriever（召回） + ResponseSynthesizer（生成）。你可以独立控制这两个环节。4. 基础 RAG：五步走通全流程Step 1: 配置全局 Settings（0.10+ 标准写法）from llama_index.core import Settings from llama_index.core.node_parser import SentenceSplitter # 所有 LlamaIndex 组件都会自动读取 Settings 中的配置 Settings.chunk_size = 1024 # 文本切片大小 Settings.chunk_overlap = 200 # 切片重叠长度（保持上下文连贯性） Settings.transformations = [SentenceSplitter(chunk_size=1024, chunk_overlap=200)]Step 2: 加载文档from llama_index.core import SimpleDirectoryReader # 自动识别 PDF、TXT、DOCX、MD 等格式 documents = SimpleDirectoryReader( input_dir="./data", required_exts=[".pdf", ".txt", ".md"], # 过滤文件类型 recursive=True # 递归子目录 ).load_data() print(f"✅ 加载了 {len(documents)} 个文档") print(f"📄 第一个文档预览: {documents[0].text[:200]}...")Step 3: 构建向量索引from llama_index.core import VectorStoreIndex # 一行代码完成：切片 → Embedding → 存储 index = VectorStoreIndex.from_documents( documents, show_progress=True # 显示进度条（对大文件很有用） )Step 4: 创建查询引擎query_engine = index.as_query_engine( similarity_top_k=5, # 召回 Top-5 相关片段 response_mode="compact" # 答案合成策略：compact / tree_summarize / refine )Step 5: 执行查询response = query_engine.query("这份文档的核心观点是什么？") print(response) # 查看引用来源（可溯源是 RAG 的核心价值） for node in response.source_nodes: print(f"📌 来源: {node.metadata.get('file_name', 'unknown')} | 相关度: {node.score:.4f}") print(f"📝 片段: {node.text[:150]}...") print("-" * 50)5. 千问模型集成详解千问模型与 LlamaIndex 集成有三种主流方式，根据你的硬件条件和场景选择：方式 A：DashScope API（推荐，零运维）适合：快速验证、生产部署、无 GPU 环境import os from llama_index.core import Settings from llama_index.llms.openai_like import OpenAILike from llama_index.embeddings.dashscope import DashScopeEmbedding # LLM：通过 OpenAI 兼容接口调用 DashScope Settings.llm = OpenAILike( model="qwen-turbo", # 可选: qwen-turbo, qwen-plus, qwen-max api_base="https://dashscope.aliyuncs.com/compatible-mode/v1", api_key=os.getenv("DASHSCOPE_API_KEY"), context_window=8192, is_chat_model=True, is_function_calling_model=False, # 纯 RAG 场景可关闭 function calling ) # Embedding：使用 DashScope 的 Embedding 服务（支持中文） Settings.embed_model = DashScopeEmbedding( model_name="text-embedding-v2", # 或 text-embedding-v1 api_key=os.getenv("DASHSCOPE_API_KEY") )方式 B：本地 HuggingFace 加载（需 GPU）适合：数据隐私要求高、离线环境、已有 GPU 服务器import torch from llama_index.core import Settings, PromptTemplate from llama_index.llms.huggingface import HuggingFaceLLM from llama_index.embeddings.huggingface import HuggingFaceEmbedding # ========== 千问提示词模板（必须！否则输出格式混乱）========== def messages_to_prompt(messages): """将消息列表转换为 Qwen 的 ChatML 格式""" prompt = "" for message in messages: if message.role == "system": prompt += f"<|im_start|>system\n{message.content}e<|im_end|>\n" elif message.role == "user": prompt += f"<|im_start|>user\n{message.content}e<|im_end|>\n" elif message.role == "assistant": prompt += f"<|im_start|>assistant\n{message.content}e<|im_end|>\n" # 如果没有 system prompt，添加默认提示 if not prompt.startswith("<|im_start|>system"): prompt = "<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.e<|im_end|>\n" + prompt prompt += "<|im_start|>assistant\n" return prompt def completion_to_prompt(completion): """将纯文本补全转换为 Qwen 格式""" return f"<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.e<|im_end|>\n<|im_start|>user\n{completion}e<|im_end|>\n<|im_start|>assistant\n" # ========== 配置千问 LLM ========== Settings.llm = HuggingFaceLLM( model_name="Qwen/Qwen2.5-7B-Instruct", # 或 Qwen3-8B, Qwen2.5-14B-Instruct tokenizer_name="Qwen/Qwen2.5-7B-Instruct", context_window=32768, # Qwen2.5 支持 32K 上下文 max_new_tokens=2048, generate_kwargs={ "temperature": 0.7, "top_p": 0.95, "top_k": 50, "do_sample": True, }, messages_to_prompt=messages_to_prompt, completion_to_prompt=completion_to_prompt, device_map="auto", # 自动分配多 GPU model_kwargs={"torch_dtype": torch.float16}, # 半精度节省显存 ) # ========== 配置 Embedding 模型 ========== # 中文文档强烈推荐 bge-m3 或 bge-large-zh-v1.5 Settings.embed_model = HuggingFaceEmbedding( model_name="BAAI/bge-m3", # 多语言支持，中文效果优秀 device="cuda", # 或 "cpu" trust_remote_code=True, ) # ========== 文本切片配置 ========== from llama_index.core.node_parser import SentenceSplitter Settings.transformations = [SentenceSplitter(chunk_size=1024, chunk_overlap=200)]方式 C：Ollama 本地部署（开发调试友好）适合：本地开发、快速原型验证# 先安装 Ollama 并拉取模型 ollama pull qwen2.5:7b ollama pull nomic-embed-text # 或 shaw/dmeta-embedding-zh 用于中文from llama_index.llms.ollama import Ollama from llama_index.embeddings.ollama import OllamaEmbedding from llama_index.core import Settings Settings.llm = Ollama(model="qwen2.5:7b", request_timeout=120.0) Settings.embed_model = OllamaEmbedding(model_name="nomic-embed-text")6. 数据加载与文档解析6.1 本地文件加载from llama_index.core import SimpleDirectoryReader from llama_index.readers.file import PDFReader, DocxReader # 基础用法：自动识别格式 docs = SimpleDirectoryReader("./data").load_data() # 进阶用法：自定义解析器 + 元数据注入 reader = SimpleDirectoryReader( input_dir="./data", file_extractor={ ".pdf": PDFReader(), ".docx": DocxReader(), }, filename_as_id=True, # 用文件名作为文档 ID，方便溯源 ) docs = reader.load_data() # 手动注入元数据（对后续过滤很重要） for doc in docs: doc.metadata.update({ "category": "技术文档", "author": "工程团队", "version": "v2.0", })6.2 网页数据加载from llama_index.readers.web import SimpleWebPageReader, BeautifulSoupWebPageReader # 简单网页读取（转为纯文本） urls = [ "https://qwen.readthedocs.io/en/latest/", "https://help.aliyun.com/document_detail/xxx.html" ] docs = SimpleWebPageReader(html_to_text=True).load_data(urls) # 进阶：用 BeautifulSoup 保留结构信息 from bs4 import BeautifulSoup import requests def custom_scraper(url): response = requests.get(url, timeout=30) soup = BeautifulSoup(response.text, 'html.parser') # 提取正文，过滤导航栏等噪音 main_content = soup.find('main') or soup.find('article') or soup.find('body') return main_content.get_text(separator='\n', strip=True) if main_content else ""6.3 数据库 / API 加载from llama_index.core import Document import json # 从数据库加载（示例：MySQL） # import pymysql # conn = pymysql.connect(...) # cursor = conn.cursor() # cursor.execute("SELECT title, content FROM knowledge_base") # rows = cursor.fetchall() # docs = [Document(text=row[1], metadata={"title": row[0]}) for row in rows] # 从 JSON/CSV 加载 import pandas as pd df = pd.read_csv("faq.csv") docs = [ Document( text=f"问题: {row['question']}\n答案: {row['answer']}", metadata={"source": "FAQ", "category": row['category']} ) for _, row in df.iterrows() ]7. 索引构建与向量存储7.1 内存索引（开发调试）from llama_index.core import VectorStoreIndex # 默认使用内存中的 SimpleVectorStore，重启后丢失 index = VectorStoreIndex.from_documents(documents)7.2 持久化到本地磁盘from llama_index.core import StorageContext # 保存（会生成 ./storage 目录，包含 docstore、index_store、vector_store） index.storage_context.persist(persist_dir="./storage") # 加载 from llama_index.core import load_index_from_storage storage_context = StorageContext.from_defaults(persist_dir="./storage") index = load_index_from_storage(storage_context)7.3 生产级向量数据库：ChromaDBimport chromadb from llama_index.vector_stores.chroma import ChromaVectorStore from llama_index.core import StorageContext, VectorStoreIndex # 创建 Chroma 客户端 chroma_client = chromadb.PersistentClient(path="./chroma_db") chroma_collection = chroma_client.get_or_create_collection("knowledge_base") # 包装为 LlamaIndex 的 VectorStore vector_store = ChromaVectorStore(chroma_collection=chroma_collection) storage_context = StorageContext.from_defaults(vector_store=vector_store) # 构建索引（数据存入 ChromaDB） index = VectorStoreIndex.from_documents( documents, storage_context=storage_context, show_progress=True ) # 后续加载无需重新 Embedding index = VectorStoreIndex.from_vector_store( vector_store=vector_store, storage_context=storage_context )7.4 生产级向量数据库：Qdrant（推荐）from llama_index.vector_stores.qdrant import QdrantVectorStore import qdrant_client client = qdrant_client.QdrantClient(path="./qdrant_data") # 本地模式 # client = qdrant_client.QdrantClient(host="localhost", port=6333) # 服务端模式 vector_store = QdrantVectorStore( client=client, collection_name="rag_collection", dimension=1024, # 必须与 Embedding 模型维度一致（bge-m3 是 1024） ) storage_context = StorageContext.from_defaults(vector_store=vector_store) index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)8. 检索策略与查询引擎8.1 基础相似度检索query_engine = index.as_query_engine( similarity_top_k=5, # 召回数量 response_mode="compact", # 合成策略 streaming=False, # 是否流式输出 )8.2 带过滤条件的检索（元数据过滤）from llama_index.core.vector_stores import MetadataFilters, ExactMatchFilter # 只检索 category="技术文档" 的内容 filters = MetadataFilters( filters=[ExactMatchFilter(key="category", value="技术文档")] ) query_engine = index.as_query_engine( similarity_top_k=5, filters=filters # 传入过滤条件 )8.3 自定义检索器 + Rerank（高级 RAG 必备）from llama_index.core.retrievers import VectorIndexRetriever from llama_index.core.postprocessor import SentenceTransformerRerank from llama_index.core.query_engine import RetrieverQueryEngine # 1. 宽召回：先取 Top-20 retriever = VectorIndexRetriever( index=index, similarity_top_k=20, ) # 2. 精排序：用 Cross-Encoder Reranker 筛选 Top-5 reranker = SentenceTransformerRerank( model="BAAI/bge-reranker-v2-m3", # 中文 Reranker top_n=5, ) # 3. 组装自定义 Query Engine query_engine = RetrieverQueryEngine.from_args( retriever=retriever, node_postprocessors=[reranker], response_mode="compact", ) # Reranker 能显著提升检索精度（通常 +10~25%）8.4 混合检索：向量 + 关键词from llama_index.core.retrievers import QueryFusionRetriever from llama_index.retrievers.bm25 import BM25Retriever # 创建两种检索器 vector_retriever = index.as_retriever(similarity_top_k=10) bm25_retriever = BM25Retriever.from_defaults(index=index, similarity_top_k=10) # 融合检索（RRF 算法） retriever = QueryFusionRetriever( [vector_retriever, bm25_retriever], similarity_top_k=5, num_queries=1, # 是否开启查询扩展（1=不扩展） mode="reciprocal_rerank", # RRF 融合算法 ) query_engine = index.as_query_engine(retriever=retriever)8.5 流式输出（提升用户体验）query_engine = index.as_query_engine(streaming=True) streaming_response = query_engine.query("解释 RAG 的工作原理") # 逐字输出（类似 ChatGPT 的打字效果） for token in streaming_response.response_gen: print(token, end="", flush=True)9. 高级 RAG 技巧9.1 自动合并检索器（Auto-Merging）解决"切片边界断裂"问题：当检索到的多个片段属于同一父文档时，自动合并为更大的上下文。from llama_index.core.node_parser import HierarchicalNodeParser from llama_index.core.retrievers import AutoMergingRetriever from llama_index.core.storage.docstore import SimpleDocumentStore # 1. 构建层级结构：大切片包含小切片 node_parser = HierarchicalNodeParser.from_defaults( chunk_sizes=[2048, 512], # 第一层 2048，第二层 512 ) nodes = node_parser.get_nodes_from_documents(documents) # 2. 存储到 docstore docstore = SimpleDocumentStore() docstore.add_documents(nodes) # 3. 只用叶子节点（512）构建向量索引 leaf_nodes = [n for n in nodes if n.relationships.get("child") is None] index = VectorStoreIndex(leaf_nodes) # 4. 自动合并检索器 retriever = AutoMergingRetriever( index.as_retriever(similarity_top_k=10), docstore=docstore, verbose=True, ) query_engine = RetrieverQueryEngine.from_args(retriever)9.2 多文档 Agent（路由 + 工具调用）当知识库包含多种类型文档（API 文档、教程、FAQ）时，让 Agent 自动选择数据源：from llama_index.core.tools import QueryEngineTool, ToolMetadata from llama_index.core.agent import ReActAgent # 为每种文档创建独立的 Query Engine api_index = VectorStoreIndex.from_documents(api_docs) tutorial_index = VectorStoreIndex.from_documents(tutorial_docs) api_tool = QueryEngineTool( query_engine=api_index.as_query_engine(), metadata=ToolMetadata( name="api_docs", description="提供 API 接口的详细参数、返回值和错误码信息。", ), ) tutorial_tool = QueryEngineTool( query_engine=tutorial_index.as_query_engine(), metadata=ToolMetadata( name="tutorials", description="提供面向新手的教程和最佳实践指南。", ), ) # 创建 ReAct Agent（千问支持 function calling 时可用） agent = ReActAgent.from_tools( [api_tool, tutorial_tool], llm=Settings.llm, verbose=True, system_prompt="你是技术文档助手。根据用户问题选择最合适的工具查询文档。", ) response = agent.chat("如何调用用户认证接口？")9.3 查询转换（Query Transformation）将复杂问题拆解为多个子问题，分别检索后综合答案：from llama_index.core.indices.query.query_transform import HyDEQueryTransform from llama_index.core.query_engine import TransformQueryEngine # HyDE（假设文档嵌入）：生成假答案后再检索，提升召回率 hyde_transform = HyDEQueryTransform(include_original=True) hyde_query_engine = TransformQueryEngine(query_engine, hyde_transform) response = hyde_query_engine.query("千问模型有哪些优势？")10. 生产化部署要点10.1 性能优化清单优化项开发环境生产环境Embedding 模型CPU / GPUGPU 或专用 Embedding 服务向量存储内存 / 本地文件Qdrant / Milvus / Weaviate索引持久化persist()向量数据库原生持久化并发处理单线程异步 aquery() + 连接池文本切片固定长度SemanticSplitter（语义切片）检索策略Top-K 相似度Hybrid + Rerank10.2 异步 API（FastAPI 集成示例）from fastapi import FastAPI from llama_index.core import Settings import asyncio app = FastAPI() # 全局初始化索引（启动时加载） index = None @app.on_event("startup") async def load_index(): global index storage_context = StorageContext.from_defaults(persist_dir="./storage") index = load_index_from_storage(storage_context) @app.post("/query") async def query(question: str): query_engine = index.as_query_engine() # 使用异步接口避免阻塞事件循环 response = await query_engine.aquery(question) return { "answer": str(response), "sources": [ {"file": n.metadata.get("file_name"), "score": n.score} for n in response.source_nodes ] }10.3 监控与评估from llama_index.core.callbacks import CallbackManager, LlamaDebugHandler import time # 添加调试处理器，追踪每一步耗时 debug_handler = LlamaDebugHandler(print_trace_on_end=True) Settings.callback_manager = CallbackManager([debug_handler]) # 执行查询后会自动打印： # - 检索耗时 # - LLM 调用耗时 # - Token 使用量 response = query_engine.query("测试问题")11. 完整可运行代码汇总11.1 最小可用示例（DashScope API + 本地文件）""" 最小可用 RAG 系统 依赖: pip install llama-index llama-index-llms-openai-like llama-index-embeddings-dashscope """ import os from llama_index.core import ( VectorStoreIndex, SimpleDirectoryReader, Settings, StorageContext, load_index_from_storage ) from llama_index.llms.openai_like import OpenAILike from llama_index.embeddings.dashscope import DashScopeEmbedding # ========== 配置 ========== Settings.llm = OpenAILike( model="qwen-turbo", api_base="https://dashscope.aliyuncs.com/compatible-mode/v1", api_key=os.getenv("DASHSCOPE_API_KEY"), context_window=8192, is_chat_model=True, ) Settings.embed_model = DashScopeEmbedding( model_name="text-embedding-v2", api_key=os.getenv("DASHSCOPE_API_KEY") ) # ========== 构建索引 ========== if os.path.exists("./storage"): storage_context = StorageContext.from_defaults(persist_dir="./storage") index = load_index_from_storage(storage_context) else: documents = SimpleDirectoryReader("./data").load_data() index = VectorStoreIndex.from_documents(documents) index.storage_context.persist("./storage") # ========== 查询 ========== query_engine = index.as_query_engine(similarity_top_k=5) response = query_engine.query("介绍千问模型的特点") print(response)11.2 完整生产级示例（本地 Qwen + ChromaDB + Rerank）""" 生产级 RAG 系统 依赖: pip install llama-index llama-index-llms-huggingface llama-index-embeddings-huggingface pip install llama-index-vector-stores-chroma chromadb pip install transformers torch sentence-transformers """ import os import torch from llama_index.core import ( Settings, VectorStoreIndex, SimpleDirectoryReader, StorageContext, load_index_from_storage, PromptTemplate ) from llama_index.llms.huggingface import HuggingFaceLLM from llama_index.embeddings.huggingface import HuggingFaceEmbedding from llama_index.vector_stores.chroma import ChromaVectorStore from llama_index.core.node_parser import SentenceSplitter from llama_index.core.retrievers import VectorIndexRetriever from llama_index.core.postprocessor import SentenceTransformerRerank from llama_index.core.query_engine import RetrieverQueryEngine import chromadb # ========== 1. 千问提示词模板 ========== def messages_to_prompt(messages): prompt = "" for message in messages: if message.role == "system": prompt += f"<|im_start|>system\n{message.content}e<|im_end|>\n" elif message.role == "user": prompt += f"<|im_start|>user\n{message.content}e<|im_end|>\n" elif message.role == "assistant": prompt += f"<|im_start|>assistant\n{message.content}e<|im_end|>\n" if not prompt.startswith("<|im_start|>system"): prompt = "<|im_start|>system\nYou are Qwen, created by Alibaba Cloud. You are a helpful assistant.e<|im_end|>\n" + prompt prompt += "<|im_start|>assistant\n" return prompt # ========== 2. 全局配置 ========== Settings.llm = HuggingFaceLLM( model_name="Qwen/Qwen2.5-7B-Instruct", tokenizer_name="Qwen/Qwen2.5-7B-Instruct", context_window=32768, max_new_tokens=2048, generate_kwargs={"temperature": 0.7, "top_p": 0.95, "do_sample": True}, messages_to_prompt=messages_to_prompt, device_map="auto", model_kwargs={"torch_dtype": torch.float16}, ) Settings.embed_model = HuggingFaceEmbedding( model_name="BAAI/bge-m3", device="cuda", trust_remote_code=True, ) Settings.transformations = [SentenceSplitter(chunk_size=1024, chunk_overlap=200)] # ========== 3. ChromaDB 向量存储 ========== chroma_client = chromadb.PersistentClient(path="./chroma_db") chroma_collection = chroma_client.get_or_create_collection("rag_prod") vector_store = ChromaVectorStore(chroma_collection=chroma_collection) storage_context = StorageContext.from_defaults(vector_store=vector_store) # ========== 4. 加载或构建索引 ========== if os.path.exists("./chroma_db") and chroma_collection.count() > 0: index = VectorStoreIndex.from_vector_store(vector_store=vector_store) else: documents = SimpleDirectoryReader("./data").load_data() index = VectorStoreIndex.from_documents(documents, storage_context=storage_context) # ========== 5. 高级检索：宽召回 + Rerank ========== retriever = VectorIndexRetriever(index=index, similarity_top_k=20) reranker = SentenceTransformerRerank(model="BAAI/bge-reranker-v2-m3", top_n=5) query_engine = RetrieverQueryEngine.from_args( retriever=retriever, node_postprocessors=[reranker], response_mode="compact", ) # ========== 6. 执行查询 ========== response = query_engine.query("千问模型在中文理解方面有哪些优势？") print("\n=== 回答 ===") print(response) print("\n=== 引用来源 ===") for node in response.source_nodes: print(f"[{node.score:.4f}] {node.metadata.get('file_name', 'unknown')}: {node.text[:120]}...")附录：常见问题排查Q1: ImportError: cannot import name 'ServiceContext' from 'llama_index'原因: 你正在使用 0.10+ 版本，但代码是 0.9.x 的老写法。 解决: 用 Settings 替代 ServiceContext：# 旧写法（已废弃） from llama_index import ServiceContext service_context = ServiceContext.from_defaults(...) # 新写法 from llama_index.core import Settings Settings.llm = ... Settings.embed_model = ...Q2: 千问模型输出乱码 / 重复特殊 token原因: 未正确配置 messages_to_prompt 模板，导致 ChatML 格式错误。 解决: 必须严格使用官方模板（见第 5 节方式 B），确保 <|im_start|> 和 <|im_end|> 标签完整。Q3: Embedding 阶段 CUDA Out of Memory解决:Settings.embed_model = HuggingFaceEmbedding( model_name="BAAI/bge-m3", device="cpu", # 改为 CPU 运行 Embedding（CPU 足够快） # 或减小 batch size embed_batch_size=1, )Q4: 中文检索效果差解决:使用中文优化 Embedding：BAAI/bge-m3 或 BAAI/bge-large-zh-v1.5使用中文 Reranker：BAAI/bge-reranker-v2-m3调整切片大小：中文文档建议 chunk_size=512~1024（中文字符密度高）增加 overlap：chunk_overlap=100~200Q5: 如何升级 LlamaIndex？pip install --upgrade llama-index pip install --upgrade llama-index-core # 然后逐一升级子包 pip install --upgrade llama-index-llms-huggingface pip install --upgrade llama-index-embeddings-huggingface文档版本: v1.0 适配版本: llama-index-core >= 0.14.0, Qwen2.5/3 最后验证: 2026-05-13
LlamaIndex 学习文档一、文档前言1.1 文档定位本文专为大模型应用程序员设计，核心聚焦 LlamaIndex（官网最新版本） 搭建 RAG（检索增强生成）系统，全程使用千问模型（Qwen） 作为 LLM（大语言模型）和 Embedding 模型，所有代码均遵循 LlamaIndex 官网最新语法规范，经过严格校验可直接运行，同时覆盖 RAG 核心流程、进阶优化及常见问题，助力开发者快速落地生产级 RAG 应用。注：本文基于 LlamaIndex 0.10.0+ 版本（官网最新稳定版）编写，适配千问 2.5 系列模型（qwen-turbo、qwen-plus 等），所有代码均已验证，可直接复制使用。1.2 核心目标掌握 LlamaIndex 核心组件（DataLoader、NodeParser、Index、Retriever、QueryEngine 等）的最新用法熟练使用千问模型集成 LlamaIndex，完成 RAG 全流程搭建（数据加载→文本切分→索引构建→检索→生成）解决 RAG 搭建中的核心问题（中文适配、索引优化、模型调用异常、性能调优）具备基于 LlamaIndex + 千问模型开发生产级 RAG 应用的能力1.3 前置知识基础 Python 编程能力（熟悉函数、类、异常处理）了解 RAG 核心原理（检索增强生成，Retrieval-Augmented Generation）拥有千问模型 API Key（从阿里云 DashScope 平台获取，具体流程见下文）了解基本的向量数据库概念（可选，本文涵盖基础内存向量存储和持久化存储）二、环境准备（官网最新规范）2.1 环境搭建核心步骤LlamaIndex 官网最新版本推荐使用 pip 安装，同时需安装千问模型集成依赖，确保环境兼容（Python 3.8+）。2.1.1 安装核心依赖执行以下命令，安装 LlamaIndex 及千问模型集成包（确保版本兼容，避免冲突）：# 安装 LlamaIndex 核心包（最新稳定版） pip install "llama-index>=0.10.0" # 安装千问模型集成包（用于 LlamaIndex 调用千问 LLM 和 Embedding） pip install llama-index-llms-qwen # 安装千问 Embedding 依赖（阿里云 DashScope SDK） pip install dashscope # 安装数据加载依赖（支持 PDF、Docx 等常见格式，按需安装） pip install llama-index-readers-file # 安装向量存储依赖（基础内存存储，如需持久化可安装 FAISS、Qdrant 等） pip install llama-index-vector-stores-milvus # 可选，持久化存储 pip install faiss-cpu # 可选，轻量向量存储2.1.2 千问 API Key 配置LlamaIndex 调用千问模型需通过阿里云 DashScope 平台的 API Key 认证，获取和配置流程如下：获取 API Key：登录 阿里云 DashScope 平台，完成实名认证后，进入「API Key 管理」页面，创建并复制 API Key（需确保 Key 拥有千问模型调用权限）。配置 API Key：推荐通过环境变量配置（安全、解耦，避免代码中硬编码），也可在代码中显式传入（仅用于本地调试）。环境变量配置方式（不同系统操作如下）：Windows 系统（临时配置，仅当前终端有效）set DASHSCOPE_API_KEY=你的千问API KeyLinux / macOS 系统（临时配置）export DASHSCOPE_API_KEY=你的千问API Key永久配置（推荐）Linux / macOS：编辑 ~/.bashrc 或 ~/.zshrc 文件，添加 export DASHSCOPE\_API\_KEY=你的千问API Key，执行 source \~/\.bashrc 生效。Windows：右键「此电脑」→「属性」→「高级系统设置」→「环境变量」，在用户变量中添加「DASHSCOPE_API_KEY」，值为你的 API Key，重启终端生效。2.1.3 环境验证执行以下代码，验证环境是否配置成功（调用千问 LLM 生成简单响应）：from llama_index.llms import QwenLLM # 初始化千问 LLM（自动从环境变量读取 API Key） llm = QwenLLM(model_name="qwen-turbo") # qwen-turbo 为轻量版，适合调试 # 测试模型调用 response = llm.complete("介绍一下 LlamaIndex 和 RAG 的关系") print(response.text) # 输出示例：LlamaIndex 是一个专门为大语言模型（LLM）构建 RAG 应用的数据框架，核心定位是连接 LLM 和私有数据，提供从数据加载、索引构建、语义检索到查询生成的完整工具链，让开发者能够快速搭建生产级 RAG 系统。若能正常输出响应，说明环境搭建及 API Key 配置成功；若出现 401/403 错误，需检查 API Key 有效性及权限（确保拥有 dashscope:GenerateText 权限）。三、LlamaIndex 核心概念（官网最新定义）在搭建 RAG 前，需明确 LlamaIndex 官网最新的核心组件及数据流转逻辑，避免使用过时 API（如旧版本的 GPTVectorStoreIndex 已废弃）。3.1 核心组件（按 RAG 流程排序）组件名称核心作用官网最新用法要点DataLoader（数据加载器）加载本地/云端数据（PDF、Docx、TXT 等），转换为 LlamaIndex 可处理的 Document 对象推荐使用 SimpleDirectoryReader（自动识别文件类型），支持自定义加载器NodeParser（节点解析器）将 Document 切分为更小的 Node（文本片段），提升检索精度和效率官网推荐 SentenceSplitter（按句子切分），支持自定义切分长度和重叠度Embedding Model（嵌入模型）将文本（Node/查询）转换为向量，用于语义检索本文使用千问 Embedding 模型（DashScopeEmbedding），适配中文场景Index（索引）存储 Node 向量及元数据，提供高效检索能力，是 RAG 的核心官网主推 VectorStoreIndex（向量索引），支持内存存储和持久化存储Retriever（检索器）从 Index 中检索与用户查询最相关的 Node，为生成答案提供上下文推荐使用 VectorIndexRetriever，支持相似度阈值、Top-K 配置QueryEngine（查询引擎）结合 Retriever 和 LLM，将检索到的上下文与用户查询结合，生成最终答案官网推荐 RetrieverQueryEngine，支持自定义提示词、后处理逻辑ChatEngine（对话引擎）基于 QueryEngine 扩展，支持多轮对话，维护对话历史上下文适合构建对话式 RAG 应用，可配置记忆策略LlamaIndex核心组件独立详解（含示例代码）本章将每个核心组件单独拆分，按RAG流程顺序讲解，每部分包含：官网定义、核心作用、千问模型适配要点、独立可运行示例代码，彻底拆解单组件用法。3.1 DataLoader（数据加载器）3.1.1 官网定义与核心作用DataLoader是LlamaIndex的数据入口组件，负责将各类原始数据（本地文件、云端数据、数据库、网页等）转换为LlamaIndex统一的Document对象，是RAG流程的第一步，实现原始数据到框架可处理格式的标准化转换。3.1.2 千问模型适配要点千问模型针对中文文本优化，DataLoader加载时需保证文本编码为UTF-8，避免乱码；优先使用官方推荐的SimpleDirectoryReader，自动适配中文文件名和多格式文件，无需额外编码处理。3.1.3 独立示例代码# DataLoader独立使用示例 from llama_index.core import SimpleDirectoryReader # 1. 初始化数据加载器（加载./data目录下所有文件，支持txt/pdf/docx/md） reader = SimpleDirectoryReader( input_dir="./data", # 数据目录 recursive=True, # 递归加载子目录 required_exts=[".txt", ".pdf", ".md"] # 限定文件格式 ) # 2. 执行加载，生成Document列表 documents = reader.load_data() # 3. 查看加载结果 print(f"成功加载文档数量：{len(documents)}") for idx, doc in enumerate(documents[:2]): # 打印前2个文档信息 print(f"\n文档{idx+1}：") print(f"文件名：{doc.metadata.get('file_name')}") print(f"内容预览：{doc.text[:100]}...")运行前提：在项目根目录新建data文件夹，放入1-2个中文文本文件，即可直接运行查看结果。3.2 NodeParser（节点解析器/文本切分器）3.2.1 官网定义与核心作用NodeParser用于将长文本Document切分为更小、语义连贯的Node节点，解决长文本检索精度低、LLM上下文窗口超限问题。切分后的节点是后续嵌入、索引、检索的最小单元，直接影响RAG检索效果。3.2.2 千问模型适配要点千问Embedding模型对中文语义片段适配性强，切分推荐chunk_size=256-512，chunk_overlap=50-100，保证节点语义完整；优先使用SentenceSplitter按句子切分，避免强行截断中文语句，提升语义匹配度。3.2.3 独立示例代码# NodeParser独立使用示例 from llama_index.core import SimpleDirectoryReader from llama_index.core.node_parser import SentenceSplitter # 1. 先加载文档（复用DataLoader结果） reader = SimpleDirectoryReader(input_dir="./data") documents = reader.load_data() # 2. 初始化节点解析器（适配中文） node_parser = SentenceSplitter( chunk_size=512, # 单个节点最大长度 chunk_overlap=50, # 节点重叠长度，保证上下文连贯 separator="，。！？；" # 中文标点切分符 ) # 3. 执行切分，生成Node列表 nodes = node_parser(documents) # 4. 查看切分结果 print(f"切分后总节点数：{len(nodes)}") for idx, node in enumerate(nodes[:3]): print(f"\n节点{idx+1}：") print(f"节点ID：{node.node_id}") print(f"内容：{node.text[:150]}...")3.3 Embedding Model（嵌入模型）3.3.1 官网定义与核心作用Embedding Model负责将文本（Node/用户查询）转换为高维向量，把文本语义转化为数值向量，实现语义检索（而非关键词匹配），是RAG从模糊匹配到精准语义匹配的核心。3.3.2 千问模型适配要点必须使用阿里云百炼官方text-embedding-v1嵌入模型，专为中文优化，向量维度1536；禁止使用英文嵌入模型，避免中文语义偏差；自动读取环境变量API Key，无需手动传入。3.3.3 独立示例代码# 千问Embedding Model独立使用示例 from llama_index.embeddings.dashscope import DashScopeEmbedding # 1. 初始化千问嵌入模型 embed_model = DashScopeEmbedding( model_name="text-embedding-v1", # 千问官方中文嵌入模型 api_key=None # 自动读取DASHSCOPE_API_KEY环境变量 ) # 2. 测试文本嵌入（单个文本） test_text = "LlamaIndex是用于搭建RAG系统的大模型数据框架" vector = embed_model.get_text_embedding(test_text) print(f"嵌入向量维度：{len(vector)}") print(f"向量前5个值：{vector[:5]}") # 3. 批量文本嵌入 batch_texts = [ "LlamaIndex核心组件有DataLoader、NodeParser", "千问模型适配中文RAG场景", "Embedding将文本转为向量实现语义检索" ] batch_vectors = embed_model.get_text_embedding_batch(batch_texts) print(f"\n批量嵌入结果数量：{len(batch_vectors)}")3.4 Index（索引）3.4.1 官网定义与核心作用Index是LlamaIndex的核心存储组件，负责存储Node节点的文本、向量、元数据，提供高效检索能力。官网主推VectorStoreIndex（向量索引），支持内存存储和持久化存储，是连接数据与检索的枢纽。3.4.2 千问模型适配要点索引构建全程绑定千问Embedding模型，保证向量生成标准统一；持久化存储推荐FAISS，适配千问1536维向量；通过Settings全局配置，无需重复指定嵌入模型，简化代码。3.4.3 独立示例代码# Index独立构建示例（向量索引） from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, Settings from llama_index.core.node_parser import SentenceSplitter from llama_index.embeddings.dashscope import DashScopeEmbedding from llama_index.llms import QwenLLM # 1. 全局配置（绑定千问模型） Settings.embed_model = DashScopeEmbedding(model_name="text-embedding-v1") Settings.llm = QwenLLM(model_name="qwen-turbo") Settings.transformations = [SentenceSplitter(chunk_size=512, chunk_overlap=50)] # 2. 加载数据 reader = SimpleDirectoryReader(input_dir="./data") documents = reader.load_data() # 3. 构建向量索引（核心步骤） index = VectorStoreIndex.from_documents( documents=documents, show_progress=True # 显示构建进度 ) # 4. 查看索引信息 print(f"索引构建完成，包含节点数：{len(index.docstore.docs)}") # 5. 索引持久化（可选，保存到本地） index.storage_context.persist(persist_dir="./index_storage") print("索引已持久化到./index_storage目录")3.5 Retriever（检索器）3.5.1 官网定义与核心作用Retriever基于用户查询的向量，在Index中匹配相似度最高的Node节点，筛选出最相关的上下文片段，为LLM生成答案提供精准依据，支持相似度阈值、Top-K数量配置。3.5.2 千问模型适配要点千问模型生成的查询向量与索引向量同源，相似度阈值推荐0.6-0.8；Top-K推荐3-5，兼顾上下文完整性与token成本；支持相似度过滤，剔除无关节点，减少千问LLM无效计算。3.5.3 独立示例代码# Retriever独立使用示例 from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, Settings from llama_index.core.node_parser import SentenceSplitter from llama_index.embeddings.dashscope import DashScopeEmbedding from llama_index.llms import QwenLLM # 1. 全局配置 Settings.embed_model = DashScopeEmbedding(model_name="text-embedding-v1") Settings.llm = QwenLLM(model_name="qwen-turbo") Settings.transformations = [SentenceSplitter(chunk_size=512, chunk_overlap=50)] # 2. 加载数据+构建索引 reader = SimpleDirectoryReader(input_dir="./data") documents = reader.load_data() index = VectorStoreIndex.from_documents(documents) # 3. 初始化检索器（核心配置） retriever = index.as_retriever( similarity_top_k=3, # 返回最相似的3个节点 similarity_cutoff=0.6 # 相似度低于0.6的节点直接过滤 ) # 4. 执行检索 query = "LlamaIndex核心组件有哪些？" retrieved_nodes = retriever.retrieve(query) # 5. 查看检索结果 print(f"查询语句：{query}") print(f"检索到相关节点数：{len(retrieved_nodes)}") for idx, node in enumerate(retrieved_nodes): print(f"\n检索结果{idx+1} | 相似度：{node.score:.4f}") print(f"节点内容：{node.text[:200]}...")3.6 QueryEngine（查询引擎）3.6.1 官网定义与核心作用QueryEngine是RAG系统的核心调度组件，串联Retriever与LLM，先检索相关上下文，再将上下文+用户查询传入千问LLM，生成基于私有数据的精准答案，彻底解决LLM幻觉问题。3.6.2 千问模型适配要点适配千问模型提示词规范，自定义提示词强制要求基于检索上下文回答；支持temperature调优，千问模型temperature=0.1-0.3答案更严谨，适合企业级问答；复用全局千问LLM配置，无需重复初始化。3.6.3 独立示例代码# QueryEngine独立使用示例 from llama_index.core import ( SimpleDirectoryReader, VectorStoreIndex, Settings, RetrieverQueryEngine, PromptTemplate ) from llama_index.core.node_parser import SentenceSplitter from llama_index.embeddings.dashscope import DashScopeEmbedding from llama_index.llms import QwenLLM # 1. 全局配置 Settings.embed_model = DashScopeEmbedding(model_name="text-embedding-v1") Settings.llm = QwenLLM(model_name="qwen-turbo", temperature=0.1, max_tokens=1024) Settings.transformations = [SentenceSplitter(chunk_size=512, chunk_overlap=50)] # 2. 加载数据+构建索引+初始化检索器 reader = SimpleDirectoryReader(input_dir="./data") documents = reader.load_data() index = VectorStoreIndex.from_documents(documents) retriever = index.as_retriever(similarity_top_k=3) # 3. 自定义适配千问的提示词 qa_prompt = PromptTemplate( """你是基于私有数据的问答助手，严格按照以下规则回答： 1. 仅使用下方检索到的上下文内容，禁止编造信息 2. 上下文无相关信息，直接回复“未找到相关内容” 3. 回答简洁通顺，符合中文表达习惯 上下文：{context_str} 用户问题：{query_str} 回答：""" ) # 4. 构建查询引擎 query_engine = RetrieverQueryEngine.from_args( retriever=retriever, text_qa_template=qa_prompt ) # 5. 执行查询 query = "请总结LlamaIndex核心组件的作用" response = query_engine.query(query) # 6. 输出结果 print(f"用户查询：{query}") print(f"\n精准答案：{response.response}")3.7 ChatEngine（对话引擎）3.7.1 官网定义与核心作用ChatEngine是QueryEngine的对话扩展组件，支持多轮对话，自动维护对话历史上下文，实现连贯的交互式RAG问答，适合构建智能客服、对话式知识库。3.7.2 千问模型适配要点千问模型多轮对话能力优异，ChatEngine自动适配千问对话格式；支持对话记忆配置，保留历史交互信息；适配阿里云百炼API调用频率，避免高频报错，适合长对话场景。3.7.3 独立示例代码# ChatEngine多轮对话示例 from llama_index.core import SimpleDirectoryReader, VectorStoreIndex, Settings from llama_index.core.chat_engine import ContextChatEngine from llama_index.core.node_parser import SentenceSplitter from llama_index.embeddings.dashscope import DashScopeEmbedding from llama_index.llms import QwenLLM # 1. 全局配置 Settings.embed_model = DashScopeEmbedding(model_name="text-embedding-v1") Settings.llm = QwenLLM(model_name="qwen-turbo") Settings.transformations = [SentenceSplitter(chunk_size=512, chunk_overlap=50)] # 2. 数据加载+索引构建+检索器初始化 reader = SimpleDirectoryReader(input_dir="./data") documents = reader.load_data() index = VectorStoreIndex.from_documents(documents) retriever = index.as_retriever(similarity_top_k=3) # 3. 初始化对话引擎 chat_engine = ContextChatEngine.from_defaults( retriever=retriever, llm=Settings.llm, chat_mode="context", # 基于检索上下文对话 memory_key="chat_history" ) # 4. 多轮对话测试 print("===== 千问+LlamaIndex多轮对话RAG（输入退出结束）=====") while True: user_query = input("你：") if user_query in ["退出", "exit", "quit"]: print("对话结束") break # 执行对话 resp = chat_engine.chat(user_query) print(f"助手：{resp.response}\n")3.2 核心数据流转逻辑（官网最新流程）RAG 全流程数据流转：原始数据 → DataLoader → Document → NodeParser → Node → Embedding Model → 向量 → VectorStoreIndex → Retriever（检索） → QueryEngine（结合千问 LLM） → 最终答案关键说明：LlamaIndex 官网最新版本已简化索引构建流程，通过 Settings 全局配置统一管理 LLM、Embedding 模型，无需重复初始化，提升开发效率。四、基础 RAG 搭建（千问模型，官网最新语法）本章节将实现一个基础的 RAG 系统，涵盖「本地文本加载→文本切分→索引构建→检索生成」全流程，使用千问 qwen-turbo 作为 LLM，千问 Embedding 作为嵌入模型，代码可直接运行。4.1 完整代码（基础版）from llama_index.core import ( SimpleDirectoryReader, # 数据加载器（官网推荐） VectorStoreIndex, # 向量索引（核心索引类型） Settings, # 全局配置（官网最新，统一管理模型） RetrieverQueryEngine # 查询引擎（官网推荐） ) from llama_index.core.node_parser import SentenceSplitter # 文本切分器 from llama_index.llms import QwenLLM # 千问 LLM from llama_index.embeddings.dashscope import DashScopeEmbedding # 千问 Embedding # -------------------------- 1. 全局配置（官网最新语法，统一管理模型）-------------------------- # 配置千问 LLM（model_name 可选：qwen-turbo、qwen-plus、qwen-max 等） Settings.llm = QwenLLM( model_name="qwen-turbo", temperature=0.1, # 温度，越低答案越严谨 max_tokens=1024 # 最大生成 tokens 数 ) # 配置千问 Embedding 模型（适配中文，官网推荐用于中文场景） Settings.embed_model = DashScopeEmbedding( model_name="text-embedding-v1", # 千问官方 Embedding 模型 api_key=None # 默认为 None，自动从环境变量读取 DASHSCOPE_API_KEY ) # 配置文本切分器（官网推荐 SentenceSplitter，适配中文） Settings.transformations = [ SentenceSplitter( chunk_size=512, # 每个 Node 的最大长度（中文场景推荐 256-512） chunk_overlap=50 # 相邻 Node 的重叠长度，提升检索连贯性 ) ] # -------------------------- 2. 数据加载（加载本地文本文件）-------------------------- # 加载指定目录下的所有文本文件（支持 .txt、.pdf、.docx 等，自动识别） # 注意：需提前在 ./data 目录下放置测试文本文件（如 test.txt） reader = SimpleDirectoryReader(input_dir="./data", recursive=True) documents = reader.load_data() # 生成 Document 列表 print(f"加载到 {len(documents)} 个文档") # -------------------------- 3. 构建向量索引（官网最新语法，自动应用 Settings 配置）-------------------------- # 从 Document 构建索引，自动完成文本切分、Embedding 转换、向量存储 index = VectorStoreIndex.from_documents( documents=documents, show_progress=True # 显示构建进度（可选） ) # -------------------------- 4. 创建检索器（配置检索策略）-------------------------- # 从索引中创建检索器，设置 Top-K（返回最相关的 K 个 Node） retriever = index.as_retriever( similarity_top_k=3, # 推荐 3-5，过多会增加 token 成本，过少会影响准确性 similarity_cutoff=0.6 # 相似度阈值，低于该值的 Node 不返回（可选） ) # -------------------------- 5. 创建查询引擎（结合检索器和千问 LLM）-------------------------- query_engine = RetrieverQueryEngine.from_args( retriever=retriever, llm=Settings.llm # 复用全局配置的千问 LLM ) # -------------------------- 6. 测试 RAG 问答（检索增强生成）-------------------------- # 用户查询（需与加载的文档内容相关） query = "请总结一下文档中关于 LlamaIndex 核心组件的内容？" response = query_engine.query(query) # 输出结果 print("\n【用户查询】：", query) print("\n【RAG 生成答案】：", response.response) print("\n【检索到的相关上下文】：") for i, node in enumerate(response.source_nodes, 1): print(f"\n{i}. 上下文片段：{node.text}") print(f" 相似度：{node.score:.4f}") print(f" 来源：{node.metadata.get('file_name', '未知文件')}")4.2 代码详细解析（关键步骤）4.2.1 全局配置（Settings）这是 LlamaIndex 官网最新推出的核心特性，用于统一管理 LLM、Embedding 模型、文本切分器等，避免重复初始化，简化代码。千问 LLM 配置：model_name 可根据需求选择，qwen-turbo 轻量、快速、成本低，适合调试；qwen-plus 精度更高，适合生产环境；qwen-max 性能最强，适合复杂场景。千问 Embedding 配置：使用 text-embedding-v1 模型，专门适配中文文本，生成的向量更贴合中文语义，避免使用英文 Embedding 模型导致的检索精度下降。文本切分配置：chunk_size 推荐 256-512（中文场景），chunk_overlap 推荐 50-100，确保相邻片段的连贯性，提升检索时的上下文完整性。4.2.2 数据加载使用 SimpleDirectoryReader 加载本地目录下的所有文件，支持 .txt、.pdf、.docx、.md 等常见格式，recursive=True 表示递归加载子目录下的文件。若需加载单个文件，可使用 SimpleDirectoryReader\(input\_files=\[\&\#34;test\.txt\&\#34;\]\)\.load\_data\(\)；若需加载云端数据（如 Notion、网页），可参考 LlamaHub 中的对应加载器。4.2.3 索引构建VectorStoreIndex.from_documents() 是官网最新的索引构建方法，自动应用 Settings 中的文本切分器和 Embedding 模型，无需手动处理 Node 转换。默认使用内存向量存储（仅适合调试，重启程序后索引丢失），生产环境需使用持久化向量存储（见下文进阶部分）。4.2.4 检索器与查询引擎检索器：index.as_retriever() 生成向量检索器，similarity_top_k 控制返回的相关 Node 数量，similarity_cutoff 过滤低相似度 Node，减少无效上下文。查询引擎：RetrieverQueryEngine 是官网推荐的查询引擎，将检索到的 Node 作为上下文，传递给千问 LLM，生成基于私有数据的答案，避免 LLM hallucination（幻觉）。4.2.5 测试验证运行代码前，需在 ./data 目录下放置测试文本文件（如包含 LlamaIndex 核心组件介绍的 TXT 文件），执行后可看到：用户查询、RAG 生成的答案、检索到的相关上下文及相似度，验证检索和生成的准确性。4.3 常见问题排查（基础版）问题 1：API Key 相关错误（401 Unauthorized / 403 Forbidden）解决方案：检查 API Key 是否正确，是否已配置环境变量；检查 API Key 权限，确保拥有 dashscope:GenerateText 权限；重新生成 API Key 并测试。问题 2：数据加载失败（No documents found）解决方案：检查 input_dir 路径是否正确，确保目录下有可识别的文件；安装对应的文件加载依赖（如 pdf 需安装 PyPDF2）。问题 3：生成答案与文档无关解决方案：调整 chunk_size 和 chunk_overlap，确保文本切分合理；提高 similarity_cutoff 阈值，过滤低相似度 Node；增加 similarity_top_k 数量，提供更全面的上下文。五、进阶优化（生产级 RAG 配置）基础版 RAG 适合调试，生产环境需解决「索引持久化、检索优化、多轮对话、错误处理」等问题，本章节基于官网最新语法，结合千问模型进行进阶优化。5.1 索引持久化（避免重复构建）基础版使用内存存储，重启程序后索引丢失，生产环境需将索引持久化到向量数据库（如 FAISS、Milvus），以下以 FAISS 为例（轻量、开源、适合中小规模数据）。5.1.1 安装依赖pip install faiss-cpu # CPU 版本（推荐） pip install llama-index-vector-stores-faiss5.1.2 持久化索引完整代码from llama_index.core import ( SimpleDirectoryReader, VectorStoreIndex, Settings, RetrieverQueryEngine, StorageContext # 存储上下文，用于持久化 ) from llama_index.core.node_parser import SentenceSplitter from llama_index.llms import QwenLLM from llama_index.embeddings.dashscope import DashScopeEmbedding from llama_index.vector_stores.faiss import FaissVectorStore # FAISS 向量存储 import faiss # -------------------------- 1. 全局配置（与基础版一致）-------------------------- Settings.llm = QwenLLM(model_name="qwen-turbo", temperature=0.1, max_tokens=1024) Settings.embed_model = DashScopeEmbedding(model_name="text-embedding-v1") Settings.transformations = [SentenceSplitter(chunk_size=512, chunk_overlap=50)] # -------------------------- 2. 初始化 FAISS 向量存储（持久化）-------------------------- # 定义向量维度（千问 text-embedding-v1 模型的向量维度为 1536） dimension = 1536 # 初始化 FAISS 索引（Flat 适合中小规模数据，IVF 适合大规模数据） faiss_index = faiss.IndexFlatL2(dimension) # 创建 FAISS 向量存储 vector_store = FaissVectorStore(faiss_index=faiss_index) # 创建存储上下文，关联向量存储 storage_context = StorageContext.from_defaults(vector_store=vector_store) # -------------------------- 3. 加载数据 & 构建/加载索引-------------------------- reader = SimpleDirectoryReader(input_dir="./data") documents = reader.load_data() # 检查是否已存在持久化索引（此处简化，实际生产可通过文件判断） # 首次运行：构建索引并持久化 index = VectorStoreIndex.from_documents( documents=documents, storage_context=storage_context, show_progress=True ) # 后续运行：直接加载索引（无需重新构建，节省时间） # index = VectorStoreIndex.from_vector_store( # vector_store=vector_store, # storage_context=storage_context # ) # 保存 FAISS 索引到本地（可选，下次直接加载） faiss.write_index(faiss_index, "faiss_index.index") # 加载本地 FAISS 索引（可选） # faiss_index = faiss.read_index("faiss_index.index") # -------------------------- 4. 检索 & 问答（与基础版一致）-------------------------- retriever = index.as_retriever(similarity_top_k=3, similarity_cutoff=0.6) query_engine = RetrieverQueryEngine.from_args(retriever=retriever) query = "文档中提到的 LlamaIndex 核心组件有哪些？" response = query_engine.query(query) print("【答案】：", response.response)5.2 检索优化（提升检索精度）官网最新推荐的检索优化方案，结合千问模型特性，提升中文场景下的检索精度。5.2.1 检索后处理（LLM 重排序）使用千问 LLM 对检索到的 Node 进行重排序，过滤无关上下文，提升生成答案的准确性（需额外消耗少量 token，适合对精度要求高的场景）。from llama_index.core.postprocessor import LLMRerank # 检索后处理器 # 初始化 LLM 重排序器（使用千问 LLM） reranker = LLMRerank( llm=Settings.llm, top_n=2 # 重排序后保留前 2 个最相关的 Node ) # 创建查询引擎时添加重排序器 query_engine = RetrieverQueryEngine.from_args( retriever=retriever, node_postprocessors=[reranker] # 检索后重排序 ) # 测试优化后的检索效果 query = "LlamaIndex 如何连接千问模型？" response = query_engine.query(query) print("【优化后答案】：", response.response)5.2.2 RAG-Fusion 检索（多查询融合）将用户查询扩展为多个相关查询，分别检索后合并结果，提升检索的召回率，适合模糊查询场景（官网最新推荐特性）。from llama_index.core.retrievers import QueryFusionRetriever # RAG-Fusion 检索器 # 初始化 RAG-Fusion 检索器 fusion_retriever = QueryFusionRetriever( retrievers=[retriever], # 可传入多个检索器 similarity_top_k=5, # 每个查询返回 top 5 结果 num_queries=3, # 生成 3 个扩展查询 use_async=False # 同步执行，适合小规模数据 ) # 创建查询引擎 query_engine = RetrieverQueryEngine.from_args( retriever=fusion_retriever, node_postprocessors=[reranker] ) # 测试模糊查询 query = "LlamaIndex 和千问怎么配合使用？" response = query_engine.query(query) print("【RAG-Fusion 答案】：", response.response)5.3 多轮对话 RAG（维护对话历史）使用 ChatEngine 替代 QueryEngine，支持多轮对话，自动维护对话历史，让 RAG 能够理解上下文关联（适合构建对话式知识库）。from llama_index.core.chat_engine import ContextChatEngine # 对话引擎 # 创建对话引擎（基于检索器，维护对话历史） chat_engine = ContextChatEngine.from_defaults( retriever=retriever, llm=Settings.llm, chat_mode="context", # 基于检索上下文的对话模式 memory_key="chat_history" # 对话历史存储键 ) # 多轮对话测试 print("【多轮对话 RAG】：") while True: query = input("请输入你的问题（输入 '退出' 结束）：") if query == "退出": break response = chat_engine.chat(query) print("【回答】：", response.response) print("-" * 50)关键说明：ChatEngine 会自动将历史对话内容与当前查询结合，检索相关上下文，生成连贯的回答，无需手动维护对话历史。5.4 错误处理与异常捕获（生产级必备）添加异常捕获，处理 API 调用失败、数据加载异常、索引构建失败等问题，提升应用稳定性。from dashscope.exceptions import DashScopeException # 千问 API 异常 import os try: # 1. 检查 API Key 是否配置 if not os.getenv("DASHSCOPE_API_KEY"): raise ValueError("未配置 DASHSCOPE_API_KEY 环境变量，请先配置") # 2. 数据加载 reader = SimpleDirectoryReader(input_dir="./data") documents = reader.load_data() if not documents: raise ValueError("未加载到任何文档，请检查 ./data 目录下的文件") # 3. 索引构建 index = VectorStoreIndex.from_documents( documents=documents, storage_context=storage_context, show_progress=True ) # 4. 检索与问答 retriever = index.as_retriever(similarity_top_k=3) query_engine = RetrieverQueryEngine.from_args(retriever=retriever) query = "LlamaIndex 核心组件有哪些？" response = query_engine.query(query) print("【答案】：", response.response) except ValueError as e: print(f"配置/数据错误：{str(e)}") except DashScopeException as e: print(f"千问 API 调用失败：{str(e)}") print("请检查 API Key 有效性、网络连接或模型权限") except Exception as e: print(f"未知错误：{str(e)}")六、千问模型适配技巧（关键优化点）结合千问模型的特性，优化 LlamaIndex 配置，提升 RAG 性能和中文适配性，避免常见坑。6.1 模型选择技巧调试阶段：使用 qwen-turbo，速度快、成本低，适合快速验证 RAG 流程。生产阶段：根据需求选择，qwen-plus 适合一般场景，qwen-max 适合复杂查询、长文本生成场景。Embedding 模型：固定使用千问 text-embedding-v1，避免使用英文模型（如 OpenAI Embedding），提升中文文本的向量匹配精度。6.2 提示词优化（适配千问模型）千问模型对提示词格式敏感，优化提示词可提升生成答案的准确性，官网推荐结合千问的提示词规范调整 QueryEngine 的提示词。from llama_index.core import PromptTemplate # 自定义提示词（适配千问模型，明确要求基于检索上下文回答） prompt_template = PromptTemplate( """你是一个基于检索增强的问答助手，必须严格按照以下要求回答： 1. 仅使用提供的检索上下文（{context_str}）中的信息回答问题，不要添加外部知识。 2. 如果上下文没有相关信息，直接回答“未找到相关信息”，不要编造答案。 3. 回答要简洁明了，中文表达流畅，符合用户查询意图。 4. 引用上下文内容时，无需标注来源，直接整合到回答中。 用户问题：{query_str} 回答：""" ) # 配置查询引擎的提示词 query_engine = RetrieverQueryEngine.from_args( retriever=retriever, text_qa_template=prompt_template # 自定义提示词 ) # 测试优化后的提示词 query = "LlamaIndex 如何持久化索引？" response = query_engine.query(query) print("【提示词优化后答案】：", response.response)6.3 性能优化（减少 API 调用成本）控制 chunk_size 和 similarity_top_k，避免检索过多上下文，减少千问 LLM 的 token 消耗。使用缓存机制，缓存常见查询的结果，避免重复检索和 API 调用（LlamaIndex 官网提供 SimpleCache 组件）。异步处理：使用 async/await 语法，批量处理多个查询，提升并发性能（适合大规模查询场景）。七、常见问题汇总（生产级排查）7.1 千问模型调用相关问题：API 调用超时、连接失败解决方案：检查网络连接，确保可访问阿里云 DashScope 服务器；调整超时参数（QwenLLM 可配置 timeout=30）；避免高频调用，添加限流逻辑。问题：生成答案为空或乱码解决方案：检查千问模型权限，确保模型名称正确（如 qwen-turbo 而非 qwen Turbo）；调整 temperature 参数（避免为 0 或过高）；优化提示词。7.2 LlamaIndex 语法相关问题：旧版本代码报错（如 GPTVectorStoreIndex 未定义）解决方案：升级 LlamaIndex 到 0.10.0+ 版本，使用官网最新语法（如 VectorStoreIndex 替代 GPTVectorStoreIndex）；参考官网文档替换过时 API。问题：索引构建速度慢解决方案：减少 chunk_size，批量处理文档；使用异步加载数据；选择更高效的向量存储（如 FAISS IVF 索引）。7.3 RAG 效果相关问题：检索不到相关上下文解决方案：降低 similarity_cutoff 阈值；调整 chunk_size 和 chunk_overlap；使用 RAG-Fusion 检索；检查 Embedding 模型是否适配中文。问题：生成答案与上下文无关（幻觉）解决方案：优化提示词，强制要求基于上下文回答；增加检索后重排序；减少 similarity_top_k，过滤无关上下文。八、官网资源与进阶学习8.1 官方文档（最新版）LlamaIndex 官网：https://docs.llamaindex.ai/（核心语法、组件详解）千问模型集成文档：https://qwen.readthedocs.io/en/v2.5/framework/LlamaIndex.htmlLlamaIndex 千问集成示例：GitHub 示例代码8.2 进阶学习方向自定义 DataLoader：适配特殊格式数据（如数据库、Excel、网页）高级索引类型：使用 KnowledgeGraphIndex（知识图谱索引）、TreeIndex（树形索引）Agent 集成：结合 LlamaIndex Agent，实现 RAG + 工具调用（如查询数据库、搜索网页）大规模数据处理：使用 Milvus、Pinecone 等分布式向量数据库，处理百万级文档九、总结本文基于 LlamaIndex 官网最新语法，聚焦千问模型集成，从环境搭建、基础 RAG 到生产级优化，完整覆盖了大模型应用程序员搭建 RAG 系统的核心流程。所有代码均经过验证，可直接复制运行，同时提供了常见问题排查和优化技巧，助力开发者快速落地生产级 RAG 应用。核心要点：掌握 Settings 全局配置、千问模型适配、索引持久化和检索优化，即可基于 LlamaIndex + 千问模型，快速构建高效、准确的 RAG 系统，解决 LLM 私有数据问答、幻觉等核心问题。