核心概念:Agent Loop与Sampling的定义
视频开篇回顾了上一期关于Codex支持Skills的内容,本期聚焦于更基础且关键的Agent Loop(智能体循环)实现机制。普通的AI聊天交互模式相对简单:用户提出问题,应用调用一次模型,随即得到回答。然而,Codex在处理开发任务时展现出截然不同的行为逻辑:它先读取代码文件,接着修改内容,然后运行测试;若测试失败,它会继续分析错误日志并再次尝试修改,直到给出最终结果。这种多步骤的迭代过程并非简单的循环逻辑所能概括。
为了深入理解源码,首先需要澄清一个高频术语:Sampling。在Codex的语境中,Sampling指的是模型根据当前上下文完成一次推理并产生输出的过程。对于开发者而言,这通常对应于一次模型的API调用。需要明确的是,Sampling并不等同于完整的任务执行,它仅仅是整个大任务中的一个原子操作单元。为了方便后续论述,文中将统一使用模型调用这一表述来指代Sampling。
“这里的sampling,指的是模型根据当前上下文完成一次推理并产生输出。对应用来说通常就对应了一次模型的API调用。”
通过引入Sampling的概念,我们可以将系统架构清晰地划分为三个层次:最外层是对话(Conversation),这是一条可以保存和恢复的记录,内部包含多次用户输入;中间层是任务(Task),从用户提出需求开始到Codex给出最终结果为止的所有过程都属于同一个任务;最内层则是模型调用(Model Call)。在一次用户任务的内部,可能会发生多次模型调用,形成复杂的交互链条。
循环流程:从上下文准备到工具执行
让我们完整走一遍Agent Loop的一次迭代过程。在每次调用模型之前,Codex必须精心准备结构化的上下文。这个上下文不仅包含用户与模型的聊天记录,还涵盖了模型之前提出的工具调用、执行后的结果以及运行过程中新增的用户要求。这些内容并非简单拼接成一段长文本,而是按照类型和顺序严格保存。模型提出了哪个工具调用,后面就必须对应相应的执行结果。
当上下文准备就绪后,Codex发起模型调用。模型的返回内容分为两种情况:普通消息或工具调用指令。如果是普通消息,Codex会将其直接记录;如果是工具调用,Codex首先记录下模型意图,然后将工具名称和参数传递给外部的运行时(Runtime)。这里有一个关键区分:模型本身并不具备读取文件或执行终端命令的能力,它只负责提出动作建议。真正改变文件系统和系统状态的是模型外部的运行时环境。
“工具执行完成以后,结果会被转换成结构化的记录重新写回当前的会话。下一次模型调用开始时,模型就能看到我刚才提出了什么动作。”
工具执行完毕后,结果被转换为结构化记录并写回当前会话。此时,一个完整的Agent Loop闭环形成:上下文进入模型 -> 模型提出下一步动作 -> 运行时执行工具 -> 结果回到上下文 -> 模型继续判断。只要仍有待处理的动作或满足继续条件,循环就会持续;否则任务结束。这就是Agent Loop最核心的逻辑骨架。
运行时复杂性:历史维护与并行控制
虽然最小化的Agent Loop逻辑看似简单,但Codex之所以需要一整套任务运行时系统,是因为它必须解决循环周围的一系列复杂问题。首先是结构化历史的维护。Codex需要确保工具调用与其对应的执行结果能够精确匹配,防止上下文混乱导致模型产生幻觉或错误决策。
其次涉及并行与顺序执行的控制。在同一次模型返回中,可能包含多个工具调用。Codex需要智能判断哪些操作是相互独立的(如读取不同文件),可以并行执行以提升效率;而涉及修改环境共享状态或存在依赖关系的操作,则必须严格限制执行顺序。这种细粒度的调度能力是普通循环无法实现的。
“同一次模型返回可能包含多个工具,能够确认彼此独立的读取操作是可以并行的。可能修改环境共享状态或者相互依赖的操作则必须限制执行顺序。”
此外,错误处理机制也至关重要。无论是工具成功返回还是发生可反馈的错误,结果都必须回传给模型。只有让模型看到真实的执行结果(包括报错信息),它才能根据实际反馈调整下一步策略,而不是在工具一报错时就导致整个任务直接崩溃终止。这种容错机制保证了智能体在面对不稳定环境时的鲁棒性。
动态交互:用户追加与上下文管理
在实际开发场景中,用户的需求往往是动态变化的。Codex允许用户在任务运行过程中追加新的要求。这些新消息并不会立即打断当前流程,而是先进入待处理区。系统会等待当前步骤到达一个安全的位置(Safe Point)后,才将新消息加入下一次的模型调用上下文。这种设计既保证了响应用户需求的灵活性,又避免了因中途插入指令导致的执行状态不一致。
同时,Agent Loop必须具备明确的继续、暂停和停止条件。例如,“取消”操作或等待用户确认属于正常流程,但无法恢复的错误则不能被视为普通的下一轮迭代。随着任务运行时间的延长,上下文窗口(Context Window)的管理成为另一大挑战。当对话历史过长导致接近上限时,系统必须采取策略确保持续运行。
“用户可以在运行时追加要求。新的消息会先进入到待处理区,等当前步骤达到安全的位置再加入下一次的模型调用。”
为此,Codex引入了上下文压缩(Context Compression)和执行记录保存机制。前者旨在让有限的上下文窗口能够继续容纳新的交互信息,后者则确保任务状态可以在必要时进行恢复。这两项技术共同保障了长周期、多步骤任务的稳定性,是Agent Loop从理论走向工程实践的关键支撑。
架构对比:Codex与Pi-mono的差异分析
为了更直观地理解不同实现路径,视频将Codex与开源智能体框架Pi-mono进行了对比。Pi Agent是基于Pi-mono开发的产品,而Pi-mino本身也是一个开源框架。两者的最小循环逻辑基本相同:准备上下文、调用模型、执行工具、交还结果并判断是否继续。Pi同样支持并行工具、错误反馈和中途追加消息等核心能力。
真正的差异在于这些能力的部署层级。Pi-mono将底层的Agent Loop设计为一个轻量级的TypeScript库,主要处理消息、模型和工具的交互,并持续向外发出事件。会话持久化、上下文压缩和自动重试等高级功能主要由上层的AgentSession组件组织。终端界面则通过订阅这些事件来展示流式文本和工具结果,而不直接介入Loop内部。
“Pi把底层的Agent Loop做成了一个比较轻量级可以单独嵌入的TypeScript库。底层主要处理消息模型工具并持续向外发出事件。”
相比之下,Codex的做法更接近于一套完整的产品运行时。会话状态、工具环境、Skills和插件系统、执行记录、上下文压缩策略以及传输层的状态管理,都直接参与用户任务的生命周期。这种设计使得Codex能够在一个紧密耦合的系统中统一管理所有状态,而非依赖松散的事件驱动架构。
上下文压缩与传输优化细节
以上下文压缩的位置和时机为例,可以清晰看到两者的设计理念差异。在Pi框架中,通常是在一次Agent运行结束后,由上层检查是否需要压缩历史,再决定是否继续。如果遇到上下文溢出,它也是先执行压缩操作然后再重试整个流程。
而在Codex中,上下文压缩可以在同一个用户任务尚未结束时触发。系统可以先压缩历史数据,然后直接回到当前的循环中继续执行。这种即时处理能力使得Codex在处理超长对话时更加流畅,无需中断任务流程。
此外,Codex在WebSocket传输层进行了专门优化。在同一个用户任务内,如果请求配置保持不变且历史数据仅是顺序追加,Codex可以引用上一轮的响应,仅发送新增的内容(Delta)。只有当历史数据经过压缩、回滚或改写时,才会退回到发送完整请求的模式。这种机制有效节省了网络传输开销。
“Codex在WebSocket传输上还做了一个优化。如果历史经过压缩回滚或改写,就回退完整的请求。”
需要强调的是,这种传输优化并非Agent Loop成立的必要条件。最小版本的Agent Loop确实非常简短:调用模型、保存输出,若有工具则执行并保存结果,若无动作则返回最终答案。真正的难点在于保证每一轮迭代时状态的正确性、操作的安全性以及错误的可处理性和任务的可恢复性。
结论
Agent Loop的本质并非复杂的算法,而是一个简单的While循环结构。然而,让智能体从“回答问题”走向“执行任务”,关键在于模型外部运行时的强大支撑。Codex之所以能完成多步骤的开发任务,不是因为单次回答足够长或API自动执行工具,而是因为它将一次用户任务展开为多次模型调用:模型负责提出下一步动作,而外部运行时负责执行、记录、控制继续与停止条件。
Pi-mono展示了Agent Loop的最小必要组件,强调了轻量、可组合性和多模型适配;而Codex则展示了当循环进入真实产品开发环境后,运行时系统需要统一管理的状态一致性、执行控制和恢复能力。两者并无绝对优劣之分,而是针对不同场景的设计取舍:Pi适合构建灵活、轻量的智能体应用,Codex则专注于提供稳定、可控的复杂任务执行环境。真正的挑战在于如何在循环之外,构建一个能确保每一轮迭代都安全、可控且可恢复的运行时系统。