首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >AI 智能体工作流:从零构建可复用的 ReAct 代理系统

AI 智能体工作流:从零构建可复用的 ReAct 代理系统

原创
作者头像
用户12339161
发布2026-07-29 10:44:18
发布2026-07-29 10:44:18
2670
举报

AI 智能体工作流:从零构建可复用的 ReAct 代理系统

本文深入剖析 AI 智能体的核心工作流,手把手带你实现一个基于 ReAct 模式的自主代理,支持工具调用、多步推理和动态决策,适用于自动化任务处理、数据分析等场景。


一、为什么需要 AI 智能体工作流?

大语言模型(LLM)虽然强大,但本质上是“静态”的——它只能基于训练数据生成回答,无法主动调用外部工具、无法记忆上下文、也无法执行多步骤的复杂任务。例如,当你问“明天北京天气如何,顺便帮我算一下 100 美元等于多少人民币”时,模型只能给出基于知识的猜测,而无法实时查询天气或汇率。

AI 智能体(Agent) 的出现解决了这个问题。它像一个“大脑”,能够:

  • 理解用户意图,分解为子任务;
  • 调用外部工具(API、数据库、计算器等)获取实时信息;
  • 根据中间结果进行推理,决定下一步动作;
  • 循环迭代,直到完成最终目标。

工作流(Workflow) 则是将这些能力组织成可预测、可复用的执行流程,使得智能体不再是“黑盒”,而是可控、可调试的生产级系统。


二、核心设计模式:ReAct

ReAct(Reasoning + Acting)是当前最流行的智能体框架之一,由 Yao 等人在 2022 年提出。其核心思想是将推理行动交替进行:

代码语言:javascript
复制
Thought: 思考当前需要做什么
Action: 选择一个工具并传入参数
Observation: 观察工具返回的结果
... (重复上述步骤直到完成)
Final Answer: 给出最终答案

这种循环结构让智能体能够动态调整策略,应对不确定环境。


三、系统架构设计

我们将构建一个轻量级但功能完整的智能体工作流系统,包含以下模块:

  1. LLM 控制器:负责与语言模型交互,生成推理和动作指令。
  2. 工具注册表:管理所有可用工具(函数),并提供统一的调用接口。
  3. 记忆组件:存储对话历史、中间推理步骤和观察结果。
  4. 执行引擎:解析 LLM 输出,调度工具执行,控制循环终止。
  5. 工作流管道:定义输入、输出、超参数(最大迭代次数、温度等)。

四、代码实现

我们使用 Python 3.10+ 和 OpenAI API(兼容接口),但代码设计上易于替换为本地模型(如 Ollama)。

4.1 环境准备

代码语言:javascript
复制
pip install openai requests python-dotenv

创建 .env 文件:

代码语言:javascript
复制
OPENAI_API_KEY=your_key_here
OPENAI_BASE_URL=https://api.openai.com/v1  # 可替换为代理或本地端点

4.2 定义工具

工具是智能体的“手脚”。我们定义三个实用工具:天气查询、计算器、搜索(模拟)。

代码语言:javascript
复制
import requests
import json
import re

# 工具注册字典
TOOLS = {}

def register_tool(func):
    """装饰器:注册工具"""
    TOOLS[func.__name__] = func
    return func

@register_tool
def get_weather(city: str) -> str:
    """查询城市当前天气(使用 wttr.in 免费 API)"""
    try:
        url = f"https://wttr.in/{city}?format=%C+%t"
        resp = requests.get(url, timeout=5)
        return resp.text.strip()
    except Exception as e:
        return f"天气查询失败: {str(e)}"

@register_tool
def calculator(expression: str) -> str:
    """安全计算数学表达式,例如 '2 + 3 * 4'"""
    # 移除危险字符,只允许数字和运算符
    sanitized = re.sub(r'[^0-9+\-*/().]', '', expression)
    try:
        result = eval(sanitized, {"__builtins__": {}})
        return str(result)
    except Exception as e:
        return f"计算错误: {str(e)}"

@register_tool
def search(query: str) -> str:
    """模拟搜索,返回固定结果(实际可接入 SerpAPI 或 Bing)"""
    # 这里模拟一些常见问题,实际可替换为真实搜索 API
    mock_db = {
        "北京人口": "北京常住人口约 2185 万(2023 年)",
        "Python 版本": "最新稳定版为 Python 3.12",
        "AI 智能体": "AI 智能体是一种能够自主感知环境、做出决策并执行动作的实体。"
    }
    for key, value in mock_db.items():
        if key in query:
            return value
    return f"未找到关于 '{query}' 的准确信息,建议进一步核实。"

4.3 构建提示模板

我们需要一个清晰的指令,让 LLM 遵循 ReAct 格式输出。

代码语言:javascript
复制
SYSTEM_PROMPT = """你是一个智能助理,能够使用工具解决用户问题。
你的回答必须严格遵循以下格式:

Thought: 你当前的想法,分析需要做什么。
Action: 你要调用的工具名称,必须是 [{tool_names}] 之一。
Action Input: 工具的输入参数(JSON 字符串)。

如果已经获得足够信息,则输出:
Thought: 我已经得到最终答案。
Final Answer: 对用户的最终回复。

注意:每次只输出一个 Thought/Action/Action Input 组合,不要输出多余内容。
工具列表及说明:
{tool_descriptions}
"""

def build_prompt(tools, messages):
    tool_names = ", ".join(tools.keys())
    tool_descriptions = "\n".join(
        [f"- {name}: {func.__doc__}" for name, func in tools.items()]
    )
    system = SYSTEM_PROMPT.format(
        tool_names=tool_names,
        tool_descriptions=tool_descriptions
    )
    # 将消息列表组装成 LLM 所需格式
    prompt_messages = [{"role": "system", "content": system}] + messages
    return prompt_messages

4.4 执行引擎(核心循环)

代码语言:javascript
复制
import os
import json
from openai import OpenAI

client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY"),
    base_url=os.getenv("OPENAI_BASE_URL")
)

def run_agent(user_query, max_steps=5):
    messages = [{"role": "user", "content": user_query}]
    step = 0
    while step < max_steps:
        step += 1
        print(f"\n--- Step {step} ---")
        
        # 调用 LLM
        prompt = build_prompt(TOOLS, messages)
        response = client.chat.completions.create(
            model="gpt-4o-mini",  # 可替换为其他模型
            messages=prompt,
            temperature=0.2
        )
        output = response.choices[0].message.content
        print(f"LLM Output:\n{output}")
        
        # 解析输出
        if "Final Answer" in output:
            # 提取最终答案
            final_match = re.search(r"Final Answer:\s*(.+)", output, re.DOTALL)
            if final_match:
                return final_match.group(1).strip()
            else:
                return "无法提取最终答案。"
        
        # 尝试提取 Action 和 Action Input
        action_match = re.search(r"Action:\s*(\w+)", output)
        input_match = re.search(r"Action Input:\s*(\{.+\})", output, re.DOTALL)
        
        if not action_match or not input_match:
            # 如果格式不对,要求 LLM 重新输出
            messages.append({"role": "assistant", "content": output})
            messages.append({"role": "user", "content": "请按照指定格式输出,包含 Action 和 Action Input。"})
            continue
        
        action_name = action_match.group(1)
        try:
            action_input = json.loads(input_match.group(1))
        except json.JSONDecodeError:
            messages.append({"role": "assistant", "content": output})
            messages.append({"role": "user", "content": "Action Input 必须是合法的 JSON 字符串。"})
            continue
        
        # 调用工具
        if action_name in TOOLS:
            tool_func = TOOLS[action_name]
            try:
                if isinstance(action_input, dict):
                    result = tool_func(**action_input)  # 传递参数
                else:
                    result = tool_func(action_input)
            except Exception as e:
                result = f"工具调用异常: {str(e)}"
        else:
            result = f"未知工具: {action_name}"
        
        print(f"Tool Result: {result}")
        
        # 将观察结果加入历史
        messages.append({"role": "assistant", "content": output})
        messages.append({"role": "user", "content": f"Observation: {result}"})
    
    return "超过最大迭代步数,未能完成任务。"

4.5 整合运行

代码语言:javascript
复制
if __name__ == "__main__":
    query = "明天北京天气怎么样?顺便帮我算一下 (25 + 30) * 2 等于多少。"
    answer = run_agent(query, max_steps=4)
    print("\n=== Final Answer ===")
    print(answer)

五、运行示例

执行上述代码,你将看到类似以下的交互日志:

代码语言:javascript
复制
--- Step 1 ---
LLM Output:
Thought: 用户需要查询北京明天的天气,并计算一个数学表达式。我需要分别调用天气和计算器工具。
Action: get_weather
Action Input: {"city": "北京"}
Tool Result: Partly cloudy +22°C

--- Step 2 ---
LLM Output:
Thought: 天气已获取,现在需要计算 (25+30)*2。
Action: calculator
Action Input: {"expression": "(25+30)*2"}
Tool Result: 110

--- Step 3 ---
LLM Output:
Thought: 我已经获得了天气和计算结果,可以给出最终答案。
Final Answer: 明天北京天气为 partly cloudy,气温约 22°C。您计算的 (25+30)*2 等于 110。

最终输出:

代码语言:javascript
复制
=== Final Answer ===
明天北京天气为 partly cloudy,气温约 22°C。您计算的 (25+30)*2 等于 110。

六、进阶:工作流编排与多智能体协作

上面的实现是单智能体顺序执行。在实际复杂场景中,我们需要更强大的工作流,例如:

  • 并行执行:多个独立子任务同时调用不同工具。
  • 条件分支:根据中间结果决定后续路径。
  • 多智能体协作:一个智能体负责规划,另一个负责执行,再一个负责验证。

一种轻量级实现是使用 LangGraphAutoGen,但我们可以基于现有代码扩展工作流状态机。例如,定义工作流 YAML:

代码语言:javascript
复制
workflow:
  - step: query_weather
    tool: get_weather
    params: { city: input.city }
    next: calculate
  - step: calculate
    tool: calculator
    params: { expression: input.expr }
    next: aggregate
  - step: aggregate
    prompt: "整合天气和计算结果,生成友好回复"

通过解析这类 DSL,我们可以实现声明式工作流,更适用于企业级应用。


七、优化与生产化建议

  1. 错误重试与回退:工具调用可能失败,应设计重试机制和备选策略。
  2. 流式输出:对于耗时的推理过程,采用流式返回中间步骤,提升用户体验。
  3. 可观测性:记录每次推理的 token 消耗、耗时、工具调用链,方便调试和成本控制。
  4. 安全与权限:严格限制工具的执行权限,避免注入攻击或越权访问。
  5. 缓存:相同查询可使用缓存结果,节省 API 调用费用。

八、总结

AI 智能体工作流是连接大模型与真实世界的桥梁。通过 ReAct 模式,我们能够构建一个可推理、可行动、可迭代的自动化系统,适用于客服、数据分析、自动化办公等场景。本文提供的完整代码实现了核心循环,并展示了如何注册自定义工具,读者可在此基础上快速扩展。

掌握智能体工作流,你将不再仅仅是一个 API 调用者,而是能够设计出自主决策系统的 AI 工程师。这是未来 AI 应用开发的核心能力之一。


参考资料

  • Yao et al., "ReAct: Synergizing Reasoning and Acting in Language Models", 2022.
  • LangChain 官方文档
  • OpenAI Function Calling 指南

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • AI 智能体工作流:从零构建可复用的 ReAct 代理系统
    • 一、为什么需要 AI 智能体工作流?
    • 二、核心设计模式:ReAct
    • 三、系统架构设计
    • 四、代码实现
      • 4.1 环境准备
      • 4.2 定义工具
      • 4.3 构建提示模板
      • 4.4 执行引擎(核心循环)
      • 4.5 整合运行
    • 五、运行示例
    • 六、进阶:工作流编排与多智能体协作
    • 七、优化与生产化建议
    • 八、总结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档