Agent 規劃與推理:從 ReAct 到 Reflexion,讓 Agent 學會「邊想邊做邊反省」

Agent 規劃與推理:從 ReAct 到 Reflexion,讓 Agent 學會「邊想邊做邊反省」

今天要談的是所有 Agent 的地基:規劃(planning)與推理(reasoning)。一個 Agent 能調用多少工具不重要,重要的是它知不知道「下一步該做什麼」。Agent 會不會解決複雜問題,天花板就畫在這一層。這個領域有兩篇里程碑論文,一篇來自普林斯頓(Princeton),一篇在 NeurIPS 2023 發表,剛好示範了 Agent 能力的兩次躍升:先學會邊想邊做,再學會從錯誤中反省。

一、ReAct:思考與行動的交替迴圈

2022 年 10 月,普林斯頓大學姚順雨(Shunyu Yao)等人與 Google Brain 團隊發表了 ReAct(ReAct: Synergizing Reasoning and Acting in Language Models,arXiv:2210.03629,ICLR 2023),它只做了一件事:規定一個提示格式,讓 LLM 把「思考」與「行動」交替寫出來:

問題:2022 年世界盃冠軍是哪一國?首都為何?

思考(Thought):我需要先查出 2022 年世界盃冠軍。
行動(Action):Search[2022 年世界盃冠軍]
觀察(Observation):阿根廷隊在決賽擊敗法國奪冠。
思考(Thought):冠軍是阿根廷,首都為布宜諾斯艾利斯。
行動(Action):Finish[布宜諾斯艾利斯]

如圖一,這個 Thought→Action→Observation 的迴圈,解決了之前兩個極端的困境:純 Chain-of-Thought 會「想得很順但查無實據」(hallucination),純工具呼叫則是「做得很勤但不思考」(遇到意外就崩潰)。ReAct 讓推理引導下一步該查什麼,讓工具的回傳修正推理的方向——交替進行,互相校正。

實驗數據很直白:在 HotpotQA 多跳問答上,ReAct 比純 CoT 高出約 6 個百分點;把幻覺率從 56% 壓到 6%;在 ALFWorld 互動任務上,成功率從純行動基線的 45% 拉到 79%。更關鍵的是後續影響:今天所有主流框架的預設 Agent 迴圈(LangChain、AutoGen、OpenAI 的 function calling、Claude 的 tool use)骨子裡都是 ReAct——都是「想一下、做一下、看結果、再想一下」。

二、Reflexion:用語言代替梯度,讓 Agent 反省

ReAct 解決了「單次任務」的推理,但 Agent 做錯了怎麼辦?傳統強化學習要大量試錯加梯度更新,又貴又慢。2023 年 NeurIPS 的 Reflexion 論文(Reflexion: Language Agents with Verbal Reinforcement Learning,arXiv:2303.11366)提出一個漂亮的替代方案:不更新權重,用語言做強化學習。

如圖二,Reflexion 由三個角色組成一個迴圈:

  1. Actor:就是 ReAct Agent,負責產生 Thought / Action / Observation 軌跡去解題。
  2. Evaluator:評判結果對錯(可以是精確匹配、單元測試,或另一個 LLM 擔任裁判)。
  3. Self-Reflection:失敗時,把「哪裡做錯了」寫成一段文字反思,存進情節記憶緩衝區(episodic memory buffer)。

下一次嘗試時,這些反思文字會被塞進 prompt,Agent 等於帶著「上次的教訓」重新上場。幾輪下來,Agent 靠「跟自己對話」把答案談對——沒有任何梯度更新。

效果驚人:在 HumanEval 程式基準上,Reflexion 達到 91% pass@1,超越當時 GPT-4 的 80%。它的限制也很誠實:反思品質完全取決於 LLM 自我評估的能力——不會反省的模型,加了反思迴圈也不會變強。

三、實務選型:你的任務需要哪一層推理?

Anthropic 在 2024 年底的工程部落格 Building Effective Agents(anthropic.com/engineering/building-effective-agents)給了一個務實的提醒:先用最簡單的 workflow,證明不夠了再升級到真正的 agent 迴圈。對照今天的兩篇論文,可以畫出一條升級階梯:

  • 單次 CoT:答案在模型腦中就有,幻覺風險低(分類、摘要、改寫)。
  • ReAct 迴圈:需要查外部資料、多步驟工具呼叫,且步驟順序事先寫不死。
  • ReAct + Reflexion:任務可重試、有明確的驗證器(測試、編譯器、答案比對),值得花多輪試錯換正確率。
  • 樹搜尋(Tree Search):部分狀態可回溯的難題(解謎、複雜規劃),在推理時做 best-first 搜尋。

記住匹配原則:迴圈形狀要配任務結構。單次生成用自我批判(in-place critique),可重試任務用反思記憶(Reflexion),可回溯的難題用樹搜尋。錯配只會燒 token。

四、實作要點:一個最小 ReAct 迴圈

實作上,ReAct 迴圈不到 50 行就能跑。關鍵細節有三個:第一,Observation 要截斷——工具回傳塞爆 context 是最常見的死法;第二,設最大步數與停損,避免 Agent 無限鬼打牆;第三,Reflexion 的反思要只存「可行動的教訓」,不要存整段軌跡,否則記憶緩衝區很快變成垃圾場。

def react_loop(task, tools, llm, max_steps=8):
    trace = [f"Task: {task}"]
    for _ in range(max_steps):
        # Thought + Action:一次 LLM 呼叫產生下一步
        thought, action = llm.decide("\n".join(trace), tools)
        trace.append(f"Thought: {thought}")
        if action.name == "finish":
            return action.argument          # 完成
        # Observation:執行工具並把結果截斷後接回
        obs = tools[action.name](action.argument)[:2000]
        trace.append(f"Action: {action.name}[{action.argument}]")
        trace.append(f"Observation: {obs}")
    return None  # 步數用盡:回報失敗,交給上層處理

def reflexion(task, tools, llm, trials=3):
    memory = []  # 情節記憶:只存文字反思
    for t in range(trials):
        result = react_loop(task, tools, llm.with_memory(memory))
        if evaluator(result, task):          # 驗證器說 OK
            return result
        lesson = llm.reflect(task, result)   # 寫下這次學到的教訓
        memory.append(f"Trial {t+1} lesson: {lesson}")
    return result  # 全部試完仍失敗:把軌跡交給人類

注意 llm.with_memory(memory) 只是把反思文字拼進 prompt——沒有訓練、沒有向量庫升級版那麼複雜,先讓最簡單的版本跑起來,再考慮要不要上長期記憶系統。

結語

ReAct 教會 LLM 說「我不知道,我查一下」;Reflexion 教會 Agent 說「我錯了,我記下來」。兩篇論文加起來,就是今天所有 Agent 運行時的核心迴圈:推理指引行動,行動提供證據,失敗轉化為語言記憶。

下次你在調 Agent 時遇到鬼打牆,先問三個問題:它的 Thought 有沒有真的在規劃下一步(還是只是複述)?Observation 有沒有被截斷到看不見關鍵資訊?失敗的軌跡有沒有變成下一次的養分?多數 Agent 的問題,都出在這三個地方。

參考來源

Uploaded Image Uploaded Image

沒有留言:

張貼留言