1.概述
在人工智能快速发展的今天,AI不再仅仅是回答问题的聊天机器人,而是正在演变为能够主动完成复杂任务的智能代理。OpenAI的Codex CLI就是这一趋势的典型代表------一个跨平台的本地软件代理,能够在用户的机器上安全高效地生成高质量的软件变更。
2.内容
如果你只把 Codex 当成"更会写代码的 ChatGPT",那你只理解了它 10% 的价值。真正让 Codex 不同的,是它背后那套完整、可运行、可反复思考的 Agent Loop(智能体循环)系统。
2.1 Codex 到底和普通大模型有什么区别?
我们先看一个最普通的大模型交互流程:
你:帮我写一个 Python 脚本
模型:给你一段代码
结束
这是一次性生成,模型:
- 不知道代码能不能运行
- 不知道有没有报错
- 更不知道"下一步该干什么"
1. Codex 的真实工作方式完全不同
Codex 的思路更像一个新手工程师坐在你电脑前:
1 看需求
2 写点代码
3 运行一下
4 报错了?看看错误
5 改代码
6 再运行
7 直到成功
这个「反复尝试」的过程,就是 Codex Agent Loop。
2.2 什么是 Agent Loop?
Agent Loop = 让模型在一个循环里,不断思考 → 行动 → 看结果 → 再思考。Codex CLI 的核心不是"一次推理",而是反复展开这个循环,模型不是直接给答案,而是每一轮只决定:我下一步该干什么?
1. 先忘掉「大模型」,把 Codex 当成一个"新人程序员"
想象一个刚入职的初级工程师,你给他一个任务:
“帮我把这个项目跑起来,并写一个 README。”
他会怎么做?一定不是:
“我闭上眼睛,一次性把所有事情做对。”
而是更接近下面这个过程:
1 先看看项目目录结构
2 猜一猜怎么运行
3 真的运行一下
4 发现报错
5 根据报错改代码
6 再运行
7 直到跑通
8 最后再总结,写 README
注意:
这个过程中,每一步都依赖上一步的结果。这,就是 Agent Loop 的直觉来源。
2.普通 ChatBot VS Agent:根本区别在哪?
普通 ChatBot 的工作方式
输入问题
↓
模型"想一想"
↓
一次性输出答案
↓
结束
它的特点是:
- 只能"想",不能"做"
- 没有真实世界的反馈
- 更像是在考试答题
Codex Agent 的工作方式
目标
↓
想一小步
↓
做一小步
↓
看结果
↓
再想一小步
↓
......
↓
完成
它的特点是:
- 每一轮只解决一个非常小的问题
- 每一步都基于真实执行结果
- 更像是在真实工作
Agent Loop,本质上就是把"一次性回答问题",拆成了"多轮小决策"。
3. 「Loop」这个词,为什么这么重要?
我们先看一个不展开的情况:
模型在脑子里想 10 步
↓
一次性输出最终答案
这种方式的问题是:
- 中间哪一步想错了,你完全不知道
- 没有机会修正
- 对复杂任务非常不稳定
而 Agent Loop 是把这 10 步"摊开":
第 1 步:我该不该看目录?
↓
第 2 步:我该不该运行测试?
↓
第 3 步:这个报错是什么意思?
↓
第 4 步:我该改哪个文件?
这就是 unrolling the loop 的含义:把模型原本"在脑子里一次性完成的思考",拆成一轮一轮、可执行、可观察的步骤。
4.为什么说「模型不是直接给答案」?
复杂问题,没有人能在"看都没看现场"的情况下,一次就给出完美答案。Agent Loop 的设计,正是承认了这一点。所以 Codex 的策略是:
- 不追求"一次答对"
- 而是追求:
- 每一步都有依据
- 每一步都能被验证
- 每一步错了都能修
假设你的项目现在是这样:
“一个 Node 项目,运行 npm start 会报错”
Codex 的内心独白,并不是一句话,而是类似这样一轮一轮展开:
1 我不知道项目结构,我需要先看看 → 调用工具:ls
2 看起来是 Node 项目,我应该试着运行 → 调用工具:npm start
3 报错说缺依赖 → 调用工具:npm install
4 再运行一次 → npm start
5 现在跑通了,我可以总结了 → 输出最终回答
2.3 把 Agent Loop 拆成 5 个步骤
2.3.1 接收用户目标(不是马上干活)
1 用户输入 ≠ 模型直接思考的内容
当你在 Codex CLI(或任何 Agent 系统)里输入一句话,比如:
“帮我给这个项目补一个 README。”
很多人会误以为:
这句话直接被送进模型,然后模型开始思考。
但实际上,在 Agent 系统里,这句话的角色更接近于:
“任务目标(Goal)”
也就是说,它只是告诉系统:
最终你要把事情做到什么状态
2 为什么要把"目标"和"过程"分开?
因为 Agent Loop 的设计理念是:
- 目标是稳定的
- 过程是动态变化的
举个生活化的例子:
你的目标是“把房间收拾干净”
你并不会一开始就决定:
- 先扫地还是先整理桌子
- 垃圾有多少
- 要不要换垃圾袋
你只是知道:最后要干净
Codex 也是一样。
用户输入只负责定义“终点”,不负责定义“路径”。
2.3.2 构造当前上下文(Prompt)
1.Prompt 是"模型看世界的全部信息"
这是 Agent Loop 里最关键、也最容易被低估的一步。
我们先说一句非常重要的话:
对模型来说,它并不知道"刚刚发生了什么",
除非你把这些信息放进 Prompt。
所以,每一轮 Agent Loop,都会重新构造一个 Prompt。
2.Prompt 里通常包含哪些东西?
一个完整的 Prompt,通常包含:
- 你是谁(系统设定)
- 你是一个 coding agent
- 你可以修改文件、运行命令
- 你能用什么工具
- shell
- 文件读写
- 测试运行
- 用户目标
- 比如:补 README
- 到目前为止发生了什么
- 我刚才运行了什么命令
- 输出结果是什么
- 有没有报错
对模型来说,这些内容就是它的"记忆"。
3.为什么每一轮都要"重新构造" Prompt?
举个例子:
- 第一轮:你还没看过项目结构
- 第二轮:你已经知道有哪些文件
- 第三轮:你已经看到测试报错
如果 Prompt 不更新,模型就会:
- 永远以为自己什么都不知道
所以 Agent Loop 的一个核心动作就是:
- 把"刚刚发生的现实结果",翻译成模型能理解的文字,再塞回 Prompt。
2.3.3 让模型做"下一步决策"
1.模型在这一轮,只回答一个问题
这是 Agent Loop 的灵魂所在。
- 模型不会在这一轮里把所有事情想完。
它只做一个非常具体、非常有限的判断:
- "在当前信息条件下,我下一步该做什么?"
2.这个"下一步",通常只有两种可能
情况一:我还需要更多信息 / 行动
模型会说类似:
- "我需要看看目录结构"
- "我需要跑一下测试"
- "我需要打开某个文件看看内容"
在系统层面,这会被表达为:
- Tool Call(工具调用)
情况二:信息已经够了,可以结束
模型会说类似:
- "现在我可以写 README 了"
- "问题已经修复完成"
这时,它会直接输出最终回答,Agent Loop 结束。
3.为什么要限制成"只想一步"?
因为这是控制复杂度的关键。
如果模型一次性想 10 步:
- 中间哪一步错了,你不知道
- 无法插入真实反馈
- 很难纠正
而"一步一想"的好处是:
- 每一步都可以被验证
- 错了就马上修
- 对复杂任务更稳
2.3.4 如果要干活 → 调工具
1.模型自己"不会干活"
模型 ≠ 能执行命令的程序,模型只能输出文字(或结构化指令),但:
- 它不能真的运行 ls
- 不能真的执行 npm install
- 不能真的写文件
2.Tool 的作用:把"建议"变成"现实动作"
当模型说:"我需要运行 ls 看看目录",Agent 系统会:
1 解析模型输出
2 发现这是一个 tool call
3 在真实环境里执行命令
4 收集真实输出
2.3.5 把结果塞回上下文,继续循环
1.这是 Agent Loop 最"反直觉"的一步
很多人会以为:工具执行完,模型"就知道结果了",其实不然。模型并不知道工具执行结果,除非你把结果写进 Prompt。
2.现实 → 文本 → Prompt
Agent 会把刚才的执行结果,转成类似这样的内容:
你刚刚运行了 ls
输出是:
src/
package.json
然后:
- 把这段文字加入 Prompt
- 再发起下一轮模型推理
这一步完成后,新的一轮 Loop 开始。
我们现在可以把这 5 步,用一句非常生活化的话说清楚:
1 把当前情况告诉模型
2 让模型决定下一小步
3 把真实结果反馈回去
4 直到模型觉得“可以收工了”
3.Agent Loop代码示例
前面我们讲了很多概念:
Agent Loop、目标、Prompt、工具、反馈......
现在我们用一段最小但完整的代码,把这些概念全部落到实处。
class SimpleAgent:
def __init__(self, llm):
self.llm = llm
self.history = []
def run(self, goal):
while True:
prompt = self.build_prompt(goal)
response = self.llm(prompt)
# 如果模型说"完成了"
if response["type"] == "final":
print(response["text"])
break
# 如果模型要用工具
if response["type"] == "tool_call":
result = self.execute_tool(response)
self.history.append(result)
def build_prompt(self, goal):
return {
"goal": goal,
"history": self.history
}
def execute_tool(self, call):
if call["name"] == "shell":
return os.popen(call["command"]).read()
这段代码不是生产级,但它100%体现了 Agent Loop 的本质结构。下面我们从整体 → 局部 → 每一行的"为什么"来拆。
1.先整体理解:这段代码在干什么?
它在做一件事:
不断把"当前状态"交给模型,让模型决定下一步,
然后根据结果更新状态,直到模型说"可以结束了"。
可以理解为:"你先想一步 → 我帮你干 → 把结果告诉你 → 你再想一步"
2.class SimpleAgent:Agent 不是模型,而是"调度者"
Agent ≠ 模型(LLM)
- llm:负责"思考 / 决策"
- Agent:负责"循环 / 执行 / 状态管理"
Agent 的角色更像是一个项目经理 + 执行助理。
3.init:Agent 的"长期记忆"在哪里?
self.llm 是什么?
- 它是一个函数或对象
- 输入:Prompt
- 输出:模型的"下一步决策"
你可以把它理解成:
response = 大模型(prompt)
4.self.history 为什么这么重要?
这是整个 Agent Loop 的核心状态。
history 里存的不是聊天记录,而是:
- 你刚刚执行了什么命令
- 命令输出了什么
- 有没有报错
它是"现实世界发生过的事情"的文本化记录
如果没有 history:
- 模型每一轮都会"失忆"
- 永远不知道自己刚才干过什么
5.run 方法:Agent Loop 的真正入口
def run(self, goal):
这里的 goal,就是你输入的那句:
“帮我给这个项目加一个 README”
它只做一件事:定义终点,不定义路径。
6.while True:为什么 Agent 必须是"死循环"?
这行代码非常关键。
很多人一看到"死循环"会下意识觉得不优雅,但在 Agent 里:
- 没有循环,就没有 Agent
为什么?
因为 Agent 的工作模式是:
- 不知道要循环多少轮
- 不知道什么时候信息才"足够"
- 只能一轮一轮试
结束条件不是写死的,而是由模型决定的。
7.build_prompt:模型"看到的世界"是怎么来的?
prompt = self.build_prompt(goal)
这是 Agent Loop 中最容易被忽略,但最重要的一步。
def build_prompt(self, goal):
return {
"goal": goal,
"history": self.history
}
它做的事情非常简单,但意义非常大:把"目标 + 已发生的事实"打包,交给模型。
8.response = self.llm(prompt):模型只做一件事
response = self.llm(prompt)
这一行,看似简单,其实决定了整个 Agent 的风格。
模型在这里不会:
- 写完整代码
- 一次性解决所有问题
它只回答一个问题:
- "在当前 prompt 条件下,我下一步该做什么?"
我们用一句完整的流程复述:
- Agent 把目标 + 历史交给模型
- 模型说:"下一步干这个"
- Agent 去真实执行
- Agent 把结果记录下来
- 回到第 1 步
- 直到模型说:
- "可以结束了。"
4.总结
Codex Agent 的真正价值,并不在于它"写代码有多快",而在于它被设计成一个可以反复思考和行动的系统。通过 Agent Loop,模型不再试图一次性给出完美答案,而是像真实工程师一样:先尝试、再观察、再修正,逐步推进目标完成。这种"思考 → 执行 → 反馈 → 再思考"的循环机制,让复杂问题被自然拆解成一连串可验证的小步骤,也让错误变成系统的一部分,而不是失败的终点。
5.结束语
这篇博客就和大家分享到这里,如果大家在研究学习的过程当中有什么问题,可以加群进行讨论或发送邮件给我,我会尽我所能为您解答,与君共勉!
另外,博主出新书了《Hadoop与Spark大数据全景解析》、同时已出版的《深入理解Hive》、《Kafka并不难学》和《Hadoop大数据挖掘从入门到进阶实战》也可以和新书配套使用,喜欢的朋友或同学, 可以在公告栏那里点击购买链接购买博主的书进行学习,在此感谢大家的支持。关注下面公众号,根据提示,可免费获取书籍的教学视频。