AI大模型實(shí)戰(zhàn)篇:AI Agent設(shè)計(jì)模式,ReAct
隨著人工智能技術(shù)的不斷進(jìn)步,AI Agent設(shè)計(jì)模式逐漸成為研究和應(yīng)用的熱點(diǎn)。ReAct模式作為AI Agent設(shè)計(jì)模式的起點(diǎn),以其模擬人類(lèi)思考和行動(dòng)過(guò)程的特點(diǎn),為各種智能應(yīng)用提供了一種有效的實(shí)現(xiàn)途徑。
在《大佬們都在關(guān)注的AI Agent,到底是什么?用5W1H分析框架拆解AI Agent(下篇)》中,風(fēng)叔簡(jiǎn)單介紹了AI Agent的八種設(shè)計(jì)模式。對(duì)于這八種設(shè)計(jì)模式,風(fēng)叔整理了一張圖,來(lái)闡明它們之間的關(guān)系。
ReAct模式最早出現(xiàn)的Agent設(shè)計(jì)模式,目前也是應(yīng)用最廣泛的。從ReAct出發(fā),有兩條發(fā)展路線:
一條更偏重Agent的規(guī)劃能力,包括REWOO、Plan & Execute、LLM Compiler。
另一條更偏重反思能力,包括Basic Reflection、Reflexion、Self Discover、LATS。
在后續(xù)文章中,風(fēng)叔將沿著上圖的脈絡(luò),結(jié)合產(chǎn)品流程和源代碼,詳細(xì)介紹這八種AI Agent設(shè)計(jì)模式。
為什么選擇結(jié)合源代碼呢?因?yàn)樵贏I大模型時(shí)代,很多的概念和方法都太新了。只有結(jié)合源代碼,產(chǎn)品經(jīng)理才能真正理解背后的原理和邏輯,才能知道什么能做,什么不能做,AI的邊界在哪里,以及該如何與人類(lèi)經(jīng)驗(yàn)配合。
下面,我們先從ReAct模式開(kāi)始。
一、ReAct的概念
ReAct的概念來(lái)自論文《ReAct: Synergizing Reasoning and Acting in Language Models》,這篇論文提出了一種新的方法,通過(guò)結(jié)合語(yǔ)言模型中的推理(reasoning)和行動(dòng)(acting)來(lái)解決多樣化的語(yǔ)言推理和決策任務(wù)。ReAct 提供了一種更易于人類(lèi)理解、診斷和控制的決策和推理過(guò)程。
它的典型流程如下圖所示,可以用一個(gè)有趣的循環(huán)來(lái)描述:思考(Thought)→ 行動(dòng)(Action)→ 觀察(Observation),簡(jiǎn)稱(chēng)TAO循環(huán)。
- 思考(Thought):面對(duì)一個(gè)問(wèn)題,我們需要進(jìn)行深入的思考。這個(gè)思考過(guò)程是關(guān)于如何定義問(wèn)題、確定解決問(wèn)題所需的關(guān)鍵信息和推理步驟。
- 行動(dòng)(Action):確定了思考的方向后,接下來(lái)就是行動(dòng)的時(shí)刻。根據(jù)我們的思考,采取相應(yīng)的措施或執(zhí)行特定的任務(wù),以期望推動(dòng)問(wèn)題向解決的方向發(fā)展。
- 觀察(Observation):行動(dòng)之后,我們必須仔細(xì)觀察結(jié)果。這一步是檢驗(yàn)我們的行動(dòng)是否有效,是否接近了問(wèn)題的答案。
- 循環(huán)迭代
如果觀察到的結(jié)果并不匹配我們預(yù)期的答案,那么就需要回到思考階段,重新審視問(wèn)題和行動(dòng)計(jì)劃。這樣,我們就開(kāi)始了新一輪的TAO循環(huán),直到找到問(wèn)題的解決方案。
和ReAct相對(duì)應(yīng)的是Reasoning-Only和Action-Only。在Reasoning-Only的模式下,大模型會(huì)基于任務(wù)進(jìn)行逐步思考,并且不管有沒(méi)有獲得結(jié)果,都會(huì)把思考的每一步都執(zhí)行一遍。在Action-Only的模式下,大模型就會(huì)處于完全沒(méi)有規(guī)劃的狀態(tài)下,先進(jìn)行行動(dòng)再進(jìn)行觀察,基于觀察再調(diào)整行動(dòng),導(dǎo)致最終結(jié)果不可控。
假設(shè)我們正在構(gòu)建一個(gè)智能助手,用于管理我們的日程安排。
在reason-only模式中,智能助手專(zhuān)注于分析和推理,但不直接采取行動(dòng)。
- 你告訴智能助手:“我明天有個(gè)會(huì)議?!?/li>
- 智能助手分析這句話,確定明天的會(huì)議時(shí)間、地點(diǎn)等細(xì)節(jié)。
- 它可能會(huì)提醒你:“明天下午3點(diǎn)有個(gè)會(huì)議,在公司會(huì)議室?!?/li>
在action-only模式中,智能助手專(zhuān)注于執(zhí)行任務(wù),但不做深入的推理或分析。
- 你告訴智能助手:“把我明天的會(huì)議改到上午10點(diǎn)?!?/li>
- 智能助手立即執(zhí)行這個(gè)任務(wù),將會(huì)議時(shí)間修改為上午10點(diǎn)。
- 它可能會(huì)簡(jiǎn)單確認(rèn):“您的會(huì)議已改到明天上午10點(diǎn)?!?/li>
在ReAct模式中,智能助手結(jié)合推理和行動(dòng),形成一個(gè)循環(huán)的感知-動(dòng)作循環(huán)。不僅分析了你的需求(推理),還實(shí)際修改了日程安排(行動(dòng))。
- 你告訴智能助手:“我明天有個(gè)會(huì)議,但我想提前到上午10點(diǎn)。”
- 智能助手首先分析這句話,確定會(huì)議的原始時(shí)間和地點(diǎn)(感知階段)。
- 然后,它更新你的日程安排,將會(huì)議時(shí)間改為上午10點(diǎn)(決策和動(dòng)作執(zhí)行階段)。
- 最后,智能助手確認(rèn)修改,并提供額外的信息:“您的會(huì)議已成功改到明天上午10點(diǎn)。提醒您,會(huì)議地點(diǎn)不變。
二、ReAct的實(shí)現(xiàn)過(guò)程
下面,風(fēng)叔通過(guò)實(shí)際的源碼,詳細(xì)介紹ReAct模式的實(shí)現(xiàn)方法。在手機(jī)端閱讀源代碼的體驗(yàn)不太好,建議大家在PC端打開(kāi)。
大家可以私信風(fēng)叔,或者在評(píng)論區(qū)留言“ReAct源碼”,獲取ReAct設(shè)計(jì)模式的示例源代碼。
第一步 準(zhǔn)備Prompt模板
在實(shí)現(xiàn)ReAct模式的時(shí)候,首先需要設(shè)計(jì)一個(gè)清晰的Prompt模板,主要包含以下幾個(gè)元素:
- 思考(Thought):這是推理過(guò)程的文字展示,闡明我們想要LLM幫我們做什么,為了達(dá)成目標(biāo)的前置條件是什么
- 行動(dòng)(Action):根據(jù)思考的結(jié)果,生成與外部交互的指令文字,比如需要LLM進(jìn)行外部搜索
- 行動(dòng)參數(shù)(Action Input):用于展示LLM進(jìn)行下一步行動(dòng)的參數(shù),比如LLM要進(jìn)行外部搜索的話,行動(dòng)參數(shù)就是搜索的關(guān)鍵詞。主要是為了驗(yàn)證LLM是否能提取準(zhǔn)確的行動(dòng)參數(shù)
- 觀察(Observation):和外部行動(dòng)交互之后得到的結(jié)果,比如LLM進(jìn)行外部搜索的話,那么觀察就是搜索的結(jié)果。
Prompt模板示例:
TOOL_DESC = """{name_for_model}: Call this tool to interact with the {name_for_human} API. What is the {name_for_human} API useful for? {description_for_model} Parameters: {parameters} Format the arguments as a JSON object."""
REACT_PROMPT = """Answer the following questions as best you can. You have access to the following tools:
{tool_descs}
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can be repeated zero or more times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Begin!
Question: {query}"""
第二步 構(gòu)建Agent
一個(gè)ReAct Agent需要定義好以下元素
- llm:背后使用的LLM大模型
- tools:后續(xù)會(huì)用到的Tools集合
- stop:什么情況下ReAct Agent停止循環(huán)
class LLMSingleActionAgent {
llm: AzureLLM
tools: StructuredTool[]
stop: string[]
private _prompt: string = '{input}'
constructor({ llm, tools = [], stop = [] }: LLMSingleActionAgentParams) {
this.llm = llm
this.tools = tools
if (stop.length > 4)
throw new Error('up to 4 stop sequences')
this.stop = stop
}
}
第三步 定義Tools
Tools有兩個(gè)最重要的參數(shù),name和description。
Name就是函數(shù)名,description是工具的自然語(yǔ)言描述,LLM 根據(jù)description來(lái)決定是否需要使用該工具。工具的描述應(yīng)該非常明確,說(shuō)明工具的功能、使用的時(shí)機(jī)以及不適用的情況。
export abstract class StructuredTool {
name: string
description: string
constructor(name: string, description: string) {
this.name = name
this.description = description
}
abstract call(arg: string, config?: Record<string, any>): Promise<string>
getSchema(): string {
return `${this.declaration} | ${this.name} | ${this.description}`
}
abstract get declaration(): string
}
我們先簡(jiǎn)單地將兩個(gè)描述信息拼接一下,為Agent提供4個(gè)算數(shù)工具:
1. Addition Tool: A tool for adding two numbers
2. Subtraction Tool: A tool for subtracting two numbers
3. Division Tool: A tool for dividing two numbers
4.MultiplicationTool: Atoolformultiplyingtwonumbers
一個(gè)很有意思的事情是,這幾個(gè)算數(shù)工具函數(shù)并不需要實(shí)際的代碼,大模型可以僅靠自身的推理能力就完成實(shí)際的算數(shù)運(yùn)算。當(dāng)然,對(duì)于更復(fù)雜的工具函數(shù),還是需要進(jìn)行詳細(xì)的代碼構(gòu)建。
第四步 循環(huán)執(zhí)行
執(zhí)行器executor是在Agent的運(yùn)行時(shí),協(xié)調(diào)各個(gè)組件并指導(dǎo)操作。還記得ReAct模式的流程嗎?Thought、Action、Observation、循環(huán),Executor的作用就是執(zhí)行這個(gè)循環(huán)。
class AgentExecutor {
agent: LLMSingleActionAgent
tools: StructuredTool[] = []
maxIterations: number = 15
constructor(agent: LLMSingleActionAgent) {
this.agent = agent
}
addTool(tools: StructuredTool | StructuredTool[]) {
const _tools = Array.isArray(tools) ? tools : [tools]
this.tools.push(..._tools)
}
}
executor會(huì)始終進(jìn)行如下事件循環(huán)直到目標(biāo)被解決了或者思考迭代次數(shù)超過(guò)了最大次數(shù):
- 根據(jù)之前已經(jīng)完成的所有步驟(Thought、Action、Observation)和 目標(biāo)(用戶的問(wèn)題),規(guī)劃出接下來(lái)的Action(使用什么工具以及工具的輸入)
- 檢測(cè)是否已經(jīng)達(dá)成目標(biāo),即Action是不是ActionFinish。是的話就返回結(jié)果,不是的話說(shuō)明還有行動(dòng)要完成
- 根據(jù)Action,執(zhí)行具體的工具,等待工具返回結(jié)果。工具返回的結(jié)果就是這一輪步驟的Observation
- 保存當(dāng)前步驟到記憶上下文,如此反復(fù)
async call(input: promptInputs): Promise<AgentFinish> {
const toolsByName = Object.fromEntries(
this.tools.map(t => [t.name, t]),
)
const steps: AgentStep[] = []
let iterations = 0
while (this.shouldContinue(iterations)) {
const output = await this.agent.plan(steps, input)
console.log(iterations, output)
// Check if the agent has finished
if ('returnValues' in output)
return output
const actions = Array.isArray(output)
? output as AgentAction[]
: [output as AgentAction]
const newSteps = await Promise.all(
actions.map(async (action) => {
const tool = toolsByName[action.tool]
if (!tool)
throw new Error(`${action.tool} is not a valid tool, try another one.`)
const observation = await tool.call(action.toolInput)
return { action, observation: observation ?? '' }
}),
)
steps.push(...newSteps)
iterations++
}
return {
returnValues: { output: 'Agent stopped due to max iterations.' },
log: '',
}
}
第五步 實(shí)際運(yùn)行
我們提出一個(gè)問(wèn)題,看看Agent怎么通過(guò)ReAct方式進(jìn)行解決。 “一種減速機(jī)的價(jià)格是750元,一家企業(yè)需要購(gòu)買(mǎi)12臺(tái)。每臺(tái)減速機(jī)運(yùn)行一小時(shí)的電費(fèi)是0.5元,企業(yè)每天運(yùn)行這些減速機(jī)8小時(shí)。請(qǐng)計(jì)算企業(yè)購(gòu)買(mǎi)及一周運(yùn)行這些減速機(jī)的總花費(fèi)。”
describe('agent', () => {
const llm = new AzureLLM({
apiKey: Config.apiKey,
model: Config.model,
})
const agent = new LLMSingleActionAgent({ llm })
agent.setPrompt(REACT_PROMPT)
agent.addStop(agent.observationPrefix)
agent.addTool([new AdditionTool(), new SubtractionTool(), new DivisionTool(), new MultiplicationTool()])
const executor = new AgentExecutor(agent)
executor.addTool([new AdditionTool(), new SubtractionTool(), new DivisionTool(), new MultiplicationTool()])
it('test', async () => {
const res = await executor.call({ input: '一種減速機(jī)的價(jià)格是750元,一家企業(yè)需要購(gòu)買(mǎi)12臺(tái)。每臺(tái)減速機(jī)運(yùn)行一小時(shí)的電費(fèi)是0.5元,企業(yè)每天運(yùn)行這些減速機(jī)8小時(shí)。請(qǐng)計(jì)算企業(yè)購(gòu)買(mǎi)及一周運(yùn)行這些減速機(jī)的總花費(fèi)。' })
expect(res).toMatchInlineSnapshot(`
{
"log": "Final Answer: The total cost of purchasing and operating the gearboxes for a week is 9336 yuan.",
"returnValues": {
"output": "The total cost of purchasing and operating the gearboxes for a week is 9336 yuan.",
},
}
`)
}, { timeout: 50000 })
})
我們來(lái)看一下Agent的輸出,以及Agent在這個(gè)過(guò)程,是如何思考和行動(dòng)的??梢钥吹?,通過(guò)Thought、Action、Observation的循環(huán),AI Agent很好地一步步完成最終答案的輸出。
Question:一種減速機(jī)的價(jià)格是750元,一家企業(yè)需要購(gòu)買(mǎi)12臺(tái)。每臺(tái)減速機(jī)運(yùn)行一小時(shí)的電費(fèi)是0.5元,企業(yè)每天運(yùn)行這些減速機(jī)8小時(shí)。請(qǐng)計(jì)算企業(yè)購(gòu)買(mǎi)及一周運(yùn)行這些減速機(jī)的總花費(fèi)
Thought:I need to calculate the total cost of purchasing and operating the gearboxes for a week.
Action: Multiplication Tool
Action Input: [750, 12]
Observation: 9000
Thought: Now I need to calculate the cost of operating the gearboxes for a day.
Action: Multiplication Tool
ActionInput:[0.5,8,12]
Observation: 48
Thought: Now I need to calculate the cost of operating the gearboxes for a week.
Action: Multiplication Tool
Action Input: [48, 7]
Observation: 336
Thought: Now I need to calculate the total cost of purchasing and operating the gearboxes for a week.
Action: Addition Tool
Action Input: [9000, 336]
Observation: 9336
總結(jié)
在AI Agent的多種實(shí)現(xiàn)模式中,ReAct模式是最早出現(xiàn)、也是目前使用最廣泛的模式。ReAct的核心思想就是模擬人思考和行動(dòng)的過(guò)程,通過(guò)Thought、Action、Observation的循環(huán),一步步解決目標(biāo)問(wèn)題。
ReAct模式也存在很多的不足:
- 首先是LLM大模型的通病,即產(chǎn)出內(nèi)容不穩(wěn)定,不僅僅是輸出內(nèi)容存在波動(dòng),也體現(xiàn)在對(duì)復(fù)雜問(wèn)題的分析,解決上存在一定的波動(dòng)
- 然后是成本,采用ReAct方式,我們是無(wú)法控制輸入內(nèi)容的。因?yàn)樵谌蝿?wù)提交給LLM后,LLM對(duì)任務(wù)的拆解、循環(huán)次數(shù)是不可控的。因此存在一種可能性,過(guò)于復(fù)雜的任務(wù)導(dǎo)致Token過(guò)量消耗。
- 最后是響應(yīng)時(shí)間,比起大部分API接口毫秒級(jí)的響應(yīng),LLM響應(yīng)時(shí)間是秒級(jí)以上。在ReAct模式下,這個(gè)時(shí)間變得更加不可控。因?yàn)闊o(wú)法確定需要拆分多少步驟,需要訪問(wèn)多少次LLM模型。因此在在秒級(jí)接口響應(yīng)的背景下,做成同步接口顯然是不合適的,需要采用異步的方式。而異步方式,又會(huì)影響用戶體驗(yàn),對(duì)應(yīng)用場(chǎng)景的選擇又造成了限制。
但是無(wú)論如何,ReAct框架提出了一種非常好的思路,讓現(xiàn)有的應(yīng)用得到一次智能化的進(jìn)化機(jī)會(huì)?,F(xiàn)在很多場(chǎng)景已經(jīng)有了非常成熟的ReAct Agent應(yīng)用,比如智能客服、知識(shí)助手、個(gè)性化營(yíng)銷(xiāo)、智能銷(xiāo)售助理等等。
在下一篇文章中,風(fēng)叔將介紹另一種AI Agent設(shè)計(jì)模式,REWOO。
作者:風(fēng)叔,微信公眾號(hào):風(fēng)叔云
本文由@風(fēng)叔 原創(chuàng)發(fā)布于人人都是產(chǎn)品經(jīng)理,未經(jīng)作者許可,禁止轉(zhuǎn)載。
題圖來(lái)自Unsplash,基于CC0協(xié)議。
該文觀點(diǎn)僅代表作者本人,人人都是產(chǎn)品經(jīng)理平臺(tái)僅提供信息存儲(chǔ)空間服務(wù)。
- 目前還沒(méi)評(píng)論,等你發(fā)揮!