
引言随着大语言模型LLM能力的爆发AI Agent成为当前最热门的技术方向之一。从 AutoGPT 到各类智能助手Agent 赋予了 LLM 像人一样使用工具、规划任务、记忆上下文的能力使其从“对话机器”进化为“行动者”。但如何设计一个稳定、可扩展的 Agent它背后的核心模式是什么本文将从设计模式的角度出发深入浅出地解析 AI Agent 的架构思想并以ReActReasoning Acting模式为主线通过一个完整的 Python 实战项目带你从零构建一个可运行的智能代理。核心概念AI Agent 的设计模式一个典型的 AI Agent 由四个关键模块组成感知Perception接收用户输入与环境反馈。大脑Brain基于 LLM 进行推理、规划和决策。行动Action执行具体操作如调用 API、查询数据库、控制设备。记忆Memory存储短期/长期信息维持上下文连贯性。这四个模块形成一个循环感知 → 推理 → 行动 → 观察结果 → 更新记忆 → 再次推理直到完成任务。这一循环正是 Agent 设计的核心骨架。主流的 Agent 设计模式在工程实践中演化出了几种经典的设计模式ReAct 模式由 Google 提出将推理Reasoning和行动Acting交织在一起。模型输出“思考过程”和“行动指令”然后执行行动并将结果反馈给下一步推理。这种模式极大提高了可解释性和任务完成率。Plan-and-Execute 模式先由 LLM 生成一个完整的计划步骤再逐步执行。更适合复杂、长链条的任务但灵活性稍弱计划可能出现偏差。Reflection 模式允许 Agent 在执行过程中自我评估、反思错误并纠正提升决策质量。Multi-Agent 协作模式多个 Agent 分工合作通过消息传递协同完成复杂目标如 ChatDev 中的模拟软件开发团队。本文重点讲解最通用、最易落地的ReAct 模式并给出一个可直接运行的实现。ReAct 设计思想ReAct 的核心在于提示词Prompt设计。我们告诉 LLM你可以使用以下工具Tool每个工具有名称、描述和参数。你需要按固定格式输出Thought:你的推理、Action:工具名、Action Input:输入参数。当可以给出最终答案时输出Final Answer:。系统会不断解析模型输出调用真实工具将结果作为Observation反馈给模型循环直到产生最终答案。这种显式的思维链行动交织让模型学会像人类一样“边想边做”。实战示例构建一个 ReAct Agent下面我们用 Python 实现一个能搜索互联网和执行数学计算的 Agent。为了简化我们使用一个模拟的搜索函数和真实的 Pythoneval()做计算生产环境需安全处理。完整可运行代码import openai import json import re import os # 配置 OpenAI API请替换为你的 key或设置环境变量 openai.api_key os.getenv(OPENAI_API_KEY, your-api-key-here) # ---------- 工具定义 ---------- def search(query: str) - str: 模拟搜索引擎实际可接 SerpAPI 或 Bing API # 返回一些虚构的结果仅作演示 fake_db { 2024年诺贝尔物理学奖: 2024年诺贝尔物理学奖授予了研究人工神经网络的科学家。, Python最新版本: 截至2024年10月Python最新稳定版为3.12。 } return fake_db.get(query, f未找到与{query}相关的结果。) def calculator(expression: str) - str: 安全的计算器工具 try: # 仅允许数字和基本运算符防止注入 if not re.match(r^[\d\.\\-\*\/\(\) ]$, expression): return 错误表达式包含非法字符。 result eval(expression) return str(result) except Exception as e: return f计算错误{str(e)} # 工具列表名称、描述、参数 TOOLS [ { name: search, description: 当需要查找实时信息或常识时使用。输入一个查询字符串。, parameters: {query: string} }, { name: calculator, description: 执行数学计算。输入一个合法的数学表达式。, parameters: {expression: string} } ] # ---------- 构造 Prompt ---------- def build_prompt(user_query: str, tools_desc: str) - str: return f你是一个智能助手可以利用工具来回答问题。请严格按照以下格式回复 可用工具 {tools_desc} 格式要求 - 每次只输出一个 Thought/Action/Action Input 组合或最终答案。 - 如果你想使用工具必须按以下格式输出 Thought: [你的思考] Action: [工具名] Action Input: [输入参数] - 工具执行后你会收到一个 Observation请根据它继续思考。 - 当你已经得到足够信息可以回答用户时输出 Thought: 我已经知道答案 Final Answer: [最终回答] - 禁止输出多余内容。 开始 用户问题{user_query} # ---------- 工具描述字符串 ---------- def tools_to_string(tools: list) - str: lines [] for t in tools: params , .join(f{k}: {v} for k, v in t[parameters].items()) lines.append(f- {t[name]}: {t[description]} 参数: ({params})) return \n.join(lines) # ---------- 调用 LLM ---------- def call_llm(messages: list) - str: response openai.ChatCompletion.create( modelgpt-3.5-turbo, # 或 gpt-4 messagesmessages, temperature0, stop[Observation:] ) return response.choices[0].message.content.strip() # ---------- 解析 Action ---------- def parse_action(llm_text: str): 从模型输出中提取 Action 和 Action Input thought_match re.search(rThought:\s*(.*), llm_text, re.IGNORECASE) action_match re.search(rAction:\s*(.*), llm_text, re.IGNORECASE) input_match re.search(rAction Input:\s*(.*), llm_text, re.IGNORECASE) final_match re.search(rFinal Answer:\s*(.*), llm_text, re.IGNORECASE) if final_match: return {type: final, answer: final_match.group(1).strip()} elif action_match and input_match: return { type: action, thought: thought_match.group(1).strip() if thought_match else , action: action_match.group(1).strip(), action_input: input_match.group(1).strip() } else: return {type: unknown, text: llm_text} # ---------- 执行工具 ---------- def execute_tool(action_name: str, action_input: str) - str: if action_name search: return search(action_input) elif action_name calculator: return calculator(action_input) else: return f错误未知工具 {action_name} # ---------- 主循环 ---------- def run_agent(user_query: str, max_steps: int 5) - str: tools_desc tools_to_string(TOOLS) system_prompt build_prompt(user_query, tools_desc) messages [{role: user, content: system_prompt}] for _ in range(max_steps): llm_output call_llm(messages) print(f LLM 输出:\n{llm_output}\n{-*40}) parsed parse_action(llm_output) if parsed[type] final: return parsed[answer] elif parsed[type] action: action_name parsed[action] action_input parsed[action_input] # 执行工具 observation execute_tool(action_name, action_input) print(f 工具执行: {action_name}({action_input}) - {observation}\n) # 将本轮输出和观察结果加入对话 messages.append({role: assistant, content: llm_output}) messages.append({role: user, content: fObservation: {observation}}) else: # 解析失败原样返回错误提示 messages.append({role: assistant, content: llm_output}) messages.append({role: user, content: 请按指定格式回复必须包含 Thought/Action/Action Input 或 Final Answer。}) return 抱歉我无法在限定步骤内完成任务。 # ---------- 测试运行 ---------- if __name__ __main__: query 2024年诺贝尔物理学奖颁给了谁 result run_agent(query) print(✅ 最终答案, result)运行说明安装openai库pip install openai设置环境变量OPENAI_API_KEY或直接替换代码中的 key运行脚本即可看到 Agent 一步步思考、调用搜索工具、返回结果的过程。输出示例 LLM 输出: Thought: 我需要搜索2024年诺贝尔物理学奖的获奖者 Action: search Action Input: 2024年诺贝尔物理学奖 ---------------------------------------- 工具执行: search(2024年诺贝尔物理学奖) - 2024年诺贝尔物理学奖授予了研究人工神经网络的科学家。 LLM 输出: Thought: 我已经知道答案 Final Answer: 2024年诺贝尔物理学奖授予了研究人工神经网络的科学家。 ---------------------------------------- ✅ 最终答案 2024年诺贝尔物理学奖授予了研究人工神经网络的科学家。常见问题与注意事项1. 模型输出格式不稳定ReAct 严重依赖模型响应格式。在实践中可能会遇到不输出Action:或格式混乱的情况。可以通过以下方式提升稳定性- 使用能力更强的模型如 GPT-4- 在 prompt 中加入 few-shot 示例- 利用 OpenAI 的函数调用Function Calling特性绕过文本解析直接获得结构化输出2. 工具安全与错误处理工具可能抛出异常或返回超长内容。务必- 捕获所有异常返回友好的错误信息给模型- 限制工具返回的长度避免超出 token 限制-绝对不要在生产环境中直接使用eval()示例中我们用正则限制了输入字符但仍建议用更安全的表达式解析库如numexpr3. Token 消耗控制每一轮对话都会将完整历史发送给 LLM步骤一多 token 会迅速增长。优化手段- 对 Observation 进行摘要压缩- 采用滑动窗口只保留最近 N 轮- 使用长期记忆模块如向量数据库存储关键信息需要时检索4. 死循环问题Agent 可能反复调用同一个工具却得不到有用信息。可设置最大步数上限并在连续多次相同 Action 时强制终止或引导其改变策略。总结本文从 AI Agent 的核心设计模式出发重点剖析了ReAct 模式并给出了一个完整的 Python 实现。通过这个最小化代理你可以清晰地看到 LLM 如何将推理与行动结合从而蜕变为真正能“做事”的智能体。未来随着模型能力的提升和工程框架的成熟Agent 设计模式会进一步演化但感知-推理-行动-记忆这一基本循环将始终是构建智能代理的基石。掌握这些模式思想你将能更从容地设计出自己的 AutoGPT、数据分析 Agent甚至自动驾驶决策系统。希望本篇内容能帮助你打开 AI Agent 开发的大门。如有疑问欢迎在评论区交流探讨