? ? ? ?盡管LlamaIndex的目標市場比LangChain要小得多(使用Github stars表示社區的活躍度),但其資金數額接近LangChain。LangChain還提供了更多企業級的產品(比如LangServe、LangSmith等等)。本文將使用兩個框架并行完成一些基本任務,通過并排展示代碼片段,希望能幫助您在自己的RAG聊天機器人中做出更明智的決定。

任務一:使用本地LLM創建聊天機器人

? ? ? ?為避免每次運行腳本時,框架都加載千兆模型到內存中,我們使用一個與OpenAI兼容的LLM推理 API

??? ???a)以下是使用LlamaIndex的實現方式:

from llama_index.llms import ChatMessage, OpenAILike llm = OpenAILike( api_base="http://localhost:1234/v1", timeout=600, # secs api_key="loremIpsum", is_chat_model=True, context_window=32768, ) chat_history = [ ChatMessage(role="system", content="You are a bartender."), ChatMessage(role="user", content="What do I enjoy drinking?"), ] output = llm.chat(chat_history) print(output)

        b)以下是使用LangChain的實現方式:

from langchain.schema import HumanMessage, SystemMessage from langchain_openai import ChatOpenAI llm = ChatOpenAI( openai_api_base="http://localhost:1234/v1", request_timeout=600, # secs, I guess. openai_api_key="loremIpsum", max_tokens=32768, ) chat_history = [ SystemMessage(content="You are a bartender."), HumanMessage(content="What do I enjoy drinking?"), ] print(llm(chat_history))

? ? ? ?對于這兩者,OpenAIAPI Key是必須的。

? ? LangChain區分了可聊天LLM(ChatOpenAI)和僅完成LLM(OpenAI),而LlamaIndex在構造函數中使用is_chat_model參數對其進行控制。

? ? LlamaIndex區分了官方的OpenAI端點和OpenAILike端點,而LangChain則通過openai_api_base參數確定將請求發送到哪里。

       雖然LlamaIndex使用role參數標記聊天消息,但LangChain使用單獨的類。

       到目前為止,這兩個框架的情況看起來并沒有太大的不同。

任務二:為本地文件構建RAG系統

? ? ? ?一旦有了LLM,我們就可以讀取本地文件夾中的文件來構建一個簡單的RAG系統。

? ? ? ? ??以下是使用LlamaIndex的實現方法:

from llama_index import ServiceContext, SimpleDirectoryReader, VectorStoreIndex
service_context = ServiceContext.from_defaults( embed_model="local", llm=llm, # This should be the LLM initialized in the task above.) documents = SimpleDirectoryReader( input_dir="mock_notebook/",).load_data() index = VectorStoreIndex.from_documents( documents=documents, service_context=service_context,)engine = index.as_query_engine( service_context=service_context, )output = engine.query("What do I like to drink?") print(output)

? ? ? ? 下面是使用LangChain的實現方式,代碼量將翻一番,不過還可以接受:

from langchain_community.document_loaders import DirectoryLoader # pip install "unstructured[md]" loader = DirectoryLoader("mock_notebook/", glob="*.md") docs = loader.load() from langchain.text_splitter import RecursiveCharacterTextSplitter text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) splits = text_splitter.split_documents(docs) from langchain_community.embeddings.fastembed import FastEmbedEmbeddings from langchain_community.vectorstores import Chroma vectorstore = Chroma.from_documents(documents=splits, embedding=FastEmbedEmbeddings()) retriever = vectorstore.as_retriever() from langchain import hub # pip install langchainhub prompt = hub.pull("rlm/rag-prompt")  def format_docs(docs): return "\n\n".join(doc.page_content for doc in docs)  from langchain_core.runnables import RunnablePassthrough rag_chain = ( {"context": retriever | format_docs, "question": RunnablePassthrough()} | prompt | llm # This should be the LLM initialized in the task above.) print(rag_chain.invoke("What do I like to drink?"))

? ? ? 這些代碼清楚地說明了這兩個框架之間的不同抽象級別。LlamaIndex使用一個名為“query_engine”的包來包裝RAG管道,但LangChain會展示內部組件,包括檢索到的文檔的連接符、提示模板“based on X please answer Y”,以及鏈本身(如上面的LCEL所示)。

? ? ? ?當使用LangChain時,你必須在第一次嘗試時就確切地知道你想要什么,例如,調用from_documents的位置。LlamaIndex不需要顯式選擇存儲后端的情況下可以使用矢量存儲索引,而LangChain似乎建議您立即選擇一個(每個人在使用LangChain從文檔中創建矢量索引時,似乎都明確選擇了后端)。

? ? ? ?更有趣的是,盡管LangChain和LlamaIndex都在提供類似Huggingface Hub的云服務(即LangSmith Hub和LlamaHub)。注意的是使用LangChain的hub.pull調用時,它只下載一個簡短的文本模板,內容如下:

You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don’t know the answer, just say that you don’t know. Use three sentences maximum and keep the answer concise.

Question: {question}

Context: {context}

Answer:

任務三:構建一個支持RAG的聊天機器人

      在第一個任務中,我們構建了一個可以對話但不太了解用戶的意圖;在第二個例子中,我們構建了一個了解你但不能保留聊天歷史數據。現在讓我們把這兩者結合起來。

? ? ? ?使用LlamaIndex,只需將as_query_engineas_chat_engine交換即可:

# Everything from above, till and including the creation of the index.engine = index.as_chat_engine()output = engine.chat("What do I like to drink?") print(output) # "You enjoy drinking coffee."output = engine.chat("How do I brew it?") print(output) # "You brew coffee with a Aeropress."

? ? ? ? 對于LangChain,我們需要詳細說明。按照官方教程(https://python.langchain.com/docs/expression_language/cookbook/retrieval),讓我們先定義記憶:

# Everything above this line is the same as that of the last task.from langchain_core.runnables import RunnablePassthrough, RunnableLambda from langchain_core.messages import get_buffer_string from langchain_core.output_parsers import StrOutputParser from operator import itemgetter from langchain.memory import ConversationBufferMemory from langchain.prompts.prompt import PromptTemplate from langchain.schema import format_document from langchain_core.prompts import ChatPromptTemplate memory = ConversationBufferMemory( return_messages=True, output_key="answer", input_key="question" )

大致步驟如下:

1.在LLM開始時,從內存中加載聊天歷史記錄。

load_history_from_memory = RunnableLambda(memory.load_memory_variables) | itemgetter( "history" ) load_history_from_memory_and_carry_along = RunnablePassthrough.assign( chat_history=load_history_from_memory )

2.要求LLM使用上下文:“Taking the chat history into consideration, what should I look for in my notes to answer this question?”來豐富問題。

rephrase_the_question = ( { "question": itemgetter("question"), "chat_history": lambda x: get_buffer_string(x["chat_history"]), } | PromptTemplate.from_template( """You're a personal assistant to the user. Here's your conversation with the user so far: {chat_history} Now the user asked: {question} To answer this question, you need to look up from their notes about """ ) | llm | StrOutputParser() )

PS:我們不能只是將兩者連接起來,因為話題可能在對話中發生了變化,使聊天日志中的大多數語義信息變得無關緊要。

3.運行RAG管道。請注意,我們是如何通過暗示“我們作為用戶將自己查找筆記”來欺騙LLM的,但事實上,我們現在要求LLM承擔重任。我感覺很糟糕。

retrieve_documents = { "docs": itemgetter("standalone_question") | retriever, "question": itemgetter("standalone_question"), }

4.向LLM提問:“Taking the retrieved documents as reference (and — optionally — the conversation so far), what would be your response to the user’s latest question?”

def _combine_documents(docs): prompt = PromptTemplate.from_template(template="{page_content}") doc_strings = [format_document(doc, prompt) for doc in docs] return "\n\n".join(doc_strings) compose_the_final_answer = ( { "context": lambda x: _combine_documents(x["docs"]), "question": itemgetter("question"), } | ChatPromptTemplate.from_template( """You're a personal assistant. With the context below: {context} To the question "{question}", you answer:""" ) | llm )

5.將最終響應附加到聊天歷史記錄中。

# Putting all 4 stages together...final_chain = ( load_history_from_memory_and_carry_along | {"standalone_question": rephrase_the_question} | retrieve_documents | compose_the_final_answer ) # Demo.inputs = {"question": "What do I like to drink?"} output = final_chain.invoke(inputs) memory.save_context(inputs, {"answer": output.content}) print(output) # "You enjoy drinking coffee."inputs = {"question": "How do I brew it?"} output = final_chain.invoke(inputs) memory.save_context(inputs, {"answer": output.content}) print(output) # "You brew coffee with a Aeropress."

任務四:Agent

? ? ? ?如果你把與你交談的LLM角色視為一個人,RAG管道可以被認為是這個人使用的工具。一個人可以使用多個工具,LLM也是如此。你可以使用它提供搜索谷歌、查找維基百科、查看天氣預報等工具。這樣,你的聊天機器人就可以回答其直接知識之外的問題。

       隨著越來越多工具的出現,需要決定使用哪些工具,以及使用順序。這種能力被稱為“agency”。因此,擁有代理權的LLM的角色被稱為“agent”。

Agent有很多種類,最常見的就是ReAct范式(https://www.promptingguide.ai/techniques/react)

? ? ? ? 下面是LlamaIndex Agent的實現方式:

# Everything above this line is the same as in the above two tasks, # till and including where notes_query_engine is defined. # Let's convert the query engine into a tool. from llama_index.tools import ToolMetadata from llama_index.tools.query_engine import QueryEngineTool notes_query_engine_tool = QueryEngineTool( query_engine=notes_query_engine, metadata=ToolMetadata( name="look_up_notes", description="Gives information about the user.", ), ) from llama_index.agent import ReActAgent agent = ReActAgent.from_tools( tools=[notes_query_engine_tool], llm=llm, service_context=service_context, ) output = agent.chat("What do I like to drink?") print(output) # "You enjoy drinking coffee."output = agent.chat("How do I brew it?") print(output) # "You can use a drip coffee maker, French press, pour-over, or espresso machine."

? ? ? ?請注意,對于我們的后續問題“我如何沖泡咖啡”,agent的回答與查詢引擎不同,這是因為agent可以自己決定是否從我們的筆記中查找。如果他們有足夠的信心回答問題,agent可能不使用任何工具。關于“我如何……”的問題可以用兩種方式來解釋:要么是關于通用選項,要么是關于事實回憶。顯然,agent選擇了前一種方式來理解它,而查詢引擎(有責任從索引中查找文檔)不得不選擇后一種方式。

? ? ? ? LangChain針對Agent提供高級抽象:

# Everything above is the same as in the 2nd task, till and including where we defined rag_chain. # Let's convert the chain into a tool. from langchain.agents import AgentExecutor, Tool, create_react_agent tools = [ Tool( name="look_up_notes", func=rag_chain.invoke, description="Gives information about the user.", ),]react_prompt = hub.pull("hwchase17/react-chat") agent = create_react_agent(llm, tools, react_prompt) agent_executor = AgentExecutor.from_agent_and_tools(agent=agent, tools=tools) result = agent_executor.invoke( {"input": "What do I like to drink?", "chat_history": ""} ) print(result) # "You enjoy drinking coffee."result = agent_executor.invoke( { "input": "How do I brew it?", "chat_history": "Human: What do I like to drink?\nAI: You enjoy drinking coffee.", })print(result) # "You can use a drip coffee maker, French press, pour-over, or espresso machine."

? ? ? ?盡管仍然需要手動管理聊天歷史記錄,但與創建RAG鏈相比,創建agent要容易得多,create_react_agentAgentExecutor可以完成大部分Agent功能。

總結

? ? ? LlamaIndexLangChain是用于構建LLM應用程序的兩個框架。雖然LlamaIndex專注于RAG用例,但LangChain似乎應用更廣泛。但它們在實踐中有何不同?在這篇文章中,我們比較了兩個框架在完成四個常見任務時的表現:

  1. 連接到本地LLM實例并構建聊天機器人。
  2. 索引本地文件并構建RAG系統。
  3. 將以上兩者結合起來,制作一個具有RAG功能的聊天機器人。
  4. 將聊天機器人轉換為Agent,這樣它可以使用更多的工具并進行簡單的推理。

參考文獻:

[1]?https://lmy.medium.com/comparing-langchain-and-llamaindex-with-4-tasks-2970140edf33

文章轉自微信公眾號@ArronAI

上一篇:

LLM之LangChain(二)| LangChain中的Agent

下一篇:

LLM之LangChain(四)| 介紹LangChain 0.1在可觀察性、可組合性、流媒體、工具、RAG和代理方面的改進
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費