第3讲:环境搭建与快速上手——跑通你的第一个“原生Agent”
欢迎来到《Python + AI Agent 实战开发完全指南》专栏!
在前两讲中,我们搞懂了Agent的底层逻辑和主流框架的选型。但说实话,很多新手刚接触AI开发时,往往会被一堆配置劝退。所以今天这一讲,我们不整虚的,直接带你把本地开发环境搭好,并且用最纯粹的原生 Python(不依赖LangChain等任何第三方复杂框架),手搓一个真正能调用大模型API、具备自主决策能力的 ReAct Agent。
一、 磨刀不误砍柴工:极简环境准备
在开始写代码之前,我们需要准备两样东西:
- Python 环境:建议使用 Python 3.9 或更高版本。
- 大模型 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 循环包含三个步骤:
- Thought(思考):分析当前状态,决定下一步该干嘛。
- Action(行动):如果决定调用工具,则输出特定的工具指令及参数。
- 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要更改为对应选择的模型
四、 代码深度解析与避坑指南
运行上面的代码,你会看到终端里打印出大模型一步步的思考过程。在这个过程中,有几个工程细节值得注意:
- Prompt 的约束力:我们在
REACT_PROMPT中规定了严格的换行标签(如Action:)。大模型本质上是文本补全机器,只有给出明确的格式模板,它才不会乱说话。 - 字符串解析的脆弱性:代码中使用了
split("\n")来提取 Action。在实际生产中,大模型偶尔会忘记加换行符或者多加空格。因此,成熟的框架通常会结合正则表达式(Regex)或者大模型原生的 Function Calling JSON 模式来进行更稳健的解析。 - 上下文管理(Memory):注意
messages列表在不断 append。这就是最简单的“短期记忆”。如果不把之前的 Thought 和 Observation 传回去,大模型就会失去记忆,陷入死循环。
本节小结
今天我们摆脱了所有高级框架的束缚,用最底层的 Python 实现了大模型与外部工具的交互闭环。理解了这套机制,你再去学 LangChain 或 AutoGen 时,就会发现它们只是帮你把这里的 while True 循环和字符串解析封装得更优雅了而已。
下一讲,我们将正式引入 LangChain 生态,看看如何用几行代码实现联网搜索与复杂计算,让 Agent 的能力产生质的飞跃!
更多推荐

所有评论(0)