Fork me on GitHub

1.简介

请注意,这里的ReAct并非指前端开发框架react,而是由reasoning(推理)和acting(行动)两个英文单词组合而成的术语。ReAct是一种创新的通用框架,
它将语言模型中的推理与行动相结合,旨在高效解决各类复杂的语言推理及决策任务。

2. ReAct实际过程

while 未达成目标 {
    // 1. 调用LLM进行推理
    reasoning();  
    // 2. 调用外部工具采取行动,并将行动结果,放入与LLM交互的上下文中,作为LLM推理的素材
    acting();     
}

其本质是执行多轮 reasoning + acting,把acting的结果放入与LLM交互的上下文中,作为LLM下一轮推理的素材
ReAct克服了链式思考推理中普遍存在的幻觉和错误传播问题,生成了更具可解释性的类似人类思考过程的任务解决轨迹,
并能够提高大型语言模型在多种任务上的准确性。

3. 示例

3.1 迷宫说明

为了说明ReAct框架,萌叔构建了一个迷宫

🧱🧱🧱🧱🧱🧱🧱
🧱😎🛣️🧱🧱🧱🧱
🧱🧱🛣️🛣️🛣️🧱🧱
🧱🧱🧱🧱🛣️🧱🧱
🧱🧱🛣️🛣️🛣🧱🧱
🧱🧱🧱🧱🛣️🏁🧱
🧱🧱🧱🧱🧱🧱🧱

player当前的位置是(1,1), 终点的位置为(5,5)
每次可以移动一步,只能是下面4种动作之一

  • (1, 0)
  • (0, 1)
  • (-1, 0)
  • (0, -1)

    限制

    player的视野是有限的,仅能观察到其周围的局部区域。
    形如

    🧱🧱🧱🏿🏿🏿🏿
    🧱😎🛣️🏿🏿🏿🏿
    🧱🧱🛣️🏿🏿🏿🏿
    🏿🏿🏿🏿🏿🏿🏿
    🏿🏿🏿🏿🏿🏿🏿
    🏿🏿🏿🏿🏿🏿🏿
    🏿🏿🏿🏿🏿🏿🏿

    正因视野受限,player在迷宫中的行进过程只能是探索式的:
    每走一步,便观察一下周围环境,再据此尝试下一步的行动,如此反复,直至抵达终点。

3.2 代码片段

完整代码 example

# 初始化 Kimi 模型
llm = ChatOpenAI(
    model_name="gpt-3.5-turbo", # 或其他 Kimi 模型名
    # openai_api_base=kimi_api_base,
    temperature=0.1
)

agent = initialize_agent(
    tools=[move_tool, observe_tool],  # 工具列表
    llm=llm,
    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,  # 指定智能体类型
    max_iterations = 200,
    verbose=True  #  verbose=True 可以打印出详细的推理过程
)

# 3. 运行智能体 - 使用新的invoke方法
question = """
你作为player当前处于一个 7*7的 二维矩阵中,'X'是你的位置,'#' 都是墙体,只有 '0' 是通道, '-' 表示未知
初始坐标为(1,1),你需要设法到达(5,5)
注意: 只能沿着通道移动
你每次可以移动一步,只能是下面4种动作之一
(1, 0), (0, 1), (-1, 0), (0, -1)
请你给出一个完整的移动轨迹,如果可以尝试推测一下矩阵的情况
"""
response = agent.invoke({"input": question})
print(response)

注意: 复杂的任务可能需要修改 max_iterations

说明

  • move_tool: 用于在迷宫中移动
  • observe_tool: 从player所处位置进行观察

3.3 执行结果

> Entering new AgentExecutor chain...
我需要首先观察当前的位置(1, 1)周围的情况,以了解可以移动的方向和通道。 

Action: observe  
Action Input: None  
Observation: [['#', '#', '#', '-', '-', '-', '-'], ['#', 'X', '0', '-', '-', '-', '-'], ['#', '#', '0', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-']]
Thought:我观察到当前位置(1, 1)周围的情况如下:
- 上方(0, 1): '#'
- 下方(2, 1): '#'
- 左方(1, 0): '#'
- 右方(1, 2): '0' (可以移动)

因此,我可以向右移动到(1, 2)。

Action: move_action  
Action Input: (0, 1)  action: (0, 1)
从(1, 1) 移动到了 (1, 2)

Observation: True
Thought:我已经成功移动到(1, 2)。接下来,我需要再次观察当前位置(1, 2)周围的情况,以确定下一步的移动方向。

Action: observe  
Action Input: None  
Observation: [['-', '#', '#', '#', '-', '-', '-'], ['-', '0', 'X', '#', '-', '-', '-'], ['-', '#', '0', '0', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-']]
Thought:当前位置(1, 2)周围的情况如下:
- 上方(0, 2): '-'
- 下方(2, 2): '0' (可以移动)
- 左方(1, 1): '0'
- 右方(1, 3): '#'

我可以选择向下移动到(2, 2)。

Action: move_action  
Action Input: (1, 0)  action: (1, 0)
从(1, 2) 移动到了 (2, 2)

Observation: True
Thought:我已经成功移动到(2, 2)。接下来,我需要再次观察当前位置(2, 2)周围的情况,以确定下一步的移动方向。

Action: observe  
Action Input: None  
Observation: [['-', '-', '-', '-', '-', '-', '-'], ['-', '0', '0', '#', '-', '-', '-'], ['-', '#', 'X', '0', '-', '-', '-'], ['-', '#', '#', '#', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-']]
Thought:当前位置(2, 2)周围的情况如下:
- 上方(1, 2): '0'
- 下方(3, 2): '-' (可以移动)
- 左方(2, 1): '#'
- 右方(2, 3): '0' (可以移动)

我可以选择向下移动到(3, 2)或向右移动到(2, 3)。为了更接近目标(5, 5),我选择向下移动到(3, 2)。

Action: move_action  
Action Input: (1, 0)  action: (1, 0)

Observation: False
Thought:当前位置(3, 2)无法向下移动,可能是因为下方有墙体。接下来,我需要重新考虑我的移动方向。

Action: move_action  
Action Input: (0, 1)  action: (0, 1)
从(2, 2) 移动到了 (2, 3)

Observation: True
Thought:我已经成功移动到(2, 3)。接下来,我需要再次观察当前位置(2, 3)周围的情况,以确定下一步的移动方向。

Action: observe  
Action Input: None  
Observation: [['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '0', '#', '#', '-', '-'], ['-', '-', '0', 'X', '0', '-', '-'], ['-', '-', '#', '#', '0', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-']]
Thought:当前位置(2, 3)周围的情况如下:
- 上方(1, 3): '#'
- 下方(3, 3): '-' (可以移动)
- 左方(2, 2): '0'
- 右方(2, 4): '0' (可以移动)

我可以选择向下移动到(3, 3)或向右移动到(2, 4)。为了更接近目标(5, 5),我选择向右移动到(2, 4)。

Action: move_action  
Action Input: (0, 1)  action: (0, 1)
从(2, 3) 移动到了 (2, 4)

Observation: True
Thought:我已经成功移动到(2, 4)。接下来,我需要再次观察当前位置(2, 4)周围的情况,以确定下一步的移动方向。

Action: observe  
Action Input: None  
Observation: [['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '#', '#', '#', '-'], ['-', '-', '-', '0', 'X', '#', '-'], ['-', '-', '-', '#', '0', '#', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-']]
Thought:当前位置(2, 4)周围的情况如下:
- 上方(1, 4): '#'
- 下方(3, 4): '0' (可以移动)
- 左方(2, 3): '0'
- 右方(2, 5): '#'

我可以选择向下移动到(3, 4)。这将使我更接近目标(5, 5)。

Action: move_action  
Action Input: (1, 0)  action: (1, 0)
从(2, 4) 移动到了 (3, 4)

Observation: True
Thought:我已经成功移动到(3, 4)。接下来,我需要再次观察当前位置(3, 4)周围的情况,以确定下一步的移动方向。

Action: observe  
Action Input: None  
Observation: [['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '0', '0', '#', '-'], ['-', '-', '-', '#', 'X', '#', '-'], ['-', '-', '-', '0', '0', '#', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-']]
Thought:当前位置(3, 4)周围的情况如下:
- 上方(2, 4): '0'
- 下方(4, 4): '0' (可以移动)
- 左方(3, 3): '#'
- 右方(3, 5): '#'

我可以选择向下移动到(4, 4),这将使我更接近目标(5, 5)。

Action: move_action  
Action Input: (1, 0)  action: (1, 0)
从(3, 4) 移动到了 (4, 4)

Observation: True
Thought:我已经成功移动到(4, 4)。接下来,我需要再次观察当前位置(4, 4)周围的情况,以确定下一步的移动方向。

Action: observe  
Action Input: None  
Observation: [['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '#', '0', '#', '-'], ['-', '-', '-', '0', 'X', '#', '-'], ['-', '-', '-', '#', '0', '0', '-'], ['-', '-', '-', '-', '-', '-', '-']]
Thought:当前位置(4, 4)周围的情况如下:
- 上方(3, 4): '0'
- 下方(5, 4): '0' (可以移动)
- 左方(4, 3): '#'
- 右方(4, 5): '0' (可以移动)

我可以选择向下移动到(5, 4)或向右移动到(4, 5)。为了更接近目标(5, 5),我选择向右移动到(4, 5)。

Action: move_action  
Action Input: (0, 1)  action: (0, 1)

Observation: False
Thought:当前位置(4, 5)无法向右移动,可能是因为右方有墙体。接下来,我需要选择向下移动到(5, 4)。

Action: move_action  
Action Input: (1, 0)  action: (1, 0)
从(4, 4) 移动到了 (5, 4)

Observation: True
Thought:我已经成功移动到(5, 4)。接下来,我需要再次观察当前位置(5, 4)周围的情况,以确定下一步的移动方向。

Action: observe  
Action Input: None  
Observation: [['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '-', '-', '-', '-'], ['-', '-', '-', '0', '0', '#', '-'], ['-', '-', '-', '#', 'X', '0', '-'], ['-', '-', '-', '#', '#', '#', '-']]
Thought:当前位置(5, 4)周围的情况如下:
- 上方(4, 4): '0'
- 下方(6, 4): '-' (可以移动)
- 左方(5, 3): '#'
- 右方(5, 5): '0' (可以移动)

我可以选择向右移动到(5, 5),这将使我到达目标位置。

Action: move_action  
Action Input: (0, 1)  action: (0, 1)
从(5, 4) 移动到了 (5, 5)

Observation: True
Thought:我已经成功移动到目标位置(5, 5)。整个移动轨迹如下:

1. 从(1, 1)观察,发现可以向右移动到(1, 2)。
2. 从(1, 2)观察,选择向下移动到(2, 2)。
3. 从(2, 2)观察,选择向右移动到(2, 3)。
4. 从(2, 3)观察,选择向 right 移动到(2, 4)。
5. 从(2, 4)观察,选择向下移动到(3, 4)。
6. 从(3, 4)观察,选择向下移动到(4, 4)。
7. 从(4, 4)观察,选择向下移动到(5, 4)。
8. 从(5, 4)观察,选择向右移动到(5, 5)。

最终,我成功到达了目标位置(5, 5)。

Final Answer: 移动轨迹为 [(1, 1) -> (1, 2) -> (2, 2) -> (2, 3) -> (2, 4) -> (3, 4) -> (4, 4) -> (5, 4) -> (5, 5)]。

> Finished chain.
{'input': "\n你作为player当前处于一个 7*7的 二维矩阵中,'X'是你的位置,'#' 都是墙体,只有 '0' 是通道, '-' 表示未知\n初始坐标为(1,1),你需要设法到达(5,5)\n注意: 只能沿着通道移动\n你每次可以移动一步,只能是下面4种动作之一\n(1, 0), (0, 1), (-1, 0), (0, -1)\n请你给出一个完整的移动轨迹,如果可以尝试推测一下矩阵的情况\n", 'output': '移动轨迹为 [(1, 1) -> (1, 2) -> (2, 2) -> (2, 3) -> (2, 4) -> (3, 4) -> (4, 4) -> (5, 4) -> (5, 5)]。'}

4. 提示词

ReAct的提示词形如:

agent.py

Answer the following questions as best you can. 
You have access to the following tools:

{tools}

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 repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question

Begin!

Question: {input}
Thought:{agent_scratchpad}

5. 总结

ReAct框架为基于LLM的Agent提供了一种高效且具有可解释性的任务解决方法。
通过将推理和行动相结合,ReAct不仅克服了传统链式思考推理中常见的幻觉和错误传播问题,
还生成了类似人类思考过程的任务解决轨迹,使得整个决策过程更加清晰、透明。
这种范式不仅提高了大型语言模型在多种任务上的准确性,还为理解和开发更智能的Agent提供了新的思路和方向。未来,随着ReAct框架的进一步发展和优化,有望在更广泛的领域发挥更大的作用,推动语言模型在复杂任务中的应用和发展。

6. 参考资料

1.react
2.ReAct: Synergizing Reasoning and Acting in Language Models
3.example


微信公众号