使用 Claude 3.5 和 Python 構(gòu)建 ReAct AI Agent
Reason+Act (ReAct) Agent 能夠通過將思維鏈推理與外部工具訪問和迭代求解能力相結(jié)合,來執(zhí)行復(fù)雜的推理任務(wù)。
ReAct Agent的工作原理
ReAct Agent的核心組件是系統(tǒng)提示,它定義了Agent的整體行為(我們稍后將看到一個示例)。
處理從用戶提示開始,用戶提示請求解決某個問題。系統(tǒng)提示指示Agent對問題進行推理,并在適當(dāng)?shù)臅r候選擇一個外部工具來幫助解決問題。
Agent調(diào)用工具,并在收到響應(yīng)后決定是否需要進一步處理。如果需要,它可以再次請求幫助。Agent會在推理和行動(調(diào)用工具)之間迭代,直到它解決了問題,然后將結(jié)果返回給用戶。
下圖說明了這個過程。
ReAct Agent過程
案例研究
也許,解釋 ReAct Agent如何工作的最簡單方法是使用一個簡單的案例研究。以下是一個Agent解決簡單算術(shù)問題的示例響應(yīng)。
我們從問題“20 * 15 等于多少”開始,Agent開始“大聲思考”。
20 * 15 等于多少
思考: 這是一個簡單的乘法問題,我可以使用 calculate 操作來解決。
行動: calculate: 20 * 15
觀察: 300
答案: 20 * 15 的結(jié)果是 300。
Agent的響應(yīng)前面帶有 思考 標(biāo)簽,它在其中推理應(yīng)該做什么。在本例中,它決定使用 calculate
下一個響應(yīng)前面帶有 行動 標(biāo)簽,我們看到Agent使用 calculate 工具來獲取答案。之后,我們看到 觀察,這是來自工具的響應(yīng)。
最后的 答案 是Agent根據(jù)原始問題和 calculate 工具的輸出創(chuàng)建的響應(yīng)的結(jié)果。
從表面上看,這里并沒有什么特別不尋常的地方——除了Agent使用了一個我們提供的工具。
而這正是 ReAct Agent的關(guān)鍵:Agent使用外部工具進行推理,然后采取行動。
迭代
當(dāng)Agent決定它還沒有得出結(jié)論,需要經(jīng)過另一個推理/行動序列時,事情就變得更有趣了。Agent可以迭代推理/行動序列,直到得出有效結(jié)論。
上面的例子很簡單,但它向您展示了事件的基本序列。
如果我們嘗試更復(fù)雜的查詢,我們可以看到迭代在實踐中的應(yīng)用。
我問了Agent以下問題:“_籃球隊和曲棍球隊的球員人數(shù)相乘的結(jié)果是多少?_”。
為了回答這個問題,Agent需要找出每項運動的球員人數(shù),然后將它們相乘。它可以使用 calculate
下面我們看到Agent在得出令人滿意的答案之前,三次經(jīng)過了思考-行動-觀察序列的方式。
要回答這個問題,我需要找出籃球隊和曲棍球隊的球員人數(shù),然后將這些數(shù)字相乘。讓我們從籃球開始。
思考: 我將先查閱籃球隊的球員人數(shù)。
行動: wikipedia: 籃球
觀察: 籃球是一項團隊運動。每支球隊在球場上同時有五名球員,盡管球隊可能在替補席上有替補球員。
思考: 現(xiàn)在我知道一支籃球隊在球場上同時有 5 名球員,我需要找出曲棍球隊的球員人數(shù)。
行動: wikipedia: 曲棍球
觀察: 曲棍球是一項團隊運動,每支球隊在球場上同時有 10 名球員:3 名進攻球員、3 名中場球員、3 名防守球員和 1 名守門員。但是,在不同版本的比賽中,人數(shù)可能會有所不同。例如,室內(nèi)曲棍球的球員人數(shù)較少。
思考: 現(xiàn)在我已經(jīng)知道兩種運動的球員人數(shù),我可以計算結(jié)果了。
行動: calculate: 5 * 10
觀察: 50
答案: 將籃球隊的人數(shù)(5)乘以曲棍球隊的人數(shù)(10)的結(jié)果是 50。
如果您通讀輸出內(nèi)容,您會看到Agent如何在得出結(jié)果之前進行推理并咨詢工具,并且在這樣做的時候,它會隨著時間的推移積累知識。
代碼非常少
實現(xiàn) ReAct Agent所需的代碼出奇地少,因為大部分工作都在提示中完成。
所以讓我們先看看這個。
prompt = """
您在一個 Thought、Action、Observation、Answer 的循環(huán)中運行。
在循環(huán)結(jié)束時,您輸出一個 Answer
使用 Thought 描述您對所問問題的想法。
使用 Action 運行您可以使用的操作之一。
Observation 將是運行這些操作的結(jié)果。
Answer 將是分析 Observation 的結(jié)果。
您可以使用的操作是:
calculate:
例如 calculate: 4 * 7 / 3
運行計算并返回數(shù)字 - 使用 Python,因此如果需要,請務(wù)必使用浮點語法
wikipedia:
例如 wikipedia: Django
從維基百科搜索返回摘要
如果您可以使用維基百科查找內(nèi)容,請始終使用維基百科進行查找。
示例會話:
問題:法國的首都是什么?
思考:我應(yīng)該在維基百科上查找有關(guān)法國的信息
行動:wikipedia: 法國
然后您應(yīng)該調(diào)用適當(dāng)?shù)牟僮鞑?結(jié)果中確定答案
然后您輸出:
答案:法國的首都為巴黎
"""
提示的第一部分告訴 LLM 如何通過我們之前看到的標(biāo)記過程部分來解決問題,這些部分在循環(huán)中運行。
然后描述了 calculate 和 wikipedia
這個提示是一個簡單的示例,當(dāng)然僅用于演示目的。很明顯,該提示是為這個特定應(yīng)用程序設(shè)計的:工具的描述是硬編碼的,而在生產(chǎn)系統(tǒng)中,您希望能夠以編程方式擴展它們。(我們很快就會看到 calculate 是使用 Python 函數(shù) eval() 實現(xiàn)的。這是一個相當(dāng)糟糕的做法,因為它很容易受到代碼注入攻擊。)
代碼和提示的基本結(jié)構(gòu)是 Simon 的,但我對其進行了修改,以便使用 Anthropic 的 Claude 3.5 Sonnet LLM,并簡化了代碼和提示。
Claude 3.5
Claude Sonnet 3.5 是 Anthropic 最近發(fā)布的一個版本,在他們的 發(fā)布公告 中,他們聲明“Claude 3.5 Sonnet 提高了行業(yè)智能標(biāo)準(zhǔn),在廣泛的評估中優(yōu)于競爭對手模型和 Claude 3 Opus,具有我們中端模型 Claude 3 Sonnet 的速度和成本”。
為了說明這一點,Anthropic 擁有三個版本的 Claude LLM,從更便宜、更快的 Haiku 模型,到更智能但更昂貴的 Opus 模型。Sonnet 是介于兩者之間的模型,是唯一在撰寫本文時擁有 3.5 版本的模型。
我一直想看看 Claude,這似乎是一個很好的機會。
代碼從必要的導(dǎo)入開始:
import anthropic
import re
import httpx
這里沒有太多東西。Anthropic,當(dāng)然,用于 LLM,正則表達式和一個 HTTP 庫來訪問維基百科。
要運行代碼,您當(dāng)然需要一個 Anthropic 帳戶,他們會向您收取使用費。不過,它相當(dāng)便宜:Claude 3.5 sonnet 比之前的版本更便宜,而且更強大——我已經(jīng)在這里運行了代碼(以及更多代碼),只收取了幾美分的費用。
代碼首先創(chuàng)建一個客戶端,然后定義一個 Python 類來實現(xiàn)聊天機器人。與 OpenAI 不同,Claude 將系統(tǒng)提示與用戶或助手的提示分開,我們在實例化 ChatBot? 時初始化提示。__call__? 函數(shù)負責(zé)存儲用戶消息和來自聊天機器人的響應(yīng),并調(diào)用 execute 來運行Agent。
client = anthropic.Anthropic(api_key="YOUR API KEY HERE")
class ChatBot:
def __init__(self, system=""):
self.system = system
self.messages = []
def __call__(self, message):
self.messages.append({"role": "user", "content": message})
result = self.execute()
self.messages.append({"role": "assistant", "content": result})
return message
def execute(self):
message = client.messages.create(
model="claude-3-5-sonnet-20240620",
max_tokens=1000,
temperature=0,
system = self.system,
messages = self.messages
)
return message.content
下一步是定義一個 query() 函數(shù),它使用聊天機器人的實例。query 函數(shù)實現(xiàn)了一個循環(huán),該循環(huán)會一直持續(xù)到?jīng)]有更多操作(或者我們已經(jīng)達到最大迭代次數(shù))為止。該函數(shù)檢測操作并使用正則表達式提取操作的名稱。這些操作被調(diào)用,當(dāng)沒有更多操作時,聊天機器人消息將被返回。
action_re = re.compile('^Action: (\w+): (.*)$')
def query(question, max_turns=5):
i = 0
bot = ChatBot(prompt)
next_prompt = question
while i < max_turns:
i += 1
result = bot(next_prompt)
print(result)
actions = [action_re.match(a) for a in result.split('\n') if action_re.match(a)]
if actions:
# 有一個要運行的操作
action, action_input = actions[0].groups()
if action not in known_actions:
raise Exception("Unknown action: {}: {}".format(action, action_input))
print(" -- running {} {}".format(action, action_input))
observation = known_actions[action](action_input)
print("Observation:", observation)
next_prompt = "Observation: {}".format(observation)
else:
return bot.messages
現(xiàn)在我們需要定義操作函數(shù)(工具)wikipedia? 和 eval,并將對它們的引用存儲在一個字典中。
def wikipedia(q):
return httpx.get("https://en.wikipedia.org/w/api.php", params={
"action": "query",
"list": "search",
"srsearch": q,
"format": "json"
}).json()["query"]["search"][0]["snippet"]
def calculate(what):
return eval(what)
known_actions = {
"wikipedia": wikipedia,
"calculate": calculate
}
接下來是一個實用程序函數(shù),它打印出由機器人生成的最后一條消息。
def get_last_message():
for m in bot.messages[-1]['content'][0].text.split('\n'):
print(m)
最后,在完成所有這些步驟后,我們可以開始使用Agent。
query("What is 20 * 15")
get_last_message()
上面的代碼產(chǎn)生了我們在文章開頭看到的第一個例子,下面的代碼展示了 ReAct Agent如何迭代地執(zhí)行各種操作以得出有效結(jié)論的另一個例子。
這是一個示例,其中Agent必須迭代調(diào)用工具。在本例中,它只使用維基百科,但它必須智能地分析響應(yīng)才能得出答案。
query("What languages are spoken in Spain that are also spoken in France")
get_last_message()
西班牙和法國都使用哪些語言?
思考: 為了準(zhǔn)確地回答這個問題,我應(yīng)該查找有關(guān)西班牙和法國使用的語言的信息。我將首先檢查維基百科以獲取有關(guān)西班牙語言的信息。
行動: wikipedia: 西班牙語
觀察: 西班牙在邊境內(nèi)部使用多種語言和方言。西班牙的官方語言是西班牙語(也稱為卡斯蒂利亞語),大多數(shù)西班牙人使用這種語言。然而,在各個自治區(qū),有幾種共同的官方語言:
加泰羅尼亞語:在加泰羅尼亞、巴利阿里群島和瓦倫西亞自治區(qū)的部分地區(qū)使用(在那里被稱為瓦倫西亞語)。
加利西亞語:在加利西亞使用。
巴斯克語:在巴斯克地區(qū)和納瓦拉的部分地區(qū)使用。
奧克語(阿蘭語):在加泰羅尼亞的阿蘭谷使用。
其他公認(rèn)的語言包括阿拉貢語和阿斯圖里亞斯語。在不同的地區(qū),還使用著幾種西班牙語方言。
思考: 現(xiàn)在我已經(jīng)了解了西班牙的語言,我應(yīng)該檢查一下法國的語言,看看哪些語言重疊。
行動: wikipedia: 法語
觀察: 法國的官方語言是法語,占人口的 88%。然而,法國使用著幾種地區(qū)語言和方言:
奧克語:在法國南部使用。
布列塔尼語:一種凱爾特語言,在布列塔尼使用。
阿爾薩斯語:一種日耳曼語方言,在阿爾薩斯使用。
科西嘉語:在科西嘉島使用。
加泰羅尼亞語:在法國東比利牛斯省使用。
巴斯克語:在法國巴斯克地區(qū)使用。
其他地區(qū)語言包括法蘭克-普羅旺斯語、洛林弗蘭克語和各種油語。
思考: 通過比較西班牙和法國使用的語言,我可以識別出重疊的語言。
答案: 西班牙和法國都使用的語言是:
加泰羅尼亞語:在西班牙的部分地區(qū)(加泰羅尼亞、巴利阿里群島和瓦倫西亞)以及法國的東比利牛斯省使用。
巴斯克語:在西班牙的巴斯克地區(qū)和納瓦拉的部分地區(qū)使用,以及法國的巴斯克地區(qū)。
奧克語:在西班牙加泰羅尼亞的阿蘭谷被稱為阿蘭語,并在法國南部使用。
這三種語言在兩個國家都得到認(rèn)可和使用,盡管它們在西班牙和法國的官方地位和使用人數(shù)可能會有所不同。
上面的響應(yīng)展示了Agent為了得出合適的答案而經(jīng)過的合理過程。
我還嘗試了更復(fù)雜的問題,Agent似乎也能很好地處理這些問題(您可以在下載的代碼中看到更多示例)。
結(jié)論
本文介紹的代碼展示了 ReAct Agent的工作方式。它并不健壯,也不適合生產(chǎn)環(huán)境。但我希望您現(xiàn)在對 ReAct Agent的原理以及如何實現(xiàn)它們有了相當(dāng)好的理解。
請使用更復(fù)雜的示例嘗試代碼,并可能添加更多工具。我很樂意聽到您的實驗結(jié)果。
當(dāng)然,使用 Langchain 和 Llamaindex(例如)有更簡單的解決方案,我可能會在以后的文章中介紹它們。
本文轉(zhuǎn)載自 ??DevOpsAI??,作者:ReAct Agent
