从零构建AI Agent:以Codex源码为教材的实战拆解
2026/9/23 6:59:33 网站建设 项目流程

让 Agent 不再是玄学——我用 Codex 源码当教材,手把手拆给你看怎么从零构建一个真正能干活的 AI Agent。

这两年 AI Agent 从概念火到了各种技术群里,但真到自己动手写的时候,很多人其实一头雾水:网上教程张口闭口都是 ReAct、多智能体、记忆机制、MCP,听着很唬人,落地却两眼一抹黑。我自己带团队做 Agent 项目踩了不少坑,最后发现一个特别好的学习路径——直接啃 OpenAI Codex 的源码。它不是那种一上来就甩给你几百个文件的巨型框架,而是把 Agent 最核心的骨架(模型调用、工具注册、上下文管理、任务循环)用非常工程化的方式摆在你面前。这篇文章我就以 Codex 源码为教材,从概念到实操,带你把“Agent 到底是什么、代码长什么样、自己怎么搭一个能跑的出来”这三件事彻底搞明白。

开始之前先回答一个很多人纠结的问题:Agent、LLM、AI 模型到底是什么关系?拿 DeepSeek 举例,它就是典型的 LLM(大语言模型),是一个脑子,能理解语言、生成文本,但它不会主动用工具,也不会自己规划多步任务。而 Agent 是“脑子 + 手 + 记忆 + 规划能力”的完整个体,LLM 是它的核心引擎,Agent 则是在这个引擎外面套了一层能感知环境、调用工具、迭代执行的壳。你可以把 LLM 想成一个特别聪明但没手没脚的专家,Agent 就是给这个专家配了电脑、扳手、记事本,还帮他列干活清单的助理。今天要拆的 Codex,就是“配好手脚后的专家”的一个优秀参考实现。

1. 内容整体设计与思路拆解

1.1 先搞明白我们要学的是什么:Codex 的整体架构

Codex 在源码层面的设计,其实就干了几件事:接受用户用自然语言描述的目标,然后把目标拆解成一系列可执行的动作,通过调用各种工具(比如执行 shell 命令、读写文件、搜代码)一步步逼近结果,最后把过程与结论汇报给用户。这个循环听起来不复杂,但工程实现上有几个非常关键的设计决策,决定了 Agent 能不能真正稳定地干活。

从源码目录结构来看,Codex 的代码组织很有教学价值。它把代码分成了核心运行时(runtime)、会话管理层(session)、工具层(tools)、配置层(config)几个大块。其中最值得学习的是它的运行时设计:每一条消息进来,内部都会经历“解析用户输入 -> 组装上下文 -> 调用模型 -> 解析模型输出 -> 执行工具调用 -> 将执行结果再喂给模型”这样一条完整闭环。这个闭环就是 Agent 的生命线,也是我在自己项目里反复打磨的核心逻辑。

我自己在带新人时有个体会:很多人一上来就想写一个通用的 Agent 框架,觉得越抽象越高级,结果半个月过去连一个能稳定完成“查天气并写进文件存下来”这种简单任务的 Agent 都跑不通。Codex 给我们最大的启发恰恰相反——它先把具体场景做扎实,再把可复用的部分抽象出来。它里面大量用到了“策略模式”,不同的工具执行策略、不同的模型适配策略,全都通过接口定义,然后在配置里自由切换。所以当你要构建自己的 Agent 时,第一原则是:先别急着写抽象层,先把具体的一条链路跑通,再回头抽公用代码。

1.2 为什么选 Codex 源码当教材:三个别人没告诉你的理由

市面上讲 Agent 的资料很多,有纯概念的科普文,有照搬 LangChain 的教程,有学术论文的复现解读,但 Codex 源码有它不可替代的教学价值。

第一,它是“真实产品级”的代码,不是 demo。很多教学项目为了演示方便,把错误处理、超时重试、配置校验这些“麻烦事”全部砍掉,你学完写出来的东西一上生产就崩。Codex 不一样,它是真正跑在成千上万人终端里的产品,所以在源码里能看到很多极其实战的处理细节:模型返回不符合格式时怎么纠偏、并发执行工具时怎么控制、上下文超长时怎么裁剪。这些才是真金白银的经验,普通教程根本不会写。

第二,它的边界划分特别干净,适合当解剖样本。Codex 严格区分了“模型的思考”和“Agent 的行动”。模型输出一律是大段自然语言加结构化的工具调用指令,Agent 则只负责解析这些指令并调度执行。很多人写 Agent 容易犯一个错误:把业务逻辑直接塞进模型 prompt 里,或者把工具执行的细节暴露给了模型,结果模型输出动不动就乱来。看 Codex 源码你能清晰地学到怎么画这条“模型与应用之间的边界线”。

第三,它支撑了“以源码为教材”的完整学习闭环。学概念 -> 看代码实现 -> 自己改代码跑通 -> 遇到问题回源码找答案,这个循环里每一步都能从 Codex 源码里找到对应内容。不像某些黑盒框架,出了问题你只能去发 issue 等回复,Codex 的代码结构足够清晰,自己就能定位问题。

1.3 在学习之前先树立正确的心智模型

我想强调一件比看代码更重要的事:Agent 不是某一项具体技术,而是一种工程架构思想。它没有一个标准答案,不是说必须用 LangChain、必须用 MCP、必须有记忆和规划才算 Agent。你在终端里敲一个命令让 AI 帮你改代码,这已经是 Agent 的雏形了。

以我个人的理解,Agent 要解决的核心矛盾是:把 LLM 这种“概率性的、不可控的”大脑,嵌入到一套“确定性的、可预期的”工程系统里。所以构建 Agent 最核心的能力反而在工程侧——你如何将模型输出的非结构化内容与你的系统安全地对接,如何做好错误处理,如何设计工具让模型更容易正确调用。这些能力都得靠动手写代码、踩坑来积累,单纯看文章是学不会的。

我建议的学习路径是:先有几天时间快速过一遍代码结构,不要深入每一行;然后盯住一个具体流程(比如让 Agent 执行一条 shell 命令并解释结果)从头跟到尾;最后再尝试自己扩展一个工具,或者换一个模型后端(比如把默认模型改成 DeepSeek 的 API),在这个过程中你会碰到大量实际问题,解决它们的能力就是构建 Agent 的真正功底。

2. 核心细节解析与实操要点

2.1 Agent 的核心组成结构:一个能干活的大脑需要哪些部件

在深入代码前,我们先从更高的视角捋一下一个完整的 AI Agent 需要哪些组成部件。按我的工程实践拆解,必要的部件包括:模型接入层、提示词与上下文管理、工具系统、任务规划循环、记忆系统、安全与权限控制,以及日志与可观测性。

模型接入层负责与 LLM 通信。这一层要考虑的远不止“调一下 API”那么简单:不同的模型(OpenAI 的、DeepSeek 的、本地跑的)在接口格式、参数支持、输出风格上有差异,你需要做一层适配;还要处理超时、重试、限流、token 统计等问题。Codex 里这一层就是核心运行时的一部分,它把模型的请求和响应都做了规范化包装,上层逻辑完全不需要关心背后是哪个模型。

提示词与上下文管理是很多人忽略的重头戏。Agent 每轮对话都要把系统提示词、历史对话、工具定义、工具执行结果拼装成一个上下文,这件事实测下来是 Agent 稳定性的分水岭。上下文拼得太长容易超限,拼得太短模型容易失忆;工具定义描述不清楚,模型就会产生幻觉乱调参数;历史对话不裁剪,几轮之后整个上下文就乱套了。Codex 的代码里对上下文管理有非常细致的处理,这也是我推荐读它源码的一个核心原因。

工具系统是 Agent 的“手脚”。一个 Agent 能干什么,完全取决于你给它接了什么工具。工具系统的设计有几个关键点:工具的描述信息要能被模型理解、参数定义要结构化(一般用 JSON Schema)、执行结果要能合理地返回给模型。Codex 支持调用 shell 执行命令、读写文件、搜索代码等工具,每个工具都封装成了模型可调用的函数形式。

任务规划循环是 Agent 区别于普通聊天机器人的根本特征。聊天机器人是“一问一答”,Agent 则在一个任务上反复迭代:思考下一步做什么、调用某个工具、观察结果、再思考、再行动,直到任务完成或达到终止条件。这就是经典的 Agentic Loop。Codex 源码里对这个循环的实现非常清晰:模型输出里可以直接包含多个内部思考步骤和多个工具调用请求,Agent 逐个执行这些请求,把结果收集起来再一次交给模型判断。

2.2 Agent 与 LLM 和 AI 模型的原理解读:DeepSeek 在哪个位置

结合前面的概念,我再用更具象的方式解释一下热搜词里那个高频问题:“Agent、LLM、AI 模型有什么区别?DeepSeek 属于哪个?”

大多数人对 AI 的认知是“有一个智能的东西,你跟它说话,它回答你”。但实际上这个链条是分层的。最底层是 AI 模型,指经过训练、能以某种形式处理输入的参数化系统,可以是语言模型、视觉模型、多模态模型;往上一层是大语言模型(LLM),专指基于 Transformer 架构、在大规模文本上预训练的语言模型,DeepSeek、GPT、Claude、Qwen 都属于这一类;再往上是 Agent,它不是一个模型,而是一个用 LLM 做引擎的完整应用系统,包含规划、记忆、工具调用等能力。

用一个类比来说:LLM 相当于一个应届 PhD 的大脑——知识丰富、推理能力强,但你给他一个“帮我整理桌面文件”的任务,他只会跟你讲应该怎么整理,却不会自己动手。Agent 就好比给这个 PhD 配了一双手、一套工具、一个日程本,让他不仅知道怎么做,还能真正动手去做、做完还能总结经验。

所以在技术选型上要特别搞清楚一件事:如果你只是想做一个聊天机器人,用 LLM 就够了;但如果你要做的是让 AI 自动完成某个业务流程,比如自动部署代码、自动分析数据报表、自动回复客户邮件,那你就需要 Agent。DeepSeek 本身是 LLM,但你可以基于它来构建 Agent 系统——这也是“codex 接入 deepseek”这种需求火爆的原因:Codex 原本默认调用 OpenAI 的模型,但通过修改配置和适配层,可以让它的 Agent 骨架配上 DeepSeek 这个国产 LLM 大脑。

2.3 方案选型:怎么选择合适的 Agent 构建路径

理解了概念和部件之后,接下来面临一个很现实的问题:我该用什么方式构建自己的 Agent?目前市面上有三条主流路径,我分别说说它们的优缺点。

第一条路径是使用现成的 Agent 框架,比如 LangChain、LlamaIndex、AutoGPT 这类。优点是上手快、生态全、内置大量工具和集成;缺点是抽象层次太高,出了问题很难定位,而且框架更新频繁,今天学的东西明天可能就被 deprecated 了。我见过太多团队把 LangChain 用成了“黑盒子胶水”,最后遇到一个诡异的 bug 无从下手,被迫读它的源码,读了两天放弃。

第二条路径是使用平台型产品,比如字节的 Coze(扣子)、Dify、阿里百炼这些。它们提供可视化编排,不用写代码就能搭出简单的 Agent 工作流。这条路径很适合快速验证想法和非技术背景的人,但如果你的业务场景比较复杂,或者需要在本地环境做深度集成,可视化平台往往力不从心。

第三条路径就是我从 Codex 源码里领悟到,也是目前我最推荐进阶者走的路:基于 LLM API 自己动手写一个轻量级的 Agent 核心。不要怕“重复造轮子”,对于一个 Agent 来说,最核心的循环逻辑其实不到 500 行代码就能写清楚。自己写过一遍,你对 Agent 的理解深度和用框架的人完全不是一个量级。而且这个核心写完后,你完全可以再去用它来理解 LangChain 之类的框架,这时候读框架源码会有一种“原来如此”的豁然开朗感。

2.4 为什么“工具”是 Agent 的灵魂:一个实践案例

说了这么多,我举一个我实际项目里的例子来加深理解。之前我帮客户做一个代码仓库自动梳理的 Agent,要求是:给它一个仓库地址,它自动分析项目结构、找出核心模块、生成 README。如果用一个“裸” DeepSeek 模型,你让它“分析这个仓库”,它会直接拒绝,因为它根本访问不了文件系统。但是当我给它接上“读取文件”“列出目录”“搜索代码”这几个工具后,同样一个模型,就能自己一步步去看目录结构、逐个阅读关键文件、总结出项目脉络。

这中间的差别,就是工具的威力。而且工具的威力不仅在于“能访问文件”,更在于给了模型一个“行动的抓手”。人在面对一个复杂任务时,如果只有脑子没有手,会陷入空想;模型也一样,工具的调用输出不断给模型提供新的信息输入,让它的推理链能够持续推进下去。从这个案例也能看出,Agent 开发的一个核心工作就是:想清楚你的业务场景里,Agent 需要哪些手。

3. 实操过程与核心环节实现

3.1 环境准备:搭建一个最简 Agent 开发环境

理论讲再多,不如亲手跑起来一个最小闭环。我这里给出一套经过我反复验证的、最轻量的 Agent 开发环境搭建方案。在开始之前,请你确认自己的电脑能跑 Python 3.10 以上版本,并准备好了至少一个大模型 API 的访问密钥(OpenAI、DeepSeek 或其他任意兼容 OpenAI 格式的 API 都可以)。

我的建议是直接用 DeepSeek 的 API 来学习,一方面国内访问稳定、价格便宜,另一方面它兼容 OpenAI 的接口格式,后续你切换到 OpenAI 或其他模型只需要改 base_url 和 api_key 两处配置。独立开发环境下,建议先做一个 Python 虚拟环境,避免依赖冲突:

mkdir my-agent && cd my-agent python3 -m venv venv source venv/bin/activate pip install openai python-dotenv

这里只安装两个核心库。openai官方 SDK 其实可以用来调用任何兼容 OpenAI 协议的模型接口,python-dotenv用来管理环境变量。装好后创建一个.env文件,填入你的 API 密钥和模型接入地址:

OPENAI_API_KEY=sk-你的key OPENAI_BASE_URL=https://api.deepseek.com MODEL_NAME=deepseek-chat

为什么要用.env文件而不是直接把密钥写在代码里?因为密钥一旦硬编码进代码,想改成环境配置就得改代码,而且不小心把代码分享出去就会泄露密钥。用环境变量管理密钥是我在所有项目里都坚持的底线习惯。

3.2 核心代码实现:用不到 300 行写一个能自主决策的 Agent

下面是我亲手整理、精简过的一个最简 Agent 核心实现。它不依赖任何 Agent 框架,只有一个循环:把消息发给模型 -> 模型决定调用什么工具 -> 程序执行工具 -> 把结果交回给模型 -> 重复直到模型不再调用工具。这里我实现了两个工具:一个用来模拟“获取当前时间”,一个用来模拟“执行 shell 命令”(生产环境请务必谨慎授权)。

import json import os import subprocess from datetime import datetime from dotenv import load_dotenv from openai import OpenAI load_dotenv() client = OpenAI( api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL"), ) TOOLS = [ { "type": "function", "function": { "name": "get_current_time", "description": "获取当前的日期和时间,返回字符串", "parameters": { "type": "object", "properties": {}, "required": [] } } }, { "type": "function", "function": { "name": "run_shell_command", "description": "在本地环境执行一条 shell 命令。仅在必要时使用。", "parameters": { "type": "object", "properties": { "command": { "type": "string", "description": "要执行的 shell 命令" } }, "required": ["command"] } } } ] def execute_tool(name: str, arguments: dict) -> str: if name == "get_current_time": return datetime.now().strftime("%Y-%m-%d %H:%M:%S") if name == "run_shell_command": try: result = subprocess.run( arguments["command"], shell=True, capture_output=True, text=True, timeout=10, ) return f"return code: {result.returncode}\nstdout: {result.stdout}\nstderr: {result.stderr}" except subprocess.TimeoutExpired: return "命令执行超时(10秒)" except Exception as e: return f"执行出错: {str(e)}" return f"未知工具: {name}" def agent_loop(prompt: str, max_iters: int = 8): messages = [ {"role": "system", "content": "你是一个能调用工具的智能助手。请根据用户的问题合理调用工具,并在确认完成后给出最终答复。"}, {"role": "user", "content": prompt} ] for i in range(max_iters): print(f"--- 第 {i + 1} 轮思考 ---") response = client.chat.completions.create( model=os.getenv("MODEL_NAME"), messages=messages, tools=TOOLS, tool_choice="auto", ) message = response.choices[0].message messages.append({ "role": "assistant", "content": message.content, "tool_calls": getattr(message, "tool_calls", None), }) if not message.tool_calls: print("Agent 最终回复:", message.content) return message.content for tool_call in message.tool_calls: print(f"调用工具: {tool_call.function.name} {tool_call.function.arguments}") result = execute_tool( tool_call.function.name, json.loads(tool_call.function.arguments or "{}"), ) messages.append({ "role": "tool", "tool_call_id": tool_call.id, "content": result, }) print("达到最大迭代次数,强制终止") return None if __name__ == "__main__": user_input = input("请输入你的任务: ") agent_loop(user_input)

这段代码就是整个 Agent 的核心骨架,我来逐步拆解每个环节为什么这么写。

代码的核心是agent_loop函数。它维护了一个messages列表,这个列表就是 Agent 整个生命周期里的“对话记忆”。在这个列表里,既有模型的思考过程(assistant 角色的内容),也有工具执行的结果(tool 角色)。把工具执行结果也拼接到 messages 里,是 Agent 能持续推理的关键,因为模型每多一个工具结果,就多了一条上下文证据,它的下一步决策就有更充分的依据。

再看tool_choice="auto"这个参数,它告诉模型:你可以根据对话内容自主决定是否调用某个工具,以及调用哪个工具,也可以不调用工具直接给出最终回答。这是模型侧“自主决策”的实现方式。当模型的返回里不包含tool_calls字段时,就说明它认为不需要再调用工具了,这时我们就认为任务已经完成,把它的话作为最终结果输出。

execute_tool函数是工具层的实现。它接收模型输出中关于工具名称和参数的解析结果,然后分发给对应的处理函数执行。这里面最关键的设计是:无论工具成功还是失败,都要把结果以字符串形式返回给模型。很多初学者会把工具执行放在 try/except 外面,一报错整个 Agent 就崩了,其实工具执行失败本身也是一条重要信息,模型看了之后可以调整策略重试。

3.3 运行测试:让 Agent 完成一个真实任务

代码写好后,我们在终端里跑一个测试看效果。我故意设计了一个需要调两次工具的任务:“先查看当前系统时间,再执行echo hello-agent命令,最后告诉我两个命令分别的结果。”

python agent.py

Agent 的输出大致是这样的(不同模型的回复措辞会有差异,但流程一致):

--- 第 1 轮思考 --- 调用工具: get_current_time {} --- 第 2 轮思考 --- 调用工具: run_shell_command {"command": "echo hello-agent"} --- 第 3 轮思考 --- Agent 最终回复: 当前时间是 2025-06-11 20:30:15;执行 echo hello-agent 的结果是:return code 0,stdout 为 hello-agent。

这个过程完整展示了 Agent 的核心工作方式:它不是一次性给出结果,而是分多轮决策,每一步都会结合前面的工具返回结果来规划下一步行动。第一次调用时间工具获取时间,第二次调用 shell 工具执行命令,第三次发现所有信息都齐了,就不再调用工具,直接组织自然语言回答。这就是 Agent 和普通 LLM 对话最本质的区别——它不是“我问你答”,而是“我发指令,你执行并反馈,直到任务完成”。

3.4 工具的安全边界与实际落地改造

前面给的示例可以在学习阶段安全运行,但如果你要把它用到真实工作里,有几个工程化改造必须做,否则会出事。最危险的就是那个run_shell_command,它让模型可以直接在终端执行任意命令。如果模型被恶意提示词诱导,或者它自己产生了偏差,运行了rm -rf /之类的命令,后果不堪设想。

我自己的工程实践里,对工具权限控制做了三层限制。第一层是命令白名单,只允许模型执行预设好的那几条命令(比如git statuslscat等只读命令);第二层是参数校验,即使命令在白名单里,也要对参数做正则校验,防止cat /etc/passwd这种越权读取;第三层是全部命令用沙箱用户运行,不给它宿主机完整权限。这三层下来,Agent 的安全性基本可控。

另外,真实场景里工具结果往往不是简单字符串,可能是大段日志、表格数据、图片路径等。这时候你需要考虑“结果摘要”策略:把海量结果先做一个局部摘要再放回模型上下文,防止 token 爆炸。我在处理日志分析类 Agent 时就经常用这个策略——工具先取出日志文件的前 N 行,让模型决定是继续看更多行还是基于当前信息分析,避免一次性把所有日志都塞给模型。

3.5 上下文管理与记忆机制:从会话级到持久级

很多 Agent 聊到十几轮就开始“失忆”,根源在于上下文管理没做好。LLM 的输入窗口有限,你不可能把所有历史对话和工具结果都无限塞进去。Codex 源码的处理方式是:对旧的对话做摘要压缩,把“完整的历史信息”压缩成“保留了关键信息的小体积摘要”,再与最近的对话内容拼接起来,一起送给模型。

对于自己的 Agent,我建议从简单到复杂逐步升级记忆方案。最简单的是滑动窗口,只保留最近 N 轮对话,超过的丢弃;进阶一点的是摘要记忆,每过几轮让模型把前面的核心信息总结成一段文字,后续用这段摘要替代原始对话;再进阶是外部向量库记忆,把关键信息存入向量数据库,需要时按相关性检索出来加入上下文。

这几种方案各自的适用场景不同。滑动窗口适合任务型 Agent,做完一个任务就结束;摘要记忆适合长对话的咨询场景;向量库记忆适合需要长期存储用户偏好的场景(比如购物助手)。刚开始做 Agent 别想着一上来就上向量库,先试试滑动窗口和摘要记忆,效果不一定差,而且代码量小一个数量级。

3.6 Codex 源码中的高级设计:Agent 工程化必须掌握的范式

读完 Codex 源码后,我提炼出几个设计上的亮点,它们对任何 Agent 项目都有直接的借鉴意义。

第一个是“结构化工具调用”的设计。Codex 要求模型输出的工具调用必须符合严格的 JSON 结构,凡是格式不正确的,Agent 会反馈一个“解析错误”给模型,并要求它重新生成。这种做法保证了解析层的稳定性。对比一些用正则表达式从自然语言里提取函数参数的方案,结构化调用无论从准确率还是扩展性上都完胜。这就是为什么现在 OpenAI 推出了 function calling、MCP 等标准协议,它们本质都是在推进结构化工具调用的标准化。

第二个是“分步骤可观测”。Codex 在每一步工具调用时都会输出日志,记录模型说了什么、调用了哪个工具、返回了什么结果。这个简单的“日志输出”习惯,在 Agent 出问题时就是救命稻草。我看过太多团队搭的 Agent 像黑盒一样,每次出问题只能靠猜,而 Codex 源码里就可以看到它把日志工程做得非常完善,从配置加载到请求发出到响应接收,每一步都有迹可循。

第三个是“可重试与容错设计”。模型 API 调用失败是常态,限流、超时、网络波动、模型接口返回异常,都需要 Agent 自己处理。Codex 源码的请求层针对不同类型的错误做了差异化处理:瞬时错误(网络超时、503)自动重试;永久错误(401、403)直接放弃并告知用户;限流错误(429)则等待一段时间后重试。这个设计思路值得直接抄进自己的 Agent 项目里。

4. 常见问题与排查技巧实录

4.1 模型输出的 Tool Call 解析失败

这是我在开发中最常遇到的问题,现象是:模型明明说了要调用某个工具,但代码却解析不到tool_calls字段。排查下来发现原因通常有两种。

第一种是模型不支持 function calling 或 tools 参数。像一些非 OpenAI 协议的本地模型,可能只支持纯文本输出,这时候你需要通过显式要求在 prompt 里让模型输出一个固定的 JSON 格式,然后再用json.loads去解析。这个方法虽然“土”,但在某些场景下是唯一方案。codex 接入 deepseek 时用的还是兼容协议,所以没有这个问题,但你如果换一些不兼容的模型,就得走 prompt 解析这条路。

第二种是 API 返回结构差异。如果你用了某个中转 API 或者框架的 SDK,它可能没有把tool_calls字段透传出来。遇到这类问题,我的排查习惯是先把 API 原始返回的 JSON 完整打印出来看一眼,确认字段结构,再写解析代码,千万别想当然。

4.2 上下文长度超限(Token Limit)

Agent 跑着跑着突然报错“context length exceeded”,这是第二个高频问题。原因是我们的messages列表无脑累积,历史对话加工具结果越来越多,撑爆了窗口。解决方案就是我前面提到的记忆管理策略:加一个简单的滑动窗口,只保留最近 8 轮的 messages,或者做完一轮工具调用后调用一次摘要,把摘要塞回 messages,清掉旧消息。

我实测下来有一个经验数据:一个工具执行结果动辄几百上千 token,如果 Agent 循环里频繁调用工具,5 到 10 轮就可能撑爆 8k 的上下文窗口。所以在设计 Agent 时就该提前规划好上下文预算——给系统提示词预留多少、给工具定义预留多少、给历史对话预留多少、给模型输出预留多少,心里要有数。

4.3 Agent 陷入无意义循环或死循环

有时候 Agent 会一直调同一个工具,得到相同的结果,然后接着再调,似乎“忘了”自己已经试过一次。这是 Agent 开发里常见的“无限循环”问题。我在本地跑示例时就遇到过一次,Agent 检查某个文件不存在后,仍然是反复调用“列出目录工具”尝试寻找,每次结果都一样。

排查到根因是:工具返回的信息在高频轮次之后被挤出了上下文窗口,模型“失忆”了。解决方法是调整上下文保留策略,确保最近的工具结果一定不被裁剪;另一个兜底方案是设置最大迭代次数(我前面代码里就设置了max_iters=8),到次数直接强制终止,防止 Agent 把 API 费用烧光。

4.4 Codex 自身安装与使用中的典型报错

很多同学在自己安装和使用 Codex 时也会碰到问题。我根据社区高频反馈总结了两个最常见的错误。

第一个是codex auth token is unavailable,这代表无法正常读取登录凭证。通常是基于 Codex 改造后没有正确登录,或者环境变量没设置。解决方法很简单:查看官方文档确认环境变量的变量名,检查注入方式(终端、CI、IDE 环境),确保变量名没有拼写错误。

第二个是cc switch local proxy failed while handling codex endpoint /responses. provi...,这类报错一般出现在网络代理配置不当时。本地开发代理无法正常处理 Codex 的 HTTPS 请求地址,导致请求被拦截或错误转发。解决办法是检查本地代理是否支持 HTTPS 证书,把 Codex 的域名加入代理的白名单(NO_PROXY 白名单),或者临时关闭代理直连试一下。这类问题十有八九是网络层的问题,排查时先确认好“当前 Agent 进程能不能直接访问到模型 API 地址”。

4.5 常见问题速查表

我把开发 Agent 时的高频问题整理成了一张速查表,方便你对照排查。

现象大概率原因排查/解决方向
模型不调用工具,直接给话工具描述不清 / 模型不支持 tools优化工具 description;加示例;换兼容模型
tool_calls 老是解析失败API 返回结构不标准打印原始返回结构确认字段名
上下文长度超限messages 无限累积加滑动窗口;对旧对话做摘要压缩
Agent 重复调用同个工具近期上下文被裁剪 / 状态未记录确保最近工具结果写入上下文;维护外部状态表
API 限流 429并发太多或额度过低指数退避重试策略;降低并发数
代码能运行但结果不理想prompt 描述不够具体细化工具说明;增加 few-shot 示例
可达性异常(连接超时、代理报错)网络层拦截 / 代理没配好检查 base_url 可达性;确认代理白名单配置

5. 从 Codex 源码到你自己的 Agent:一个可复制的进阶路线

5.1 第一周的目标:读懂模型接入层的秘密

很多人拿到 Codex 源码第一反应是“从 main 函数开始读”,但一个大项目从头读很容易劝退。我的建议是第一周只盯一个目标:把“请求是如何发给模型,响应又是怎么被处理的”这条链路彻底读透。

打开源码找到模型调用的接口实现,从“构建请求体 -> 配置请求参数(model、temperature、tools)-> 发送请求 -> 接收流式或非流式响应 -> 解析 response -> 根据响应决定下一步动作”这一整条链路上,每一个方法你都溯源去看它做了什么。读的时候建议配合打印日志或者加断点,跑一遍真实任务,观察每一步的请求和响应结构。这周结束你就能回答一个问题:Agent 的“思考”在工程上到底是怎么发生和被捕获的。

5.2 第二周的目标:读懂工具定义并自己加一个新工具

第二周开始动手修改:基于你第一周读通的链路,在 Codex 或你自己的 Agent 方案里新增一个定制工具。比如一个“获取系统 CPU 使用率”的工具,这需要做三件事:定义好工具的 JSON Schema(描述、参数、返回类型)、编写实际的函数体、把工具注册到代码里。加完后给它一个任务:“获取当前 CPU 使用率,如果超过 80% 提醒我注意。”观察模型能不能正确调用你的新工具。如果失败了,大概率是描述信息写得不够清晰,这能帮你理解工具描述与模型调用准确率之间的强关联。

5.3 第三周及以后:向多工具、多模型、持久记忆迈进

从第三周开始,可以尝试做这些升级:给 Agent 接上多轮记忆(用数据库存历史对话摘要);支持多个模型之间切换(比如 OpenAI 处理推理任务、DeepSeek 处理日常问答);把 Agent 暴露成 HTTP 服务接口,给前端页面调用。这些升级每一样都会碰到新问题,但核心的 Agent 骨架已经稳定了,你的所有工作都是在骨架之上做扩展。

我见过太多人一周想学会 Agent,结果什么都没学深。Agent 开发是一个需要长期积累才能精进的工程领域,按周定好目标慢慢打磨,才是正路。

这段从零构建 AI Agent 的实操旅程,本质上是一场“脑与手结合”的工程实践。Codex 源码的价值不在于让你背下每一行代码,而在于它像一本优秀的教材,把 Agent 最核心的设计范式(模型、工具、上下文、安全边界)以近乎标准答案的形式展示在你面前。以它为起点,先跑通最小闭环,再有意识地去扩展工具、管理记忆、控制权限,你会发现自己对 Agent 的理解远超那些只刷概念的人。

我个人这段时间做得最有效的一件事,是坚持给每一个 Agent 项目都留一份“失败记录”文档:什么场景下模型开始答非所问了、什么 prompt 会诱导它乱调工具、什么上下文结构让它准确率飙升,全部记录在案。时间长了你会发现,Agent 开发的真正门槛并不在模型,而在于你有没有把自己当成工程师,去认真打磨 System Prompt、上下文管理、工具定义这些周边工程。接下来动起来,哪怕从复制我上面那段最小代码开始,你也会很快体会到自己动手构建 Agent 的真正乐趣。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询