Codex CLI 没有 worktrees(教你手动实现!)

如果你读过我之前写的 关于 Claude Code 中 worktrees 的文章,你应该知道这个功能的核心就是一个小小的参数:--worktree。执行这个参数之后,每个代理都能在一个隔离的代码仓库副本中运行。每次启动一个代理程序,就在独立的目录中操作。三个代理同时跑也互不干扰,仿佛魔术一般。 现在打开 Codex CLI,想找一下等效的参数,结果发现它根本不存在。 没有 --worktree。没有 --tmux。也没有支持自定义代理的 isolation: worktree 参数。而且,尽管issue #12862 在 GitHub 上已经开了很久,并且已经有人在 fork 中实现了这些功能,但官方始终没有合并代码。到目前为止,Codex CLI 还是无法原生支持多个代理并行操作。 这是否意味着无法使用 Codex 实现并行工作?答案是否定的。这只是意味着你需要自己动手 “折腾” 一下。而这件事说穿了,不过是几个 git 命令和一些预防措施。 计划:手动 worktrees + 每个目录运行一个 Codex 整体思路跟 Claude Code 中的方法类似,只是没有自动化功能。简单来说,就是你自己创建 worktree,自己启动代理程序,事情完了也需要自己清理。这工作听上去有点人工,但它确实管用。 # 从你的主仓库目录开始 cd ~/code/mi-proyecto # 为每个任务创建一个 worktree git worktree add ../mi-proyecto-feat-auth -b feature/auth git worktree add ../mi-proyecto-fix-tests -b fix/tests-rotos git worktree add ../mi-proyecto-refactor -b chore/refactor-db --- 现在你有四个目录:一个主目录和三个 worktree,每个 worktree 都是相互独立的。每个 worktree 拥有自己的分支、暂存区 (*staging area*) 和 HEAD,但共享仓库的元数据(`.git/` 目录),其他一切隔离。 接下来,在每个 worktree 运行一个 Codex: ```bash # 终端 1 cd ../mi-proyecto-feat-auth codex --approval-mode never --sandbox workspace-write \ "实现 JWT 鉴权中间件,编写测试代码。" # 终端 2 cd ../mi-proyecto-fix-tests codex --approval-mode never --sandbox workspace-write \ "运行测试套件,修复所有失败的测试,一直重复直到全部通过。" # 终端 3 cd ../mi-proyecto-refactor codex --approval-mode never --sandbox workspace-write \ "重构数据库模块以使用连接池功能。" 三个代理,三个任务,它们互不干扰。每个 Codex 只看到自己对应的 worktree,并且只操作相应的分支。 ...

2026年3月11日 · Fernando

Codex CLI 自动同意:两个标志让它不再打断你

安装 Codex CLI 后,满怀期待地启动它。你告诉它“修复这个代码库中失败的测试”。然而,灾难随即开始: Codex: I want to run pytest Allow? (y/n) 你输入了 y。接下来: Codex: I want to modify test_user.py Allow? (y/n) 又输入了 y 。一次又一次,每次需要读取一个文件、执行一个命令或者修改一行代码,它都会请求确认。确认,确认,还是确认。这感觉就像跟一个刚入门的实习生合作,他每次连去洗个手间都要问你同不同意。 与此同时,Claude Code 或 Cursor Agent 却可以实现相同的功能,但却不会多说一句话。这是为什么? 原因在于:默认情况下,Codex 被配置为一个“过于谨慎”的助手。这么做是为了安全考虑,尤其是针对一款新产品来说是很合理的。但如果你对操作足够了解,这种保守模式在实际工作中将让人无法忍受。 好消息是:只需几秒钟便能调整过来。 权限模式:approval mode Codex 使用一种叫做 approval mode(批准模式)的概念来控制需要你授权的情境。默认设置下,它对所有操作都需要你的确认: 执行命令 写入文件 修改代码 创建新文件 运行测试 简单来说:默认状态下,Codex 无法在没有你按下 y 键的情况下做任何事情。可以将其形容为:对每一个操作都需要一次 sudo 操作。 这使得一个本应是自主代理的工具,变成了一场你成为整个过程中最慢环节的无休止对话。 解决方案:使用一个标志 codex --full-auto 从版本 0.1.2 起,--full-auto 是官方的快捷方式,它将 --approval-mode never 和 --sandbox workspace-write 两个参数组合在一起。如果你使用的是旧版本,也可以用完整写法: codex --approval-mode never 无论选择哪种方法,Codex 都会停止询问你,直接执行命令、修改文件、创建需要的内容。它将真正成为一个自主工作的代理。 ...

2026年3月11日 · Fernando

上下文工程:区分优秀与普通AI代理的隐形技能

想象一下,你聘请了一位才华横溢的咨询师。他拥有两个博士学位,会说七种语言,并能解决你甚至不知道存在的问题。你把他安排到一个会议室,然后告诉他:“我需要你重新设计项目的认证系统。” 咨询师看着你,点了点头,问道:“哪个项目?” 你没有提供代码访问权限,也没有解释其架构。他不知道你在使用JWT令牌还是会话cookie,也不了解你使用的编程语言或微服务数量,更不知道为什么你上一次迁移会失败。 这个咨询师,就像你的LLM(大型语言模型)。而你刚刚犯了90%的AI代理使用者都犯的错误:关注大脑本身,而不是关注大脑所看到的信息。 Prompt工程已经过时——上下文工程长盛不衰 过去几个月,我在每个论坛、每条推特讨论线程、每场团队会议中都看到同样的对话:“GPT-5还是Claude Opus?”“哪个模型对代码更好?”“哪个模型推理能力更强?” 我的回答,每次推算下来,都是一样的:这不重要。当然,不是完全不重要。但一个顶尖模型与另一个顶尖模型之间的差异,与提供优秀上下文和垃圾上下文之间的差异相比,简直微不足道。 一个表现平庸的模型但配备完美上下文,永远优于一个顶尖模型却给它垃圾上下文。总是如此,没有例外。 这就有了一个名词:上下文工程。而且,它与Prompt工程完全不同。 Prompt工程是编写一个好的提示。它是选择正确的词语、结构请求、加入示例。这很重要,但只是一个部分。 上下文工程则是设计模型看到的所有信息:哪些输入信息、顺序如何、空间有限时需要舍弃什么、压缩什么、哪些是必须保留的。这是为LLM做信息架构。 简单来说:Prompt工程是提出一个好的问题。而上下文工程则是在考试开始前决定学生桌上有什么书籍。 四阶段记忆:你看不到的生命周期 OpenAI最近发布了两个Cookbook文章,详细解构了具有长期记忆的代理如何进行上下文管理。这不是RAG,也不是矢量数据库,而是一种基于状态的系统,像一本具有严格规则的田野笔记本。 其模式是“本地优先”和“基于状态”的:一个结构化的状态对象与代理一起更新,贯穿每个阶段。 flowchart TD A["1. 注入阶段\n(会话开始)"] --> B["2. 提纯阶段\n(对话期间)"] B --> C["3. 合并阶段\n(会话结束后)"] C --> D["4. 修剪阶段\n(持久性保存)"] D -->|"新的会话"| A A1["将状态渲染为YAML\n+全局记忆(最多6个)\n+优先规则"] -.-> A B1["save_memory_note()\n验证持久性\n确保可操作性\n拒绝PII和推测"] -.-> B C1["异步任务\n合并会话→全局\nLLM辅助去重\n过滤临时记忆"] -.-> C D1["修剪会话: 最近N次\n注入修剪记忆入\nsystem prompt"] -.-> D style A fill:#2d3748,stroke:#4a9eed,color:#fff style B fill:#2d3748,stroke:#ed9a4a,color:#fff style C fill:#2d3748,stroke:#9a4eed,color:#fff style D fill:#2d3748,stroke:#4aed5c,color:#fff 阶段1:注入——考试桌上的资料 当会话启动时,代理会创建其初始上下文。这不是随机的,而是一个具体结构: YAML前置数据,包含用户状态(如偏好、配置)。 全局记忆列表:最多6个,按最近使用排序。为什么是6个?因为超过6个会相互竞争,导致信息模糊。少即是多。 <memory_policy>块,带有明确的优先规则。 优先规则至关重要:当前输入 > 会话记忆 > 全局记忆 > 同范围内的最新信息。如果用户说“我现在用Vim”,而你的全局记忆却显示“使用VS Code”,则以用户最新输入为准。虽然看起来显而易见,但没有明确规则的情况下,模型有时会选择其“记住”的内容而非用户给出的新信息。 ...

2026年3月11日 · Fernando

OpenAI如何在没有分片的情况下,用一个主库支持8亿用户的PostgreSQL

每当有大公司的基础设施相关文章发布时,Hacker News 上总会出现一堆评论,内容大多是这样的变体:“当然了,他们用Kubernetes撑起了47个微服务,还加了一套自主开发的分布式共识协议数据库。”然而,当真相是他们只是用单纯的PostgreSQL主库和一点使用规范支撑其业务时,评论区就会陷入一片尴尬的沉默。 这次,OpenAI就再次打了这样一个大脸。 超出所有人想象的数字 OpenAI基础设施工程师Bohan Zhang刚刚分享了他们如何用PostgreSQL支持ChatGPT的具体细节。令人惊讶的数据如下: 8亿用户 单一PostgreSQL主库(写入操作专用)部署在Azure上 ~50个只读副本 每秒百万次查询 p99延迟仅10-19毫秒 99.999%的可用性 一年内仅出现一次SEV-0事故 (而且还是因为ImageGen产品的病毒式传播,让一周之内新增了1亿用户) 再读一遍。一个。主库。支撑8亿用户。 “可是他们为什么不分片?” 不需要。背后的原因非常简单而务实。 给PostgreSQL分片需要改动数百个应用的端点。每一个默认假设所有数据都在同一个数据库查询——基本是所有查询——都需要重写,来判断每个数据属于哪个分片。 这么迁移需要付出的成本呢?是数月的工作量、新的bug层出不穷,再加上一个混乱的迁移过渡期——同时需要维护老旧和新系统。 于是他们采用了另一种方式:识别最占用写入负载的数据,然后将其移至Cosmos DB。而这样做的原因并不是因为Cosmos比PostgreSQL更好,而是因为这些特定的工作负载更适合文档数据库模型。而其他大部分业务逻辑依旧保留在PostgreSQL中。 用大白话说:他们没有让整个系统变复杂,而是精确识别出问题所在,并有针对性地解决它。精密手术刀式的调整,而不是拿电锯一通乱砍。 PgBouncer:将连接延迟从50毫秒降到5毫秒 他们遇到的第一大瓶颈是建立连接的延迟。PostgreSQL会为每个新连接创建一个独立进程。而随着来自成百上千个应用Pods的并发连接数增加,光是处理新连接的开销就已达到50毫秒——甚至还没开始执行查询呢。 他们的解决方案是:使用PgBouncer作为连接池。PgBouncer会维护一个已经建立好的连接池,复用这些连接。结果是连接延迟从50毫秒降至5毫秒,直接减少了90%的延迟。仅仅通过更换一项底层工具,问题就得到了解决。 值得提到的是,这根本不是什么新技术。PgBouncer已经有15年以上的历史,并一直被各种规模的企业用于生产环境中。然而,它再次证明,一款久经考验的不起眼的工具,解决了这个地球上使用最频繁应用之一的问题。 那个做了12个表联接的ORM 这个问题是我的最爱。我见过它出现在学生的项目、初创公司,甚至银行的系统里。到处都有。 他们的ORM生成了包含12个表联合查询(join)的SQL语句。罪魁祸首并不是哪个设计人员,而是因为数据模型过于复杂且关系交织,ORM顺着这些关系“不假思索”地将每个可能的相关表都加载了进来。 解决办法既不是换ORM,也不是手动改写所有的查询。他们选择了将一些逻辑转移到应用层。与其让PostgreSQL执行一个庞大的join操作,他们分拆成多个简单查询,然后用代码对数据进行整合。 这么做优雅吗?的确没那么优雅。速度快吗?快得多。因为PostgreSQL处理简单查询比处理含有交叉条件的12表联合查询高效得多。而且,部分结果还能进行缓存和复用。 -- 之前:ORM生成的SQL SELECT u.*, p.*, s.*, t.*, ... FROM users u JOIN profiles p ON ... JOIN settings s ON ... JOIN teams t ON ... JOIN ... -- 总计12个表 WHERE u.id = $1; -- 之后:语句被拆分,逻辑移到应用层 SELECT * FROM users WHERE id = $1; SELECT * FROM profiles WHERE user_id = $1; -- 可缓存、可并行、可调试 每一条单独的查询都很简单。查询解析器几微秒内就可以完成。并且一旦其中有一条失败或者变慢,你可以直接找到问题所在。 ...

2026年3月11日 · Fernando

你的AI编程助手不过是个有妄想症的while循环

第一次使用Claude Code重构整个模块时,我几乎产生了宗教般的震撼体验。描述需求后喝了杯咖啡回来,就看见14个文件变更的PR,测试用例全更新,提交信息也像模像样。“这简直是魔法”,我当时这样想。 但根本不是魔法。就是个while循环。 OpenAI的Michael Bolin最近发文拆解了Codex CLI的内部机制。原来这些AI编程助手背后的秘密既不是革命性算法,也不是神秘神经网络,而是一个循环调用LLM、执行工具直到任务完成的简单流程。 让我们来庖丁解牛。 状态机:5阶段循环结构 所有编程助手——Codex、Claude Code、Cursor等都遵循相同的基础模式。Michael Bolin将其描述为5阶段循环: flowchart TD A["1. 提示词组装"] --> B["2. 模型推理"] B --> C{需要工具调用?} C -->|是| D["3. 工具执行"] D --> E["4. 工具结果反馈"] E --> B C -->|否| F["5. 生成最终响应"] F -->|新输入| A 用开发者能懂的话说: 提示词组装:构建包含系统指令、可用工具、读取文件、对话历史等完整上下文的提示词 模型推理:将提示词token化后传给模型,获取思维链/工具调用/文本响应 工具调用:若模型请求工具(读文件/执行命令等),则运行对应操作 工具反馈循环:将工具执行结果作为新增上下文再次传给模型,重复2-4阶段 结果生成:当模型判定任务完成时输出最终响应 就这么简单。没有知识图谱,没有符号规划器,没有复杂架构。本质上就是个封装了LLM的while循环。 优秀助手与平庸助手的差异不在循环结构——它们完全一致——而在于每个阶段的实现细节。 阶段1:提示词工程的艺术 第一阶段是核心所在。在LLM看到任何代码前,助手需要构建包含以下要素的提示词: flowchart LR subgraph 提示词组件["提示词组装"] 方向 TB SP["系统指令\n(角色设定/规则)"] Tools["可用工具\n(读/写/Bash等)"] Ctx["已读取文件/图像"] Inst["CLAUDE.md/AGENTS.md\n(项目规范)"] Env["环境信息\n(OS/git状态等)"] Hist["完整对话历史"] User["用户最新消息"] end SP --> 最终提示 Tools --> 最终提示 Ctx --> 最终提示 Inst --> 最终提示 Env --> 最终提示 Hist --> 最终提示 User --> 最终提示 这里有个关键设计决策:组件顺序至关重要。提示词按稳定性降序排列:系统指令最前(永不变动),工具定义次之(很少变动),最后是动态增长的文件内容和对话历史。 ...

2026年3月11日 · Fernando

无需 Codex 的 Codex Automations:用 Claude Code 和 systemd 打造夜班代理

两周前,OpenAI 推出了 Codex Automations。简单来说:你定义一个触发器(如 cron、代码 push 或新 issue),写下自然语言指令,一个代理在独立的 worktree 中自动执行这一切。整个过程无需人类介入。在你睡觉时,代理自动整理 issues、总结 CI 错误、生成发布文档,甚至优化自身的指令。 听上去像魔法?确实有几分神奇。但他们在 keynote 里没怎么提到的一个细节是:你必须在桌面上运行 Codex App。支持 macOS 和 Windows。没有无头服务器的选项。安装在一个迷你 PC 上并丢一边任其运行?没门。 这时我想:“等等,我已经有这个了。” 你已经拥有的组件 如果你在使用 Claude Code,那么你已经拥有 90% 的基础设施。用命令 claude --print 就能在非交互式会话中执行提示(prompt)。传递指令,获取结果,关闭,不需要图形界面或者打开的终端窗口。这对于一个 cron 工作来说简直完美。 如果你已有一台永远开机的服务器(比如迷你 PC、树莓派,或者每月 5 欧元的 VPS),那么你已经有了调度程序。systemd 或 cron,任选一个,它们都已运行了多年,已经非常稳定。 如果你在用 Gitea、GitHub 或任何支持 API 的代码托管平台,意味着你已经有了存放结果的位置:PR 评论、新建 Issue 或直接提交文件。 用简单点的话说:Codex Automations 是一种范式,而不是一个产品。而且这种范式已经存在很多年了。 ┌─────────────────────────────────────────────┐ │ systemd timer (每隔 N 小时运行) │ │ │ │ │ ▼ │ │ bash/fish 脚本 │ │ │ │ │ ├── git pull --ff-only │ │ ├── claude --print "prompt" │ │ ├── 解析结果 │ │ ├── 通知 (Telegram/email) │ │ └── git push (如果有变更) │ └─────────────────────────────────────────────┘ 自动化的构成 所有的自动化都遵循同样的结构。一个脚本会经过以下步骤: ...

2026年3月11日 · Fernando