深入浅入 AI Agent:基于 Python 与 ReAct 模式的自主智能体实现
引言:从 Chatbot 到 Autonomous Agent 的范式转移
在当前的 AI 浪潮中,大语言模型(LLM)的能力正经历着从"文本生成"向"自主行动"的深刻演进。
早期的 AI 应用更多停留在 Chatbot 层面------用户输入指令,模型输出文本。虽然其具备极高的语言理解力,但由于其被隔离在"对话框"内,无法与物理世界或数字化工具发生交互。而真正的 AI Agent(智能体) ,则具备了类似人类的自主性 (Autonomy):它不仅能思考(Brain),还能通过调用外部工具(Hands)来感知、推理并改变环境。
本文将通过一个极其精简的 Python 项目 nanoAgent(https://github.com/sanbuphy/nanoAgent),深度拆解 AI Agent 的核心运行机制------ReAct (Reason-and-Act) 模式 ,并探讨如何在本地环境下利用 Ollama 与 Gemma 4 构建一个具备工具调用能力的 Agent 雏形。
1. 核心灵魂:什么是 ReAct 模式?
Agent 的智能程度并不完全取决于模型的参数量,而在于其能否构建起一个"思考 →\rightarrow→ 行动 →\rightarrow→ 观察"的闭环。ReAct 模式(Reasoning and Acting)正是这一机制的算法核心。
我们可以通过以下闭环流程来理解:
- Reasoning (推理):LLM 解析用户指令,基于当前的上下文逻辑判断当前任务的进度,并利用其内在的逻辑推理能力决定下一步需要调用哪个工具。
- Acting (行动) :模型输出特定格式的指令(通过 OpenAI 兼容的 Function Calling 协议)。程序解析该指令并执行对应的本地函数(如
write_file或execute_bash)。 - Observation (观察):工具执行后的结果(成功状态或具体的报错信息)作为新的上下文输入回传给 LLM。
其本质是一个基于环境反馈的自我修正过程:
User Prompt →\rightarrow→ LLM (Reasoning) →\rightarrow→ Tool Call (Acting) →\rightarrow→ Tool Result (Observation) →\rightarrow→ LLM (Next Reasoning) ...
2. 环境准备:轻量化本地化部署
为了保证研究的可复现性与隐私性,我们推荐使用 Ollama 在本地构建 Agent 环境。
2.1 依赖环境
- Ollama: 用于本地运行大型语言模型。
- Python 3.x: 核心运行环境。
- 依赖库 :
pip install openai
2.2 配置步骤
-
下载并启动 Ollama。
-
拉取模型 :在终端运行
ollama pull gemma4:26b(或其他可用版本)。 -
环境变量设置 :为了使 Python 的
openaiSDK 能够无缝对接本地服务,需要配置以下环境变量:bashexport OPENAI_BASE_URL="http://localhost:11434/v1" export OPENAI_MODEL="gemma4:26b" export OPENAI_API_KEY="ollama" # 本地服务通常不需要真实的 API Key
3. 源码剖析:解构 nanoAgent
nanoAgent 的实现非常精简,核心逻辑集中在工具定义 与 ReAct 循环驱动上。
A. 工具定义 (Tool Definition) ------ Agent 的"手"
Agent 的能力边界是由一组预定义的函数及其 JSON Schema 描述构成的。请注意:description 字段的内容实际上是 Prompt 的一部分,模型正是通过阅读这些描述来学习"何时"以及"如何"调用工具。
python
# agent.py 中的核心工具配置示例
tools = [
{
"type": "function",
// ... (此处省略部分代码以保持精简)
},
]
B. ReAct 循环驱动 (The Event Loop) ------ Agent 的"大脑循环"
run_api_loop 函数展示了如何驱动模型不断进行自我迭代,通过 tool_calls 与 role: tool 的交替,实现上下文的逻辑闭环。
python
def run_api_loop(messages, max_iterations=5):
for _ in range(max_iterations):
# 1. Reasoning & Acting: 获取模型的推理结果与工具调用指令
response = client.chat.completions.create(
model=os.environ.get("OPENAI_MODEL"),
messages=messages,
tools=tools,
)
message = response.choices[0].message
messages.append(message)
# 如果模型不再需要调用工具(即给出了最终回答),则结束循环
if not message.tool_calls:
return message.content
# 2. Executing & Observing: 执行工具并捕捉反馈
for tool_call in message.tool_calls:
name = tool_call.function.name
args = json.loads(tool_call.function.arguments)
# 调用预定义的函数执行真实任务
result = functions[name](**args)
# 3. State Closure: 将观察结果反馈给模型,实现上下文的逻辑闭环
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
return "Max iterations reached"
4. 运行实战:观察 Agent 的自主行为
通过运行封装好的脚本 run_agent.sh,我们可以直观地观察到 Agent 是如何"自主"完成任务的。
运行命令
bash
bash run_agent.sh
运行输出(真实终端捕获)
text
[Task] 你好,我是 ABC,我已经将我的名字写入了 name.txt 文件中。
[Tool] write_file({'content': 'ABC', 'path': 'name.txt'})
5. 工程进阶:从 Demo 到 Production 的鸿沟
虽然上述代码足以演示原理,但在真实的生产环境下,构建一个可靠的 Agent 面临着巨大的工程挑战:
🚨 挑战 A: 终止条件与死循环防御 (The Infinite Loop Trap)
如果工具执行失败(例如权限不足导致 write_file 报错),Agent 可能会陷入"尝试 →\rightarrow→ 报错 →\rightarrow→ 再次尝试"的死循环中。
- 对策 :必须引入严格的
max_iterations计数器,并且在Observation中显式告知模型当前的重试次数,引导其转向其他策略。
🚨 挑战 B: 上下文窗口的"膨胀危机" (Context Window Explosion)
随着 Observation(工具执行结果)的不断累积,messages 列表会迅速消耗大量的 Token 额度,导致响应延迟增加甚至超出模型限制。
- 对策 :引入 Context Management 策略,如定期对过长的历史 Observation 进行摘要(Summarization),或者采用滑动窗口机制丢采用滑动窗口机制丢弃过旧的交互记录。
🚨 挑战 C: 安全性与沙箱化 (Security & Sandboxing)
正如我们在工具中定义的 execute_bash,一旦 Agent 获得了执行 Shell 命令的能力,它就可能在你的主机上执行 rm -rf /。
- 对策 :绝对禁止 在宿主机直接运行具有高权限的 Agent。必须将 Agent 运行在受限的 Docker 容器 或专用的 Sandboxed Environment 中,并实施严格的系统调用审计。
总结
通过 ReAct 模式,AI 不再只是一个只会聊天的机器人,而是一个能够使用工具、观察环境并根据反馈自我修正的智能代理。虽然从一个简单的 Demo 到一个生产级的 Agent 之间还隔着巨大的工程鸿沟,但"推理 + 行动"的范式已经为构建下一代自主智能体铺平了道路。