欢迎来到《Python + AI Agent 实战开发完全指南》专栏!

在前两讲中,我们搞懂了Agent的底层逻辑和主流框架的选型。但说实话,很多新手刚接触AI开发时,往往会被一堆配置劝退。所以今天这一讲,我们不整虚的,直接带你把本地开发环境搭好,并且用最纯粹的原生 Python(不依赖LangChain等任何第三方复杂框架),手搓一个真正能调用大模型API、具备自主决策能力的 ReAct Agent。

一、 磨刀不误砍柴工:极简环境准备

在开始写代码之前,我们需要准备两样东西:

  1. Python 环境:建议使用 Python 3.9 或更高版本。
  2. 大模型 API Key:你可以选择 OpenAI、智谱AI(国内免费额度多)或阿里云通义千问等。这里我们以兼容 OpenAI 接口格式的模型为例。

打开终端,执行以下命令安装必备库:

pip install openai python-dotenv

注:*python-dotenv** 用于安全地读取环境变量,防止你的 API Key 泄露到 GitHub 上。*

在你的项目根目录下创建一个 .env 文件,写入你的密钥:

OPENAI_API_KEY=sk-xxxxxxxxxxxxx
BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1  # 替换为你所用模型的Base URL,我目前使用的是阿里云通义千问

二、 核心架构拆解:ReAct 循环的本质

要让大模型变成 Agent,关键在于给它一套行为准则(Prompt)。目前业界最经典的范式就是 ReAct (Reasoning + Acting)。它的核心思想是强迫大模型在输出最终答案前,先按照固定格式输出自己的思考过程。

一个标准的 ReAct 循环包含三个步骤:

  1. Thought(思考):分析当前状态,决定下一步该干嘛。
  2. Action(行动):如果决定调用工具,则输出特定的工具指令及参数。
  3. Observation(观察):程序拦截这个指令,执行真实函数,并把结果反馈给大模型。

三、 实战演练:20行代码打造原生 ReAct Agent

接下来,我们把理论落地。这段代码展示了大模型是如何与我们自定义的工具进行“对话”并完成任务的。

import os, json
from dotenv import load_dotenv
from openai import OpenAI

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

# ========== 1. 定义真实的工具函数 ==========
def calculator(num1: float, num2: float, operation: str) -> str:
    """这是一个数学计算器"""
    if operation == "add": return str(num1 + num2)
    elif operation == "multiply": return str(num1 * num2)
    else: return "不支持的操作"

TOOLS_MAP = {"calculator": calculator}

# ========== 2. 构建 ReAct 专属 Prompt ==========
REACT_PROMPT = """你是一个智能助手。请严格按照以下格式回复:
Question: 用户的问题
Thought: 你的思考过程
Action: 需要调用的工具名称(仅限 {tools_list})
Action Input: 工具的JSON格式参数
Observation: 工具返回的结果(这部分由系统自动补充)
... (重复以上 Thought/Action/Observation 直到得出最终答案)
Final Answer: 最终的回复内容
"""

# ========== 3. 封装 Agent 核心执行引擎 ==========
def run_native_agent(query: str):
    # 拼接初始提示词
    messages = [{"role": "user", "content": REACT_PROMPT.format(tools_list=list(TOOLS_MAP.keys())) + f"\nQuestion: {query}"}]
    
    while True:
        response = client.chat.completions.create(model="qwen-turbo", messages=messages)
        agent_output = response.choices[0].message.content
        print(f"[Agent]: {agent_output}")
        
        # 如果大模型输出了 Final Answer,说明任务完成,退出循环
        if "Final Answer:" in agent_output:
            return agent_output.split("Final Answer:")[-1].strip()
            
        # 解析 Action 和 Action Input
        try:
            action_line = [line for line in agent_output.split("\n") if line.startswith("Action:")][0]
            input_line = [line for line in agent_output.split("\n") if line.startswith("Action Input:")][0]
            
            tool_name = action_line.split("Action:")[-1].strip()
            tool_args = json.loads(input_line.split("Action Input:")[-1].strip())
            
            # 执行工具并获取 Observation
            observation = TOOLS_MAP[tool_name](**tool_args)
            print(f"[System Observation]: {observation}")
            
            # 将大模型的输出和系统的观察结果追加到上下文中,进入下一轮循环
            messages.append({"role": "assistant", "content": agent_output})
            messages.append({"role": "user", "content": f"Observation: {observation}"})
        except Exception as e:
            # 容错处理:如果大模型格式不对,提醒它纠正
            messages.append({"role": "assistant", "content": agent_output})
            messages.append({"role": "user", "content": f"Error: 你的输出不符合格式要求,请严格按照 Thought/Action/Final Answer 格式重新思考。"})

# 测试运行
if __name__ == "__main__":
    result = run_native_agent("帮我算一下 15 乘以 8 再加 20 等于多少?")
    print(f"\n最终结果: {result}")

需要注意的是选择了不同的大模型时,response = client.chat.completions.create(model="qwen-turbo", messages=messages)中的model要更改为对应选择的模型

四、 代码深度解析与避坑指南

运行上面的代码,你会看到终端里打印出大模型一步步的思考过程。在这个过程中,有几个工程细节值得注意:

  1. Prompt 的约束力:我们在 REACT_PROMPT 中规定了严格的换行标签(如 Action:)。大模型本质上是文本补全机器,只有给出明确的格式模板,它才不会乱说话。
  2. 字符串解析的脆弱性:代码中使用了 split("\n") 来提取 Action。在实际生产中,大模型偶尔会忘记加换行符或者多加空格。因此,成熟的框架通常会结合正则表达式(Regex)或者大模型原生的 Function Calling JSON 模式来进行更稳健的解析。
  3. 上下文管理(Memory):注意 messages 列表在不断 append。这就是最简单的“短期记忆”。如果不把之前的 Thought 和 Observation 传回去,大模型就会失去记忆,陷入死循环。

本节小结

今天我们摆脱了所有高级框架的束缚,用最底层的 Python 实现了大模型与外部工具的交互闭环。理解了这套机制,你再去学 LangChain 或 AutoGen 时,就会发现它们只是帮你把这里的 while True 循环和字符串解析封装得更优雅了而已。

下一讲,我们将正式引入 LangChain 生态,看看如何用几行代码实现联网搜索与复杂计算,让 Agent 的能力产生质的飞跃!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐