自主代理技術仰賴記憶和工具提升效能,利用記憶儲存過往經驗,並運用工具執行特定任務。正規表示式則能有效提取關鍵資訊,例如從LLM輸出中擷取動作和輸入。LangChain 提供了便捷的工具和代理構建方法,讓開發者能輕鬆整合外部資源,例如網路搜尋或特定功能的 API。OpenAI 函式則賦予 LLM 在執行過程中動態呼叫外部函式的能力,提升問題解決的靈活性。理解 ReAct 框架與 OpenAI 函式的差異,有助於選擇合適的工具開發自主代理應用。在實務應用中,工作分工和工具的品質評估至關重要,這能確保自主代理的穩定性和效率。
自主代理與記憶和工具
在自主代理的設計中,記憶和工具扮演著重要的角色。代理需要記憶來儲存和回顧過去的經驗和知識,以便在未來做出更好的決策。工具則提供了代理實作其目標和任務的能力。
使用正規表示式提取動作和輸入
在代理的實作中,常常需要提取特定的動作和輸入。例如,代理可能需要提取最後一次的搜尋動作和輸入。為了實作這一點,可以使用正規表示式。
正規表示式模式
以下是兩個正規表示式模式,分別用於提取動作和輸入:
action_pattern = re.compile(r"(?i)action\s*:\s*([^\n]+)", re.MULTILINE)
action_input_pattern = re.compile(r"(?i)action_input\s*:\s*([^\n]+)", re.MULTILINE)
這兩個模式都使用了 (?i) 標誌,使得匹配物件的查詢變得不區分大小寫。然後,它們分別匹配 “action” 和 “action_input” 這兩個詞彙,後面跟著零個或多個空白字元、一個冒號、零個或多個空白字元,然後是捕捉群組 ([^\n]+),它匹配一個或多個非換行字元。
提取最後一次動作和輸入
使用這兩個模式,可以提取文字中的所有動作和輸入。然後,可以從結果列表中提取最後一次動作和輸入:
actions = action_pattern.findall(text)
action_inputs = action_input_pattern.findall(text)
last_action = actions[-1] if actions else None
last_action_input = action_inputs[-1] if action_inputs else None
抽象化為函式
可以將這個過程抽象化為一個函式,方便重複使用:
def extract_last_action_and_input(text):
action_pattern = re.compile(r"(?i)action\s*:\s*([^\n]+)", re.MULTILINE)
action_input_pattern = re.compile(r"(?i)action_input\s*:\s*([^\n]+)", re.MULTILINE)
actions = action_pattern.findall(text)
action_inputs = action_input_pattern.findall(text)
last_action = actions[-1] if actions else None
last_action_input = action_inputs[-1] if action_inputs else None
return {"action": last_action, "action_input": last_action_input}
這個函式接受一個文字字串作為輸入,傳回一個字典,其中包含最後一次動作和輸入。
使用LLM進行問題解決
在使用LLM(Large Language Model)進行問題解決時,瞭解如何從LLM的輸出中提取最終答案是非常重要的。這可以透過使用正規表示式來實作。
提取最終答案
以下是一個使用Python和正規表示式來提取最終答案的例子:
import re
def extract_final_answer(text):
final_answer_pattern = re.compile(r"(?i)I've found the answer:\s*([^\n]+)", re.MULTILINE)
final_answers = final_answer_pattern.findall(text)
if final_answers:
return final_answers[0]
else:
return None
final_answer_text = "I've found the answer: final_answer"
print(extract_final_answer(final_answer_text))
這個例子定義了一個函式extract_final_answer,它使用正規表示式來查詢以"I’ve found the answer:“開頭的行,並提取該行後面的答案。
處理LLM回應錯誤
LLM不總是會以預期的方式回應,因此您的應用程式需要能夠處理正規表示式解析錯誤。有幾種方法可以處理這種情況,包括使用另一個LLM來修復之前的LLM回應,或傳送一個新的LLM請求,包含之前的狀態。
組合所有元件
現在,我們可以組合所有元件,以下是步驟解釋:
from langchain_openai.chat_models import ChatOpenAI
from langchain.prompts.chat import SystemMessagePromptTemplate
# 初始化ChatOpenAI例項
chat = ChatOpenAI(model_kwargs={"stop": ["tool_result:"]})
# 定義可用的工具
tools = {}
def search_on_google(query: str):
return f"Jason Derulo doesn't have a wife or partner."
tools["search_on_google"] = {
"function": search_on_google,
"description": "Searches on google for a query",
}
# 設定基礎提示範本
base_prompt = """
You will attempt to solve the problem of finding the answer to a question.
Use chain-of-thought reasoning to solve through the problem, using the following pattern:
1. Observe the original question:
original_question: original_problem_text
2. Create an observation with the following pattern:
observation: observation_text
這個例子初始化了一個ChatOpenAI例項,定義了一個工具search_on_google,並設定了一個基礎提示範本。這個基礎提示範本將用於引導LLM進行問題解決。
圖表翻譯:
這個流程圖描述了問題解決的過程,從問題輸入到最終答案提取和結果輸出。
thought: Jason Derulo 的個人生活和關係狀態可能會在公眾場合被提及或討論。
action: search_engine
action_input: Jason Derulo partner
output = chat.invoke(SystemMessagePromptTemplate
.from_template(template=base_prompt)
.format_messages(tools=tools, question=“Is Jason Derulo with a partner?”))
print(output)
tool_name = “search_engine” tool_input = “Jason Derulo partner”
tool_result = tools[tool_name]“function”
print(f”““The agent has opted to use the following tool:
tool_name: {tool_name}
tool_input: {tool_input}
tool_result: {tool_result}””")
current_prompt = f""" You are answering this query: Is Jason Derulo with a partner? Based on the provided tool result:
tool_result: {tool_result} Either provide the next observation, action, action_input, or the final answer if available. If you are providing the final answer, you must return the following pattern: “I’ve found the answer: final_answer” """
output = chat.invoke(SystemMessagePromptTemplate
.from_template(template=base_prompt)
.format_messages(tools=tools, question=“Is Jason Derulo with a partner?”))
使用工具以增強LLM能力
在探索LangChain代理和其功能之前,瞭解工具和如何建立及使用它們至關重要。由於大語言模型(LLM)如GPT-4只能生成文字,提供可以執行其他操作的工具,例如與資料函式庫互動或讀寫檔案,可以有效地增加LLM的能力。
什麼是工具?
工具簡單地定義為一個預先定義的函式,允許代理採取特定的行動。這些行動可以是任何可以用程式碼實作的事情,例如:
- 與外部API進行互動
- 讀寫檔案或資料函式庫
- 執行系統命令
- 進行網路搜尋
建立工具
要建立工具,需要定義工具的功能和輸入引數。這通常涉及編寫一段程式碼,該程式碼實作了所需的功能。例如,如果要建立一個工具來查詢某個人的當前關係狀態,可以編寫一段程式碼來搜尋網路並傳回結果。
使用工具
使用工具時,代理會將工具名稱和輸入引數包含在提示中。例如,如果要使用之前建立的工具來查詢Jason Derulo的當前關係狀態,代理可能會生成以下提示:
tool_name: search_on_google
tool_input: "Jason Derulo current relationship status"
代理然後會執行工具並傳回結果,結果可以用於生成最終答案或進一步的提示。
LangChain代理和工具
LangChain代理可以自動化前面描述的步驟,並提供多個工具使用(透過迴圈)和工具失敗時的處理(當代理無法解析動作或動作輸入時)。這使得代理可以更有效地使用工具並擴充套件其能力。
建立工具和代理
在 LangChain 中,我們可以建立自己的工具和代理,以實作特定的任務。首先,我們需要匯入必要的類別和函式:
from langchain.agents import AgentExecutor, create_react_agent
from langchain import hub
from langchain_openai import ChatOpenAI
from langchain.tools import Tool
接下來,我們定義了一個 LLM(Large Language Model)來使用:
model = ChatOpenAI()
然後,我們建立了一個工具,該工具可以計算字串中的字元數:
def count_characters_in_string(string):
return len(string)
我們建立了一個工具列表,其中包含了我們剛剛定義的工具:
tools = [
Tool.from_function(
func=count_characters_in_string,
name="Count Characters in a text string",
description="Count the number of characters in a text string",
)
]
下一步,我們下載了一個反應提示(react prompt):
prompt = hub.pull("hwchase17/react")
然後,我們構建了一個 ReAct 代理:
agent = create_react_agent(model, tools, prompt)
接著,我們初始化了一個代理執行器:
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
最後,我們呼叫代理以查詢給定單詞中的字元數:
agent_executor.invoke({"input": '''How many characters are in the word "supercalifragilisticexpialidocious"?'''})
內容解密:
在這個範例中,我們建立了一個工具,可以計算字串中的字元數。然後,我們建立了一個代理,該代理可以使用這個工具來完成特定的任務。代理執行器被用來呼叫代理並執行查詢。
圖表翻譯:
在這個圖表中,我們展示了建立工具、建立代理、初始化代理執行器、呼叫代理和執行查詢的流程。這個圖表幫助我們瞭解 LangChain 中工具和代理的建立和使用過程。
建立一個計算字串長度的工具
首先,我們需要建立一個計算字串長度的工具。這個工具將被封裝在一個名為 Tool 的物件中,提供一個描述性的名稱和解釋。
from langchain.agents import Tool
# 建立一個計算字串長度的工具
def count_characters_in_string(input_string):
return len(input_string)
# 封裝工具
tool = Tool(
name="計算字串長度",
description="計算給定字串的長度",
fn=count_characters_in_string
)
建立一個互動式代理
接下來,我們需要建立一個互動式代理,使用 create_openai_functions_agent 函式初始化代理,結合定義好的工具、ChatOpenAI 模型和一個從 LangChain hub 提取的 react 提示。
from langchain.agents import create_openai_functions_agent, AgentExecutor
# 建立一個互動式代理
agent = create_openai_functions_agent(
model=ChatOpenAI(temperature=0),
tools=[tool]
)
# 啟用詳細輸出
executor = AgentExecutor(agent, verbose=True)
執行代理
最後,我們需要執行代理,使用 invoke 方法執行代理,並傳入一個關於 “supercalifragilisticexpialidocious” 字串長度的查詢。
# 執行代理
output = executor.invoke("計算 'supercalifragilisticexpialidocious' 的字串長度")
print(output)
內容解密:
上述程式碼建立了一個計算字串長度的工具,封裝在 Tool 物件中,並建立了一個互動式代理,使用 create_openai_functions_agent 函式初始化代理。代理使用 ChatOpenAI 模型和定義好的工具,啟用詳細輸出,並執行代理以計算 “supercalifragilisticexpialidocious” 字串的長度。
圖表翻譯:
上述流程圖描述了建立一個計算字串長度的工具,封裝在 Tool 物件中,建立一個互動式代理,使用 create_openai_functions_agent 函式初始化代理,啟用詳細輸出,並執行代理以計算 “supercalifragilisticexpialidocious” 字串的長度。每一步驟都清楚地展示了程式碼的邏輯和過程。
使用LLM作為API(OpenAI Functions)進行數學計算和搜尋
在本文中,我們將探討如何使用LLM(Large Language Model)作為API,實作數學計算和搜尋功能。首先,我們需要建立一個LLMMathChain例項,使用ChatOpenAI模型,並將verbose引數設定為True,以便輸出詳細的執行過程。
llm_math_chain = LLMMathChain.from_llm(llm=model, verbose=True)
接下來,我們需要下載一個prompt從hub,這個prompt將用於初始化agent。
prompt = hub.pull("hwchase17/openai-functions-agent")
現在,我們可以定義工具(tools)列表,其中包含了LLMMathChain工具,用於數學計算,以及一個名為google_search的工具,用於搜尋。
tools = [
Tool(
name="Calculator",
func=llm_math_chain.run,
description="用於回答數學問題",
return_direct=True,
),
Tool(
name="google_search",
func=google_search,
description="用於搜尋詳情",
),
]
其中,google_search函式是一個簡單的搜尋函式,傳回一個固定的字串。
def google_search(query: str) -> str:
return "James Phoenix is 31 years old."
接下來,我們可以建立一個agent,使用ChatOpenAI模型和工具列表。
agent = create_openai_functions_agent(llm=model, tools=tools, prompt=prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
現在,我們可以使用agent_executor來執行任務。例如,我們可以問agent計算5 + 5的結果。
result = agent_executor.invoke({"input": "What is 5 + 5?"})
print(result)
輸出結果將是:
{'input': 'What is 5 + 5?', 'output': 'Answer: 10'}
此外,我們還可以使用agent_executor來執行搜尋任務。例如,我們可以問agent搜尋James Phoenix的年齡。
result = agent_executor.invoke({"input": "How old is James Phoenix?"})
print(result)
輸出結果將是:
{'input': 'How old is James Phoenix?', 'output': 'James Phoenix is 31 years old.'}
這樣,我們就實作了使用LLM作為API,進行數學計算和搜尋的功能。
自主代理與工具整合:提升智慧體的能力
自主代理(Autonomous Agents)是指能夠自主執行任務並根據環境變化做出決策的智慧體。當我們將自主代理與各種工具整合在一起時,可以大大增強其能力,讓它們能夠解決更複雜的問題。
工具整合的重要性
工具整合是指將不同的工具和功能整合到自主代理中,以擴充套件其能力。這些工具可以是網路搜尋、檔案系統工具、HTTP請求工具等。透過整合不同的工具,自主代理可以根據不同的情況選擇最適合的工具來解決問題。
推薦工具
以下是一些推薦的工具,可能對自主代理有所幫助:
- 網路搜尋:能夠提供及時和相關的內容。
- 檔案系統工具:能夠管理檔案,包括讀取、寫入和重新組織。
- HTTP請求工具:能夠執行HTTP請求,包括建立、讀取、更新和刪除。
- Twilio:能夠提供通訊服務,包括傳送和接收簡訊、電話等。
工作分工和品質評估
當使用工具時,需要確保工作分工得當。例如,可以將通訊服務交給Twilio,將HTTP相關任務交給HTTP請求工具。同時,也需要不斷評估工具的效能和品質,以確保自主代理的整體效能。
OpenAI函式和ReAct框架的比較
OpenAI函式和ReAct框架都是用於執行任務的框架,但它們有不同的特點。OpenAI函式執行在執行時,LLM可以自主決定是否執行函式。這對於對話代理來說是有益的,因為它提供了多種功能,包括執行時決策。
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title 自主代理整合記憶工具與LLM應用
package "正規表示式" {
package "基本語法" {
component [字元類 [abc]] as char_class
component [量詞 * + ?] as quantifier
component [錨點 ^ $] as anchor
}
package "進階功能" {
component [群組 ()] as group
component [後向參考 \1] as backref
component [前瞻後顧] as lookahead
}
package "Python re 模組" {
component [re.match()] as match
component [re.search()] as search
component [re.findall()] as findall
component [re.sub()] as sub
}
}
char_class --> quantifier : 重複匹配
quantifier --> anchor : 位置定位
group --> backref : 捕獲參考
match --> search : 模式搜尋
search --> findall : 全部匹配
findall --> sub : 取代操作
note right of lookahead
(?=...) 正向前瞻
(?!...) 負向前瞻
(?<=...) 正向後顧
end note
@enduml圖表翻譯:
此圖表示了自主代理的工作流程。首先,自主代理需要選擇合適的工具(B),然後執行任務(C)。接下來,需要評估結果(D),並根據評估結果進行調整和最佳化(E)。
從技術架構視角來看,賦予自主代理記憶和工具使用能力,是邁向通用人工智慧的關鍵一步。本文深入探討瞭如何利用正規表示式提取代理的動作和輸入,如何運用LLM解決問題並從其輸出中提取最終答案,以及如何建立和使用工具來增強LLM的能力。分析顯示,正規表示式的精確匹配能力確保了代理行為的可控性和可靠性,而工具的引入則顯著擴充套件了LLM的應用範圍,使其能處理更複雜的任務。然而,LLM的回應錯誤處理和工具整合的最佳實踐仍需進一步探索。展望未來,預期會有更多標準化工具和框架出現,簡化工具的建立和整合流程,並提升代理在不同領域的效能。玄貓認為,自主代理的發展仍處於早期階段,但其潛力巨大,值得持續投入研究和開發,特別是在工具標準化和錯誤處理機制方面。技術團隊應著重於提升代理的魯棒性和可靠性,才能真正釋放自主代理的巨大潛力。