LangChain的Agent使用介紹

LangChain

LangChain 介紹

隨著各種開源大模型的發(fā)布,越來越多的人開始嘗試接觸和使用大模型。在感嘆大模型帶來的驚人表現(xiàn)的同時,也發(fā)現(xiàn)一些問題,比如沒法查詢到最新的信息,有時候問一些數(shù)學問題時候,會出現(xiàn)錯誤答案,還有一些專業(yè)領域類問題甚至編造回答等等。有沒有什么辦法能解決這些問題呢?答案就是LangChain。

LangChain 是一個開源的語言模型集成框架,旨在簡化使用大型語言模型(LLM)創(chuàng)建應用程序的過程。利用它可以讓開發(fā)者使用語言模型來實現(xiàn)各種復雜的任務,例如文本到圖像的生成、文檔問答、聊天機器人、調用特定的SaaS服務等等。隨著ChatGPT、midjourney等AI技術的爆火,LangChain也是在短時間內得到6w+的star數(shù),版本迭代也是異常的快,社區(qū)十分活躍。

LangChain 在沒有任何收入也沒有任何明顯的創(chuàng)收計劃的情況下,獲得了 1000 萬美元的種子輪融資和 2000-2500 萬美元的 A 輪融資,估值達到 2 億美元左右。

LangChain架構圖

上面是LangChain的核心架構圖,可以看到LangChain主要包含如下模塊:

  • Model I/O:大模型的輸入輸出,包含提示詞、任何大模型、結果解析器。
  • Retrieval:涉及到數(shù)據(jù)集相關,主要包含文檔提取器、文檔轉換器、向量數(shù)據(jù)庫等。
  • Chains:允許將多個不同組件組合在一起使用,形成鏈條式調用。
  • Memory:在大模型調用期間提供存儲能力。
  • Agents:鏈式調用是硬編碼的,而代理是由大模型根據(jù)實時情況來決定如何調用工具。
  • Callbacks:大模型各個階段的的回調系統(tǒng),對于日志記錄、監(jiān)控、流傳輸和其他任務非常有用。

Agent

大模型一般只擁有他們被訓練的知識,這種知識可能很快就會過時了,所以在推理的時候大模型與外界是處于“斷開”狀態(tài)。為了克服這一限制,LangChain在Yao等人在2022年11月提出的推理和行動(ReAct)框架上提出了“代理”(Agent)的解決方案。此方案可以獲取最新的數(shù)據(jù),并將其作為上下文插入到提示中。Agent也可以用來采取行動(例如,運行代碼,修改文件等),然后該行動的結果可以被LLM觀察到,并被納入他們關于下一步行動的決定。

運行大體流程: 1用戶給出一個任務(Prompt) -> 2思考(Thought) -> 3行動(Action) -> 4觀察(Observation),
然后循環(huán)執(zhí)行上述 2-4 的流程,直到大模型認為找到最終答案為止。

Agent內部具體拆解:


Agent結構圖

使用Agent有兩個必備條件:相關能力工具和對這些工具的正確描述。

定義工具

工具的定義只需要集成BaseTool類,然后在_run方法中編寫你的邏輯就行,大模型會把合適的參數(shù)傳進來。
需要定義類變量有:

  • name: 工具名稱,很重要,大模型內部會使用到
  • description:工具描述,很重要,告知大模型在什么情況下來使用這個工具
  • return_direct:這個字段默認為false,如果設置為true,工具返回結果后,大模型就不再循環(huán)思考了會直接將這個結果當做答案。

LangChain 已經內置了 duckduckgo 搜索引擎,pip install duckduckgo-search安裝一下依賴包即可使用,只是需要科學上網(wǎng)才能調通。

下面是我定義的兩個工具,一個用于電影搜索,一個用于數(shù)學計算:

from langchain.tools import BaseTool, DuckDuckGoSearchRun

# 搜索工具
class SearchTool(BaseTool):
    name = "Search"
    description = "當問電影相關問題時候,使用這個工具"
    return_direct = False  # 直接返回結果

    def _run(self, query: str) -> str:
        print("\n正在調用搜索引擎執(zhí)行查詢: " + query)
        search = DuckDuckGoSearchRun()
        return search.run(query)

# 計算工具
class CalculatorTool(BaseTool):
    name = "Calculator"
    description = "如果問數(shù)學相關問題時,使用這個工具"
    return_direct = False  # 直接返回結果

    def _run(self, query: str) -> str:
        return eval(query)

定義結果解析類

每次大模型輸出之后,都會對結果進行解析,如果找到action就會去調用。但是默認的解析類我測試的時候總報錯,所以我改寫了一下:

from typing import Dict, Union, Any, List

from langchain.output_parsers.json import parse_json_markdown
from langchain.agents.conversational_chat.prompt import FORMAT_INSTRUCTIONS
from langchain.agents import AgentExecutor, AgentOutputParser
from langchain.schema import AgentAction, AgentFinish

# 自定義解析類
class CustomOutputParser(AgentOutputParser):

    def get_format_instructions(self) -> str:
        return FORMAT_INSTRUCTIONS

    def parse(self, text: str) -> Union[AgentAction, AgentFinish]:
        print(text)
        cleaned_output = text.strip()
        # 定義匹配正則
        action_pattern = r'"action":\s*"([^"]*)"'
        action_input_pattern = r'"action_input":\s*"([^"]*)"'
        # 提取出匹配到的action值
        action = re.search(action_pattern, cleaned_output)
        action_input = re.search(action_input_pattern, cleaned_output)
        if action:
            action_value = action.group(1)
        if action_input:
            action_input_value = action_input.group(1)
        
        # 如果遇到'Final Answer',則判斷為本次提問的最終答案了
        if action_value and action_input_value:
            if action_value == "Final Answer":
                return AgentFinish({"output": action_input_value}, text)
            else:
                return AgentAction(action_value, action_input_value, text)

        # 如果聲明的正則未匹配到,則用json格式進行匹配
        response = parse_json_markdown(text)
        
        action_value = response["action"]
        action_input_value = response["action_input"]
        if action_value == "Final Answer":
            return AgentFinish({"output": action_input_value}, text)
        else:
            return AgentAction(action_value, action_input_value, text)
output_parser = CustomOutputParser()

初始化Agent

如果你使用ChatGPT的話,這里需要配置ChatGPT的api-key,同時需要科學上網(wǎng)。也可以配置一些本地的開源大模型,比如ChatGLM2-6B、Baichuan-13B等,但是效果確實要比ChatGPT差很多。

from langchain.memory import ConversationBufferMemory
from langchain.agents.conversational_chat.base import ConversationalChatAgent 
from langchain.agents import AgentExecutor, AgentOutputParser

SYSTEM_MESSAGE_PREFIX = """盡可能用中文回答以下問題。您可以使用以下工具"""

# 初始化大模型實例,可以是本地部署的,也可是是ChatGPT
# llm = ChatGLM(endpoint_url="http://你本地的實例地址")
llm = ChatOpenAI(openai_api_key="sk-xxx", model_name='gpt-3.5-turbo', request_timeout=60)
# 初始化工具
tools = [CalculatorTool(), SearchTool()]
# 初始化對話存儲,保存上下文
memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)
# 配置agent
chat_agent = ConversationalChatAgent.from_llm_and_tools(
    system_message=SYSTEM_MESSAGE_PREFIX, # 指定提示詞前綴
    llm=llm, tools=tools, memory=memory, 
    verbose=True, # 是否打印調試日志,方便查看每個環(huán)節(jié)執(zhí)行情況
    output_parser=output_parser # 
)
agent = AgentExecutor.from_agent_and_tools(
    agent=chat_agent, tools=tools, memory=memory, verbose=True,
    max_iterations=3 # 設置大模型循環(huán)最大次數(shù),防止無限循環(huán)
)

調用Agent

調用就很簡單了,執(zhí)行agent.run(prompt)即可,下面是一個詳細的調用日志輸出:

執(zhí)行結果

日志已經完整的體現(xiàn)出了整個流程,大模型的確每次都匹配到了正確的tool。如果還覺得日志不詳細,可以設置langchain.debug = True,這樣會打印更詳細日志。

總結

可以這么理解Agent,它讓大模型變成了一個決策者。用戶的問題首先由它去理解和拆分,它來從工具列表中找到覺得合適的工具,然后將用戶的提問信息轉化成結構化的數(shù)據(jù),當成參數(shù)傳遞給工具函數(shù)。工具函數(shù)返回結果又交還給了大模型去觀察分析,如果它覺得不是正確答案,那么繼續(xù)這個循環(huán)直到得出它認為的正確答案。

它就像是一個優(yōu)秀的項目經理,分解用戶的問題,可能他不擅長完成某一項任務,但是他能找到合適專業(yè)的外部的人去完成子任務,最后他再匯總任務結果交付給用戶。

優(yōu)點

  • 框架層上來說,對大模型的有更系統(tǒng)化的干預機制,方便集成。
  • 拓展了大模型更多的能力,而且是不需要經過復雜且昂貴的訓練過程。
  • 不用再去寫那些匹配場景的規(guī)則了,大模型已經幫你做了,前提是這個模型參數(shù)要夠大,能理解用戶的意思。
  • 整個流程都有詳細的記錄日志,方便調試。

不足

  • 大模型會被多次調用,響應用戶的時間可能會比較久,因此相應產品也就會限制在一些特定領域。
  • 雖然不用寫工具匹配規(guī)則,但是這也讓這一塊邏輯變成一個黑盒了,很難去精準的匹配或者調試。
  • 對大模型本身能力要求很高,如果使用低參數(shù)大模型,很有可能無法識別問題并正確的分發(fā)給對應工具。

當然還是有優(yōu)化的方向的:比如可以考慮去使用語料專門往解析action方面訓練,讓模型能更好的解析出action。

引用鏈接:

  1. Introduction | ????? Langchain
  2. 【LangChain】模塊架構解析:一圖帶你了解 LangChain 的內部結構!
  3. Prophet-Andrew-Ng/langchain/李魯魯學LangChain 11.md
  4. 面向開發(fā)者的 LLM 入門教程
  5. 我為什么放棄了 LangChain? - 知乎 (zhihu.com)
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容