LlamaIndex 介绍
LlamaIndex 是一个为开发「知识增强」的大语言模型应用的框架(也就是 SDK)。知识增强,泛指任何在私有或特定领域数据基础上应用大语言模型的情况。例如:
- Question-Answering Chatbots (也就是 RAG)
- Document Understanding and Extraction (文档理解与信息抽取)
- Autonomous Agents that can perform research and take actions (智能体应用)
- Workflow orchestrating single and multi-agent (编排单个或多个智能体形成工作流)
LlamaIndex 有 Python 和 Typescript 两个版本,Python 版的文档相对更完善。
-Python文档地址:https://docs.llamaindex.ai/en/stable/-PythonAPI文档:https://docs.llamaindex.ai/en/stable/api_reference/-TS文档地址:https://ts.llamaindex.ai/LlamaIndex是一个开源框架Github链接:https://github.com/run-llama
LlamaIndex 的核心模块
安装 LlamaIndex
pipinstallllama-index
数据加载(Loading)
加载本地数据
`SimpleDirectoryReader` 是一个简单的本地文件加载器。它会遍历指定目录,并根据文件扩展名自动加载文件(文本内容)。
支持的文件类型:-`.csv`-comma-separatedvalues-`.docx`-MicrosoftWord-`.epub`-EPUBebookformat-`.hwp`-HangulWordProcessor-`.ipynb`-JupyterNotebook-`.jpeg`,`.jpg`-JPEGimage-`.mbox`-MBOXemailarchive-`.md`-Markdown-`.mp3`,`.mp4`-audioandvideo-`.pdf`-PortableDocumentFormat-`.png`-PortableNetworkGraphics-`.ppt`,`.pptm`,`.pptx`-MicrosoftPowerPoint
importjsonfrompydantic.v1importBaseModeldefshow_json(data):"""用于展示json数据"""ifisinstance(data,str)bj=json.loads(data)print(json.dumps(obj,indent=4,ensure_ascii=False))elifisinstance(data,dict)orisinstance(data,list):print(json.dumps(data,indent=4,ensure_ascii=False))elifissubclass(type(data),BaseModel):print(json.dumps(data.dict(),indent=4,ensure_ascii=False))defshow_list_obj(data):"""用于展示一组对象"""ifisinstance(data,list):foritemindata:show_json(item)else:raiseValueError("Inputisnotalist")
fromllama_index.coreimportSimpleDirectoryReaderreader=SimpleDirectoryReader(input_dir="./data",#目标目录recursive=False,#是否递归遍历子目录required_exts=[".pdf"]#(可选)只读取指定后缀的文件)documents=reader.load_data()
print(documents[0].text)show_json(documents[0].json())
默认的 `PDFReader` 效果并不理想,我们可以更换文件加载器
LlamaParse(LlamaIndex自带的加载器)
首先,登录并从 https://cloud.llamaindex.ai ↗ 注册并获取 api-key 。
然后,安装该包:
pipinstallllama-cloud-services
#在系统环境变量里配置LLAMA_CLOUD_API_KEY=XXXfromllama_cloud_servicesimportLlamaParsefromllama_index.coreimportSimpleDirectoryReaderimportnest_asyncionest_asyncio.apply()#只在Jupyter笔记环境中需要此操作,否则会报错#setupparserparser=LlamaParse(result_type="markdown"#"markdown"and"text"areavailable)file_extractor={".pdf":parser}documents=SimpleDirectoryReader(input_dir="./data",required_exts=[".pdf"],file_extractor=file_extractor).load_data()print(documents[0].text)Data Connectors
用于处理更丰富的数据类型,并将其读取为 `Document` 的形式。
例如:直接读取网页
pip install llama-index-readers-webfromllama_index.readers.webimportSimpleWebPageReaderdocuments = SimpleWebPageReader(html_to_text=True).load_data(["https://www.baidu.com/"])print(documents[0].text)
更多DataConnectors内置的文件加载器:https://llamahub.ai/l/readers/llama-index-readers-file连接三方服务的数据加载器:https://docs.llamaindex.ai/en/stable/module_guides/loading/connector/modules/更多加载器可以在LlamaHub:https://llamahub.ai/上找到
文本切分与解析(Chunking)
为方便检索,我们通常把`Document`切分为`Node`。
在 LlamaIndex 中,`Node`被定义为一个文本的「chunk」。
使用 TextSplitters 对文本做切分
例如:`TokenTextSplitter`按指定token数切分文本fromllama_index.coreimportDocumentfromllama_index.core.node_parserimportTokenTextSplitternode_parser=TokenTextSplitter(chunk_size=512,#每个chunk的最大长度chunk_overlap=200#chunk之间重叠长度)nodes=node_parser.get_nodes_from_documents(documents,show_progress=False)show_json(nodes[1].json())show_json(nodes[2].json())
LlamaIndex 提供了丰富的 `TextSplitter`:
-[`SentenceSplitter`](https://docs.llamaindex.ai/en/stable/api_reference/node_parsers/sentence_splitter/):在切分指定长度的 chunk 同时尽量保证句子边界不被切断;
-[`CodeSplitter`](https://docs.llamaindex.ai/en/stable/api_reference/node_parsers/code/):根据 AST(编译器的抽象句法树)切分代码,保证代码功能片段完整;
-[`SemanticSplitterNodeParser`](https://docs.llamaindex.ai/en/stable/api_reference/node_parsers/semantic_splitter/):根据语义相关性对将文本切分为片段。
更多的`NodeParser`:
[`MarkdownNodeParser`]:https://docs.llamaindex.ai/en/stable/api_reference/node_parsers/markdown/
[`JSONNodeParser`]:https://docs.llamaindex.ai/en/stable/api_reference/node_parsers/json/等等。
索引(Indexing)与检索(Retrieval)
**基础概念**:在「检索」相关的上下文中,「索引」即`index`, 通常是指为了实现快速检索而设计的特定「数据结构」。
索引的具体原理与实现可以参考:
传统索引:https://en.wikipedia.org/wiki/Search_engine_indexing
向量索引:https://medium.com/kx-systems/vector-indexing-a-roadmap-for-vector-databases-65866f07daf5
向量检索
1. `VectorStoreIndex` 直接在内存中构建一个 Vector Store 并建索引
from llama_index.core import VectorStoreIndex, SimpleDirectoryReaderfrom llama_index.core.node_parser import TokenTextSplitter, SentenceSplitter# 加载 pdf 文档documents = SimpleDirectoryReader("./data",required_exts=[".pdf"],).load_data()# 定义 Node Parsernode_parser = TokenTextSplitter(chunk_size=512, chunk_overlap=200)# 切分文档nodes = node_parser.get_nodes_from_documents(documents)# 构建 index,默认是在内存中index = VectorStoreIndex(nodes)# 另外一种实现方式# index = VectorStoreIndex.from_documents(documents=documents, transformations=[SentenceSplitter(chunk_size=512)])# 写入本地文件# index.storage_context.persist(persist_dir="./doc_emb")# 获取 retrievervector_retriever = index.as_retriever(similarity_top_k=2# 返回2个结果)# 检索results = vector_retriever.retrieve("DeepSeek v3数学能力怎么样?")print(results[0].text)
2. 使用自定义的 Vector Store,以 `Qdrant` 为例
pipinstallllama-index-vector-stores-qdrant
fromllama_index.core.indices.vector_store.baseimportVectorStoreIndexfromllama_index.vector_stores.qdrantimportQdrantVectorStorefromllama_index.coreimportStorageContextfromqdrant_clientimportQdrantClientfromqdrant_client.modelsimportVectorParams,Distanceclient=QdrantClient(location=":memory:")collection_name="demo"collection=client.create_collection(collection_name=collection_name,vectors_config=VectorParams(size=1536,distance=Distance.COSINE))vector_store=QdrantVectorStore(client=client,collection_name=collection_name)#storage:指定存储空间storage_context=StorageContext.from_defaults(vector_store=vector_store)#创建index:通过StorageContext关联到自定义的VectorStoreindex=VectorStoreIndex(nodes,storage_context=storage_context)#获取retrievervector_retriever=index.as_retriever(similarity_top_k=1)#检索results=vector_retriever.retrieve("deepseekv3数学能力怎么样")print(results[0])###5.2、更多索引与检索方式LlamaIndex内置了丰富的检索机制,例如:-关键字检索-[`BM25Retriever`](https://docs.llamaindex.ai/en/stable/api_reference/retrievers/bm25/):基于tokenizer实现的BM25经典检索算法-[`KeywordTableGPTRetriever`](https://docs.llamaindex.ai/en/stable/api_reference/retrievers/keyword/#llama_index.core.indices.keyword_table.retrievers.KeywordTableGPTRetriever):使用GPT提取检索关键字-[`KeywordTableSimpleRetriever`](https://docs.llamaindex.ai/en/stable/api_reference/retrievers/keyword/#llama_index.core.indices.keyword_table.retrievers.KeywordTableSimpleRetriever):使用正则表达式提取检索关键字-[`KeywordTableRAKERetriever`](https://docs.llamaindex.ai/en/stable/api_reference/retrievers/keyword/#llama_index.core.indices.keyword_table.retrievers.KeywordTableRAKERetriever):使用[`RAKE`](https://pypi.org/project/rake-nltk/)算法提取检索关键字(有语言限制)-RAG-Fusion[`QueryFusionRetriever`](https://docs.llamaindex.ai/en/stable/api_reference/retrievers/query_fusion/)-还支持[KnowledgeGraph](https://docs.llamaindex.ai/en/stable/api_reference/retrievers/knowledge_graph/)[SQL](https://docs.llamaindex.ai/en/stable/api_reference/retrievers/sql/#llama_index.core.retrievers.SQLRetriever)[Text-to-SQL](https://docs.llamaindex.ai/en/stable/api_reference/retrievers/sql/#llama_index.core.retrievers.NLSQLRetriever)等等
检索后处理
LlamaIndex 的 `Node Postprocessors` 提供了一系列检索后处理模块。
例如:我们可以用不同模型对检索后的 `Nodes` 做重排序
#获取retrievervector_retriever=index.as_retriever(similarity_top_k=5)#检索nodes=vector_retriever.retrieve("deepseekv3有多少参数?")fori,nodeinenumerate(nodes):print(f"[{i}]{node.text}\n")fromllama_index.core.postprocessorimportLLMRerankpostprocessor=LLMRerank(top_n=2)nodes=postprocessor.postprocess_nodes(nodes,query_str="deepseekv3有多少参数?")fori,nodeinenumerate(nodes):print(f"[{i}]{node.text}")更多的 Rerank 及其它后处理方法,参考官方文档:
Node Postprocessor Modules:https://docs.llamaindex.ai/en/stable/module_guides/querying/node_postprocessors/node_postprocessors/
生成回复(QA & Chat)
单轮问答(Query Engine)
qa_engine=index.as_query_engine()response=qa_engine.query("deepseekv3数学能力怎么样?")print(response)流式输出
qa_engine=index.as_query_engine(streaming=True)response=qa_engine.query("deepseekv3数学能力怎么样?")response.print_response_stream()多轮对话(Chat Engine)
chat_engine=index.as_chat_engine()response=chat_engine.chat("deepseekv3数学能力怎么样?")print(response)response=chat_engine.chat("代码能力呢?")print(response)流式输出
chat_engine=index.as_chat_engine()streaming_response=chat_engine.stream_chat("deepseekv3数学能力怎么样?")#streaming_response.print_response_stream()fortokeninstreaming_response.response_gen:print(token,end="",flush=True)语言模型
fromllama_index.llms.openaiimportOpenAIllm=OpenAI(temperature=0,model="gpt-4o")
response=llm.complete(prompt.format(topic="小明"))print(response.text)
response=llm.complete(text_qa_template.format(name="小明",context="这是一个测试",question="你是谁,我们在干嘛"))print(response.text)
使用DeepSeek
pipinstallllama-index-llms-deepseek
importosfromllama_index.llms.deepseekimportDeepSeekllm=DeepSeek(model="deepseek-chat",api_key=os.getenv("DEEPSEEK_API_KEY"),temperature=1.5)response=llm.complete("作首唐诗")print(response)设置全局使用的语言模型
fromllama_index.coreimportSettingsSettings.llm=DeepSeek(model="deepseek-chat",api_key=os.getenv("DEEPSEEK_API_KEY"),temperature=1.5)除 OpenAI 外,LlamaIndex 已集成多个大语言模型,包括云服务 API 和本地部署 API,详见官方文档:https://docs.llamaindex.ai/en/stable/module_guides/models/llms/modules/
Embedding 模型
fromllama_index.embeddings.openaiimportOpenAIEmbeddingfromllama_index.coreimportSettings#全局设定Settings.embed_model=OpenAIEmbedding(model="text-embedding-3-small",dimensions=512)
LlamaIndex 同样集成了多种 Embedding 模型,包括云服务 API 和开源模型(HuggingFace)等,详见官方文档:https://docs.llamaindex.ai/en/stable/module_guides/models/embeddings/。
基于 LlamaIndex 实现一个功能较完整的 RAG 系统
功能要求:- 加载指定目录的文件- 支持 RAG-Fusion- 使用 Qdrant 向量数据库,并持久化到本地- 支持检索后排序- 支持多轮对话
fromqdrant_clientimportQdrantClientfromqdrant_client.modelsimportVectorParams,DistanceEMBEDDING_DIM=1536COLLECTION_NAME="full_demo"ATH="./qdrant_db"client=QdrantClient(path=PATH)
fromllama_index.coreimportVectorStoreIndex,SimpleDirectoryReader,get_response_synthesizerfromllama_index.vector_stores.qdrantimportQdrantVectorStorefromllama_index.core.node_parserimportSentenceSplitterfromllama_index.core.response_synthesizersimportResponseModefromllama_index.core.ingestionimportIngestionPipelinefromllama_index.coreimportSettingsfromllama_index.coreimportStorageContextfromllama_index.core.postprocessorimportLLMRerank,SimilarityPostprocessorfromllama_index.core.retrieversimportQueryFusionRetrieverfromllama_index.core.query_engineimportRetrieverQueryEnginefromllama_index.core.chat_engineimportCondenseQuestionChatEnginefromllama_index.llms.dashscopeimportDashScope,DashScopeGenerationModelsfromllama_index.embeddings.dashscopeimportDashScopeEmbedding,DashScopeTextEmbeddingModels#1.指定全局llm与embedding模型Settings.llm=DashScope(model_name=DashScopeGenerationModels.QWEN_MAX,api_key=os.getenv("DASHSCOPE_API_KEY"))Settings.embed_model=DashScopeEmbedding(model_name=DashScopeTextEmbeddingModels.TEXT_EMBEDDING_V1)#2.指定全局文档处理的IngestionPipelineSettings.transformations=[SentenceSplitter(chunk_size=512,chunk_overlap=200)]#3.加载本地文档documents=SimpleDirectoryReader("./data").load_data()ifclient.collection_exists(collection_name=COLLECTION_NAME):client.delete_collection(collection_name=COLLECTION_NAME)#4.创建collectionclient.create_collection(collection_name=COLLECTION_NAME,vectors_config=VectorParams(size=EMBEDDING_DIM,distance=Distance.COSINE))#5.创建VectorStorevector_store=QdrantVectorStore(client=client,collection_name=COLLECTION_NAME)#6.指定VectorStore的Storage用于indexstorage_context=StorageContext.from_defaults(vector_store=vector_store)index=VectorStoreIndex.from_documents(documents,storage_context=storage_context)#7.定义检索后排序模型reranker=LLMRerank(top_n=2)#最终打分低于0.6的文档被过滤掉sp=SimilarityPostprocessor(similarity_cutoff=0.6)#8.定义RAGFusion检索器fusion_retriever=QueryFusionRetriever([index.as_retriever()],similarity_top_k=5,#检索召回topk结果num_queries=3,#生成query数use_async=False,#query_gen_prompt="",#可以自定义query生成的prompt模板)#9.构建单轮queryenginequery_engine=RetrieverQueryEngine.from_args(fusion_retriever,node_postprocessors=[reranker],response_synthesizer=get_response_synthesizer(response_mode=ResponseMode.REFINE))#10.对话引擎chat_engine=CondenseQuestionChatEngine.from_defaults(query_engine=query_engine,#condense_question_prompt=""#可以自定义chatmessageprompt模板)#测试多轮对话#User:deepseekv3有多少参数#User:每次激活多少whileTrue:question=input("User:")ifquestion.strip()=="":breakresponse=chat_engine.chat(question)print(f"AI:{response}")| 欢迎光临 链载Ai (https://www.lianzai.com/) | Powered by Discuz! X3.5 |