LangChain 手冊 langchain-agents範例 Agents 就像是 LLM 的「工具」。它們允許 LLM 存取 Google 搜尋、執行 Python的複雜計算,甚至進行 SQL 查詢。 在本筆記本中,我們將探索 Agents 以及如何在 LangChain 中使用它們。 我們將從安裝示例中所需的前置程式庫開始。 !pip install -qU openai google-search-results wikipedia sqlalchemy !pip install langchain==0.3.7 !pip install langchain_community==0.3.7 import langchain langchain.__version__ 要執行此筆記本,我們需要使用 OpenAI 的LLM。在此我們將設定將用於整個筆記本的 LLM,當提示時輸入您的 OpenAI API金鑰即可。 from getpass import getpass # OPENAI_API_KEY = getpass() OPENAI_API_KEY = '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' from langchain import OpenAI llm = OpenAI( openai_api_key=OPENAI_API_KEY, temperature=0 ) 我們會計算每次呼叫中使用的 tokens 數量。 from langchain.callbacks import get_openai_callback def count_tokens(agent, query): with get_openai_callback() as cb: result = agent(query) print(f'Spent a total of {cb.total_tokens} tokens') return result 設定完成後,讓我們進入 Agents 的主題。 什麼是 Agent? 定義:Agents 的核心在於為 LLM 提供使用工具的能力。這正是 LangChain與 ChatGPT的實現有所區別的地方,也讓我們初步了解它能為開發者帶來的價值。到目前為止,我們只介紹了幾個獨立的構建模組。現在,讓我們看看它們是如何組合起來的。 Agents 的官方定義如下: Agents 使用 LLM來決定要採取哪些行動以及行動的順序。行動可以是使用工具並觀察其輸出,或者直接返回結果給使用者。 在本節中,我們將介紹所謂的「通用」Agents,它們能執行許多元任務。此外,還有針對不同任務進行調整的更專用Agents(稱為 "agent-toolkits"),我們將在未來的章節中介紹。 建立資料庫 我們將使用 Agents來與一個小型的股票示例資料庫進行互動。由於這只是用於說明的工具,我們不會深入詳細內容。現在讓我們開始建立它。 from sqlalchemy import MetaData metadata_obj = MetaData() from sqlalchemy import Column, Integer, String, Table, Date, Float stocks = Table( "stocks", metadata_obj, Column("obs_id", Integer, primary_key=True), Column("stock_ticker", String(4), nullable=False), Column("price", Float, nullable=False), Column("date", Date, nullable=False), ) from sqlalchemy import create_engine engine = create_engine("sqlite:///:memory:") metadata_obj.create_all(engine) from datetime import datetime observations = [ [1, 'ABC', 200, datetime(2023, 1, 1)], [2, 'ABC', 208, datetime(2023, 1, 2)], [3, 'ABC', 232, datetime(2023, 1, 3)], [4, 'ABC', 225, datetime(2023, 1, 4)], [5, 'ABC', 226, datetime(2023, 1, 5)], [6, 'XYZ', 810, datetime(2023, 1, 1)], [7, 'XYZ', 803, datetime(2023, 1, 2)], [8, 'XYZ', 798, datetime(2023, 1, 3)], [9, 'XYZ', 795, datetime(2023, 1, 4)], [10, 'XYZ', 791, datetime(2023, 1, 5)], ] from sqlalchemy import insert def insert_obs(obs): stmt = insert(stocks).values( obs_id=obs[0], stock_ticker=obs[1], price=obs[2], date=obs[3] ) with engine.begin() as conn: conn.execute(stmt) for obs in observations: insert_obs(obs) 我們在這裡安裝 langchain_experimental 程式庫,因為 SQLDatabaseChain位於其中。未來可能會將其移至官方的 langchain 程式庫中。 !pip install langchain_experimental -qU from langchain.utilities import SQLDatabase from langchain_experimental.sql import SQLDatabaseChain db = SQLDatabase(engine) sql_chain = SQLDatabaseChain(llm=llm, database=db, verbose=True) Agent 類型 在本節中,我們將回顧多種 Agent 並看看它們如何「思考」以及它們能做什麼。 使用 LangChain 的預建 Agent 涉及三個變數: 定義工具或工具包 定義 LLM 定義 Agent 類型 在 LangChain 中,這些都非常容易完成,我們將在以下示例中看到。 Agent 類型 #1:Zero Shot React 在這個示例中,我們將使用稍有不同類型的 Agent ------ SQLAgent,它可以通過自己的方法 create_sql_agent 實例化。其他 Agents將以更通用的方式進行實例化,我們將在後續示例中看到。 這種方法使用 toolkit 而不是簡單的工具清單。您可以在文件中了解更多相關內容。對於此用例,我們將使用 SQLDatabaseToolkit。 顧名思義,我們將使用這個 Agent對輸入執行「零記憶」任務。這意味著我們不會進行多次相互依賴的交互,而僅僅執行一次。換句話說,這個Agent 沒有記憶功能。 現在我們準備初始化 Agent!我們將 verbose 設為True,這樣我們就可以觀察到 Agent 的「思考」過程。 重要提示: 當與 Agents 互動時,設置 max_iterations參數非常重要,因為 Agents 可能陷入無限循環,消耗大量 tokens。預設值為15,允許使用多個工具和進行複雜推理,但對於大多數應用,您應該將其設置得更低。 from langchain.agents import create_sql_agent from langchain.agents.agent_toolkits import SQLDatabaseToolkit from langchain.agents.agent_types import AgentType agent_executor = create_sql_agent( llm=llm, toolkit=SQLDatabaseToolkit(db=db, llm=llm), verbose=True, agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION, max_iterations=3 ) 讓我們看看我們新創建的 Agent的效果!我們將向它提出一個涉及股票價格數學運算的問題。 result = count_tokens( agent_executor, "What is the multiplication of the ratio between stock " + "prices for 'ABC' and 'XYZ' in January 3rd and the ratio " + "between the same stock prices in January the 4th?" ) from pprint import pprint pprint(vars(agent_executor.agent)) # 深入检查 Runnable 中的结构 pprint(vars(agent_executor.agent.runnable)) 一如既往,我們來看看這裡的 Prompt 是什麼: from langchain.prompts import PromptTemplate # 提取 middle 部分的组件 middle_components = agent_executor.agent.runnable.middle # 遍历 middle 找到 PromptTemplate for component in middle_components: if isinstance(component, PromptTemplate): prompt_template = component.template print(prompt_template) 我們必須問自己:Agents 與 Chains 有什麼不同? 如果我們查看 Agent 的邏輯和剛才打印的Prompt,我們會看到一些明顯的差異。首先,Prompt中包含了工具。其次,原本在 Chains中是立即完成的思考過程,現在則涉及到「思考」、「行動」、「行動輸入」、「觀察」的序列。這是什麼意思? 簡單來說,LLM現在能夠「推理」如何最佳使用工具來解決問題,並且僅憑工具的簡短描述就可以以智能的方式結合它們。如果您想詳細了解這種MRKL(Modular Reasoning, Knowledge and Language)模式,請參考這篇論文。 最後,我們來關注「agent_scratchpad」。這是什麼?這是我們將每次 Agent執行的思考或行動追加的地方。通過這種方式,Agent在每個時間點都知道已經找到了哪些信息,並可以繼續其思考過程。換句話說,在使用工具後,Agent會將其思考和觀察追加到 Scratchpad,然後繼續推進。 Agent 類型 #2:Conversational React Zero Shot Agent很有趣,但正如我們之前所說,它沒有記憶功能。如果我們希望助手能記住我們之前談過的事情,並能對其進行推理和使用工具,這時我們需要使用Conversational React Agent。 我們將在這個示例中使用數學工具並按如下方式加載: from langchain.agents import load_tools tools = load_tools( ["llm-math"], llm=llm ) 這裡使用的記憶類型是一種簡單的緩衝記憶,它允許我們記住推理鏈中的前幾步。關於記憶的更多信息,請參考本系列的第三章。 from langchain.memory import ConversationBufferMemory memory = ConversationBufferMemory(memory_key="chat_history") from langchain.agents import initialize_agent conversational_agent = initialize_agent( agent=AgentType.CONVERSATIONAL_REACT_DESCRIPTION, tools=tools, llm=llm, verbose=True, max_iterations=3, memory=memory, ) result = count_tokens( conversational_agent, "What's the result of an investment of $10,000 growing at 8% annually for 5 years with compound interest?" ) 如下所見,Prompt類似,但它包含了一個出色的指令開頭,使其成為一個有效的助手,並在內存模組中包含了聊天歷史記錄的欄位: print(conversational_agent.agent.llm_chain.prompt.template) 讓我們看看,如果我們試圖回答與之前問題相關的問題,會發生什麼: result = count_tokens( conversational_agent, "If we start with $15,000 instead and follow the same 8% annual growth for 5 years with compound interest, how much more would we have compared to the previous scenario?" ) Agent 類型 #3:React Docstore 這種類型的 Agent與我們之前看到的類似,但它包括與文檔存儲(Docstore)的互動。它只有兩個工具可用:「搜尋(Search)」和「查找(Lookup)」。 使用「搜尋」,它將調出相關文章;使用「查找」,Agent會在文章中找到正確的資訊片段。這可能通過示例最容易理解: from langchain import Wikipedia from langchain.agents.react.base import DocstoreExplorer, Tool docstore=DocstoreExplorer(Wikipedia()) tools = [ Tool( name="Search", func=docstore.search, description='search wikipedia' ), Tool( name="Lookup", func=docstore.lookup, description='lookup a term in wikipedia' ) ] docstore_agent = initialize_agent( tools, llm, agent="react-docstore", verbose=True, max_iterations=3 ) count_tokens(docstore_agent, "What were Archimedes' last words?") 我們不會在這裡打印Prompt,因為它太大了。但如果您想看到它,可以自己嘗試(我們已經知道如何操作了)。 簡而言之,它包含了幾個 Question > Thought > Action >Observation 循環的示例,這些循環包括「搜尋」和「查找」工具。 如果您想了解這種方法的更多信息,請參考這篇論文。 Agent 類型 #4:Self Ask with Search 當使用 LLM 從搜索引擎提取資訊時,這是首選 Agent。Agent會提問後續問題,並使用搜索功能來獲取中間答案,以幫助它達到最終答案。 from langchain import OpenAI, SerpAPIWrapper from langchain.agents import initialize_agent, Tool search = SerpAPIWrapper(serpapi_api_key='api_key') tools = [ Tool( name="Intermediate Answer", func=search.run, description='google search' ) ] self_ask_with_search = initialize_agent(tools, llm, agent="self-ask-with-search", verbose=True) 我們不會與此 Agent 互動,因為需要使用 SerpAPI 金鑰。然而,通過檢查Prompt,我們可以看到其運作的幾個示例: print(self_ask_with_search.agent.llm_chain.prompt.template) 如我們所見,Prompt 基本上是一系列示例,向 LLM展示如何對搜索工具進行後續提問,直到獲得最終答案。 再次強調,您可以在 這裡查看相關論文以進一步深入研究! 總結 這就是關於 Agents 的全部內容!它還有很多其他可以完成的事情,僅舉幾例: 創建您自己的自定義 Agent 與其他工具(甚至是自定義工具)一起使用 通過方便的用戶界面追踪 Agent 的每次呼叫 查看這些操作指南以了解更多!