当你第一次接触 AI Agent 开发时,是否有过这样的困惑:明明都是调用大语言模型的 API,为什么有些系统只能"一问一答",而有些却能像真正的助手一样,自己去搜索信息、执行代码、生成文件,甚至在遇到问题时自动调整策略重新尝试?
这个问题的答案,就藏在今天我们要深入探讨的核心概念里——Agent Loop。
如果把一个 AI Agent 比作一个人,那么 Agent Loop 就是它的"心跳"。每一次心跳,Agent 都在进行"感知当前状态→思考下一步行动→执行并观察结果"的循环。这个循环会持续运转,直到 Agent 判断任务已经完成。理解 Agent Loop 的设计,是掌握任何生产级 Agent 系统的第一把钥匙。
什么是 Agent Loop?
从"单次调用"到"自主循环"
当你使用 ChatGPT 的 API 进行一次普通对话时,流程是这样的:发送消息→等待响应→获得回复,结束。这是一个单次 API 调用,控制权始终在调用方手中。
但 Agent Loop 完全不同。当用户说"帮我分析这份数据并生成可视化报告"时,Agent 内部可能会经历这样的过程:
-
- 第一轮:读取数据文件,发现是 CSV 格式
-
- 第二轮:执行 Python 代码进行数据清洗
-
- 第三轮:计算关键指标,发现有异常值需要处理
-
- 第四轮:重新清洗数据,生成统计结果
-
- 第五轮:调用绘图工具生成可视化图表
-
- 第六轮:整合所有结果,生成最终报告
-
在这个过程中,LLM 自己决定是否继续循环——这是 Agent Loop 与普通 API 调用的本质区别。
Agent Loop 的三个关键特征

这三个特征共同构成了业界所说的 "ReAct"(Reasoning and Acting)范式的核心——Agent 在一个循环中反复交替进行推理(Reasoning)和行动(Acting),直到任务完成。

这个循环看起来简单,但它解释了 Claude Code 最核心的能力来源。你给它一个 bug,它不是"看一眼就猜答案"——它是反复观察、假设、验证的。先看报错日志,再搜索相关代码,再理解上下文,最后才动手改。这种行为不是编程进去的,是循环结构涌现出来的。模型在每一轮循环中都能看到上一轮的工具结果,所以它自然会做出"再看看""再试试"的决策。
循环什么时候结束? 满足下面两个条件之一即可:
-
- 模型主动停止——Agent 认为任务完成,生成纯文本回复,不再请求工具调用
-
- 达到最大轮次——Harness 设置了 --max-turns 限制,防止无限循环
-
核心思想
大模型不能直接操作外部世界,但它会 "思考"(Reason) 当前情况,然后决定 "行动"(Act)——调用某个工具。工具执行完毕后,将结果 "观察"(Observe) 反馈给模型,模型据此继续推理,直到认为可以给出最终答案。
实践项目简介
本项目的 ReAct 实现:Agent 维护一个 messages 列表,每次循环把完整历史(system prompt → user 问题 → LLM 的 tool_calls → 工具执行结果)整体传给大模型,大模型据此自主决定下一步是继续调用工具还是直接回答。循环上限 max_steps=10 防止无限调用。
基于 MiniMax-M2.7 模型构建的智能 Agent,使用原生 OpenAI SDK(无 smolagents / HuggingFace 依赖),支持 Function Calling 工具调用,并通过 ReAct 循环实现自主推理与工具执行。
✨ 核心特性
- 🧠 MiniMax-M2.7 大语言模型驱动
- 📦 纯 OpenAI SDK,无需访问 HuggingFace
- 🔧 Function Calling:LLM 输出结构化工具调用指令
- 🔄 ReAct 循环:Reason → Act → Observe 迭代推理
- 🛠️ Skill 层:注册 calc / search / sysinfo 三类本地工具
- 🌐 MCP Client:通过 Model Context Protocol 调用远程 MCP Server 上的 VDI 健康检查工具
🏗️ 架构

📁 目录结构
~/project-structure
agent/minimax_agent/
├── config.py # 所有配置
├── skills.py # SKILLS 注册表
├── handlers.py # 工具处理函数
├── mini_max_agent.py # Agent 入口
└── README.md # 本文档
消息流转(ReAct Loop 一次迭代)
~/react-loop
role=system : 提示词(Agent 角色定义 + 可用工具)
role=user : 用户问题
role=assistant : LLM 返回 tool_calls(如果有)
role=tool : 工具执行结果(多轮可能)
^
| 循环直到 assistant 返回 content(非 tool_calls)
v
最终答案
项目搭建流程
定义系统提示词
~/system-prompt
SYSTEM_PROMPT = """
你是一个智能助手,可以通过调用工具来完成任务。
主动执行原则(批量/自动化场景):
- 收到多个任务时,一次性分析所有任务,规划最优执行顺序
- 如果任务之间有关联(如先搜索文件再读取内容),在一次 ReAct 循环中依次调用工具
- 如果多个任务完全独立,可以在一个回答中依次说明每个任务的结果
- 不需要用户确认,直接执行你认为必要的工具调用"""
LLM 客户端创建
~/llm-client
client = OpenAI(
api_key=OPENAI_API_KEY,
base_url=OPENAI_BASE_URL,
)
工具定义注册与调用映射
~/skills-definition
SKILLS = [
# calc 工具定义
{
"type": "function",
"function": {
"name": "calc",
"description": (
"安全数学求值器。支持 + - * / // % ** sqrt log sin cos tan abs round ceil floor min max 以及常量 pi e。",
),
"parameters": {
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "数学表达式,如 2**10、sqrt(144)+pi"
},
},
"required": ["expression"],
},
},
}
# 其他工具...
]
~/tool-map
OpenAI SKILLS (Function Calling Schema)
|
v
TOOL_MAP
{
"calc" -> calc_handler -> subprocess -> mycli calc --json
"search" -> search_handler -> subprocess -> mycli search --json
"sysinfo" -> sysinfo_handler -> subprocess -> mycli sysinfo --json
"vdi_check_healthy" -> vdi_check_healthy_handler -> MCP Client -> HTTP -> MCP Server
}
🔄 ReAct 循环详解
ReAct(Reason + Act + Observe)是一种让 LLM 自主决定是否调用工具、如何调用、调用后如何继续的循环机制。
算法
~/algorithm
输入: 问题 Q, 最大步数 MAX_STEPS
messages = [system_prompt, user(Q)]
FOR i in range(MAX_STEPS):
1. 调用 OpenAI Chat API
2. 获取 assistant 回复 msg
IF msg.tool_calls 存在:
执行工具,添加结果到 messages
CONTINUE
ELSE:
RETURN msg.content
RETURN "无法在有限步骤内完成任务"
关键设计点
- tool_choice="auto":由 LLM 自行判断是否需要调用工具、调用哪个工具
- 多轮工具调用:单次响应中可能有多个 tool_calls,每个都执行并收集结果
- 消息累积:所有历史对话都传回 LLM,保证上下文完整
- MAX_STEPS 限制:防止无限循环
ReAct 循环完整代码实现
~/react-loop
def ask(question: str) -> str:
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": question},
]
for _ in range(max_steps):
# 1. THINK + ACT
response = client.chat.completions.create(
model=MODEL,
messages=messages,
tools=SKILLS,
tool_choice="auto",
)
msg = response.choices[0].message
# 2. 分叉
if msg.tool_calls:
messages.append(msg.model_dump(exclude_none=True))
for tc in msg.tool_calls:
result = TOOL_MAP[tc.function.name](
**json.loads(tc.function.arguments)
)
messages.append({
"role":"tool",
"tool_call_id":tc.id,
"name":tc.function.name,
"content":json.dumps(result)
})
else:
return msg.content or ""
return "无法在有限步骤内完成"
为什么 LLM 知道要调用工具? — 因为 tools=SKILLS 里的 description 字段告诉它每个工具是干什么的,LLM 自己判断用户问题是否匹配某个工具。
交互式运行入口
~/cli
if __name__ == "__main__":
print("MiniMax M2.7 Agent")
while True:
q = input("\nYou: ").strip()
if q.lower() in ("quit", "exit", "q"):
print("再见!")
break
print("\nThinking...")
answer = ask(q)
print(f"\nAnswer: {answer}")
效果演示
~/demo
python mini_max_agent.py
You:帮我计算2的10次方
Thinking...
Tool: calc({'expression': '2**10'})
Result: {'success': True, 'data': {'result': 1024}}
Answer: 2的10次方是1024。

代码库地址:
https://github.com/mambo-wang/ai-agent/tree/main/agent/minimax_agent