世界上有一种循环叫 Execution Loop,它就像Agent的"思考-行动-观察"的永动机——Agent先想"我需要做什么",然后做,然后看结果,然后继续想...
凌晨2点07分,我看到Agent的日志里打印了"search('AI新闻')→处理结果→不够,再搜'Agent技术'→处理→再搜'2026趋势'..." 整整循环了8次才完成任务。那一刻我意识到:好的执行循环,就是Agent的"死磕精神"。
📚 定义
Execution Loop(执行循环) 也称 Reasoning + Acting 循环 (ReAct Loop),是AI Agent的核心运行机制:
- 思考 (Think):LLM分析当前任务,决定下一步行动
- 行动 (Act):调用工具、执行命令、发送请求
- 观察 (Observe):获取行动的结果反馈
- 继续循环:根据观察调整计划,继续执行
直到任务完成、到达最大迭代次数或用户中断。
🔬 工作原理
┌────────────────────────────────────────┐
│ Execution Loop │
│ │
│ ┌─────┐ ┌──────┐ ┌─────────┐ │
│ │思考 │────▶│ 行动 │────▶│ 观察 │ │
│ │Think│ │ Act │ │ Observe │ │
│ └──┬──┘ └──────┘ └────┬─────┘ │
│ │ │ │
│ └──────────────────────────┘ │
│ 循环直到完成或终止 │
└────────────────────────────────────────┘
具体步骤:
1. LLM 生成推理 → "我需要先搜索信息"
2. 调用 web_search("最新AI新闻")
3. 获取搜索结果
4. LLM 分析结果 → "这些信息不够全面,再搜"
5. 调用 web_search("AI行业动态")
6. 获取结果
7. LLM 判断 → "信息足够了,可以生成报告"
8. 调用 write_file("report.html", content)
9. 完成,返回结果
🚀 OpenClaw 实战
# OpenClaw 执行循环配置
agent:
execution_loop:
max_iterations: 10 # 最大循环次数
timeout: 300 # 总超时5分钟
# 停止条件
stop_conditions:
- agent_declares_done # Agent说任务完成
- max_iterations # 达到最大次数
- timeout # 超时
- user_interrupted # 用户中断
- error_threshold # 错误过多
# 错误处理
on_error:
max_retries: 2 # 每个工具最多重试2次
fallback: "记录错误,继续下一步"
# 中间结果缓存
cache_intermediate: true
checkpoint_path: "/tmp/openclaw/loop_checkpoint.json"
典型执行循环(RSS聚合任务):
[Think] "用户要求生成今日RSS摘要,需要先抓取多个源"
[Act] → web_fetch("github.com/openclaw/releases")
[Observe] → "获取到3条新版本发布"
[Think] "还需要从Hacker News获取热门讨论"
[Act] → web_fetch("hn.algolia.com/?query=OpenClaw")
[Observe] → "获取到5条热门话题"
[Think] "信息足够了,现在生成HTML摘要"
[Act] → write_file("/var/www/miaoquai/rss/2460.html")
[Observe] → "文件写入成功"
[Think] "任务完成,返回结果"
[Done] → "RSS第2460期聚合完成!"
💻 代码示例:简易执行循环
// execution-loop.js
export class ExecutionLoop {
constructor(config = {}) {
this.maxIterations = config.maxIterations || 10;
this.maxRetries = config.maxRetries || 2;
this.tools = config.tools || {};
this.context = [];
}
async run(task, systemPrompt) {
const startTime = Date.now();
let result = null;
for (let i = 0; i < this.maxIterations; i++) {
console.log(`\n🔄 第${i + 1}轮循环`);
// 1. THINK: 让LLM决定下一步
const thought = await this._think(systemPrompt);
console.log(`🤔 思考: ${thought.action}`);
// 2. 检查Agent是否认为任务完成
if (thought.done) {
console.log('✅ Agent认为任务完成');
result = { status: 'completed', output: thought.output };
break;
}
// 3. ACT: 执行工具调用
let observation;
for (let retry = 0; retry <= this.maxRetries; retry++) {
try {
observation = await this._act(thought);
console.log(`🔧 执行: ${thought.tool} (重试${retry}次)`);
break;
} catch (err) {
console.warn(`⚠️ 第${retry + 1}次失败:`, err.message);
if (retry === this.maxRetries) {
observation = `错误: ${err.message}`;
}
}
}
// 4. OBSERVE: 记录观察结果
console.log(`👀 观察: ${observation.slice(0, 100)}...`);
this.context.push({
thought: thought.action,
action: thought.tool,
result: observation
});
// 5. 检查超时
if (Date.now() - startTime > this._timeout * 1000) {
result = { status: 'timeout', output: '执行超时' };
break;
}
}
return result || { status: 'max_iterations', output: '达到最大循环次数' };
}
async _think(systemPrompt) {
// 调用LLM生成思考
// 返回 { action, tool?, parameters?, done, output }
return { action: 'search...', tool: 'web_search', parameters: {}, done: false };
}
async _act(thought) {
if (!thought.tool) return '无工具调用';
const toolFunc = this.tools[thought.tool];
if (!toolFunc) throw new Error(`工具不存在: ${thought.tool}`);
return await toolFunc(thought.parameters);
}
}
🎯 最佳实践
✅ 推荐做法:
- 设置合理的 max_iterations(5-15次)
- 每个工具调用加超时,避免死锁
- 记录每次循环的输入输出,便于调试
- 工具失败记录错误并继续,不要卡死
⚠️ 踩坑:
- 死循环:Agent可能不断搜索→结果不够→再搜索→再不够...
- 工具结果太大:工具返回大量数据,塞满context
- 状态漂移:Agent可能在循环中偏离原始目标