17-ReactAgent:让AI学会"边思考边行动"

0 阅读20分钟

什么是ReactAgent?

ReactAgent是基于**ReAct(Reasoning and Acting)范式的智能体架构,让大模型通过交替进行推理(Reasoning)和行动(Acting)**来解决复杂任务。

传统方法的局限

在ReAct出现之前,AI解决问题主要有两种方式:

方式1:纯推理(Chain-of-Thought)
用户问题:明天北京的天气怎么样?

AI思考过程:
1. 用户想知道明天北京的天气
2. 这需要实时天气数据
3. 我的知识截止到2024年1月
4. 因此我无法准确回答

AI回答:抱歉,我无法获取实时天气信息...

问题:只能思考,无法采取实际行动获取信息。

方式2:纯行动(Action-Only)
用户问题:明天北京的天气怎么样?

系统:检测到"天气"关键词
→ 调用天气API(location="北京", date="明天")
→ 返回:晴天,10-20°C

AI回答:明天北京晴天,温度10-20°C

问题:无法处理复杂的多步骤任务,缺乏灵活性。

ReAct:思考与行动的结合

ReAct将推理和行动交织在一起:

用户问题:明天北京的天气怎么样?

Thought 1: 我需要查询明天北京的天气信息
Action 1: search_weather(location="北京", date="明天")
Observation 1: {"weather": "晴", "temp": "10-20°C"}

Thought 2: 我已经获得了天气信息,可以回答用户了
Action 2: finish(answer="明天北京是晴天,温度在10-20°C之间")

优势

  • 有思考:知道该做什么
  • 有行动:能够执行工具获取信息
  • 有观察:根据反馈调整策略

ReAct的核心概念

三大组件

ReAct循环包含三个核心组件:

┌─────────────────────────────────────┐
│        Thought (思考)                │
│  分析当前情况,规划下一步             │
└─────────────┬───────────────────────┘
              ↓
┌─────────────────────────────────────┐
│        Action (行动)                 │
│  执行具体操作(调用工具/API)         │
└─────────────┬───────────────────────┘
              ↓
┌─────────────────────────────────────┐
│     Observation (观察)               │
│  获取行动结果,作为下一步输入         │
└─────────────┬───────────────────────┘
              ↓
         (回到Thought)

Thought(思考)

作用

  • 分析当前任务状态
  • 规划下一步行动
  • 决定是否需要更多信息

示例

Thought 1: 用户想知道埃隆·马斯克的年龄,我需要查询最新信息
Thought 2: 我已经知道他的出生日期(1971年6月28日),现在需要计算年龄
Thought 3: 计算完成,我可以给出最终答案了

Action(行动)

作用

  • 调用外部工具/API
  • 执行具体操作
  • 与环境交互

常见操作

# 搜索操作
Action: search("Elon Musk age")

# 计算操作
Action: calculate("2024 - 1971")

# 结束操作
Action: finish("Elon Musk is 53 years old")

Observation(观察)

作用

  • 接收行动的反馈
  • 提供给下一轮思考
  • 更新任务状态

示例

Observation 1: 搜索结果显示埃隆·马斯克出生于1971年6月28日
Observation 2: 计算结果为53

ReAct的工作流程

完整示例

任务:查询"北京到上海的高铁票价"

User: 北京到上海的高铁票价是多少?

Thought 1: 用户想知道北京到上海的高铁票价,我需要查询交通信息
Action 1: search_train("北京", "上海")
Observation 1: 查询结果:二等座553元,一等座933元,商务座1748元

Thought 2: 我已经获得了票价信息,但用户可能想知道最常见的二等座价格
Action 2: finish("北京到上海的高铁二等座票价是553元,一等座933元,商务座1748元")

流程图

开始
  ↓
[用户输入问题]
  ↓
┌─────────────────────┐
│  大模型生成Thought   │ ← 理解任务,规划行动
└──────────┬──────────┘
           ↓
┌─────────────────────┐
│  大模型生成Action    │ ← 决定执行什么操作
└──────────┬──────────┘
           ↓
     需要工具?
       ↙    ↘
      是      否(finish)
      ↓         ↓
[调用工具]   [返回答案]
      ↓         ↓
[Observation]  结束
      ↓
  添加到上下文
      ↓
  回到Thought

实现ReactAgent

基础版本

import re
from typing import List, Dict, Callable

class ReactAgent:
    def __init__(self, llm, tools: Dict[str, Callable], max_steps: int = 10):
        """
        llm: 大语言模型(如GPT-4、Claude等)
        tools: 可用工具字典 {"工具名": 工具函数}
        max_steps: 最大循环步数
        """
        self.llm = llm
        self.tools = tools
        self.max_steps = max_steps

    def run(self, question: str) -> str:
        """运行ReAct循环"""
        # 初始化上下文
        context = f"Question: {question}\n\n"

        for step in range(1, self.max_steps + 1):
            # 1. 生成Thought和Action
            prompt = self._build_prompt(context, step)
            response = self.llm.generate(prompt)

            # 2. 解析响应
            thought, action, action_input = self._parse_response(response)

            # 3. 记录Thought
            context += f"Thought {step}: {thought}\n"

            # 4. 执行Action
            if action == "finish":
                # 任务完成
                return action_input

            if action not in self.tools:
                context += f"Action {step}: {action}({action_input})\n"
                context += f"Observation {step}: Error - Unknown action '{action}'\n"
                continue

            # 调用工具
            try:
                observation = self.tools[action](action_input)
                context += f"Action {step}: {action}({action_input})\n"
                context += f"Observation {step}: {observation}\n\n"
            except Exception as e:
                context += f"Action {step}: {action}({action_input})\n"
                context += f"Observation {step}: Error - {str(e)}\n\n"

        return "达到最大步数限制,任务未完成"

    def _build_prompt(self, context: str, step: int) -> str:
        """构建prompt"""
        return f"""你是一个智能助手,可以通过思考和行动来回答问题。

可用工具:
{self._format_tools()}

你必须按照以下格式回答:

Thought: 分析当前情况,决定下一步
Action: 工具名称
Action Input: 工具参数

或者,当你有了最终答案:

Thought: 我已经有了答案
Action: finish
Action Input: 最终答案

{context}
现在开始思考第{step}步:"""

    def _format_tools(self) -> str:
        """格式化工具描述"""
        tool_desc = []
        for name, func in self.tools.items():
            doc = func.__doc__ or "无描述"
            tool_desc.append(f"- {name}: {doc}")
        return "\n".join(tool_desc)

    def _parse_response(self, response: str):
        """解析模型响应"""
        thought_pattern = r"Thought:\s*(.+?)(?=\n|$)"
        action_pattern = r"Action:\s*(.+?)(?=\n|$)"
        input_pattern = r"Action Input:\s*(.+?)(?=\n|$)"

        thought = re.search(thought_pattern, response)
        action = re.search(action_pattern, response)
        action_input = re.search(input_pattern, response)

        thought = thought.group(1).strip() if thought else ""
        action = action.group(1).strip() if action else ""
        action_input = action_input.group(1).strip() if action_input else ""

        return thought, action, action_input

定义工具

def search_web(query: str) -> str:
    """在网上搜索信息"""
    # 实际应该调用搜索API
    # 这里用模拟数据
    mock_results = {
        "埃隆马斯克年龄": "埃隆·马斯克出生于1971年6月28日",
        "北京天气": "北京今天晴,温度15-25°C",
    }
    for key, value in mock_results.items():
        if key in query:
            return value
    return "未找到相关信息"

def calculate(expression: str) -> str:
    """执行数学计算"""
    try:
        result = eval(expression)
        return str(result)
    except Exception as e:
        return f"计算错误: {str(e)}"

def get_current_time() -> str:
    """获取当前时间"""
    from datetime import datetime
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

# 工具字典
tools = {
    "search": search_web,
    "calculate": calculate,
    "get_time": get_current_time,
}

使用示例

# 初始化Agent
agent = ReactAgent(
    llm=your_llm_model,  # 你的语言模型
    tools=tools,
    max_steps=5
)

# 运行
question = "埃隆·马斯克今年多少岁?"
answer = agent.run(question)
print(answer)

执行过程

Question: 埃隆·马斯克今年多少岁?

Thought 1: 我需要查询埃隆·马斯克的出生日期
Action 1: search("埃隆马斯克年龄")
Observation 1: 埃隆·马斯克出生于1971年6月28日

Thought 2: 我知道他出生于1971年,现在需要计算他的年龄
Action 2: calculate("2024 - 1971")
Observation 2: 53

Thought 3: 计算完成,我可以给出答案了
Action 3: finish("埃隆·马斯克今年53岁(出生于1971年6月28日)")

最终答案:埃隆·马斯克今年53岁(出生于1971年6月28日)

Prompt工程:让模型学会ReAct

核心要素

一个好的ReAct prompt需要包含:

  1. 角色定义:明确Agent的身份
  2. 工具描述:列出可用工具及其用法
  3. 格式示范:通过Few-shot展示ReAct格式
  4. 约束规则:限制行为,避免错误

完整Prompt模板

REACT_PROMPT = """你是一个能够使用工具解决问题的智能助手。

你可以使用以下工具:
{tool_descriptions}

请严格按照以下格式回答:

Thought: 你对当前情况的思考
Action: 工具名称
Action Input: 传给工具的参数

当你获得观察结果后,继续思考:

Thought: 基于观察结果的思考
Action: 下一个工具
Action Input: 参数

或者,当你有最终答案时:

Thought: 我现在知道最终答案了
Action: finish
Action Input: [你的最终答案]

重要规则:
1. 每次只执行一个Action
2. 必须先Thought再Action
3. 不要编造观察结果
4. 如果工具返回错误,重新思考并尝试其他方法

以下是一些例子:

--- 例子 1 ---
Question: 今天是几号?北京的天气怎么样?

Thought 1: 我需要先获取当前日期
Action 1: get_time
Action Input 1:
Observation 1: 2024-03-15 14:30:00

Thought 2: 现在我知道是3月15日,需要查询北京天气
Action 2: search
Action Input 2: 北京天气
Observation 2: 北京今天晴,温度15-25°C

Thought 3: 我已经有了完整答案
Action 3: finish
Action Input 3: 今天是2024年3月15日,北京天气晴朗,温度在15-25°C之间

--- 例子 2 ---
Question: 123 * 456 等于多少?

Thought 1: 这是一个数学计算问题,我应该使用计算器工具
Action 1: calculate
Action Input 1: 123 * 456
Observation 1: 56088

Thought 2: 计算完成,我可以回答了
Action 2: finish
Action Input 2: 123 * 456 = 56088

---

现在开始回答新问题:

Question: {question}

"""

Few-shot示例的重要性

没有Few-shot:模型容易犯错

❌ 错误示例:

Question: 明天北京天气?

Thought: 我需要查天气
我去搜索一下
答案是晴天

(混乱,没有结构)

有Few-shot:模型遵循格式

 正确示例:

Question: 明天北京天气?

Thought 1: 我需要查询明天北京的天气
Action 1: search
Action Input 1: 明天北京天气
Observation 1: 明天北京晴,10-20°C

Thought 2: 我已经获得答案
Action 2: finish
Action Input 2: 明天北京是晴天,温度10-20°C

常见问题与解决方案

问题1:模型不遵循格式

症状

Thought: 我需要搜索
让我来搜索一下吧,我觉得应该是...
(模型开始自由发挥)

解决方案

  1. 强化格式约束
def enforce_format(response: str) -> str:
    """强制检查格式"""
    required_keywords = ["Thought:", "Action:", "Action Input:"]

    for keyword in required_keywords:
        if keyword not in response:
            return f"错误:响应缺少必需的关键词 '{keyword}'。请重新按格式输出。"

    return response
  1. 使用结构化输出(如果模型支持):
# OpenAI Function Calling
response = openai.ChatCompletion.create(
    model="gpt-4",
    messages=[{"role": "user", "content": prompt}],
    functions=[{
        "name": "react_step",
        "parameters": {
            "type": "object",
            "properties": {
                "thought": {"type": "string"},
                "action": {"type": "string"},
                "action_input": {"type": "string"}
            },
            "required": ["thought", "action", "action_input"]
        }
    }],
    function_call={"name": "react_step"}
)

问题2:无限循环

症状

Thought 1: 我需要搜索
Action 1: search("天气")
Observation 1: 未找到信息

Thought 2: 我需要搜索
Action 2: search("天气")
Observation 2: 未找到信息

(重复相同操作)

解决方案

  1. 检测重复行动
class ReactAgent:
    def __init__(self, ...):
        self.action_history = []  # 记录历史行动

    def run(self, question: str):
        for step in range(self.max_steps):
            # ... 生成action ...

            # 检测重复
            if (action, action_input) in self.action_history:
                context += "Warning: 你刚才已经尝试过这个操作了,请尝试其他方法\n"
                continue

            self.action_history.append((action, action_input))

            # ... 执行action ...
  1. 添加反思机制
def add_reflection(context: str, step: int) -> str:
    """每3步添加反思"""
    if step % 3 == 0:
        return context + "\n[Reflection: 回顾一下目前的进展,是否需要改变策略?]\n"
    return context

问题3:工具使用错误

症状

Action: search
Action Input: {"query": "天气", "location": "北京"}

(工具只接受字符串,不接受JSON)

解决方案

  1. 明确工具签名
def search_web(query: str) -> str:
    """
    在网上搜索信息

    参数:
        query (str): 搜索关键词,纯文本字符串

    示例:
        search_web("北京天气")
        search_web("埃隆马斯克年龄")
    """
    # ...
  1. 参数验证
def validate_and_call_tool(tool_name: str, tool_input: str):
    """验证并调用工具"""
    tool = tools[tool_name]

    # 获取函数签名
    import inspect
    sig = inspect.signature(tool)

    # 检查参数类型
    if len(sig.parameters) == 1:
        # 单参数,直接传入
        return tool(tool_input)
    else:
        # 多参数,尝试解析JSON
        import json
        try:
            kwargs = json.loads(tool_input)
            return tool(**kwargs)
        except:
            return f"Error: 参数格式错误。工具需要{len(sig.parameters)}个参数"

问题4:过早结束

症状

Thought 1: 我需要查询天气
Action 1: finish
Action Input 1: 我需要查询天气

(还没查询就结束了)

解决方案

  1. 延迟finish
def can_finish(context: str, step: int) -> bool:
    """判断是否可以结束"""
    # 至少执行2步才能finish
    if step < 2:
        return False

    # 检查是否至少调用了一次工具
    if "Observation" not in context:
        return False

    return True
  1. 添加验证问题
PROMPT_WITH_VERIFICATION = """
...

在使用finish之前,问自己:
1. 我是否已经获得了足够的信息?
2. 我的答案是否直接回答了用户的问题?
3. 答案是否准确完整?

只有当你对以上三个问题的回答都是"是"时,才能使用finish。
"""

进阶优化

1. 自我修正(Self-Correction)

让Agent能够识别并修正自己的错误:

def add_self_correction(context: str) -> str:
    """添加自我修正机制"""
    return context + """

[Self-Check] 在继续之前,检查:
- 上一步的操作是否成功?
- 观察结果是否合理?
- 如果失败,原因是什么?
- 需要调整策略吗?
"""

示例

Thought 1: 我需要搜索"北京天气明天"
Action 1: search("北京天气明天")
Observation 1: 未找到相关信息

[Self-Check]
Thought 2: 搜索失败了,可能是查询词太具体。我应该简化查询
Action 2: search("北京天气")
Observation 2: 北京今天晴,明天多云...

(成功修正)

2. 记忆机制(Memory)

让Agent记住之前的交互:

class ReactAgentWithMemory:
    def __init__(self, ...):
        self.short_term_memory = []  # 当前会话的记忆
        self.long_term_memory = []   # 跨会话的记忆

    def run(self, question: str):
        # 添加相关记忆到上下文
        relevant_memories = self.retrieve_memories(question)
        context = f"Relevant past experiences:\n{relevant_memories}\n\n"

        # ... 正常ReAct循环 ...

        # 保存这次的经验
        self.save_memory(question, answer, steps_taken)

    def retrieve_memories(self, question: str) -> str:
        """检索相关记忆"""
        # 简化版:关键词匹配
        relevant = [m for m in self.long_term_memory
                    if any(word in m["question"] for word in question.split())]
        return "\n".join([f"- {m['summary']}" for m in relevant[:3]])

    def save_memory(self, question: str, answer: str, steps: int):
        """保存记忆"""
        memory = {
            "question": question,
            "answer": answer,
            "steps": steps,
            "summary": f"问题:{question[:20]},用了{steps}步"
        }
        self.long_term_memory.append(memory)

3. 并行工具调用

同时调用多个工具,提升效率:

def run_parallel(self, question: str):
    """支持并行工具调用"""
    # ... 前面步骤相同 ...

    # 解析是否有并行请求
    if "parallel" in response.lower():
        # 提取多个action
        actions = self._parse_parallel_actions(response)

        # 并行执行
        from concurrent.futures import ThreadPoolExecutor
        with ThreadPoolExecutor() as executor:
            futures = [executor.submit(self.tools[a], inp)
                       for a, inp in actions]
            observations = [f.result() for f in futures]

        # 合并观察结果
        for i, obs in enumerate(observations):
            context += f"Observation {step}.{i+1}: {obs}\n"

使用示例

Question: 北京和上海今天的天气分别是什么?

Thought 1: 我需要同时查询两个城市的天气
Action 1: parallel
Action Input 1:
  - search("北京天气")
  - search("上海天气")

Observation 1.1: 北京今天晴,15-25°C
Observation 1.2: 上海今天多云,18-26°C

Thought 2: 我已经获得了两个城市的天气信息
Action 2: finish
Action Input 2: 北京今天晴天(15-25°C),上海今天多云(18-26°C)

4. 分层规划(Hierarchical Planning)

将复杂任务分解为子任务:

def hierarchical_react(self, question: str):
    """分层ReAct"""
    # 第一阶段:高层规划
    plan_prompt = f"""
    分解任务:{question}

    将其分解为3-5个子任务,每个子任务应该:
    1. 明确且可执行
    2. 相互独立
    3. 完成后能推进整体目标

    输出格式:
    Subtask 1: ...
    Subtask 2: ...
    ...
    """

    plan = self.llm.generate(plan_prompt)
    subtasks = self._parse_subtasks(plan)

    # 第二阶段:逐个执行子任务
    results = []
    for i, subtask in enumerate(subtasks):
        result = self.run(subtask)  # 递归调用ReAct
        results.append(result)

    # 第三阶段:合并结果
    final_prompt = f"""
    原始问题:{question}

    子任务结果:
    {self._format_results(results)}

    请基于这些结果给出最终答案。
    """

    final_answer = self.llm.generate(final_prompt)
    return final_answer

实际应用案例

案例1:数学应用题求解

# 工具定义
def calculator(expression: str) -> str:
    """执行数学计算"""
    return str(eval(expression))

def extract_numbers(text: str) -> str:
    """从文本中提取数字"""
    import re
    numbers = re.findall(r'\d+\.?\d*', text)
    return str(numbers)

# 问题
question = """
小明有15个苹果,他给了小红3个,又给了小华5个。
请问小明还剩多少个苹果?
"""

# ReAct过程
"""
Thought 1: 这是一个数学应用题,我需要先提取数字
Action 1: extract_numbers("小明有15个苹果,他给了小红3个,又给了小华5个")
Observation 1: ['15', '3', '5']

Thought 2: 小明初始有15个,给出去3个和5个,需要计算15-3-5
Action 2: calculator("15 - 3 - 5")
Observation 2: 7

Thought 3: 计算完成,小明还剩7个苹果
Action 3: finish("小明还剩7个苹果")
"""

案例2:信息聚合

# 工具定义
def search_news(keyword: str) -> str:
    """搜索最新新闻"""
    # 调用新闻API
    pass

def summarize(text: str) -> str:
    """总结文本"""
    # 调用摘要模型
    pass

# 问题
question = "总结一下最近关于AI的重要新闻"

# ReAct过程
"""
Thought 1: 我需要先搜索关于AI的最新新闻
Action 1: search_news("AI人工智能")
Observation 1: [新闻1] OpenAI发布GPT-5... [新闻2] Google推出Gemini Ultra...

Thought 2: 我获得了多条新闻,现在需要总结它们
Action 2: summarize("OpenAI发布GPT-5... Google推出Gemini Ultra...")
Observation 2: 最近AI领域的重要进展包括:1) OpenAI发布更强大的GPT-5...

Thought 3: 总结完成,我可以给出答案了
Action 3: finish("最近AI领域有以下重要新闻:...")
"""

案例3:代码调试助手

# 工具定义
def run_code(code: str) -> str:
    """运行Python代码并返回结果"""
    try:
        exec_globals = {}
        exec(code, exec_globals)
        return "代码运行成功"
    except Exception as e:
        return f"错误:{str(e)}"

def search_error(error_msg: str) -> str:
    """搜索错误解决方案"""
    # 调用Stack Overflow API
    pass

# 问题
question = """
以下代码有错误,请帮我修复:
```python
def sum_list(lst):
    total = 0
    for i in range(len(lst)):
        total += lst[i+1]
    return total

"""

ReAct过程

""" Thought 1: 我需要先运行代码,看看具体错误 Action 1: run_code(code) Observation 1: 错误:IndexError: list index out of range

Thought 2: 出现了索引越界错误,是因为循环中使用了i+1 Action 2: fix_code("将lst[i+1]改为lst[i]") Observation 2: 修复建议已生成

Thought 3: 验证修复后的代码 Action 3: run_code(fixed_code) Observation 3: 代码运行成功

Thought 4: 问题已解决 Action 4: finish("错误原因是循环中使用lst[i+1]导致索引越界,应改为lst[i]") """


## ReAct vs 其他Agent范式

### 1. ReAct vs Chain-of-Thought (CoT)

| 特性 | CoT | ReAct |
|------|-----|-------|
| 核心 | 纯推理 | 推理+行动 |
| 工具使用 | ❌ 不支持 | ✅ 支持 |
| 适用场景 | 数学、逻辑推理 | 需要外部信息的任务 |
| 复杂度 | 低 | 中等 |

**示例对比**:

问题:明天北京的天气?

CoT:

  1. 用户想知道明天北京的天气
  2. 这需要实时天气数据
  3. 我无法获取实时数据 答:抱歉,我无法回答

ReAct: Thought: 需要查询天气 Action: search("明天北京天气") Observation: 晴,15-25°C 答:明天北京晴天,15-25°C


### 2. ReAct vs Plan-and-Execute

| 特性 | Plan-and-Execute | ReAct |
|------|-----------------|-------|
| 规划 | 先完整规划 | 边做边规划 |
| 灵活性 | 低(计划固定) | 高(动态调整) |
| 效率 | 高(无重复规划) | 中(可能重新规划) |
| 容错性 | 低(计划失败需重来) | 高(及时调整) |

**示例对比**

问题:预订北京到上海的机票

Plan-and-Execute: Plan:

  1. 查询北京到上海的航班
  2. 比较价格
  3. 选择最便宜的
  4. 预订 Execute: 按计划执行

(问题:如果步骤2发现没有便宜的,计划就失效了)

ReAct: Thought 1: 查询航班 Action 1: search_flights() Observation 1: 所有航班都很贵

Thought 2: 价格太贵了,考虑改坐高铁 Action 2: search_trains() Observation 2: 高铁553元 ... (灵活调整策略)


### 3. ReAct vs ReWOO(Reasoning WithOut Observation)

ReWOO是ReAct的改进版本,特点是**先规划所有行动,再批量执行****ReWOO流程**
  1. Planner: 规划所有步骤(不执行) Plan: #E1 = search("天气") #E2 = search("交通") #E3 = combine(#E1, #E2)

  2. Worker: 批量执行所有工具 并行执行 E1, E2

  3. Solver: 基于所有结果回答


**对比**:

| 特性 | ReAct | ReWOO |
|------|-------|-------|
| 规划 | 逐步规划 | 一次性规划 |
| 执行 | 串行(等待观察) | 并行(批量执行) |
| Token消耗 | 高(多轮对话) | 低(一次规划) |
| 适应性 | 高 | 低 |
| 速度 | 慢 | 快 |

**选择建议**:
- 任务明确,步骤可预知 → ReWOO
- 任务复杂,需要动态调整 → ReAct

## 最佳实践

### 1. 工具设计原则

**单一职责**:
```python
# ❌ 不好:工具做太多事
def handle_all(action_type, param1, param2):
    if action_type == "search":
        # 搜索逻辑
    elif action_type == "calculate":
        # 计算逻辑
    # ...

# ✅ 好:每个工具一个职责
def search(query): ...
def calculate(expr): ...
def get_time(): ...

清晰的文档

def search(query: str) -> str:
    """
    在互联网上搜索信息

    参数:
        query: 搜索关键词,应该是简洁的短语或问题

    返回:
        搜索结果的摘要文本

    示例:
        search("埃隆马斯克") → "埃隆·马斯克是..."
        search("北京天气") → "北京今天晴..."

    注意事项:
        - 使用简短关键词,不要太长的句子
        - 一次只查询一个主题
    """
    pass

错误处理

def search(query: str) -> str:
    try:
        result = api.search(query)
        if not result:
            return "未找到相关信息,请尝试其他关键词"
        return result
    except RateLimitError:
        return "搜索API达到速率限制,请稍后再试"
    except Exception as e:
        return f"搜索失败:{str(e)},请检查查询词"

2. Prompt优化技巧

明确约束

❌ 不明确:
"使用工具回答问题"

✅ 明确:
"你必须使用工具来获取信息,不要依赖你的训练数据"
"每次只调用一个工具"
"如果工具返回错误,尝试改变参数或使用其他工具"

提供反例

正确示例:
Thought: 我需要搜索
Action: search
Action Input: 北京天气

错误示例(不要这样做):
Thought: 北京天气应该是晴天吧
Action: finish
Action Input: 晴天
(错误:没有使用工具就给出答案)

3. 调试技巧

详细日志

import logging

class ReactAgent:
    def __init__(self, ..., verbose=True):
        self.verbose = verbose
        self.logger = logging.getLogger("ReactAgent")

    def run(self, question):
        if self.verbose:
            self.logger.info(f"[Question] {question}")

        for step in range(self.max_steps):
            if self.verbose:
                self.logger.info(f"[Step {step}]")
                self.logger.debug(f"Context:\n{context}")

            # ... 执行步骤 ...

            if self.verbose:
                self.logger.info(f"Thought: {thought}")
                self.logger.info(f"Action: {action}({action_input})")
                self.logger.info(f"Observation: {observation}")

中间状态检查

def run_with_checkpoints(self, question):
    """带检查点的运行"""
    checkpoints = []

    for step in range(self.max_steps):
        # ... 执行步骤 ...

        # 保存检查点
        checkpoint = {
            "step": step,
            "thought": thought,
            "action": action,
            "observation": observation,
            "context": context
        }
        checkpoints.append(checkpoint)

        # 可以在任何时候检查
        if self.debug_mode:
            print(f"检查点 {step}:")
            print(json.dumps(checkpoint, indent=2))
            input("按Enter继续...")

    return answer, checkpoints

4. 性能优化

缓存工具结果

from functools import lru_cache

@lru_cache(maxsize=100)
def search(query: str) -> str:
    """缓存搜索结果"""
    return expensive_search_api(query)

批量处理

# 如果需要处理多个问题
def batch_run(self, questions: List[str]):
    """批量运行"""
    from concurrent.futures import ThreadPoolExecutor

    with ThreadPoolExecutor(max_workers=5) as executor:
        results = executor.map(self.run, questions)

    return list(results)

小结

ReAct的核心价值

  1. 结合思考和行动:不再是"只想不做"或"只做不想"
  2. 动态适应:根据观察结果及时调整策略
  3. 可解释性强:每一步的思考过程都是透明的
  4. 易于扩展:添加新工具即可扩展能力

关键组件

组件作用关键点
Thought推理规划分析情况,决定行动
Action执行操作调用工具,与环境交互
Observation获取反馈提供给下一轮思考
Tools能力来源设计要清晰、文档要详细
Prompt行为指南Few-shot示例很重要

适用场景

适合ReAct

  • ✅ 需要外部信息(搜索、API调用)
  • ✅ 多步骤任务
  • ✅ 需要动态决策
  • ✅ 工具调用频繁

不适合ReAct

  • ❌ 纯推理任务(数学证明)
  • ❌ 单步即可完成的任务
  • ❌ 需要极快响应(ReAct有多轮开销)

实践建议

开发阶段

  1. 从简单工具开始(如搜索、计算)
  2. 使用详细的Few-shot示例
  3. 开启verbose模式,观察每一步
  4. 记录失败案例,优化prompt

生产部署

  1. 添加工具调用限制(防止滥用API)
  2. 实现超时机制
  3. 监控token消耗
  4. 准备降级方案(ReAct失败时的备选)

持续改进

  1. 收集真实用户query
  2. 分析哪些任务成功/失败
  3. 扩展工具库
  4. 优化prompt(基于失败案例)

未来发展方向

  1. 更好的规划:从ReAct到ReWOO,减少token消耗
  2. 多模态:不仅是文本,还有图像、视频工具
  3. 自我学习:从交互中学习,改进工具使用策略
  4. 协作Agent:多个ReAct Agent协同完成复杂任务

ReactAgent代表了AI从"知识库"到"行动者"的转变,它让AI不再局限于已知知识,而是能够主动探索、获取信息、解决实际问题。掌握ReAct,你就掌握了构建实用AI系统的核心范式!