逆元装置 ▍ INVERSION

丽·芙

CONSTRUCT — LIV
▍
意识海深度 · 回廊稳定
逆元装置 · 待机中
指挥官链接 · 未认证

构建你的第一个AI Agent:ReAct框架实战

Published 2025-03-25 00:00 782 words 4 min read

This post is not yet available in English. Showing the original.
从爬取网页到自动调用API,手把手教你基于ReAct模式构建一个能自主行动的AI Agent。

为什么需要 Agent?

传统的 LLM 应用是一次性的问答:用户输入问题,模型输出答案。但现实中的任务往往需要多步推理、调用外部工具、根据结果调整策略——这就是 Agent 的用武之地。

一个典型的 Agent 架构包含三个核心组件:

  • 大脑(LLM):负责推理和规划
  • 工具(Tools):代码执行、API 调用、数据库查询等
  • 记忆(Memory):存储上下文和历史交互

ReAct 模式

ReAct(Reasoning + Acting)是当前最主流的 Agent 设计范式。它的核心思想是交替进行推理和行动:

用户:帮我查一下今天北京的天气,如果有雨就提醒我带伞

AI 思考:我需要先获取北京今天的天气信息
AI 行动:调用 get_weather(city="北京", date="today")
返回结果:晴,22°C - 30°C
AI 思考:天气是晴天,不需要提醒带伞。
AI 回答:北京今天晴天,22°C 到 30°C,不需要带伞哦。

最小化实现

我们用 OpenAI API 配合一个简单的搜索工具来构建第一个 Agent:

import openai
import json
import requests

def search_web(query: str) -> str:
    """模拟搜索工具"""
    response = requests.get(f"https://api.example.com/search?q={query}")
    return response.json()["results"][:3]

tools = [
    {
        "type": "function",
        "function": {
            "name": "search_web",
            "description": "在互联网上搜索信息",
            "parameters": {
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "搜索关键词"}
                },
                "required": ["query"]
            }
        }
    }
]

def run_agent(user_message: str, max_steps: int = 5):
    messages = [{"role": "user", "content": user_message}]

    for step in range(max_steps):
        response = openai.chat.completions.create(
            model="gpt-4o",
            messages=messages,
            tools=tools
        )

        msg = response.choices[0].message
        messages.append(msg)

        # 如果模型决定直接回答,结束循环
        if msg.content:
            print(f"💬 Agent: {msg.content}")
            return msg.content

        # 如果模型选择调用工具
        for tool_call in msg.tool_calls:
            tool_name = tool_call.function.name
            tool_args = json.loads(tool_call.function.arguments)

            if tool_name == "search_web":
                result = search_web(**tool_args)
                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": str(result)
                })
                print(f"🔧 调用工具: {tool_name}({tool_args}) -> {result[:50]}...")

    return "已达到最大推理步数"

Agent 的局限与陷阱

在开发 Agent 的过程中,我遇到了几个实际问题:

1. 循环困境

模型有时会在同一个思路上反复推理而不采取行动。解决方案是限制最大步数,并在 prompt 中明确指示”当你已经收集到足够信息时,立即给出最终回答”。

2. 幻觉调用

模型偶尔会编造工具调用的参数。比如把 city="北京小汤山" 传给天气 API。通过参数校验和错误反馈来缓解。

3. Token 消耗

每次工具调用结果都要追加到消息历史中,导致 Token 消耗极快。通过摘要(Summarization)来压缩历史,或使用滑动窗口截断。

4. 安全边界

Agent 如果被赋予执行 Shell 命令的能力,必须严格沙箱化。Prompt injection 可以让 Agent 执行攻击者想要的任意操作,这是安全从业者必须警惕的。

下一步

一个完整的 Agent 系统还需要:

  • 规划能力:Plan-and-Execute 模式,先制定计划再分步执行
  • 反思机制:Self-Reflection,让 Agent 检查自己的输出质量
  • 工具制作:让 Agent 动态创建和使用新工具
  • 多 Agent 协作:多个 Agent 分工配合

这些我会在后续文章中逐一展开。