AI大模型實(shí)戰(zhàn)篇:AI Agent設(shè)計(jì)模式 – REWOO
本文將介紹一種創(chuàng)新的優(yōu)化方法——REWOO,它通過分離推理與觀察、采用模塊化設(shè)計(jì),顯著提升了效率并降低了Token消耗。然而,REWOO的成功實(shí)施離不開精準(zhǔn)的規(guī)劃能力。
在上篇文章《AI大模型實(shí)戰(zhàn)篇:AI Agent設(shè)計(jì)模式 – ReAct》中,風(fēng)叔結(jié)合原理和具體源代碼,詳細(xì)介紹了ReAct這種非常有效的AI Agent設(shè)計(jì)模式。但是ReAct模式有一個(gè)非常突出的問題,就是冗余計(jì)算,冗余會(huì)導(dǎo)致過多的計(jì)算開銷和過長的Token使用。
在本篇文章中,風(fēng)叔介紹一種優(yōu)化ReAct冗余問題的方法,REWOO。
一、REWOO的概念
REWOO的全稱是Reason without Observation,是相對ReAct中的Observation 來說的。它旨在通過以下方式改進(jìn) ReACT 風(fēng)格的Agent架構(gòu):
第一,通過生成一次性使用的完整工具鏈來減少token消耗和執(zhí)行時(shí)間,因?yàn)镽eACT模式的Agent架構(gòu)需要多次帶有冗余前綴的 LLM 調(diào)用;
第二,簡化微調(diào)過程。由于規(guī)劃數(shù)據(jù)不依賴于工具的輸出,因此可以在不實(shí)際調(diào)用工具的情況下對模型進(jìn)行微調(diào)。
ReWOO 架構(gòu)主要包括三個(gè)部分:
- Planner:規(guī)劃器,負(fù)責(zé)將任務(wù)分解并制定包含多個(gè)相互關(guān)聯(lián)計(jì)劃的藍(lán)圖,每個(gè)計(jì)劃都分配給Worker執(zhí)行。
- Worker:執(zhí)行器,根據(jù)規(guī)劃器提供的藍(lán)圖,使用外部工具獲取更多證據(jù)或者其他具體動(dòng)作。
- Solver:合并器,將所有計(jì)劃和證據(jù)結(jié)合起來,形成對原始目標(biāo)任務(wù)的最終解決方案。
下圖是REWOO的原理:
- Planner接收來自用戶的輸入,輸出詳細(xì)的計(jì)劃Task List,Task List由多個(gè)Plan(Reason)和 Execution(Tool[arguments for tool])組成;
- Worker接收Task List,循環(huán)執(zhí)行完成task;
- Woker將所有任務(wù)的執(zhí)行結(jié)果同步給Solver,Solver將所有的計(jì)劃和執(zhí)行結(jié)果整合起來,形成最終的答案輸出給用戶。
詳細(xì)對比一下ReAct和REWOO,如下圖所示。
左側(cè)是ReAct方法,當(dāng)User輸入Task后,把上下文Context和可能的樣本Example輸入到LLM中,LLM會(huì)調(diào)用一個(gè)目標(biāo)工具Tool,從而產(chǎn)生想法Thought,行動(dòng)Action,觀察Observation。由于拆解后的下一次循環(huán)也需要調(diào)用LLM,又會(huì)調(diào)用新的工具Tool,產(chǎn)生新的Thought,Action,Observation。如果這個(gè)步驟變得很長,就會(huì)導(dǎo)致巨大的重復(fù)計(jì)算和開銷。
右側(cè)ReWOO的方法,計(jì)劃器Planner把任務(wù)進(jìn)行分解,分解的依據(jù)是它們內(nèi)部哪些用同類Tool,就把它分成同一類。在最開始,依舊是User輸入Task,模型把上下文Context和Examplar進(jìn)行輸入。這里與先前有所不同的是,輸入到Planner中,進(jìn)行分解,然后調(diào)用各自的工具Tool。在得到了所有的Tool的輸出后,生成計(jì)劃結(jié)果Plan和線索,放到Solver進(jìn)行總結(jié),然后生成回答。這個(gè)過程只調(diào)用了兩次LLM。
二、REWOO的實(shí)現(xiàn)過程
下面,風(fēng)叔通過實(shí)際的源碼,詳細(xì)介紹REWOO模式的實(shí)現(xiàn)方法。在手機(jī)端閱讀源代碼的體驗(yàn)不太好,建議大家在PC端打開。
第一步 構(gòu)建Planner
Planner的作用是根據(jù)用戶輸入,輸出詳細(xì)的Task List。
首先需要給Planner規(guī)定Prompt模板,包括可以使用的Tools,以及Task List的規(guī)范。在下面的例子中,我們告訴Planner,“對于目標(biāo)任務(wù),要制定可以逐步解決問題的計(jì)劃。對于每個(gè)計(jì)劃,要指出哪個(gè)外部工具以及工具輸入來檢索證據(jù),并將證據(jù)存儲(chǔ)到變量 #E 中,以供后續(xù)工具調(diào)用”。在工具層面,我們定義了兩個(gè)工具,google search和LLM。
from langchain_openai import ChatOpenAI
model=ChatOpenAI(temperature=0)
prompt = “””For the following task, make plans that can solve the problem step by step. For each plan, indicate which external tool together with tool input to retrieve evidence. You can store the evidence into a variable #E that can be called by later tools. (Plan, #E1, Plan, #E2, Plan, …)
Tools can be one of the following:
(1) Google[input]: Worker that searches results from Google. Useful when you need to find shortand succinct answers about a specific topic. The input should be a search query.
(2) LLM[input]: A pretrained LLM like yourself. Useful when you need to act with generalworld knowledge and common sense. Prioritize it when you are confident in solving the problemyourself. Input can be any instruction.
For example,Task: Thomas, Toby, and Rebecca worked a total of 157 hours in one week. Thomas worked xhours. Toby worked 10 hours less than twice what Thomas worked, and Rebecca worked 8 hoursless than Toby. How many hours did Rebecca work?
Plan: Given Thomas worked x hours, translate the problem into algebraic expressions and solvewith Wolfram Alpha.
#E1 = WolframAlpha[Solve x + (2x ? 10) + ((2x ? 10) ? 8) = 157]
Plan: Find out the number of hours Thomas worked.
#E2 = LLM[What is x, given #E1]
Plan: Calculate the number of hours Rebecca worked.
#E3 = Calculator[(2 ? #E2 ? 10) ? 8]
Begin!
Describe your plans with rich details. Each Plan should be followed by only one #E.Task: {task}”””
task = “what is the hometown of the 2024 australian open winner”
result = model.invoke(prompt.format(task=task))
print(result.content)
下面是根據(jù)給定的問題,Planner輸出的Task List。可以看到,Planner按照Prompt的要求給出了計(jì)劃的每個(gè)步驟,以及需要調(diào)用的工具。
Plan: Use Google to search for the 2024 Australian Open winner.
#E1 = Google[2024 Australian Open winner]
Plan: Retrieve the name of the 2024 Australian Open winner from the search results.
#E2 = LLM[What is the name of the 2024 Australian Open winner, given #E1]
Plan: Use Google to search for the hometown of the 2024 Australian Open winner.
#E3 = Google[hometown of 2024 Australian Open winner, given #E2]
Plan: Retrieve the hometown of the 2024 Australian Open winner from the search results.
#E4 = LLM[What is the hometown of the 2024 Australian Open winner, given #E3]
因?yàn)槭褂昧薒angGraph,為了將Planner連接到圖表,我們將創(chuàng)建一個(gè) get_plan 節(jié)點(diǎn),該節(jié)點(diǎn)接受 ReWOO 狀態(tài)并返回steps和 plan_string 字段。
import refrom langchain_core.prompts
import ChatPromptTemplate
# Regex to match expressions of the form E#… = …[…]
regex_pattern = r”Plan:s*(.+)s*(#Ed+)s*=s*(w+)s*[([^]]+)]”
prompt_template = ChatPromptTemplate.from_messages([(“user”, prompt)])
planner = prompt_template | model
def get_plan(state: ReWOO):
task = state[“task”]
result = planner.invoke({“task”: task})
# Find all matches in the sample text
matches = re.findall(regex_pattern, result.content)
return {“steps”: matches, “plan_string”: result.content}
第二步 構(gòu)建Worker
Worker負(fù)責(zé)接收Task List并按順序使用工具執(zhí)行任務(wù)。下面實(shí)例化搜索引擎,并定義工具執(zhí)行節(jié)點(diǎn)。
from langchain_community.tools.tavily_search import TavilySearchResults
search = TavilySearchResults()
def _get_current_task(state: ReWOO):
if state[“results”] is None:
return 1
if len(state[“results”]) == len(state[“steps”]):
return None
else:
return len(state[“results”]) + 1
def tool_execution(state: ReWOO):
“””Worker node that executes the tools of a given plan.”””
_step = _get_current_task(state)
_, step_name, tool, tool_input = state[“steps”][_step – 1]
_results = state[“results”] or {}
for k, v in _results.items():
tool_input = tool_input.replace(k, v)
if tool == “Google”:
result = search.invoke(tool_input)
elif tool == “LLM”:
result = model.invoke(tool_input)
else:
raise ValueError
_results[step_name] = str(result)
return {“results”: _results}
第三步 構(gòu)建Solver
Solver接收完整的計(jì)劃,并根據(jù)來自Worker的工具調(diào)用結(jié)果,生成最終響應(yīng)。
我們給Solver的Prompt很簡單,“根據(jù)上面提供的證據(jù),解決問題或任務(wù),直接回答問題,不要多說”。
solve_prompt = “””Solve the following task or problem. To solve the problem, we have made step-by-step Plan and retrieved corresponding Evidence to each Plan. Use them with caution since long evidence might contain irrelevant information.{plan}
Now solve the question or task according to provided Evidence above. Respond with the answerdirectly with no extra words.
Task: {task}
Response:”””
def solve(state: ReWOO):
plan = “”
for _plan, step_name, tool, tool_input in state[“steps”]:
_results = state[“results”] or {}
for k, v in _results.items():
tool_input = tool_input.replace(k, v)
step_name = step_name.replace(k, v)
plan += f”Plan: {_plan}n{step_name} = {tool}[{tool_input}]”
prompt = solve_prompt.format(plan=plan, task=state[“task”])
result = model.invoke(prompt)
return {“result”: result.content}
第四步 構(gòu)建Graph
下面,我們構(gòu)建流程圖,將Planner、Worker、Solver等節(jié)點(diǎn)添加進(jìn)來,執(zhí)行并輸出結(jié)果。
def _route(state):
_step = _get_current_task(state)
if _step is None:
# We have executed all tasks
return “solve”
else:
# We are still executing tasks, loop back to the “tool” node
return “tool”
from langgraph.graph import END, StateGraph, START
graph = StateGraph(ReWOO)
graph.add_node(“plan”, get_plan)
graph.add_node(“tool”, tool_execution)
graph.add_node(“solve”, solve)
graph.add_edge(“plan”, “tool”)
graph.add_edge(“solve”, END)
graph.add_conditional_edges(“tool”, _route)
graph.add_edge(START, “plan”)
app = graph.compile()
for s in app.stream({“task”: task}):
print(s)
print(“—“)
下圖詳細(xì)介紹了Planner、Worker和Solver的協(xié)作流程。
三、總結(jié)
相比ReAct,ReWOO 的創(chuàng)新點(diǎn)主要包括以下幾個(gè)方面:
- 分離推理與觀察:ReWOO 將推理過程與使用外部工具的過程分開,避免了在依賴觀察的推理中反復(fù)提示的冗余問題,從而大幅減少了 Token 的消耗。
- 模塊化設(shè)計(jì):ReWOO 使用模塊化框架,通過planer、worker和solver的分工合作,提高了系統(tǒng)的擴(kuò)展性和效率。
- 效率提升:實(shí)驗(yàn)結(jié)果表明,REWOO不僅提升了準(zhǔn)確率,還顯著降低token消耗。
- 工具調(diào)用的魯棒性:ReWOO 在工具失效的情況下表現(xiàn)出更高的魯棒性,這意味著即使某些工具無法返回有效證據(jù),ReWOO 仍能通過合理的計(jì)劃生成和證據(jù)整合,提供有效的解決方案。
但是,REWOO的缺陷在于,非常依賴于Planner的規(guī)劃能力,如果規(guī)劃有誤,則后續(xù)所有的執(zhí)行都會(huì)出現(xiàn)錯(cuò)誤。尤其是對于復(fù)雜任務(wù),很難在初始階段就制定合理且完備的計(jì)劃清單。
因此,如果要提升Agent的準(zhǔn)確率,需要有規(guī)劃調(diào)整機(jī)制,即在執(zhí)行的過程中,根據(jù)環(huán)境反饋,不斷調(diào)整計(jì)劃。這就是下一篇將要介紹的AI Agent設(shè)計(jì)模式,Plan & Execute。
作者:風(fēng)叔,微信公眾號:風(fēng)叔云
本文由@風(fēng)叔 原創(chuàng)發(fā)布于人人都是產(chǎn)品經(jīng)理,未經(jīng)作者許可,禁止轉(zhuǎn)載。
題圖來自Unsplash,基于CC0協(xié)議。
該文觀點(diǎn)僅代表作者本人,人人都是產(chǎn)品經(jīng)理平臺(tái)僅提供信息存儲(chǔ)空間服務(wù)。
動(dòng)態(tài)的work flow?
將復(fù)雜的任務(wù)分解成簡單、可執(zhí)行的步驟,從而確保了系統(tǒng)的高效運(yùn)行。對未來很多AI工具可以帶來很多啟發(fā)。