WWW.YOUINFO.SITE
标签聚合 精通

/tag/精通

v2ex · 2026-06-10 08:06:02+08:00 · tech

核心要求(精通) Golang Gin 或 Go-Zero 框架 PostgreSQL Redis (缓存、限流、状态管理) WebSocket (实时通信、低延迟,实时最高 500 同时在线) REST API 设计 JWT/Token 认证机制 安全设计(权限控制、防越权、防刷接口、接口安全、数据保护等) 具备独立系统设计能力(模块拆分、服务解耦、状态流设计) 网页防爬虫 熟练使用 AI ,减少开发周期 前端要求(熟悉) Vue3 TypeScript Vite WebSocket 前端通信 Pinia/状态管理 Element Plus 或类似后台框架 部署要求(熟悉) Docker Linux 服务器部署 Nginx CI/CD 基础流程 最好有过的其中的经验 SaaS 系统开发经验 私有化部署系统经验 IM/在线客服/实时监控系统经验 SDK 或平台型产品开发经验 低代码平台开发经验 可扩展系统架构设计经验 可视化编辑器开发经验 拖拽搭建系统开发经验 Tauri 桌面应用开发经验 对<实践论><矛盾论>有较深理解 希望你: 人品好,有原则,有责任心,合作精神 可远程合作,但要求全职 能力过硬,能独立负责开发,维护,效率高 沟通及时,沟通理解能力强 身体健康,少/不喝酒 请你提供: 个人情况 个人项目案例 项目和股权简介 项目正在运营,现产品技术弱水平不够,急需一款高性能的产品垄断市场。 有初代产品(低质量)验证市场和盈利(非正式推广)的 5 个月营收流水 7 位数明细。 有三年行业经验总结和最全面的行业旗舰产品完整设计方案。 现有客户展示,不是构思项目阶段。 合作 50/50 股份,你负责全部技术问题,我负责推广营销变现。 项目年盈利高于 8 位数(保守) 开发周期,预计 2-4 个月(含主要 bug 修复,主性能优化),主要功能完善后即可开始投放。 投放即有老客户付费内测,在主体性能稳定后正式推广,周期大概 1 个月后有稳定收入,且逐月高递增,3-5 月后趋于稳定状态,半年后几乎垄断市场。 项目寿命预计 5 年内稳定 联系方式: 请发邮件到: [email protected] 大概介绍一些您的情况和联系方式。以及对<实践论><矛盾论>的理解。

v2ex · 2026-06-10 08:06:02+08:00 · tech

核心要求(精通) Golang Gin 或 Go-Zero 框架 PostgreSQL Redis (缓存、限流、状态管理) WebSocket (实时通信、低延迟,实时最高 500 同时在线) REST API 设计 JWT/Token 认证机制 安全设计(权限控制、防越权、防刷接口、接口安全、数据保护等) 具备独立系统设计能力(模块拆分、服务解耦、状态流设计) 网页防爬虫 熟练使用 AI ,减少开发周期 前端要求(熟悉) Vue3 TypeScript Vite WebSocket 前端通信 Pinia/状态管理 Element Plus 或类似后台框架 部署要求(熟悉) Docker Linux 服务器部署 Nginx CI/CD 基础流程 最好有过的其中的经验 SaaS 系统开发经验 私有化部署系统经验 IM/在线客服/实时监控系统经验 SDK 或平台型产品开发经验 低代码平台开发经验 可扩展系统架构设计经验 可视化编辑器开发经验 拖拽搭建系统开发经验 Tauri 桌面应用开发经验 对<实践论><矛盾论>有较深理解 希望你: 人品好,有原则,有责任心,合作精神 可远程合作,但要求全职 能力过硬,能独立负责开发,维护,效率高 沟通及时,沟通理解能力强 身体健康,少/不喝酒 请你提供: 个人情况 个人项目案例 项目和股权简介 项目正在运营,现产品技术弱水平不够,急需一款高性能的产品垄断市场。 有初代产品(低质量)验证市场和盈利(非正式推广)的 5 个月营收流水 7 位数明细。 有三年行业经验总结和最全面的行业旗舰产品完整设计方案。 现有客户展示,不是构思项目阶段。 合作 50/50 股份,你负责全部技术问题,我负责推广营销变现。 项目年盈利高于 8 位数(保守) 开发周期,预计 2-4 个月(含主要 bug 修复,主性能优化),主要功能完善后即可开始投放。 投放即有老客户付费内测,在主体性能稳定后正式推广,周期大概 1 个月后有稳定收入,且逐月高递增,3-5 月后趋于稳定状态,半年后几乎垄断市场。 项目寿命预计 5 年内稳定 联系方式: 请发邮件到: [email protected] 大概介绍一些您的情况和联系方式。以及对<实践论><矛盾论>的理解。

v2ex · 2026-06-09 23:43:27+08:00 · tech

核心要求(精通) Golang Gin 或 Go-Zero 框架 PostgreSQL Redis (缓存、限流、状态管理) WebSocket (实时通信、低延迟,实时最高 500 同时在线) REST API 设计 JWT/Token 认证机制 安全设计(权限控制、防越权、防刷接口、接口安全、数据保护等) 具备独立系统设计能力(模块拆分、服务解耦、状态流设计) 网页防爬虫 熟练使用 AI ,减少开发周期 前端要求(熟悉) Vue3 TypeScript Vite WebSocket 前端通信 Pinia/状态管理 Element Plus 或类似后台框架 部署要求(熟悉) Docker Linux 服务器部署 Nginx CI/CD 基础流程 最好有过的其中的经验 SaaS 系统开发经验 私有化部署系统经验 IM/在线客服/实时监控系统经验 SDK 或平台型产品开发经验 低代码平台开发经验 可扩展系统架构设计经验 可视化编辑器开发经验 拖拽搭建系统开发经验 Tauri 桌面应用开发经验 对<实践论><矛盾论>有较深理解 希望你: 人品好,有原则,有责任心,合作精神 可远程合作,但要求全职 能力过硬,能独立负责开发,维护,效率高 沟通及时,沟通理解能力强 身体健康,少/不喝酒 请你提供: 个人情况 个人项目案例 项目和股权简介 项目正在运营,现产品技术弱水平不够,急需一款高性能的产品垄断市场。 有初代产品(低质量)验证市场和盈利(非正式推广)的 5 个月营收流水 7 位数明细。 有三年行业经验总结和最全面的行业旗舰产品完整设计方案。 现有客户展示,不是构思项目阶段。 合作 50/50 股份,你负责全部技术问题,我负责推广营销变现。 项目年盈利高于 8 位数(保守) 开发周期,预计 2-4 个月(含主要 bug 修复,主性能优化),主要功能完善后即可开始投放。 投放即有老客户付费内测,在主体性能稳定后正式推广,周期大概 1 个月后有稳定收入,且逐月高递增,3-5 月后趋于稳定状态,半年后几乎垄断市场。 项目寿命预计 5 年内稳定 联系方式: 请发邮件到: [email protected] 大概介绍一些您的情况和联系方式。以及对<实践论><矛盾论>的理解。

LinuxDo 最新话题 · 2026-05-20 10:41:08+08:00 · tech

你是一名精通图形学算法与 Web 交互的前端专家。请仅用一个 HTML 文件,基于 Three.js (ES Modules) 实现一个物理级高保真、支持自然手势的 3x3 魔方。 一、 交付规范 单文件架构:HTML/CSS/JS 必须合并在一个文件中。 依赖管理:必须通过 importmap 从 unpkg 或 cdn.skypack 引入 Three.js 及其 OrbitControls、Tween.js。 零素材依赖:禁止加载任何外部图片/贴图,所有材质纹理必须使用 HTML5 Canvas API 程序化动态生成。 二、 视觉与物理标准 模型构建: 场景需包含 27 个独立的小方块(Cubies)。 物理间隙:小方块之间必须保留微小的物理间距(Spacing),不可紧贴。 倒角质感:通过 Canvas 绘制带有圆角矩形(Rounded Rect)的贴纸纹理,模拟真实魔方的塑料黑边与贴纸高光效果。 光影环境: 必须开启 ShadowMap。 配置环境光(Ambient)与平行光(Directional),确保魔方有清晰的立体感和阴影投射。 三、 核心逻辑考点(数据结构与变换) 禁止维护复杂的 3D 状态数组,请使用基于"空间位置"的动态计算方案: 动态层级筛选: 不要写死索引。当需要旋转某一层时,遍历所有方块,根据其在世界坐标系(World Position)下的 x, y, z 值与阈值(Epsilon)来判断它是否属于当前旋转层。 Pivot 变换机制(关键考点): 实现旋转时,必须创建一个临时的 Pivot(轴心对象)。 核心API:使用 pivot.attach(object) 将选中的方块挂载到轴心,旋转轴心,动画结束后使用 scene.attach(object) 将方块放回场景。 作用:利用 attach 自动计算世界矩阵变换,避免手动处理复杂的四元数乘法。 坐标清洗: 每次旋转结束后,必须对所有方块的位置(Position)和旋转(Rotation)进行 Math.round() 取整处理,消除浮点数累积误差,防止魔方"散架"。 四、 交互系统考点(算法重难点) 这是区分初级与高级开发者的核心点,请实现类似原生 App 的自然手势体验: 操作分离: 左键拖拽:旋转魔方的某一层。 右键拖拽:旋转视角(OrbitControls)。 基于投影向量的手势识别算法: 射线检测:点击时获取被点击方块的"表面法线(Face Normal)“。 意图判断: 根据法线,锁定潜在的两个旋转轴(例如点击前面,潜在轴为 X 或 Y)。 将这两个 3D 轴的向量**投影(Project)**到 2D 屏幕空间。 计算用户鼠标滑动的 2D 向量与这两个投影向量的点积(Dot Product),选择匹配度最高的轴作为旋转轴。 方向修正与实时跟随: 实现1:1 实时跟手:鼠标移动多少像素,魔方层转动对应角度。 符号修正:通过叉乘(Cross Product)或投影符号判断,确保无论从魔方正面、背面还是顶面操作,鼠标向右划动始终对应"向右转"的视觉逻辑(解决方向反转 bug)。 磁吸效果: 松开鼠标后,自动计算最近的 90 度倍数,使用 Tween.js 播放回弹动画并对齐网格。 五、 代码质量 代码需包含清晰的注释,解释"手势投影算法"和"Pivot 挂载逻辑”。 具备 Scramble(打乱)和 Reset(重置)功能按钮。 以上是提示词,glm5.1也能做出来,但是有点小瑕疵,我用gemini3.5flash尝试着做了一下 一点问题没有,完成度特别高,旋转时的ui,逻辑都没问题,这个看完了之后真是瘫坐在椅子上了 3 个帖子 - 2 位参与者 阅读完整话题

LinuxDo 最新话题 · 2026-05-18 18:45:36+08:00 · tech

目前国内中大厂的后端开发,用一个词来形容就是“ Java稳坐王位,Go、Rust等新贵崛起 ”。 Java:核心业务岗位最多、生态最成熟的选择。 Go: 云原生领域的话语权 RUst: 底层系统、高性能基础设施的异军突起 C++: 在后端业务开发领域,份额已被Java、Go等蚕食,但在游戏服务器、音视频处理等性能关键领域,依然是无可替代的存在 Python:AI时代的必备语言 目前主流应该就是这些开发语言,如果在你已有的开发语言之外,你会选择哪个?或者工作市场会选择哪个?咱们不说什么AI都会,我们不用学这种观点,就主打一个探讨!!!不要太过于上升 10 个帖子 - 10 位参与者 阅读完整话题

v2ex · 2026-05-13 16:33:48+08:00 · tech

招聘 java 全栈 硬性要求: 统招大学及以上学历,计算机相关专业。 精通 java 基础 熟练使用 springboot springcloud dubbo mybatisplus 常用技术 熟练使用 mysql 数据库,有数据库优化经验,索引创建等。使用过 pgsql 更好 熟练使用 redis ,要会点 lua 脚本。 熟练使用常用中间件,mq es 等。 有 IM 即时通讯经验更好。 了解使用过 netty 和 websocket 。 前端要求: 会使用 vue 了解 nodejs 精通 ts 。 薪资待遇: 10000 起,面试定薪资。 小伙伴可以私聊我微信 cGFzdF90b193aW5k ,或者直接发简历到我的邮箱 MzA5NjkzMjMyQHFxLmNvbQ== 替朋友发的, 轻喷~

www.v2ex.com · 2026-04-30 09:34:25+08:00 · tech

视频版: https://www.bilibili.com/video/BV1Kk9kBAEJv 最近 Codex APP 的能力越来越全面,变成了 Codex 四大产品形态里面最强的一个。Codex 比起 Claude Code ,额度更高,功能更全,上手更快,免费账户也能用,而且不会出现限速、封号、降智等问题,用过的小伙伴们直呼真香。本期视频带来一个 Codex APP 的完整教程,主要分为以下 12 个章节。 每个章节里面都会穿插一些重要的知识,对 Codex 的全部功能进行细致讲解。好,废话不多说,我们直接开始。 安装 在安装使用 Codex APP 之前,需要进行 3 个准备工作,也就是需要先把 Git 、Nodejs 还有 VSCode 安装一下。在我上期视频《从 0 开始用国内网络跑通一切 AI Agent 》里面,有详细的操作步骤,不熟悉的朋友们可以参考那一期视频。 接下来我们来到 Codex 的官网,Codex 支持 Windows 跟 Mac 两大操作系统。官网会根据你的操作系统,自动提供对应的安装包。本期视频我主要使用 Windows 来进行演示。Windows 跟 Mac 电脑的功能基本是一致的,唯一欠缺的功能是 computer use ,也就是自动操作电脑的能力。等需要演示这部分的时候,我会切换到 Mac 电脑进行演示。 然后我们一路点击下一步完成安装。接下来我们把 Codex APP 启动起来,选择 ChatGPT 账户完成登录。现在 ChatGPT 的免费账户也能使用 Codex 了,不过额度比较低。第一次进入软件要选一下希望 Codex 为你处理的工作,Codex 会根据你的选择预装一些内置的插件和 skills 。当然进入软件以后,我们还可以按需安装这些插件。然后选择主要的使用场景,是编程还是日常工作,这些都可以后续在设置里面进行修改。接下来点击设置沙盒按钮,完成沙盒的初始化。关于沙盒这部分的内容,我们下一个章节再来介绍。 项目与任务列表 我们点击右上角的按钮显示侧边栏,我们看到 Codex APP 是非常经典的三栏布局:左侧是任务列表,中间是对话窗口,右侧是多功能区域。 我们先创建两个项目文件夹,来展示一下它的基础使用。这里我在桌面新建了两个文件夹,作为两个项目文件夹。然后我们来到 Codex ,点击进入项目工作,使用现有文件夹。我们先选择第一个文件夹,这里我让它做一个 html 单页面的宠物洗护店的网页,开始。在左侧边栏里面增加了一个项目,项目的名称就是文件夹的名称,里面展示了正在运行的任务。 接下来我们点击左上角的新对话按钮。Windows 上的快捷键是 Ctrl+N ,Mac 系统的快捷键是 command+N ,来开启一个新的对话。我们可以选择新对话属于哪个项目。这里我准备开启一个新的项目,把第二个文件夹也添加进来,点击添加新项目,然后选择我们的第二个文件夹。 这里输入我第二个项目的需求:用 react 框架做一个网页版待办事项的提醒工具,回车开始执行。 在两个项目并行工作的同时,我们还可以开启更多的工作对话。比如这里我想询问 Codex 一个技术问题,我们把鼠标指向第二个项目,点击这个小按钮,在项目里面开启新的对话。 这里我询问 Codex:react 框架是什么,回车。这里看到我们开启了 3 个任务并行执行,有两个任务属于项目一,一个任务属于项目 2 。正在执行的任务上面都有一个转圈的小图标,表示 AI 正在工作。我们耐心等待一会。 过了一会状态就不一样了。有一个任务上面显示一个绿色标签,表示等待批准;有一个任务上面出现了一个蓝色小点,表示已经执行完毕了;还有一个任务继续转圈。我们来到这个等待批准的任务里面,发现 Codex 需要联网下载 Vite React 项目的模板,正在申请权限。 我们点击“是”批准,这个任务就继续执行了。又过了一会,三个任务上面都标记了蓝色的小圆点,表示三个任务都执行完毕了。Codex 任务列表非常的简洁美观好用,可以很方便地观察任务状态,可以并行开启多个工作任务,还能高效地从多个任务里面自由地切换。 我们再来看一下左侧边栏任务列表的其他功能。新对话按钮用来开启新的对话,在下面可以选择对应的项目,也可以选择不使用任何的项目,纯粹的闲聊。这种不属于任何项目的对话,都会被收录到任务列表的最下面,也就是对话这一栏里面。 左侧边栏第二个按钮,快捷键是 Ctrl+G ,Mac 电脑的快捷键是 command+G ,可以搜索近期的对话历史。不过我试了一下,这个功能只能搜索到对话的标题,它无法搜索到对话里面的内容。这里补充一下,每个对话标题都是 AI 根据对话内容自动摘要生成的。我们也可以选择某个对话,双击,对它进行一个重命名。如果我们不再需要某个对话了,可以点击这个归档对话的小按钮确认,然后我们的对话就在左侧边栏消失了。在设置已归档对话里面,可以找到我们删除的对话,点击取消归档就可以把它还原回来。左侧边栏还有两个按钮,插件与自动化,这个等我们在后面的章节再来看。 权限控制与沙箱 接下来我们来看一下中间的对话页面。这里最显眼的功能就是权限控制。 Codex 的权限控制全部是围绕沙箱来展开的,这点跟 Claude Code 有本质上的不同。Claude Code 的沙箱功能需要手动开启,Claude Code 的沙箱更像是一层可以额外开启的保护,而 Codex 的沙箱,它是整个权限系统运行的地基。 Codex 会把当前的项目文件夹作为一个沙箱进行管理。在默认权限下面,Codex 具有读取修改沙箱内所有文件的权限。在默认模式下,Codex APP 可以直接修改沙箱内,也就是项目文件夹的所有文件,它并不会一个个地跑来问你。我觉得这点非常的方便,也是符合正常的使用习惯的。当然我们也可以通过设置,改成逐个文件修改都需要审批,这个在视频的后半段高级设置这个我们再来讲。 Codex 的沙箱有两个默认限制。第一点是 Codex 不能修改沙箱外的文件,第二点是 Codex 的沙箱是禁止联网的。这两点硬性限制,它并不是靠模型自觉遵守,而是 Codex 使用操作系统底层功能实现的。不同操作系统的实现机制是不一样的,比如 MacOS 使用的是系统内置的 Seatbelt Sandbox 机制。 Codex 的沙箱功能是前阵爆火的 Harness engineering 概念的一个典型的工程实现,用操作系统级别的机制把 AI 的能力约束在一个可控的范围之内。这也很形象地体现了 Harness 这个词的原始含义,也就是马具。AI 就像一匹能力很强的马,而沙箱权限审批机制这些,就是套在它身上的马具。 如果 Codex 需要修改沙箱外文件,或者需要联网,可以向用户申请权限,这个操作叫做 escalate ,也就是提权操作。在默认情况下,提权操作都是需要人工审核同意的。Codex 为我们提供了第二个档位,也就是自动审查。启动了自动审查以后,Codex 会自动调用一个小模型,对提权操作进行安全性审查。如果发现是低风险的操作,就会直接放行。只有高风险的操作才会触发人工审查,这也是我最推荐的模式。自动审查使得绝大部分操作不需要人工审批,在获取了较高安全性的同时,还极大提升了使用的便利度。 所以一般情况下,在权限管理这里,我都推荐开启第二档,也就是自动审查。Codex 还有第三档,完全访问权限。开启了这个以后,Codex 完全无视沙箱的限制,可以在电脑上执行一切的操作。不过我们尝试开启的时候,这里出现了很醒目的风险提示,提示我们要谨慎使用。 上下文 在权限控制的右边有一个圆圈,展示的是当前上下文使用情况。这里翻译得不太好,准确的翻译应该是上下文使用量信息,显示的是这个对话里的历史对话内容占用了多少模型上下文空间。当上下文超过限制的时候,Codex 会自动对对话历史进行压缩,从而释放出更多的上下文空间。我们也可以输入斜杠,选择压缩选项,手动触发一次上下文压缩。压缩完成以后,Codex 会把之前对话的一些不重要的内容排除掉,可以有效提高 AI 的专注力,并且降低 TOKEN 消耗。 不过在 AI Agent 领域,有一个通用经验是清空好于压缩。因为过多的历史会话,会干扰 AI 的注意力。当我们让 AI 执行完一个任务以后,最好是开一个新的对话,清空上下文。这样有助于 AI 把注意力全部集中到新的任务上面来,从而提高任务的执行效果。 在上下文窗口的右边是模型选择,可以根据任务的复杂程度选择模型的思考强度。下面可以切换模型,这里一般我们就选择最新的模型,比如现在是 GPT-5.5 。 下面还有一个速度选项,可以选择标准还有快速。在快速模式下,会提升 50% 的 AI 推理速度,但是快速模式会消耗两倍的套餐用量。如果你的任务很急,但是套餐的余量还有很多,可以选择开启。 说到套餐余量,我们可以在左下角的设置剩余额度里面找到你现在的套餐余量。这里有两个限额,分别是 5 小时限额,还有周限额。这两个限额任意一个到达上限,Codex 都不能继续使用了。 两个限额都有对应的重置时间,时间到了以后,额度会重置成 100%。右边还有一个语音输入功能,可以让我们跟 AI 的交互从打字变成口喷,非常的好玩。 AI 生图 Codex 内置了 AI 画图功能,而且它使用的是当今最强的 AI 生图模型 GPT-Image-2 。这是刚才我让 Codex 为我们生成的宠物洗护的网站,我们看到它已经为我们配了一些图片。这里我看了一下,这些图片其实都是网络上的免费素材。这里有两个配图非常的不合适。首先这里的店内环境展示的都是一些宠物图片,它并不是一个真正的宠物洗护店的环境。第二点是门店信息,这里画的地图也太粗糙简陋了。 我们就针对这两个问题,让 Codex 帮我们来修改一下。我们来到 Codex ,新开一个对话,项目选择宠物洗护店那个。我让 Codex 调用 AI 绘图功能,绘制三个店内环境的轮播图,三个图应该分别展示店内的不同区域。 我们看到 Codex 为我们生成了三张图片,基本都保持了店内装修风格的一致性。 然后在网页这边也替换成了 3 张图片的轮播图,非常的不错。 接下来我们要改的是门店信息,这里的地图太简陋了。我们回到 Codex ,在宠物店应用这里新开一个对话,输入我的指令: 我们的店在陕西北路 1620 号,就是地图上标记的这个点。你按我发你的位置,用可爱清新的宠物风格的地图把我们的店标记上,然后修改网页里的门店位置信息。 这里我来到地图,我截个图,然后把我们的店用箭头标记上。接下来我们直接 Ctrl+V ,Mac 系统是 Command+V ,把截图粘贴过来,开始。 在 Codex 的执行过程中,我随时跟踪进度。这里我发现了一个问题,就是他画的这个地图是用 SVG 生成的,效果很差。我原本是想让他调用内置的 AI 生图模型来画。借着这个机会,我要介绍 Codex 的一个强大功能。它的英文名叫做 steer ,中文翻译过来是引导。这个词的英文原文的意思是打方向盘。当我们发现 AI 在执行过程中理解错了我们的意思,就不应该让它继续执行了,这时候应该及时接管方向盘,人工进行引导干预。 这里我截个图发送给 Codex 说:你这图不行,应该调用 AI 绘图能力。 在默认模式下,这个新的指令进入了指令队列排队,需要 AI 把上一轮全部执行完,才能执行我们新输入的指令。我们可以点击这里的引导按钮,英文版叫做 steer ,中途接管方向盘,引导干预 AI 的执行。 我们看到 Codex 这里显示已引导对话,然后回复我说味不对,我立即改用 AI 生图,重新生成一张。我们使用 Codex 的 steer 功能,在运行中途成功纠正了模型的运行方向。 在 Codex 的设置常规设置里面,有一个跟进行为。这里可以设置在执行过程中,我们输入的指令是在后面排队,还是直接进入引导。 这里我推荐还是默认选择排队,如果需要引导的话,我们直接点击那个引导按钮,或者按快捷键 Ctrl+回车。我们看到 Codex 为我们重新生成了一张图片,并且把它替换到了网页里面,标注出了我们店的位置,效果非常的棒。 计划模式与内置浏览器 在对话窗口这里有一个加号,里面有三个功能。首先是添加照片和文件,我们可以用照片或者文件给 AI 补充上下文信息,或者可以像刚才一样通过复制粘贴,直接把照片或者文件粘贴进对话窗口。下面是插件,目前预装了 4 个插件,分别对应办公三大件( Word,Excel,PPT ),还有浏览器自动化。 我们主要看这里的计划模式。开启了计划以后,Codex 就不会立即上手干活,而是先为我们输出一份完整的工作计划,跟我们进行了确认以后再干活。对于所有的复杂任务,建议都先开启计划模式,确保你能跟 AI 对齐颗粒度,让 AI 能够精准理解我们的意图。 我们在 Codex 里面打开计划模式,输入我们的需求: 把这个项目改造成 next js 框架 在计划模式里面,Codex 会很倾向于使用这种问题卡片的形式跟用户进行沟通。这里他询问我希望使用哪种项目形态,我选择 APP Router 加 TS 。然后样式迁移希望怎么处理,这里我选择改 Tailwind 。迁移完成要不要同时启动本地开发服务器验证,这里我选择构建加启动。Codex 为我们生成了一份完整的计划,我仔细阅读了一遍,没有发现问题。这里我们点击是,实施此计划。 代码编写完成以后,Codex 可以启动它内置的浏览器进行自动化的测试,这样任务就完成了,开发服务器也启动起来了。在右侧的多功能窗口,Codex 自动打开了浏览器。我们可以点击这里的展开面板按钮,看一下项目的完整状态。我们看到这次架构迁移非常的成功,页面上所有的元素都完整地保留了,非常的不错。 如果对某个部分不满意,我们可以点击这里的批注按钮,然后选中一个元素,在这里可以添加评论。比如这里我说为什么这个星星是空心的,然后在下面点击发送,让 AI 帮我们修改一下。 在下面也可以实时看到它的修改过程。我们刷新一下页面,这个星星就被修改成了实心的。这样我们就通过 Plan 模式配合 Codex 的内置浏览器,成功完成了项目架构的迁移,还顺手修改了一个小 bug 。 代码管理 Codex APP 并不是传统的 IDE ,它并不提供完整的代码编辑功能。我们可以在右上角点击切换文件树,这里虽然可以查看代码,但是没法直接编辑。我们只能点击某行代码来写批注,并不能直接修改代码。我们可以借助第三方的 IDE 来修改代码。 在进行代码管理之前,我们需要先把项目初始化成一个 git 工程。这里我们新开启一个对话,输入提示词: 把项目初始化成一个 git 工程,注意排除掉不需要的文件。 Codex 先为我们创建了 .gitignore 文件,把一些不需要提交的内容排除出去。Codex 帮我们把项目初始化成了 Git 仓库。 初始化成 Git 仓库以后,右上角又多了很多按钮。这里有一个 VSCode 按钮,我们点击一下,我们就可以快捷地使用 VSCode 来查看和修改代码。 除了使用 VSCode ,在这个下拉列表里面,还可以使用其他的 IDE 来打开项目。如果你的电脑上装过这些 IDE ,就可以在这里关联出来。我们也可以在设置常规设置里面选择默认打开的 IDE 。 我还可以要求 AI 把代码帮我提交到 Github 上面。Codex 需要我先在 Github 上面为它创建一个仓库。这里我来到 Github ,点击这个 new 按钮,仓库的名字还叫 pet_care ,点击创建。 创建出来以后把这个地址复制一下,我们回到 Codex 扔给他,成功帮我们把代码推送到了 Github 上面。我们点击这个链接,看到我们的代码已经备份到了 GitHub 的网站上面。我们可以使用对话的方式进行一切 Git 与 Github 操作,这都属于编程的基础知识,本期视频我就不展开讲了。 Git 回滚 本期视频我主要讲两个进阶技巧。第一个是使用 Git 对开发过程进行回滚,第二个技巧是 Git WorkTree 。 我们先看第一个回滚。这里我新开一个对话,我们打开侧边栏,点击加号,浏览器输入我们项目本地开发的地址,这样进入浏览器。我们还是在这里面进行一些批注。我让 Codex 在这里添加一个期望到店时间的功能,直接点击 Ctrl 加回车发送。Codex 为我们添加了期望到店时间这个字段。 当 AI 完成一个功能的开发以后,我们就使用 Git 把它备份保存一下。这里点击提交, 填写一个提交消息,点击继续。这样最新的代码改动就以 Git 的方式保存下来了。接下来我让 AI 把期望到店时间放到联系人的上面,开始。Codex 为我们完成了修改,我们还是从内置的浏览器看一下效果。这个字段跑到了最上面,不过这么一改,我觉得更难看了,我后悔了。我觉得还是把它放到原来的位置比较好。这里我想做的是把这一次的对话,包括这一次的代码改动,全部回滚掉,最好是当做无事发生。 这里我们先借助 Codex 的分叉功能,英文是 fork 。我们先把对话回滚掉。我们找到上一次对话结尾的位置,点击这个分叉按钮,选择派生到本地。 我们看到 Codex 的分叉功能,就是在我点击的这个位置,把对话复制了一份。这样复制出来的新对话,就已经剔除掉了我们刚才想删除的部分了。 不过分叉功能只能回退对话历史,它不能同步回退代码。所以这里我们要做的是把代码一同回退掉。我们可以在 VSCode 里面点击这个 source control 按钮,查看所有的 Git 提交。这里我需要把代码回退到生成期望到店时间的这个状态上。我们点击右键,点击这个 copy commit hash , 这样我们就把这次提交的 ID 复制下来了。我们回到 Codex ,先让 AI 把代码回退到这个状态,后面就是我们刚才复制的提交 ID 。 我们看到代码回退成功了,在浏览器里可以看到这个期望到店时间又变回了原来的位置。这样我们就使用了 Codex 的对话分岔功能,加上 Git 操作,成功地把这一次不需要的改动,从代码层面和对话历史层面进行了完全的回滚。 Git worktree 接下来我们来看下一个功能,就是 Git worktree 。WorkTree 这个名字听起来比较唬人,其实它本质上就是用 git 创建一个新的分支,然后把这个新分支的代码完整地复制到一个新的文件夹里面。这个新文件夹就是一个 WorkTree 。主文件夹和分支文件夹可以并行工作,我们可以在两个文件夹里面各自修改代码,互相不干扰。我们可以基于主干创建多个分支,它们在底层通过 git 关联在一起。分支文件夹的改动,随时都能轻松合并回主干。 找到我们的项目,右键创建永久工作树。这里起个名字,我想让第一个工作树专注优化客户评价这个部分,我给它加个后缀叫 customer rating 。Codex 把整个项目复制到了一个单独的文件夹里面,它跟主干已经不是同一个文件夹了。我们在分支里面做的操作不会影响到主干。这里我们再建一个工作树,第二个工作树主要用来负责优化下面的门店信息,还有这里的地图。我们给第二个树也起个名字。这样我们就拥有了两个工作树分支,它们都位于不同的文件夹下面,所以它们之间的并行工作不会影响到主干。 这里我们来测试一下。我们先打开第一个分支新对话,输入我们的需求: 优化一下客户评价部分,多写几个评价,做一个动画轮播效果, 开始。然后我们来到第二个分支,创建一个新的对话: 优化一下门店信息部分,让门店信息跟地图上下排列,不要左右排列,把地图展示全。 我们在两个分支上面进行并行开发,因为它们位于两个不同的文件夹,所以互相之间不会产生干扰。 两个分支在各自的文件夹里面都开发完毕了。接下来我们可以把它合并回主干。里直接输入合并回主干,两个分支都一样的操作,合并回主干。 两个分支都成功合并进了主干。我们在浏览器这边可以看到,客户评价已经优化过了,门店信息也从左右排布变成了上下排布,地图展示得更全了。这样我们使用 Git worktree 功能,高效并行开发了两个任务。当我们的分支使用完毕,我们可以直接右键移除,把两个临时的分支移除掉,然后回到主干继续工作。

www.v2ex.com · 2026-04-30 09:18:57+08:00 · tech

视频版: https://www.bilibili.com/video/BV1Kk9kBAEJv 最近 Codex APP 的能力越来越全面,变成了 Codex 四大产品形态里面最强的一个。Codex 比起 Claude Code ,额度更高,功能更全,上手更快,免费账户也能用,而且不会出现限速、封号、降智等问题,用过的小伙伴们直呼真香。本期视频带来一个 Codex APP 的完整教程,主要分为以下 12 个章节。 每个章节里面都会穿插一些重要的知识,对 Codex 的全部功能进行细致讲解。好,废话不多说,我们直接开始。 安装 在安装使用 Codex APP 之前,需要进行 3 个准备工作,也就是需要先把 Git 、Nodejs 还有 VSCode 安装一下。在我上期视频《从 0 开始用国内网络跑通一切 AI Agent 》里面,有详细的操作步骤,不熟悉的朋友们可以参考那一期视频。 接下来我们来到 Codex 的官网,Codex 支持 Windows 跟 Mac 两大操作系统。官网会根据你的操作系统,自动提供对应的安装包。本期视频我主要使用 Windows 来进行演示。Windows 跟 Mac 电脑的功能基本是一致的,唯一欠缺的功能是 computer use ,也就是自动操作电脑的能力。等需要演示这部分的时候,我会切换到 Mac 电脑进行演示。 然后我们一路点击下一步完成安装。接下来我们把 Codex APP 启动起来,选择 ChatGPT 账户完成登录。现在 ChatGPT 的免费账户也能使用 Codex 了,不过额度比较低。第一次进入软件要选一下希望 Codex 为你处理的工作,Codex 会根据你的选择预装一些内置的插件和 skills 。当然进入软件以后,我们还可以按需安装这些插件。然后选择主要的使用场景,是编程还是日常工作,这些都可以后续在设置里面进行修改。接下来点击设置沙盒按钮,完成沙盒的初始化。关于沙盒这部分的内容,我们下一个章节再来介绍。 项目与任务列表 我们点击右上角的按钮显示侧边栏,我们看到 Codex APP 是非常经典的三栏布局:左侧是任务列表,中间是对话窗口,右侧是多功能区域。 我们先创建两个项目文件夹,来展示一下它的基础使用。这里我在桌面新建了两个文件夹,作为两个项目文件夹。然后我们来到 Codex ,点击进入项目工作,使用现有文件夹。我们先选择第一个文件夹,这里我让它做一个 html 单页面的宠物洗护店的网页,开始。在左侧边栏里面增加了一个项目,项目的名称就是文件夹的名称,里面展示了正在运行的任务。 接下来我们点击左上角的新对话按钮。Windows 上的快捷键是 Ctrl+N ,Mac 系统的快捷键是 command+N ,来开启一个新的对话。我们可以选择新对话属于哪个项目。这里我准备开启一个新的项目,把第二个文件夹也添加进来,点击添加新项目,然后选择我们的第二个文件夹。 这里输入我第二个项目的需求:用 react 框架做一个网页版待办事项的提醒工具,回车开始执行。 在两个项目并行工作的同时,我们还可以开启更多的工作对话。比如这里我想询问 Codex 一个技术问题,我们把鼠标指向第二个项目,点击这个小按钮,在项目里面开启新的对话。 这里我询问 Codex:react 框架是什么,回车。这里看到我们开启了 3 个任务并行执行,有两个任务属于项目一,一个任务属于项目 2 。正在执行的任务上面都有一个转圈的小图标,表示 AI 正在工作。我们耐心等待一会。 过了一会状态就不一样了。有一个任务上面显示一个绿色标签,表示等待批准;有一个任务上面出现了一个蓝色小点,表示已经执行完毕了;还有一个任务继续转圈。我们来到这个等待批准的任务里面,发现 Codex 需要联网下载 Vite React 项目的模板,正在申请权限。 我们点击“是”批准,这个任务就继续执行了。又过了一会,三个任务上面都标记了蓝色的小圆点,表示三个任务都执行完毕了。Codex 任务列表非常的简洁美观好用,可以很方便地观察任务状态,可以并行开启多个工作任务,还能高效地从多个任务里面自由地切换。 我们再来看一下左侧边栏任务列表的其他功能。新对话按钮用来开启新的对话,在下面可以选择对应的项目,也可以选择不使用任何的项目,纯粹的闲聊。这种不属于任何项目的对话,都会被收录到任务列表的最下面,也就是对话这一栏里面。 左侧边栏第二个按钮,快捷键是 Ctrl+G ,Mac 电脑的快捷键是 command+G ,可以搜索近期的对话历史。不过我试了一下,这个功能只能搜索到对话的标题,它无法搜索到对话里面的内容。这里补充一下,每个对话标题都是 AI 根据对话内容自动摘要生成的。我们也可以选择某个对话,双击,对它进行一个重命名。如果我们不再需要某个对话了,可以点击这个归档对话的小按钮确认,然后我们的对话就在左侧边栏消失了。在设置已归档对话里面,可以找到我们删除的对话,点击取消归档就可以把它还原回来。左侧边栏还有两个按钮,插件与自动化,这个等我们在后面的章节再来看。 权限控制与沙箱 接下来我们来看一下中间的对话页面。这里最显眼的功能就是权限控制。 Codex 的权限控制全部是围绕沙箱来展开的,这点跟 Claude Code 有本质上的不同。Claude Code 的沙箱功能需要手动开启,Claude Code 的沙箱更像是一层可以额外开启的保护,而 Codex 的沙箱,它是整个权限系统运行的地基。 Codex 会把当前的项目文件夹作为一个沙箱进行管理。在默认权限下面,Codex 具有读取修改沙箱内所有文件的权限。在默认模式下,Codex APP 可以直接修改沙箱内,也就是项目文件夹的所有文件,它并不会一个个地跑来问你。我觉得这点非常的方便,也是符合正常的使用习惯的。当然我们也可以通过设置,改成逐个文件修改都需要审批,这个在视频的后半段高级设置这个我们再来讲。 Codex 的沙箱有两个默认限制。第一点是 Codex 不能修改沙箱外的文件,第二点是 Codex 的沙箱是禁止联网的。这两点硬性限制,它并不是靠模型自觉遵守,而是 Codex 使用操作系统底层功能实现的。不同操作系统的实现机制是不一样的,比如 MacOS 使用的是系统内置的 Seatbelt Sandbox 机制。 Codex 的沙箱功能是前阵爆火的 Harness engineering 概念的一个典型的工程实现,用操作系统级别的机制把 AI 的能力约束在一个可控的范围之内。这也很形象地体现了 Harness 这个词的原始含义,也就是马具。AI 就像一匹能力很强的马,而沙箱权限审批机制这些,就是套在它身上的马具。 如果 Codex 需要修改沙箱外文件,或者需要联网,可以向用户申请权限,这个操作叫做 escalate ,也就是提权操作。在默认情况下,提权操作都是需要人工审核同意的。Codex 为我们提供了第二个档位,也就是自动审查。启动了自动审查以后,Codex 会自动调用一个小模型,对提权操作进行安全性审查。如果发现是低风险的操作,就会直接放行。只有高风险的操作才会触发人工审查,这也是我最推荐的模式。自动审查使得绝大部分操作不需要人工审批,在获取了较高安全性的同时,还极大提升了使用的便利度。 所以一般情况下,在权限管理这里,我都推荐开启第二档,也就是自动审查。Codex 还有第三档,完全访问权限。开启了这个以后,Codex 完全无视沙箱的限制,可以在电脑上执行一切的操作。不过我们尝试开启的时候,这里出现了很醒目的风险提示,提示我们要谨慎使用。 上下文 在权限控制的右边有一个圆圈,展示的是当前上下文使用情况。这里翻译得不太好,准确的翻译应该是上下文使用量信息,显示的是这个对话里的历史对话内容占用了多少模型上下文空间。当上下文超过限制的时候,Codex 会自动对对话历史进行压缩,从而释放出更多的上下文空间。我们也可以输入斜杠,选择压缩选项,手动触发一次上下文压缩。压缩完成以后,Codex 会把之前对话的一些不重要的内容排除掉,可以有效提高 AI 的专注力,并且降低 TOKEN 消耗。 不过在 AI Agent 领域,有一个通用经验是清空好于压缩。因为过多的历史会话,会干扰 AI 的注意力。当我们让 AI 执行完一个任务以后,最好是开一个新的对话,清空上下文。这样有助于 AI 把注意力全部集中到新的任务上面来,从而提高任务的执行效果。 在上下文窗口的右边是模型选择,可以根据任务的复杂程度选择模型的思考强度。下面可以切换模型,这里一般我们就选择最新的模型,比如现在是 GPT-5.5 。 下面还有一个速度选项,可以选择标准还有快速。在快速模式下,会提升 50% 的 AI 推理速度,但是快速模式会消耗两倍的套餐用量。如果你的任务很急,但是套餐的余量还有很多,可以选择开启。 说到套餐余量,我们可以在左下角的设置剩余额度里面找到你现在的套餐余量。这里有两个限额,分别是 5 小时限额,还有周限额。这两个限额任意一个到达上限,Codex 都不能继续使用了。 两个限额都有对应的重置时间,时间到了以后,额度会重置成 100%。右边还有一个语音输入功能,可以让我们跟 AI 的交互从打字变成口喷,非常的好玩。 AI 生图 Codex 内置了 AI 画图功能,而且它使用的是当今最强的 AI 生图模型 GPT-Image-2 。这是刚才我让 Codex 为我们生成的宠物洗护的网站,我们看到它已经为我们配了一些图片。这里我看了一下,这些图片其实都是网络上的免费素材。这里有两个配图非常的不合适。首先这里的店内环境展示的都是一些宠物图片,它并不是一个真正的宠物洗护店的环境。第二点是门店信息,这里画的地图也太粗糙简陋了。 我们就针对这两个问题,让 Codex 帮我们来修改一下。我们来到 Codex ,新开一个对话,项目选择宠物洗护店那个。我让 Codex 调用 AI 绘图功能,绘制三个店内环境的轮播图,三个图应该分别展示店内的不同区域。 我们看到 Codex 为我们生成了三张图片,基本都保持了店内装修风格的一致性。 然后在网页这边也替换成了 3 张图片的轮播图,非常的不错。 接下来我们要改的是门店信息,这里的地图太简陋了。我们回到 Codex ,在宠物店应用这里新开一个对话,输入我的指令: 我们的店在陕西北路 1620 号,就是地图上标记的这个点。你按我发你的位置,用可爱清新的宠物风格的地图把我们的店标记上,然后修改网页里的门店位置信息。 这里我来到地图,我截个图,然后把我们的店用箭头标记上。接下来我们直接 Ctrl+V ,Mac 系统是 Command+V ,把截图粘贴过来,开始。 在 Codex 的执行过程中,我随时跟踪进度。这里我发现了一个问题,就是他画的这个地图是用 SVG 生成的,效果很差。我原本是想让他调用内置的 AI 生图模型来画。借着这个机会,我要介绍 Codex 的一个强大功能。它的英文名叫做 steer ,中文翻译过来是引导。这个词的英文原文的意思是打方向盘。当我们发现 AI 在执行过程中理解错了我们的意思,就不应该让它继续执行了,这时候应该及时接管方向盘,人工进行引导干预。 这里我截个图发送给 Codex 说:你这图不行,应该调用 AI 绘图能力。 在默认模式下,这个新的指令进入了指令队列排队,需要 AI 把上一轮全部执行完,才能执行我们新输入的指令。我们可以点击这里的引导按钮,英文版叫做 steer ,中途接管方向盘,引导干预 AI 的执行。 我们看到 Codex 这里显示已引导对话,然后回复我说味不对,我立即改用 AI 生图,重新生成一张。我们使用 Codex 的 steer 功能,在运行中途成功纠正了模型的运行方向。 在 Codex 的设置常规设置里面,有一个跟进行为。这里可以设置在执行过程中,我们输入的指令是在后面排队,还是直接进入引导。 这里我推荐还是默认选择排队,如果需要引导的话,我们直接点击那个引导按钮,或者按快捷键 Ctrl+回车。我们看到 Codex 为我们重新生成了一张图片,并且把它替换到了网页里面,标注出了我们店的位置,效果非常的棒。 计划模式与内置浏览器 在对话窗口这里有一个加号,里面有三个功能。首先是添加照片和文件,我们可以用照片或者文件给 AI 补充上下文信息,或者可以像刚才一样通过复制粘贴,直接把照片或者文件粘贴进对话窗口。下面是插件,目前预装了 4 个插件,分别对应办公三大件( Word,Excel,PPT ),还有浏览器自动化。 我们主要看这里的计划模式。开启了计划以后,Codex 就不会立即上手干活,而是先为我们输出一份完整的工作计划,跟我们进行了确认以后再干活。对于所有的复杂任务,建议都先开启计划模式,确保你能跟 AI 对齐颗粒度,让 AI 能够精准理解我们的意图。 我们在 Codex 里面打开计划模式,输入我们的需求: 把这个项目改造成 next js 框架 在计划模式里面,Codex 会很倾向于使用这种问题卡片的形式跟用户进行沟通。这里他询问我希望使用哪种项目形态,我选择 APP Router 加 TS 。然后样式迁移希望怎么处理,这里我选择改 Tailwind 。迁移完成要不要同时启动本地开发服务器验证,这里我选择构建加启动。Codex 为我们生成了一份完整的计划,我仔细阅读了一遍,没有发现问题。这里我们点击是,实施此计划。 代码编写完成以后,Codex 可以启动它内置的浏览器进行自动化的测试,这样任务就完成了,开发服务器也启动起来了。在右侧的多功能窗口,Codex 自动打开了浏览器。我们可以点击这里的展开面板按钮,看一下项目的完整状态。我们看到这次架构迁移非常的成功,页面上所有的元素都完整地保留了,非常的不错。 如果对某个部分不满意,我们可以点击这里的批注按钮,然后选中一个元素,在这里可以添加评论。比如这里我说为什么这个星星是空心的,然后在下面点击发送,让 AI 帮我们修改一下。 在下面也可以实时看到它的修改过程。我们刷新一下页面,这个星星就被修改成了实心的。这样我们就通过 Plan 模式配合 Codex 的内置浏览器,成功完成了项目架构的迁移,还顺手修改了一个小 bug 。 代码管理 Codex APP 并不是传统的 IDE ,它并不提供完整的代码编辑功能。我们可以在右上角点击切换文件树,这里虽然可以查看代码,但是没法直接编辑。我们只能点击某行代码来写批注,并不能直接修改代码。我们可以借助第三方的 IDE 来修改代码。 在进行代码管理之前,我们需要先把项目初始化成一个 git 工程。这里我们新开启一个对话,输入提示词: 把项目初始化成一个 git 工程,注意排除掉不需要的文件。 Codex 先为我们创建了 .gitignore 文件,把一些不需要提交的内容排除出去。Codex 帮我们把项目初始化成了 Git 仓库。 初始化成 Git 仓库以后,右上角又多了很多按钮。这里有一个 VSCode 按钮,我们点击一下,我们就可以快捷地使用 VSCode 来查看和修改代码。 除了使用 VSCode ,在这个下拉列表里面,还可以使用其他的 IDE 来打开项目。如果你的电脑上装过这些 IDE ,就可以在这里关联出来。我们也可以在设置常规设置里面选择默认打开的 IDE 。 我还可以要求 AI 把代码帮我提交到 Github 上面。Codex 需要我先在 Github 上面为它创建一个仓库。这里我来到 Github ,点击这个 new 按钮,仓库的名字还叫 pet_care ,点击创建。 创建出来以后把这个地址复制一下,我们回到 Codex 扔给他,成功帮我们把代码推送到了 Github 上面。我们点击这个链接,看到我们的代码已经备份到了 GitHub 的网站上面。我们可以使用对话的方式进行一切 Git 与 Github 操作,这都属于编程的基础知识,本期视频我就不展开讲了。 Git 回滚 本期视频我主要讲两个进阶技巧。第一个是使用 Git 对开发过程进行回滚,第二个技巧是 Git WorkTree 。 我们先看第一个回滚。这里我新开一个对话,我们打开侧边栏,点击加号,浏览器输入我们项目本地开发的地址,这样进入浏览器。我们还是在这里面进行一些批注。我让 Codex 在这里添加一个期望到店时间的功能,直接点击 Ctrl 加回车发送。Codex 为我们添加了期望到店时间这个字段。 当 AI 完成一个功能的开发以后,我们就使用 Git 把它备份保存一下。这里点击提交, 填写一个提交消息,点击继续。这样最新的代码改动就以 Git 的方式保存下来了。接下来我让 AI 把期望到店时间放到联系人的上面,开始。Codex 为我们完成了修改,我们还是从内置的浏览器看一下效果。这个字段跑到了最上面,不过这么一改,我觉得更难看了,我后悔了。我觉得还是把它放到原来的位置比较好。这里我想做的是把这一次的对话,包括这一次的代码改动,全部回滚掉,最好是当做无事发生。 这里我们先借助 Codex 的分叉功能,英文是 fork 。我们先把对话回滚掉。我们找到上一次对话结尾的位置,点击这个分叉按钮,选择派生到本地。 我们看到 Codex 的分叉功能,就是在我点击的这个位置,把对话复制了一份。这样复制出来的新对话,就已经剔除掉了我们刚才想删除的部分了。 不过分叉功能只能回退对话历史,它不能同步回退代码。所以这里我们要做的是把代码一同回退掉。我们可以在 VSCode 里面点击这个 source control 按钮,查看所有的 Git 提交。这里我需要把代码回退到生成期望到店时间的这个状态上。我们点击右键,点击这个 copy commit hash , 这样我们就把这次提交的 ID 复制下来了。我们回到 Codex ,先让 AI 把代码回退到这个状态,后面就是我们刚才复制的提交 ID 。 我们看到代码回退成功了,在浏览器里可以看到这个期望到店时间又变回了原来的位置。这样我们就使用了 Codex 的对话分岔功能,加上 Git 操作,成功地把这一次不需要的改动,从代码层面和对话历史层面进行了完全的回滚。 Git worktree 接下来我们来看下一个功能,就是 Git worktree 。WorkTree 这个名字听起来比较唬人,其实它本质上就是用 git 创建一个新的分支,然后把这个新分支的代码完整地复制到一个新的文件夹里面。这个新文件夹就是一个 WorkTree 。主文件夹和分支文件夹可以并行工作,我们可以在两个文件夹里面各自修改代码,互相不干扰。我们可以基于主干创建多个分支,它们在底层通过 git 关联在一起。分支文件夹的改动,随时都能轻松合并回主干。 找到我们的项目,右键创建永久工作树。这里起个名字,我想让第一个工作树专注优化客户评价这个部分,我给它加个后缀叫 customer rating 。Codex 把整个项目复制到了一个单独的文件夹里面,它跟主干已经不是同一个文件夹了。我们在分支里面做的操作不会影响到主干。这里我们再建一个工作树,第二个工作树主要用来负责优化下面的门店信息,还有这里的地图。我们给第二个树也起个名字。这样我们就拥有了两个工作树分支,它们都位于不同的文件夹下面,所以它们之间的并行工作不会影响到主干。 这里我们来测试一下。我们先打开第一个分支新对话,输入我们的需求: 优化一下客户评价部分,多写几个评价,做一个动画轮播效果, 开始。然后我们来到第二个分支,创建一个新的对话: 优化一下门店信息部分,让门店信息跟地图上下排列,不要左右排列,把地图展示全。 我们在两个分支上面进行并行开发,因为它们位于两个不同的文件夹,所以互相之间不会产生干扰。 两个分支在各自的文件夹里面都开发完毕了。接下来我们可以把它合并回主干。里直接输入合并回主干,两个分支都一样的操作,合并回主干。 两个分支都成功合并进了主干。我们在浏览器这边可以看到,客户评价已经优化过了,门店信息也从左右排布变成了上下排布,地图展示得更全了。这样我们使用 Git worktree 功能,高效并行开发了两个任务。当我们的分支使用完毕,我们可以直接右键移除,把两个临时的分支移除掉,然后回到主干继续工作。

www.v2ex.com · 2026-04-30 05:26:27+08:00 · tech

视频版: https://www.bilibili.com/video/BV1Kk9kBAEJv 最近 Codex APP 的能力越来越全面,变成了 Codex 四大产品形态里面最强的一个。Codex 比起 Claude Code ,额度更高,功能更全,上手更快,免费账户也能用,而且不会出现限速、封号、降智等问题,用过的小伙伴们直呼真香。本期视频带来一个 Codex APP 的完整教程,主要分为以下 12 个章节。 每个章节里面都会穿插一些重要的知识,对 Codex 的全部功能进行细致讲解。好,废话不多说,我们直接开始。 安装 在安装使用 Codex APP 之前,需要进行 3 个准备工作,也就是需要先把 Git 、Nodejs 还有 VSCode 安装一下。在我上期视频《从 0 开始用国内网络跑通一切 AI Agent 》里面,有详细的操作步骤,不熟悉的朋友们可以参考那一期视频。 接下来我们来到 Codex 的官网,Codex 支持 Windows 跟 Mac 两大操作系统。官网会根据你的操作系统,自动提供对应的安装包。本期视频我主要使用 Windows 来进行演示。Windows 跟 Mac 电脑的功能基本是一致的,唯一欠缺的功能是 computer use ,也就是自动操作电脑的能力。等需要演示这部分的时候,我会切换到 Mac 电脑进行演示。 然后我们一路点击下一步完成安装。接下来我们把 Codex APP 启动起来,选择 ChatGPT 账户完成登录。现在 ChatGPT 的免费账户也能使用 Codex 了,不过额度比较低。第一次进入软件要选一下希望 Codex 为你处理的工作,Codex 会根据你的选择预装一些内置的插件和 skills 。当然进入软件以后,我们还可以按需安装这些插件。然后选择主要的使用场景,是编程还是日常工作,这些都可以后续在设置里面进行修改。接下来点击设置沙盒按钮,完成沙盒的初始化。关于沙盒这部分的内容,我们下一个章节再来介绍。 项目与任务列表 我们点击右上角的按钮显示侧边栏,我们看到 Codex APP 是非常经典的三栏布局:左侧是任务列表,中间是对话窗口,右侧是多功能区域。 我们先创建两个项目文件夹,来展示一下它的基础使用。这里我在桌面新建了两个文件夹,作为两个项目文件夹。然后我们来到 Codex ,点击进入项目工作,使用现有文件夹。我们先选择第一个文件夹,这里我让它做一个 html 单页面的宠物洗护店的网页,开始。在左侧边栏里面增加了一个项目,项目的名称就是文件夹的名称,里面展示了正在运行的任务。 接下来我们点击左上角的新对话按钮。Windows 上的快捷键是 Ctrl+N ,Mac 系统的快捷键是 command+N ,来开启一个新的对话。我们可以选择新对话属于哪个项目。这里我准备开启一个新的项目,把第二个文件夹也添加进来,点击添加新项目,然后选择我们的第二个文件夹。 这里输入我第二个项目的需求:用 react 框架做一个网页版待办事项的提醒工具,回车开始执行。 在两个项目并行工作的同时,我们还可以开启更多的工作对话。比如这里我想询问 Codex 一个技术问题,我们把鼠标指向第二个项目,点击这个小按钮,在项目里面开启新的对话。 这里我询问 Codex:react 框架是什么,回车。这里看到我们开启了 3 个任务并行执行,有两个任务属于项目一,一个任务属于项目 2 。正在执行的任务上面都有一个转圈的小图标,表示 AI 正在工作。我们耐心等待一会。 过了一会状态就不一样了。有一个任务上面显示一个绿色标签,表示等待批准;有一个任务上面出现了一个蓝色小点,表示已经执行完毕了;还有一个任务继续转圈。我们来到这个等待批准的任务里面,发现 Codex 需要联网下载 Vite React 项目的模板,正在申请权限。 我们点击“是”批准,这个任务就继续执行了。又过了一会,三个任务上面都标记了蓝色的小圆点,表示三个任务都执行完毕了。Codex 任务列表非常的简洁美观好用,可以很方便地观察任务状态,可以并行开启多个工作任务,还能高效地从多个任务里面自由地切换。 我们再来看一下左侧边栏任务列表的其他功能。新对话按钮用来开启新的对话,在下面可以选择对应的项目,也可以选择不使用任何的项目,纯粹的闲聊。这种不属于任何项目的对话,都会被收录到任务列表的最下面,也就是对话这一栏里面。 左侧边栏第二个按钮,快捷键是 Ctrl+G ,Mac 电脑的快捷键是 command+G ,可以搜索近期的对话历史。不过我试了一下,这个功能只能搜索到对话的标题,它无法搜索到对话里面的内容。这里补充一下,每个对话标题都是 AI 根据对话内容自动摘要生成的。我们也可以选择某个对话,双击,对它进行一个重命名。如果我们不再需要某个对话了,可以点击这个归档对话的小按钮确认,然后我们的对话就在左侧边栏消失了。在设置已归档对话里面,可以找到我们删除的对话,点击取消归档就可以把它还原回来。左侧边栏还有两个按钮,插件与自动化,这个等我们在后面的章节再来看。 权限控制与沙箱 接下来我们来看一下中间的对话页面。这里最显眼的功能就是权限控制。 Codex 的权限控制全部是围绕沙箱来展开的,这点跟 Claude Code 有本质上的不同。Claude Code 的沙箱功能需要手动开启,Claude Code 的沙箱更像是一层可以额外开启的保护,而 Codex 的沙箱,它是整个权限系统运行的地基。 Codex 会把当前的项目文件夹作为一个沙箱进行管理。在默认权限下面,Codex 具有读取修改沙箱内所有文件的权限。在默认模式下,Codex APP 可以直接修改沙箱内,也就是项目文件夹的所有文件,它并不会一个个地跑来问你。我觉得这点非常的方便,也是符合正常的使用习惯的。当然我们也可以通过设置,改成逐个文件修改都需要审批,这个在视频的后半段高级设置这个我们再来讲。 Codex 的沙箱有两个默认限制。第一点是 Codex 不能修改沙箱外的文件,第二点是 Codex 的沙箱是禁止联网的。这两点硬性限制,它并不是靠模型自觉遵守,而是 Codex 使用操作系统底层功能实现的。不同操作系统的实现机制是不一样的,比如 MacOS 使用的是系统内置的 Seatbelt Sandbox 机制。 Codex 的沙箱功能是前阵爆火的 Harness engineering 概念的一个典型的工程实现,用操作系统级别的机制把 AI 的能力约束在一个可控的范围之内。这也很形象地体现了 Harness 这个词的原始含义,也就是马具。AI 就像一匹能力很强的马,而沙箱权限审批机制这些,就是套在它身上的马具。 如果 Codex 需要修改沙箱外文件,或者需要联网,可以向用户申请权限,这个操作叫做 escalate ,也就是提权操作。在默认情况下,提权操作都是需要人工审核同意的。Codex 为我们提供了第二个档位,也就是自动审查。启动了自动审查以后,Codex 会自动调用一个小模型,对提权操作进行安全性审查。如果发现是低风险的操作,就会直接放行。只有高风险的操作才会触发人工审查,这也是我最推荐的模式。自动审查使得绝大部分操作不需要人工审批,在获取了较高安全性的同时,还极大提升了使用的便利度。 所以一般情况下,在权限管理这里,我都推荐开启第二档,也就是自动审查。Codex 还有第三档,完全访问权限。开启了这个以后,Codex 完全无视沙箱的限制,可以在电脑上执行一切的操作。不过我们尝试开启的时候,这里出现了很醒目的风险提示,提示我们要谨慎使用。 上下文 在权限控制的右边有一个圆圈,展示的是当前上下文使用情况。这里翻译得不太好,准确的翻译应该是上下文使用量信息,显示的是这个对话里的历史对话内容占用了多少模型上下文空间。当上下文超过限制的时候,Codex 会自动对对话历史进行压缩,从而释放出更多的上下文空间。我们也可以输入斜杠,选择压缩选项,手动触发一次上下文压缩。压缩完成以后,Codex 会把之前对话的一些不重要的内容排除掉,可以有效提高 AI 的专注力,并且降低 TOKEN 消耗。 不过在 AI Agent 领域,有一个通用经验是清空好于压缩。因为过多的历史会话,会干扰 AI 的注意力。当我们让 AI 执行完一个任务以后,最好是开一个新的对话,清空上下文。这样有助于 AI 把注意力全部集中到新的任务上面来,从而提高任务的执行效果。 在上下文窗口的右边是模型选择,可以根据任务的复杂程度选择模型的思考强度。下面可以切换模型,这里一般我们就选择最新的模型,比如现在是 GPT-5.5 。 下面还有一个速度选项,可以选择标准还有快速。在快速模式下,会提升 50% 的 AI 推理速度,但是快速模式会消耗两倍的套餐用量。如果你的任务很急,但是套餐的余量还有很多,可以选择开启。 说到套餐余量,我们可以在左下角的设置剩余额度里面找到你现在的套餐余量。这里有两个限额,分别是 5 小时限额,还有周限额。这两个限额任意一个到达上限,Codex 都不能继续使用了。 两个限额都有对应的重置时间,时间到了以后,额度会重置成 100%。右边还有一个语音输入功能,可以让我们跟 AI 的交互从打字变成口喷,非常的好玩。 AI 生图 Codex 内置了 AI 画图功能,而且它使用的是当今最强的 AI 生图模型 GPT-Image-2 。这是刚才我让 Codex 为我们生成的宠物洗护的网站,我们看到它已经为我们配了一些图片。这里我看了一下,这些图片其实都是网络上的免费素材。这里有两个配图非常的不合适。首先这里的店内环境展示的都是一些宠物图片,它并不是一个真正的宠物洗护店的环境。第二点是门店信息,这里画的地图也太粗糙简陋了。 我们就针对这两个问题,让 Codex 帮我们来修改一下。我们来到 Codex ,新开一个对话,项目选择宠物洗护店那个。我让 Codex 调用 AI 绘图功能,绘制三个店内环境的轮播图,三个图应该分别展示店内的不同区域。 我们看到 Codex 为我们生成了三张图片,基本都保持了店内装修风格的一致性。 然后在网页这边也替换成了 3 张图片的轮播图,非常的不错。 接下来我们要改的是门店信息,这里的地图太简陋了。我们回到 Codex ,在宠物店应用这里新开一个对话,输入我的指令: 我们的店在陕西北路 1620 号,就是地图上标记的这个点。你按我发你的位置,用可爱清新的宠物风格的地图把我们的店标记上,然后修改网页里的门店位置信息。 这里我来到地图,我截个图,然后把我们的店用箭头标记上。接下来我们直接 Ctrl+V ,Mac 系统是 Command+V ,把截图粘贴过来,开始。 在 Codex 的执行过程中,我随时跟踪进度。这里我发现了一个问题,就是他画的这个地图是用 SVG 生成的,效果很差。我原本是想让他调用内置的 AI 生图模型来画。借着这个机会,我要介绍 Codex 的一个强大功能。它的英文名叫做 steer ,中文翻译过来是引导。这个词的英文原文的意思是打方向盘。当我们发现 AI 在执行过程中理解错了我们的意思,就不应该让它继续执行了,这时候应该及时接管方向盘,人工进行引导干预。 这里我截个图发送给 Codex 说:你这图不行,应该调用 AI 绘图能力。 在默认模式下,这个新的指令进入了指令队列排队,需要 AI 把上一轮全部执行完,才能执行我们新输入的指令。我们可以点击这里的引导按钮,英文版叫做 steer ,中途接管方向盘,引导干预 AI 的执行。 我们看到 Codex 这里显示已引导对话,然后回复我说味不对,我立即改用 AI 生图,重新生成一张。我们使用 Codex 的 steer 功能,在运行中途成功纠正了模型的运行方向。 在 Codex 的设置常规设置里面,有一个跟进行为。这里可以设置在执行过程中,我们输入的指令是在后面排队,还是直接进入引导。 这里我推荐还是默认选择排队,如果需要引导的话,我们直接点击那个引导按钮,或者按快捷键 Ctrl+回车。我们看到 Codex 为我们重新生成了一张图片,并且把它替换到了网页里面,标注出了我们店的位置,效果非常的棒。 计划模式与内置浏览器 在对话窗口这里有一个加号,里面有三个功能。首先是添加照片和文件,我们可以用照片或者文件给 AI 补充上下文信息,或者可以像刚才一样通过复制粘贴,直接把照片或者文件粘贴进对话窗口。下面是插件,目前预装了 4 个插件,分别对应办公三大件( Word,Excel,PPT ),还有浏览器自动化。 我们主要看这里的计划模式。开启了计划以后,Codex 就不会立即上手干活,而是先为我们输出一份完整的工作计划,跟我们进行了确认以后再干活。对于所有的复杂任务,建议都先开启计划模式,确保你能跟 AI 对齐颗粒度,让 AI 能够精准理解我们的意图。 我们在 Codex 里面打开计划模式,输入我们的需求: 把这个项目改造成 next js 框架 在计划模式里面,Codex 会很倾向于使用这种问题卡片的形式跟用户进行沟通。这里他询问我希望使用哪种项目形态,我选择 APP Router 加 TS 。然后样式迁移希望怎么处理,这里我选择改 Tailwind 。迁移完成要不要同时启动本地开发服务器验证,这里我选择构建加启动。Codex 为我们生成了一份完整的计划,我仔细阅读了一遍,没有发现问题。这里我们点击是,实施此计划。 代码编写完成以后,Codex 可以启动它内置的浏览器进行自动化的测试,这样任务就完成了,开发服务器也启动起来了。在右侧的多功能窗口,Codex 自动打开了浏览器。我们可以点击这里的展开面板按钮,看一下项目的完整状态。我们看到这次架构迁移非常的成功,页面上所有的元素都完整地保留了,非常的不错。 如果对某个部分不满意,我们可以点击这里的批注按钮,然后选中一个元素,在这里可以添加评论。比如这里我说为什么这个星星是空心的,然后在下面点击发送,让 AI 帮我们修改一下。 在下面也可以实时看到它的修改过程。我们刷新一下页面,这个星星就被修改成了实心的。这样我们就通过 Plan 模式配合 Codex 的内置浏览器,成功完成了项目架构的迁移,还顺手修改了一个小 bug 。 代码管理 Codex APP 并不是传统的 IDE ,它并不提供完整的代码编辑功能。我们可以在右上角点击切换文件树,这里虽然可以查看代码,但是没法直接编辑。我们只能点击某行代码来写批注,并不能直接修改代码。我们可以借助第三方的 IDE 来修改代码。 在进行代码管理之前,我们需要先把项目初始化成一个 git 工程。这里我们新开启一个对话,输入提示词: 把项目初始化成一个 git 工程,注意排除掉不需要的文件。 Codex 先为我们创建了 .gitignore 文件,把一些不需要提交的内容排除出去。Codex 帮我们把项目初始化成了 Git 仓库。 初始化成 Git 仓库以后,右上角又多了很多按钮。这里有一个 VSCode 按钮,我们点击一下,我们就可以快捷地使用 VSCode 来查看和修改代码。 除了使用 VSCode ,在这个下拉列表里面,还可以使用其他的 IDE 来打开项目。如果你的电脑上装过这些 IDE ,就可以在这里关联出来。我们也可以在设置常规设置里面选择默认打开的 IDE 。 我还可以要求 AI 把代码帮我提交到 Github 上面。Codex 需要我先在 Github 上面为它创建一个仓库。这里我来到 Github ,点击这个 new 按钮,仓库的名字还叫 pet_care ,点击创建。 创建出来以后把这个地址复制一下,我们回到 Codex 扔给他,成功帮我们把代码推送到了 Github 上面。我们点击这个链接,看到我们的代码已经备份到了 GitHub 的网站上面。我们可以使用对话的方式进行一切 Git 与 Github 操作,这都属于编程的基础知识,本期视频我就不展开讲了。 Git 回滚 本期视频我主要讲两个进阶技巧。第一个是使用 Git 对开发过程进行回滚,第二个技巧是 Git WorkTree 。 我们先看第一个回滚。这里我新开一个对话,我们打开侧边栏,点击加号,浏览器输入我们项目本地开发的地址,这样进入浏览器。我们还是在这里面进行一些批注。我让 Codex 在这里添加一个期望到店时间的功能,直接点击 Ctrl 加回车发送。Codex 为我们添加了期望到店时间这个字段。 当 AI 完成一个功能的开发以后,我们就使用 Git 把它备份保存一下。这里点击提交, 填写一个提交消息,点击继续。这样最新的代码改动就以 Git 的方式保存下来了。接下来我让 AI 把期望到店时间放到联系人的上面,开始。Codex 为我们完成了修改,我们还是从内置的浏览器看一下效果。这个字段跑到了最上面,不过这么一改,我觉得更难看了,我后悔了。我觉得还是把它放到原来的位置比较好。这里我想做的是把这一次的对话,包括这一次的代码改动,全部回滚掉,最好是当做无事发生。 这里我们先借助 Codex 的分叉功能,英文是 fork 。我们先把对话回滚掉。我们找到上一次对话结尾的位置,点击这个分叉按钮,选择派生到本地。 我们看到 Codex 的分叉功能,就是在我点击的这个位置,把对话复制了一份。这样复制出来的新对话,就已经剔除掉了我们刚才想删除的部分了。 不过分叉功能只能回退对话历史,它不能同步回退代码。所以这里我们要做的是把代码一同回退掉。我们可以在 VSCode 里面点击这个 source control 按钮,查看所有的 Git 提交。这里我需要把代码回退到生成期望到店时间的这个状态上。我们点击右键,点击这个 copy commit hash , 这样我们就把这次提交的 ID 复制下来了。我们回到 Codex ,先让 AI 把代码回退到这个状态,后面就是我们刚才复制的提交 ID 。 我们看到代码回退成功了,在浏览器里可以看到这个期望到店时间又变回了原来的位置。这样我们就使用了 Codex 的对话分岔功能,加上 Git 操作,成功地把这一次不需要的改动,从代码层面和对话历史层面进行了完全的回滚。 Git worktree 接下来我们来看下一个功能,就是 Git worktree 。WorkTree 这个名字听起来比较唬人,其实它本质上就是用 git 创建一个新的分支,然后把这个新分支的代码完整地复制到一个新的文件夹里面。这个新文件夹就是一个 WorkTree 。主文件夹和分支文件夹可以并行工作,我们可以在两个文件夹里面各自修改代码,互相不干扰。我们可以基于主干创建多个分支,它们在底层通过 git 关联在一起。分支文件夹的改动,随时都能轻松合并回主干。 找到我们的项目,右键创建永久工作树。这里起个名字,我想让第一个工作树专注优化客户评价这个部分,我给它加个后缀叫 customer rating 。Codex 把整个项目复制到了一个单独的文件夹里面,它跟主干已经不是同一个文件夹了。我们在分支里面做的操作不会影响到主干。这里我们再建一个工作树,第二个工作树主要用来负责优化下面的门店信息,还有这里的地图。我们给第二个树也起个名字。这样我们就拥有了两个工作树分支,它们都位于不同的文件夹下面,所以它们之间的并行工作不会影响到主干。 这里我们来测试一下。我们先打开第一个分支新对话,输入我们的需求: 优化一下客户评价部分,多写几个评价,做一个动画轮播效果, 开始。然后我们来到第二个分支,创建一个新的对话: 优化一下门店信息部分,让门店信息跟地图上下排列,不要左右排列,把地图展示全。 我们在两个分支上面进行并行开发,因为它们位于两个不同的文件夹,所以互相之间不会产生干扰。 两个分支在各自的文件夹里面都开发完毕了。接下来我们可以把它合并回主干。里直接输入合并回主干,两个分支都一样的操作,合并回主干。 两个分支都成功合并进了主干。我们在浏览器这边可以看到,客户评价已经优化过了,门店信息也从左右排布变成了上下排布,地图展示得更全了。这样我们使用 Git worktree 功能,高效并行开发了两个任务。当我们的分支使用完毕,我们可以直接右键移除,把两个临时的分支移除掉,然后回到主干继续工作。

v2ex.com · 2026-04-30 04:26:27+08:00 · tech

视频版: https://www.bilibili.com/video/BV1Kk9kBAEJv 最近 Codex APP 的能力越来越全面,变成了 Codex 四大产品形态里面最强的一个。Codex 比起 Claude Code ,额度更高,功能更全,上手更快,免费账户也能用,而且不会出现限速、封号、降智等问题,用过的小伙伴们直呼真香。本期视频带来一个 Codex APP 的完整教程,主要分为以下 12 个章节。 每个章节里面都会穿插一些重要的知识,对 Codex 的全部功能进行细致讲解。好,废话不多说,我们直接开始。 安装 在安装使用 Codex APP 之前,需要进行 3 个准备工作,也就是需要先把 Git 、Nodejs 还有 VSCode 安装一下。在我上期视频《从 0 开始用国内网络跑通一切 AI Agent 》里面,有详细的操作步骤,不熟悉的朋友们可以参考那一期视频。 接下来我们来到 Codex 的官网,Codex 支持 Windows 跟 Mac 两大操作系统。官网会根据你的操作系统,自动提供对应的安装包。本期视频我主要使用 Windows 来进行演示。Windows 跟 Mac 电脑的功能基本是一致的,唯一欠缺的功能是 computer use ,也就是自动操作电脑的能力。等需要演示这部分的时候,我会切换到 Mac 电脑进行演示。 然后我们一路点击下一步完成安装。接下来我们把 Codex APP 启动起来,选择 ChatGPT 账户完成登录。现在 ChatGPT 的免费账户也能使用 Codex 了,不过额度比较低。第一次进入软件要选一下希望 Codex 为你处理的工作,Codex 会根据你的选择预装一些内置的插件和 skills 。当然进入软件以后,我们还可以按需安装这些插件。然后选择主要的使用场景,是编程还是日常工作,这些都可以后续在设置里面进行修改。接下来点击设置沙盒按钮,完成沙盒的初始化。关于沙盒这部分的内容,我们下一个章节再来介绍。 项目与任务列表 我们点击右上角的按钮显示侧边栏,我们看到 Codex APP 是非常经典的三栏布局:左侧是任务列表,中间是对话窗口,右侧是多功能区域。 我们先创建两个项目文件夹,来展示一下它的基础使用。这里我在桌面新建了两个文件夹,作为两个项目文件夹。然后我们来到 Codex ,点击进入项目工作,使用现有文件夹。我们先选择第一个文件夹,这里我让它做一个 html 单页面的宠物洗护店的网页,开始。在左侧边栏里面增加了一个项目,项目的名称就是文件夹的名称,里面展示了正在运行的任务。 接下来我们点击左上角的新对话按钮。Windows 上的快捷键是 Ctrl+N ,Mac 系统的快捷键是 command+N ,来开启一个新的对话。我们可以选择新对话属于哪个项目。这里我准备开启一个新的项目,把第二个文件夹也添加进来,点击添加新项目,然后选择我们的第二个文件夹。 这里输入我第二个项目的需求:用 react 框架做一个网页版待办事项的提醒工具,回车开始执行。 在两个项目并行工作的同时,我们还可以开启更多的工作对话。比如这里我想询问 Codex 一个技术问题,我们把鼠标指向第二个项目,点击这个小按钮,在项目里面开启新的对话。 这里我询问 Codex:react 框架是什么,回车。这里看到我们开启了 3 个任务并行执行,有两个任务属于项目一,一个任务属于项目 2 。正在执行的任务上面都有一个转圈的小图标,表示 AI 正在工作。我们耐心等待一会。 过了一会状态就不一样了。有一个任务上面显示一个绿色标签,表示等待批准;有一个任务上面出现了一个蓝色小点,表示已经执行完毕了;还有一个任务继续转圈。我们来到这个等待批准的任务里面,发现 Codex 需要联网下载 Vite React 项目的模板,正在申请权限。 我们点击“是”批准,这个任务就继续执行了。又过了一会,三个任务上面都标记了蓝色的小圆点,表示三个任务都执行完毕了。Codex 任务列表非常的简洁美观好用,可以很方便地观察任务状态,可以并行开启多个工作任务,还能高效地从多个任务里面自由地切换。 我们再来看一下左侧边栏任务列表的其他功能。新对话按钮用来开启新的对话,在下面可以选择对应的项目,也可以选择不使用任何的项目,纯粹的闲聊。这种不属于任何项目的对话,都会被收录到任务列表的最下面,也就是对话这一栏里面。 左侧边栏第二个按钮,快捷键是 Ctrl+G ,Mac 电脑的快捷键是 command+G ,可以搜索近期的对话历史。不过我试了一下,这个功能只能搜索到对话的标题,它无法搜索到对话里面的内容。这里补充一下,每个对话标题都是 AI 根据对话内容自动摘要生成的。我们也可以选择某个对话,双击,对它进行一个重命名。如果我们不再需要某个对话了,可以点击这个归档对话的小按钮确认,然后我们的对话就在左侧边栏消失了。在设置已归档对话里面,可以找到我们删除的对话,点击取消归档就可以把它还原回来。左侧边栏还有两个按钮,插件与自动化,这个等我们在后面的章节再来看。 权限控制与沙箱 接下来我们来看一下中间的对话页面。这里最显眼的功能就是权限控制。 Codex 的权限控制全部是围绕沙箱来展开的,这点跟 Claude Code 有本质上的不同。Claude Code 的沙箱功能需要手动开启,Claude Code 的沙箱更像是一层可以额外开启的保护,而 Codex 的沙箱,它是整个权限系统运行的地基。 Codex 会把当前的项目文件夹作为一个沙箱进行管理。在默认权限下面,Codex 具有读取修改沙箱内所有文件的权限。在默认模式下,Codex APP 可以直接修改沙箱内,也就是项目文件夹的所有文件,它并不会一个个地跑来问你。我觉得这点非常的方便,也是符合正常的使用习惯的。当然我们也可以通过设置,改成逐个文件修改都需要审批,这个在视频的后半段高级设置这个我们再来讲。 Codex 的沙箱有两个默认限制。第一点是 Codex 不能修改沙箱外的文件,第二点是 Codex 的沙箱是禁止联网的。这两点硬性限制,它并不是靠模型自觉遵守,而是 Codex 使用操作系统底层功能实现的。不同操作系统的实现机制是不一样的,比如 MacOS 使用的是系统内置的 Seatbelt Sandbox 机制。 Codex 的沙箱功能是前阵爆火的 Harness engineering 概念的一个典型的工程实现,用操作系统级别的机制把 AI 的能力约束在一个可控的范围之内。这也很形象地体现了 Harness 这个词的原始含义,也就是马具。AI 就像一匹能力很强的马,而沙箱权限审批机制这些,就是套在它身上的马具。 如果 Codex 需要修改沙箱外文件,或者需要联网,可以向用户申请权限,这个操作叫做 escalate ,也就是提权操作。在默认情况下,提权操作都是需要人工审核同意的。Codex 为我们提供了第二个档位,也就是自动审查。启动了自动审查以后,Codex 会自动调用一个小模型,对提权操作进行安全性审查。如果发现是低风险的操作,就会直接放行。只有高风险的操作才会触发人工审查,这也是我最推荐的模式。自动审查使得绝大部分操作不需要人工审批,在获取了较高安全性的同时,还极大提升了使用的便利度。 所以一般情况下,在权限管理这里,我都推荐开启第二档,也就是自动审查。Codex 还有第三档,完全访问权限。开启了这个以后,Codex 完全无视沙箱的限制,可以在电脑上执行一切的操作。不过我们尝试开启的时候,这里出现了很醒目的风险提示,提示我们要谨慎使用。 上下文 在权限控制的右边有一个圆圈,展示的是当前上下文使用情况。这里翻译得不太好,准确的翻译应该是上下文使用量信息,显示的是这个对话里的历史对话内容占用了多少模型上下文空间。当上下文超过限制的时候,Codex 会自动对对话历史进行压缩,从而释放出更多的上下文空间。我们也可以输入斜杠,选择压缩选项,手动触发一次上下文压缩。压缩完成以后,Codex 会把之前对话的一些不重要的内容排除掉,可以有效提高 AI 的专注力,并且降低 TOKEN 消耗。 不过在 AI Agent 领域,有一个通用经验是清空好于压缩。因为过多的历史会话,会干扰 AI 的注意力。当我们让 AI 执行完一个任务以后,最好是开一个新的对话,清空上下文。这样有助于 AI 把注意力全部集中到新的任务上面来,从而提高任务的执行效果。 在上下文窗口的右边是模型选择,可以根据任务的复杂程度选择模型的思考强度。下面可以切换模型,这里一般我们就选择最新的模型,比如现在是 GPT-5.5 。 下面还有一个速度选项,可以选择标准还有快速。在快速模式下,会提升 50% 的 AI 推理速度,但是快速模式会消耗两倍的套餐用量。如果你的任务很急,但是套餐的余量还有很多,可以选择开启。 说到套餐余量,我们可以在左下角的设置剩余额度里面找到你现在的套餐余量。这里有两个限额,分别是 5 小时限额,还有周限额。这两个限额任意一个到达上限,Codex 都不能继续使用了。 两个限额都有对应的重置时间,时间到了以后,额度会重置成 100%。右边还有一个语音输入功能,可以让我们跟 AI 的交互从打字变成口喷,非常的好玩。 AI 生图 Codex 内置了 AI 画图功能,而且它使用的是当今最强的 AI 生图模型 GPT-Image-2 。这是刚才我让 Codex 为我们生成的宠物洗护的网站,我们看到它已经为我们配了一些图片。这里我看了一下,这些图片其实都是网络上的免费素材。这里有两个配图非常的不合适。首先这里的店内环境展示的都是一些宠物图片,它并不是一个真正的宠物洗护店的环境。第二点是门店信息,这里画的地图也太粗糙简陋了。 我们就针对这两个问题,让 Codex 帮我们来修改一下。我们来到 Codex ,新开一个对话,项目选择宠物洗护店那个。我让 Codex 调用 AI 绘图功能,绘制三个店内环境的轮播图,三个图应该分别展示店内的不同区域。 我们看到 Codex 为我们生成了三张图片,基本都保持了店内装修风格的一致性。 然后在网页这边也替换成了 3 张图片的轮播图,非常的不错。 接下来我们要改的是门店信息,这里的地图太简陋了。我们回到 Codex ,在宠物店应用这里新开一个对话,输入我的指令: 我们的店在陕西北路 1620 号,就是地图上标记的这个点。你按我发你的位置,用可爱清新的宠物风格的地图把我们的店标记上,然后修改网页里的门店位置信息。 这里我来到地图,我截个图,然后把我们的店用箭头标记上。接下来我们直接 Ctrl+V ,Mac 系统是 Command+V ,把截图粘贴过来,开始。 在 Codex 的执行过程中,我随时跟踪进度。这里我发现了一个问题,就是他画的这个地图是用 SVG 生成的,效果很差。我原本是想让他调用内置的 AI 生图模型来画。借着这个机会,我要介绍 Codex 的一个强大功能。它的英文名叫做 steer ,中文翻译过来是引导。这个词的英文原文的意思是打方向盘。当我们发现 AI 在执行过程中理解错了我们的意思,就不应该让它继续执行了,这时候应该及时接管方向盘,人工进行引导干预。 这里我截个图发送给 Codex 说:你这图不行,应该调用 AI 绘图能力。 在默认模式下,这个新的指令进入了指令队列排队,需要 AI 把上一轮全部执行完,才能执行我们新输入的指令。我们可以点击这里的引导按钮,英文版叫做 steer ,中途接管方向盘,引导干预 AI 的执行。 我们看到 Codex 这里显示已引导对话,然后回复我说味不对,我立即改用 AI 生图,重新生成一张。我们使用 Codex 的 steer 功能,在运行中途成功纠正了模型的运行方向。 在 Codex 的设置常规设置里面,有一个跟进行为。这里可以设置在执行过程中,我们输入的指令是在后面排队,还是直接进入引导。 这里我推荐还是默认选择排队,如果需要引导的话,我们直接点击那个引导按钮,或者按快捷键 Ctrl+回车。我们看到 Codex 为我们重新生成了一张图片,并且把它替换到了网页里面,标注出了我们店的位置,效果非常的棒。 计划模式与内置浏览器 在对话窗口这里有一个加号,里面有三个功能。首先是添加照片和文件,我们可以用照片或者文件给 AI 补充上下文信息,或者可以像刚才一样通过复制粘贴,直接把照片或者文件粘贴进对话窗口。下面是插件,目前预装了 4 个插件,分别对应办公三大件( Word,Excel,PPT ),还有浏览器自动化。 我们主要看这里的计划模式。开启了计划以后,Codex 就不会立即上手干活,而是先为我们输出一份完整的工作计划,跟我们进行了确认以后再干活。对于所有的复杂任务,建议都先开启计划模式,确保你能跟 AI 对齐颗粒度,让 AI 能够精准理解我们的意图。 我们在 Codex 里面打开计划模式,输入我们的需求: 把这个项目改造成 next js 框架 在计划模式里面,Codex 会很倾向于使用这种问题卡片的形式跟用户进行沟通。这里他询问我希望使用哪种项目形态,我选择 APP Router 加 TS 。然后样式迁移希望怎么处理,这里我选择改 Tailwind 。迁移完成要不要同时启动本地开发服务器验证,这里我选择构建加启动。Codex 为我们生成了一份完整的计划,我仔细阅读了一遍,没有发现问题。这里我们点击是,实施此计划。 代码编写完成以后,Codex 可以启动它内置的浏览器进行自动化的测试,这样任务就完成了,开发服务器也启动起来了。在右侧的多功能窗口,Codex 自动打开了浏览器。我们可以点击这里的展开面板按钮,看一下项目的完整状态。我们看到这次架构迁移非常的成功,页面上所有的元素都完整地保留了,非常的不错。 如果对某个部分不满意,我们可以点击这里的批注按钮,然后选中一个元素,在这里可以添加评论。比如这里我说为什么这个星星是空心的,然后在下面点击发送,让 AI 帮我们修改一下。 在下面也可以实时看到它的修改过程。我们刷新一下页面,这个星星就被修改成了实心的。这样我们就通过 Plan 模式配合 Codex 的内置浏览器,成功完成了项目架构的迁移,还顺手修改了一个小 bug 。 代码管理 Codex APP 并不是传统的 IDE ,它并不提供完整的代码编辑功能。我们可以在右上角点击切换文件树,这里虽然可以查看代码,但是没法直接编辑。我们只能点击某行代码来写批注,并不能直接修改代码。我们可以借助第三方的 IDE 来修改代码。 在进行代码管理之前,我们需要先把项目初始化成一个 git 工程。这里我们新开启一个对话,输入提示词: 把项目初始化成一个 git 工程,注意排除掉不需要的文件。 Codex 先为我们创建了 .gitignore 文件,把一些不需要提交的内容排除出去。Codex 帮我们把项目初始化成了 Git 仓库。 初始化成 Git 仓库以后,右上角又多了很多按钮。这里有一个 VSCode 按钮,我们点击一下,我们就可以快捷地使用 VSCode 来查看和修改代码。 除了使用 VSCode ,在这个下拉列表里面,还可以使用其他的 IDE 来打开项目。如果你的电脑上装过这些 IDE ,就可以在这里关联出来。我们也可以在设置常规设置里面选择默认打开的 IDE 。 我还可以要求 AI 把代码帮我提交到 Github 上面。Codex 需要我先在 Github 上面为它创建一个仓库。这里我来到 Github ,点击这个 new 按钮,仓库的名字还叫 pet_care ,点击创建。 创建出来以后把这个地址复制一下,我们回到 Codex 扔给他,成功帮我们把代码推送到了 Github 上面。我们点击这个链接,看到我们的代码已经备份到了 GitHub 的网站上面。我们可以使用对话的方式进行一切 Git 与 Github 操作,这都属于编程的基础知识,本期视频我就不展开讲了。 Git 回滚 本期视频我主要讲两个进阶技巧。第一个是使用 Git 对开发过程进行回滚,第二个技巧是 Git WorkTree 。 我们先看第一个回滚。这里我新开一个对话,我们打开侧边栏,点击加号,浏览器输入我们项目本地开发的地址,这样进入浏览器。我们还是在这里面进行一些批注。我让 Codex 在这里添加一个期望到店时间的功能,直接点击 Ctrl 加回车发送。Codex 为我们添加了期望到店时间这个字段。 当 AI 完成一个功能的开发以后,我们就使用 Git 把它备份保存一下。这里点击提交, 填写一个提交消息,点击继续。这样最新的代码改动就以 Git 的方式保存下来了。接下来我让 AI 把期望到店时间放到联系人的上面,开始。Codex 为我们完成了修改,我们还是从内置的浏览器看一下效果。这个字段跑到了最上面,不过这么一改,我觉得更难看了,我后悔了。我觉得还是把它放到原来的位置比较好。这里我想做的是把这一次的对话,包括这一次的代码改动,全部回滚掉,最好是当做无事发生。 这里我们先借助 Codex 的分叉功能,英文是 fork 。我们先把对话回滚掉。我们找到上一次对话结尾的位置,点击这个分叉按钮,选择派生到本地。 我们看到 Codex 的分叉功能,就是在我点击的这个位置,把对话复制了一份。这样复制出来的新对话,就已经剔除掉了我们刚才想删除的部分了。 不过分叉功能只能回退对话历史,它不能同步回退代码。所以这里我们要做的是把代码一同回退掉。我们可以在 VSCode 里面点击这个 source control 按钮,查看所有的 Git 提交。这里我需要把代码回退到生成期望到店时间的这个状态上。我们点击右键,点击这个 copy commit hash , 这样我们就把这次提交的 ID 复制下来了。我们回到 Codex ,先让 AI 把代码回退到这个状态,后面就是我们刚才复制的提交 ID 。 我们看到代码回退成功了,在浏览器里可以看到这个期望到店时间又变回了原来的位置。这样我们就使用了 Codex 的对话分岔功能,加上 Git 操作,成功地把这一次不需要的改动,从代码层面和对话历史层面进行了完全的回滚。 Git worktree 接下来我们来看下一个功能,就是 Git worktree 。WorkTree 这个名字听起来比较唬人,其实它本质上就是用 git 创建一个新的分支,然后把这个新分支的代码完整地复制到一个新的文件夹里面。这个新文件夹就是一个 WorkTree 。主文件夹和分支文件夹可以并行工作,我们可以在两个文件夹里面各自修改代码,互相不干扰。我们可以基于主干创建多个分支,它们在底层通过 git 关联在一起。分支文件夹的改动,随时都能轻松合并回主干。 找到我们的项目,右键创建永久工作树。这里起个名字,我想让第一个工作树专注优化客户评价这个部分,我给它加个后缀叫 customer rating 。Codex 把整个项目复制到了一个单独的文件夹里面,它跟主干已经不是同一个文件夹了。我们在分支里面做的操作不会影响到主干。这里我们再建一个工作树,第二个工作树主要用来负责优化下面的门店信息,还有这里的地图。我们给第二个树也起个名字。这样我们就拥有了两个工作树分支,它们都位于不同的文件夹下面,所以它们之间的并行工作不会影响到主干。 这里我们来测试一下。我们先打开第一个分支新对话,输入我们的需求: 优化一下客户评价部分,多写几个评价,做一个动画轮播效果, 开始。然后我们来到第二个分支,创建一个新的对话: 优化一下门店信息部分,让门店信息跟地图上下排列,不要左右排列,把地图展示全。 我们在两个分支上面进行并行开发,因为它们位于两个不同的文件夹,所以互相之间不会产生干扰。 两个分支在各自的文件夹里面都开发完毕了。接下来我们可以把它合并回主干。里直接输入合并回主干,两个分支都一样的操作,合并回主干。 两个分支都成功合并进了主干。我们在浏览器这边可以看到,客户评价已经优化过了,门店信息也从左右排布变成了上下排布,地图展示得更全了。这样我们使用 Git worktree 功能,高效并行开发了两个任务。当我们的分支使用完毕,我们可以直接右键移除,把两个临时的分支移除掉,然后回到主干继续工作。

v2ex.com · 2026-04-30 03:26:27+08:00 · tech

视频版: https://www.bilibili.com/video/BV1Kk9kBAEJv 最近 Codex APP 的能力越来越全面,变成了 Codex 四大产品形态里面最强的一个。Codex 比起 Claude Code ,额度更高,功能更全,上手更快,免费账户也能用,而且不会出现限速、封号、降智等问题,用过的小伙伴们直呼真香。本期视频带来一个 Codex APP 的完整教程,主要分为以下 12 个章节。 每个章节里面都会穿插一些重要的知识,对 Codex 的全部功能进行细致讲解。好,废话不多说,我们直接开始。 安装 在安装使用 Codex APP 之前,需要进行 3 个准备工作,也就是需要先把 Git 、Nodejs 还有 VSCode 安装一下。在我上期视频《从 0 开始用国内网络跑通一切 AI Agent 》里面,有详细的操作步骤,不熟悉的朋友们可以参考那一期视频。 接下来我们来到 Codex 的官网,Codex 支持 Windows 跟 Mac 两大操作系统。官网会根据你的操作系统,自动提供对应的安装包。本期视频我主要使用 Windows 来进行演示。Windows 跟 Mac 电脑的功能基本是一致的,唯一欠缺的功能是 computer use ,也就是自动操作电脑的能力。等需要演示这部分的时候,我会切换到 Mac 电脑进行演示。 然后我们一路点击下一步完成安装。接下来我们把 Codex APP 启动起来,选择 ChatGPT 账户完成登录。现在 ChatGPT 的免费账户也能使用 Codex 了,不过额度比较低。第一次进入软件要选一下希望 Codex 为你处理的工作,Codex 会根据你的选择预装一些内置的插件和 skills 。当然进入软件以后,我们还可以按需安装这些插件。然后选择主要的使用场景,是编程还是日常工作,这些都可以后续在设置里面进行修改。接下来点击设置沙盒按钮,完成沙盒的初始化。关于沙盒这部分的内容,我们下一个章节再来介绍。 项目与任务列表 我们点击右上角的按钮显示侧边栏,我们看到 Codex APP 是非常经典的三栏布局:左侧是任务列表,中间是对话窗口,右侧是多功能区域。 我们先创建两个项目文件夹,来展示一下它的基础使用。这里我在桌面新建了两个文件夹,作为两个项目文件夹。然后我们来到 Codex ,点击进入项目工作,使用现有文件夹。我们先选择第一个文件夹,这里我让它做一个 html 单页面的宠物洗护店的网页,开始。在左侧边栏里面增加了一个项目,项目的名称就是文件夹的名称,里面展示了正在运行的任务。 接下来我们点击左上角的新对话按钮。Windows 上的快捷键是 Ctrl+N ,Mac 系统的快捷键是 command+N ,来开启一个新的对话。我们可以选择新对话属于哪个项目。这里我准备开启一个新的项目,把第二个文件夹也添加进来,点击添加新项目,然后选择我们的第二个文件夹。 这里输入我第二个项目的需求:用 react 框架做一个网页版待办事项的提醒工具,回车开始执行。 在两个项目并行工作的同时,我们还可以开启更多的工作对话。比如这里我想询问 Codex 一个技术问题,我们把鼠标指向第二个项目,点击这个小按钮,在项目里面开启新的对话。 这里我询问 Codex:react 框架是什么,回车。这里看到我们开启了 3 个任务并行执行,有两个任务属于项目一,一个任务属于项目 2 。正在执行的任务上面都有一个转圈的小图标,表示 AI 正在工作。我们耐心等待一会。 过了一会状态就不一样了。有一个任务上面显示一个绿色标签,表示等待批准;有一个任务上面出现了一个蓝色小点,表示已经执行完毕了;还有一个任务继续转圈。我们来到这个等待批准的任务里面,发现 Codex 需要联网下载 Vite React 项目的模板,正在申请权限。 我们点击“是”批准,这个任务就继续执行了。又过了一会,三个任务上面都标记了蓝色的小圆点,表示三个任务都执行完毕了。Codex 任务列表非常的简洁美观好用,可以很方便地观察任务状态,可以并行开启多个工作任务,还能高效地从多个任务里面自由地切换。 我们再来看一下左侧边栏任务列表的其他功能。新对话按钮用来开启新的对话,在下面可以选择对应的项目,也可以选择不使用任何的项目,纯粹的闲聊。这种不属于任何项目的对话,都会被收录到任务列表的最下面,也就是对话这一栏里面。 左侧边栏第二个按钮,快捷键是 Ctrl+G ,Mac 电脑的快捷键是 command+G ,可以搜索近期的对话历史。不过我试了一下,这个功能只能搜索到对话的标题,它无法搜索到对话里面的内容。这里补充一下,每个对话标题都是 AI 根据对话内容自动摘要生成的。我们也可以选择某个对话,双击,对它进行一个重命名。如果我们不再需要某个对话了,可以点击这个归档对话的小按钮确认,然后我们的对话就在左侧边栏消失了。在设置已归档对话里面,可以找到我们删除的对话,点击取消归档就可以把它还原回来。左侧边栏还有两个按钮,插件与自动化,这个等我们在后面的章节再来看。 权限控制与沙箱 接下来我们来看一下中间的对话页面。这里最显眼的功能就是权限控制。 Codex 的权限控制全部是围绕沙箱来展开的,这点跟 Claude Code 有本质上的不同。Claude Code 的沙箱功能需要手动开启,Claude Code 的沙箱更像是一层可以额外开启的保护,而 Codex 的沙箱,它是整个权限系统运行的地基。 Codex 会把当前的项目文件夹作为一个沙箱进行管理。在默认权限下面,Codex 具有读取修改沙箱内所有文件的权限。在默认模式下,Codex APP 可以直接修改沙箱内,也就是项目文件夹的所有文件,它并不会一个个地跑来问你。我觉得这点非常的方便,也是符合正常的使用习惯的。当然我们也可以通过设置,改成逐个文件修改都需要审批,这个在视频的后半段高级设置这个我们再来讲。 Codex 的沙箱有两个默认限制。第一点是 Codex 不能修改沙箱外的文件,第二点是 Codex 的沙箱是禁止联网的。这两点硬性限制,它并不是靠模型自觉遵守,而是 Codex 使用操作系统底层功能实现的。不同操作系统的实现机制是不一样的,比如 MacOS 使用的是系统内置的 Seatbelt Sandbox 机制。 Codex 的沙箱功能是前阵爆火的 Harness engineering 概念的一个典型的工程实现,用操作系统级别的机制把 AI 的能力约束在一个可控的范围之内。这也很形象地体现了 Harness 这个词的原始含义,也就是马具。AI 就像一匹能力很强的马,而沙箱权限审批机制这些,就是套在它身上的马具。 如果 Codex 需要修改沙箱外文件,或者需要联网,可以向用户申请权限,这个操作叫做 escalate ,也就是提权操作。在默认情况下,提权操作都是需要人工审核同意的。Codex 为我们提供了第二个档位,也就是自动审查。启动了自动审查以后,Codex 会自动调用一个小模型,对提权操作进行安全性审查。如果发现是低风险的操作,就会直接放行。只有高风险的操作才会触发人工审查,这也是我最推荐的模式。自动审查使得绝大部分操作不需要人工审批,在获取了较高安全性的同时,还极大提升了使用的便利度。 所以一般情况下,在权限管理这里,我都推荐开启第二档,也就是自动审查。Codex 还有第三档,完全访问权限。开启了这个以后,Codex 完全无视沙箱的限制,可以在电脑上执行一切的操作。不过我们尝试开启的时候,这里出现了很醒目的风险提示,提示我们要谨慎使用。 上下文 在权限控制的右边有一个圆圈,展示的是当前上下文使用情况。这里翻译得不太好,准确的翻译应该是上下文使用量信息,显示的是这个对话里的历史对话内容占用了多少模型上下文空间。当上下文超过限制的时候,Codex 会自动对对话历史进行压缩,从而释放出更多的上下文空间。我们也可以输入斜杠,选择压缩选项,手动触发一次上下文压缩。压缩完成以后,Codex 会把之前对话的一些不重要的内容排除掉,可以有效提高 AI 的专注力,并且降低 TOKEN 消耗。 不过在 AI Agent 领域,有一个通用经验是清空好于压缩。因为过多的历史会话,会干扰 AI 的注意力。当我们让 AI 执行完一个任务以后,最好是开一个新的对话,清空上下文。这样有助于 AI 把注意力全部集中到新的任务上面来,从而提高任务的执行效果。 在上下文窗口的右边是模型选择,可以根据任务的复杂程度选择模型的思考强度。下面可以切换模型,这里一般我们就选择最新的模型,比如现在是 GPT-5.5 。 下面还有一个速度选项,可以选择标准还有快速。在快速模式下,会提升 50% 的 AI 推理速度,但是快速模式会消耗两倍的套餐用量。如果你的任务很急,但是套餐的余量还有很多,可以选择开启。 说到套餐余量,我们可以在左下角的设置剩余额度里面找到你现在的套餐余量。这里有两个限额,分别是 5 小时限额,还有周限额。这两个限额任意一个到达上限,Codex 都不能继续使用了。 两个限额都有对应的重置时间,时间到了以后,额度会重置成 100%。右边还有一个语音输入功能,可以让我们跟 AI 的交互从打字变成口喷,非常的好玩。 AI 生图 Codex 内置了 AI 画图功能,而且它使用的是当今最强的 AI 生图模型 GPT-Image-2 。这是刚才我让 Codex 为我们生成的宠物洗护的网站,我们看到它已经为我们配了一些图片。这里我看了一下,这些图片其实都是网络上的免费素材。这里有两个配图非常的不合适。首先这里的店内环境展示的都是一些宠物图片,它并不是一个真正的宠物洗护店的环境。第二点是门店信息,这里画的地图也太粗糙简陋了。 我们就针对这两个问题,让 Codex 帮我们来修改一下。我们来到 Codex ,新开一个对话,项目选择宠物洗护店那个。我让 Codex 调用 AI 绘图功能,绘制三个店内环境的轮播图,三个图应该分别展示店内的不同区域。 我们看到 Codex 为我们生成了三张图片,基本都保持了店内装修风格的一致性。 然后在网页这边也替换成了 3 张图片的轮播图,非常的不错。 接下来我们要改的是门店信息,这里的地图太简陋了。我们回到 Codex ,在宠物店应用这里新开一个对话,输入我的指令: 我们的店在陕西北路 1620 号,就是地图上标记的这个点。你按我发你的位置,用可爱清新的宠物风格的地图把我们的店标记上,然后修改网页里的门店位置信息。 这里我来到地图,我截个图,然后把我们的店用箭头标记上。接下来我们直接 Ctrl+V ,Mac 系统是 Command+V ,把截图粘贴过来,开始。 在 Codex 的执行过程中,我随时跟踪进度。这里我发现了一个问题,就是他画的这个地图是用 SVG 生成的,效果很差。我原本是想让他调用内置的 AI 生图模型来画。借着这个机会,我要介绍 Codex 的一个强大功能。它的英文名叫做 steer ,中文翻译过来是引导。这个词的英文原文的意思是打方向盘。当我们发现 AI 在执行过程中理解错了我们的意思,就不应该让它继续执行了,这时候应该及时接管方向盘,人工进行引导干预。 这里我截个图发送给 Codex 说:你这图不行,应该调用 AI 绘图能力。 在默认模式下,这个新的指令进入了指令队列排队,需要 AI 把上一轮全部执行完,才能执行我们新输入的指令。我们可以点击这里的引导按钮,英文版叫做 steer ,中途接管方向盘,引导干预 AI 的执行。 我们看到 Codex 这里显示已引导对话,然后回复我说味不对,我立即改用 AI 生图,重新生成一张。我们使用 Codex 的 steer 功能,在运行中途成功纠正了模型的运行方向。 在 Codex 的设置常规设置里面,有一个跟进行为。这里可以设置在执行过程中,我们输入的指令是在后面排队,还是直接进入引导。 这里我推荐还是默认选择排队,如果需要引导的话,我们直接点击那个引导按钮,或者按快捷键 Ctrl+回车。我们看到 Codex 为我们重新生成了一张图片,并且把它替换到了网页里面,标注出了我们店的位置,效果非常的棒。 计划模式与内置浏览器 在对话窗口这里有一个加号,里面有三个功能。首先是添加照片和文件,我们可以用照片或者文件给 AI 补充上下文信息,或者可以像刚才一样通过复制粘贴,直接把照片或者文件粘贴进对话窗口。下面是插件,目前预装了 4 个插件,分别对应办公三大件( Word,Excel,PPT ),还有浏览器自动化。 我们主要看这里的计划模式。开启了计划以后,Codex 就不会立即上手干活,而是先为我们输出一份完整的工作计划,跟我们进行了确认以后再干活。对于所有的复杂任务,建议都先开启计划模式,确保你能跟 AI 对齐颗粒度,让 AI 能够精准理解我们的意图。 我们在 Codex 里面打开计划模式,输入我们的需求: 把这个项目改造成 next js 框架 在计划模式里面,Codex 会很倾向于使用这种问题卡片的形式跟用户进行沟通。这里他询问我希望使用哪种项目形态,我选择 APP Router 加 TS 。然后样式迁移希望怎么处理,这里我选择改 Tailwind 。迁移完成要不要同时启动本地开发服务器验证,这里我选择构建加启动。Codex 为我们生成了一份完整的计划,我仔细阅读了一遍,没有发现问题。这里我们点击是,实施此计划。 代码编写完成以后,Codex 可以启动它内置的浏览器进行自动化的测试,这样任务就完成了,开发服务器也启动起来了。在右侧的多功能窗口,Codex 自动打开了浏览器。我们可以点击这里的展开面板按钮,看一下项目的完整状态。我们看到这次架构迁移非常的成功,页面上所有的元素都完整地保留了,非常的不错。 如果对某个部分不满意,我们可以点击这里的批注按钮,然后选中一个元素,在这里可以添加评论。比如这里我说为什么这个星星是空心的,然后在下面点击发送,让 AI 帮我们修改一下。 在下面也可以实时看到它的修改过程。我们刷新一下页面,这个星星就被修改成了实心的。这样我们就通过 Plan 模式配合 Codex 的内置浏览器,成功完成了项目架构的迁移,还顺手修改了一个小 bug 。 代码管理 Codex APP 并不是传统的 IDE ,它并不提供完整的代码编辑功能。我们可以在右上角点击切换文件树,这里虽然可以查看代码,但是没法直接编辑。我们只能点击某行代码来写批注,并不能直接修改代码。我们可以借助第三方的 IDE 来修改代码。 在进行代码管理之前,我们需要先把项目初始化成一个 git 工程。这里我们新开启一个对话,输入提示词: 把项目初始化成一个 git 工程,注意排除掉不需要的文件。 Codex 先为我们创建了 .gitignore 文件,把一些不需要提交的内容排除出去。Codex 帮我们把项目初始化成了 Git 仓库。 初始化成 Git 仓库以后,右上角又多了很多按钮。这里有一个 VSCode 按钮,我们点击一下,我们就可以快捷地使用 VSCode 来查看和修改代码。 除了使用 VSCode ,在这个下拉列表里面,还可以使用其他的 IDE 来打开项目。如果你的电脑上装过这些 IDE ,就可以在这里关联出来。我们也可以在设置常规设置里面选择默认打开的 IDE 。 我还可以要求 AI 把代码帮我提交到 Github 上面。Codex 需要我先在 Github 上面为它创建一个仓库。这里我来到 Github ,点击这个 new 按钮,仓库的名字还叫 pet_care ,点击创建。 创建出来以后把这个地址复制一下,我们回到 Codex 扔给他,成功帮我们把代码推送到了 Github 上面。我们点击这个链接,看到我们的代码已经备份到了 GitHub 的网站上面。我们可以使用对话的方式进行一切 Git 与 Github 操作,这都属于编程的基础知识,本期视频我就不展开讲了。 Git 回滚 本期视频我主要讲两个进阶技巧。第一个是使用 Git 对开发过程进行回滚,第二个技巧是 Git WorkTree 。 我们先看第一个回滚。这里我新开一个对话,我们打开侧边栏,点击加号,浏览器输入我们项目本地开发的地址,这样进入浏览器。我们还是在这里面进行一些批注。我让 Codex 在这里添加一个期望到店时间的功能,直接点击 Ctrl 加回车发送。Codex 为我们添加了期望到店时间这个字段。 当 AI 完成一个功能的开发以后,我们就使用 Git 把它备份保存一下。这里点击提交, 填写一个提交消息,点击继续。这样最新的代码改动就以 Git 的方式保存下来了。接下来我让 AI 把期望到店时间放到联系人的上面,开始。Codex 为我们完成了修改,我们还是从内置的浏览器看一下效果。这个字段跑到了最上面,不过这么一改,我觉得更难看了,我后悔了。我觉得还是把它放到原来的位置比较好。这里我想做的是把这一次的对话,包括这一次的代码改动,全部回滚掉,最好是当做无事发生。 这里我们先借助 Codex 的分叉功能,英文是 fork 。我们先把对话回滚掉。我们找到上一次对话结尾的位置,点击这个分叉按钮,选择派生到本地。 我们看到 Codex 的分叉功能,就是在我点击的这个位置,把对话复制了一份。这样复制出来的新对话,就已经剔除掉了我们刚才想删除的部分了。 不过分叉功能只能回退对话历史,它不能同步回退代码。所以这里我们要做的是把代码一同回退掉。我们可以在 VSCode 里面点击这个 source control 按钮,查看所有的 Git 提交。这里我需要把代码回退到生成期望到店时间的这个状态上。我们点击右键,点击这个 copy commit hash , 这样我们就把这次提交的 ID 复制下来了。我们回到 Codex ,先让 AI 把代码回退到这个状态,后面就是我们刚才复制的提交 ID 。 我们看到代码回退成功了,在浏览器里可以看到这个期望到店时间又变回了原来的位置。这样我们就使用了 Codex 的对话分岔功能,加上 Git 操作,成功地把这一次不需要的改动,从代码层面和对话历史层面进行了完全的回滚。 Git worktree 接下来我们来看下一个功能,就是 Git worktree 。WorkTree 这个名字听起来比较唬人,其实它本质上就是用 git 创建一个新的分支,然后把这个新分支的代码完整地复制到一个新的文件夹里面。这个新文件夹就是一个 WorkTree 。主文件夹和分支文件夹可以并行工作,我们可以在两个文件夹里面各自修改代码,互相不干扰。我们可以基于主干创建多个分支,它们在底层通过 git 关联在一起。分支文件夹的改动,随时都能轻松合并回主干。 找到我们的项目,右键创建永久工作树。这里起个名字,我想让第一个工作树专注优化客户评价这个部分,我给它加个后缀叫 customer rating 。Codex 把整个项目复制到了一个单独的文件夹里面,它跟主干已经不是同一个文件夹了。我们在分支里面做的操作不会影响到主干。这里我们再建一个工作树,第二个工作树主要用来负责优化下面的门店信息,还有这里的地图。我们给第二个树也起个名字。这样我们就拥有了两个工作树分支,它们都位于不同的文件夹下面,所以它们之间的并行工作不会影响到主干。 这里我们来测试一下。我们先打开第一个分支新对话,输入我们的需求: 优化一下客户评价部分,多写几个评价,做一个动画轮播效果, 开始。然后我们来到第二个分支,创建一个新的对话: 优化一下门店信息部分,让门店信息跟地图上下排列,不要左右排列,把地图展示全。 我们在两个分支上面进行并行开发,因为它们位于两个不同的文件夹,所以互相之间不会产生干扰。 两个分支在各自的文件夹里面都开发完毕了。接下来我们可以把它合并回主干。里直接输入合并回主干,两个分支都一样的操作,合并回主干。 两个分支都成功合并进了主干。我们在浏览器这边可以看到,客户评价已经优化过了,门店信息也从左右排布变成了上下排布,地图展示得更全了。这样我们使用 Git worktree 功能,高效并行开发了两个任务。当我们的分支使用完毕,我们可以直接右键移除,把两个临时的分支移除掉,然后回到主干继续工作。

v2ex.com · 2026-04-30 03:26:27+08:00 · tech

视频版: https://www.bilibili.com/video/BV1Kk9kBAEJv 最近 Codex APP 的能力越来越全面,变成了 Codex 四大产品形态里面最强的一个。Codex 比起 Claude Code ,额度更高,功能更全,上手更快,免费账户也能用,而且不会出现限速、封号、降智等问题,用过的小伙伴们直呼真香。本期视频带来一个 Codex APP 的完整教程,主要分为以下 12 个章节。 每个章节里面都会穿插一些重要的知识,对 Codex 的全部功能进行细致讲解。好,废话不多说,我们直接开始。 安装 在安装使用 Codex APP 之前,需要进行 3 个准备工作,也就是需要先把 Git 、Nodejs 还有 VSCode 安装一下。在我上期视频《从 0 开始用国内网络跑通一切 AI Agent 》里面,有详细的操作步骤,不熟悉的朋友们可以参考那一期视频。 接下来我们来到 Codex 的官网,Codex 支持 Windows 跟 Mac 两大操作系统。官网会根据你的操作系统,自动提供对应的安装包。本期视频我主要使用 Windows 来进行演示。Windows 跟 Mac 电脑的功能基本是一致的,唯一欠缺的功能是 computer use ,也就是自动操作电脑的能力。等需要演示这部分的时候,我会切换到 Mac 电脑进行演示。 然后我们一路点击下一步完成安装。接下来我们把 Codex APP 启动起来,选择 ChatGPT 账户完成登录。现在 ChatGPT 的免费账户也能使用 Codex 了,不过额度比较低。第一次进入软件要选一下希望 Codex 为你处理的工作,Codex 会根据你的选择预装一些内置的插件和 skills 。当然进入软件以后,我们还可以按需安装这些插件。然后选择主要的使用场景,是编程还是日常工作,这些都可以后续在设置里面进行修改。接下来点击设置沙盒按钮,完成沙盒的初始化。关于沙盒这部分的内容,我们下一个章节再来介绍。 项目与任务列表 我们点击右上角的按钮显示侧边栏,我们看到 Codex APP 是非常经典的三栏布局:左侧是任务列表,中间是对话窗口,右侧是多功能区域。 我们先创建两个项目文件夹,来展示一下它的基础使用。这里我在桌面新建了两个文件夹,作为两个项目文件夹。然后我们来到 Codex ,点击进入项目工作,使用现有文件夹。我们先选择第一个文件夹,这里我让它做一个 html 单页面的宠物洗护店的网页,开始。在左侧边栏里面增加了一个项目,项目的名称就是文件夹的名称,里面展示了正在运行的任务。 接下来我们点击左上角的新对话按钮。Windows 上的快捷键是 Ctrl+N ,Mac 系统的快捷键是 command+N ,来开启一个新的对话。我们可以选择新对话属于哪个项目。这里我准备开启一个新的项目,把第二个文件夹也添加进来,点击添加新项目,然后选择我们的第二个文件夹。 这里输入我第二个项目的需求:用 react 框架做一个网页版待办事项的提醒工具,回车开始执行。 在两个项目并行工作的同时,我们还可以开启更多的工作对话。比如这里我想询问 Codex 一个技术问题,我们把鼠标指向第二个项目,点击这个小按钮,在项目里面开启新的对话。 这里我询问 Codex:react 框架是什么,回车。这里看到我们开启了 3 个任务并行执行,有两个任务属于项目一,一个任务属于项目 2 。正在执行的任务上面都有一个转圈的小图标,表示 AI 正在工作。我们耐心等待一会。 过了一会状态就不一样了。有一个任务上面显示一个绿色标签,表示等待批准;有一个任务上面出现了一个蓝色小点,表示已经执行完毕了;还有一个任务继续转圈。我们来到这个等待批准的任务里面,发现 Codex 需要联网下载 Vite React 项目的模板,正在申请权限。 我们点击“是”批准,这个任务就继续执行了。又过了一会,三个任务上面都标记了蓝色的小圆点,表示三个任务都执行完毕了。Codex 任务列表非常的简洁美观好用,可以很方便地观察任务状态,可以并行开启多个工作任务,还能高效地从多个任务里面自由地切换。 我们再来看一下左侧边栏任务列表的其他功能。新对话按钮用来开启新的对话,在下面可以选择对应的项目,也可以选择不使用任何的项目,纯粹的闲聊。这种不属于任何项目的对话,都会被收录到任务列表的最下面,也就是对话这一栏里面。 左侧边栏第二个按钮,快捷键是 Ctrl+G ,Mac 电脑的快捷键是 command+G ,可以搜索近期的对话历史。不过我试了一下,这个功能只能搜索到对话的标题,它无法搜索到对话里面的内容。这里补充一下,每个对话标题都是 AI 根据对话内容自动摘要生成的。我们也可以选择某个对话,双击,对它进行一个重命名。如果我们不再需要某个对话了,可以点击这个归档对话的小按钮确认,然后我们的对话就在左侧边栏消失了。在设置已归档对话里面,可以找到我们删除的对话,点击取消归档就可以把它还原回来。左侧边栏还有两个按钮,插件与自动化,这个等我们在后面的章节再来看。 权限控制与沙箱 接下来我们来看一下中间的对话页面。这里最显眼的功能就是权限控制。 Codex 的权限控制全部是围绕沙箱来展开的,这点跟 Claude Code 有本质上的不同。Claude Code 的沙箱功能需要手动开启,Claude Code 的沙箱更像是一层可以额外开启的保护,而 Codex 的沙箱,它是整个权限系统运行的地基。 Codex 会把当前的项目文件夹作为一个沙箱进行管理。在默认权限下面,Codex 具有读取修改沙箱内所有文件的权限。在默认模式下,Codex APP 可以直接修改沙箱内,也就是项目文件夹的所有文件,它并不会一个个地跑来问你。我觉得这点非常的方便,也是符合正常的使用习惯的。当然我们也可以通过设置,改成逐个文件修改都需要审批,这个在视频的后半段高级设置这个我们再来讲。 Codex 的沙箱有两个默认限制。第一点是 Codex 不能修改沙箱外的文件,第二点是 Codex 的沙箱是禁止联网的。这两点硬性限制,它并不是靠模型自觉遵守,而是 Codex 使用操作系统底层功能实现的。不同操作系统的实现机制是不一样的,比如 MacOS 使用的是系统内置的 Seatbelt Sandbox 机制。 Codex 的沙箱功能是前阵爆火的 Harness engineering 概念的一个典型的工程实现,用操作系统级别的机制把 AI 的能力约束在一个可控的范围之内。这也很形象地体现了 Harness 这个词的原始含义,也就是马具。AI 就像一匹能力很强的马,而沙箱权限审批机制这些,就是套在它身上的马具。 如果 Codex 需要修改沙箱外文件,或者需要联网,可以向用户申请权限,这个操作叫做 escalate ,也就是提权操作。在默认情况下,提权操作都是需要人工审核同意的。Codex 为我们提供了第二个档位,也就是自动审查。启动了自动审查以后,Codex 会自动调用一个小模型,对提权操作进行安全性审查。如果发现是低风险的操作,就会直接放行。只有高风险的操作才会触发人工审查,这也是我最推荐的模式。自动审查使得绝大部分操作不需要人工审批,在获取了较高安全性的同时,还极大提升了使用的便利度。 所以一般情况下,在权限管理这里,我都推荐开启第二档,也就是自动审查。Codex 还有第三档,完全访问权限。开启了这个以后,Codex 完全无视沙箱的限制,可以在电脑上执行一切的操作。不过我们尝试开启的时候,这里出现了很醒目的风险提示,提示我们要谨慎使用。 上下文 在权限控制的右边有一个圆圈,展示的是当前上下文使用情况。这里翻译得不太好,准确的翻译应该是上下文使用量信息,显示的是这个对话里的历史对话内容占用了多少模型上下文空间。当上下文超过限制的时候,Codex 会自动对对话历史进行压缩,从而释放出更多的上下文空间。我们也可以输入斜杠,选择压缩选项,手动触发一次上下文压缩。压缩完成以后,Codex 会把之前对话的一些不重要的内容排除掉,可以有效提高 AI 的专注力,并且降低 TOKEN 消耗。 不过在 AI Agent 领域,有一个通用经验是清空好于压缩。因为过多的历史会话,会干扰 AI 的注意力。当我们让 AI 执行完一个任务以后,最好是开一个新的对话,清空上下文。这样有助于 AI 把注意力全部集中到新的任务上面来,从而提高任务的执行效果。 在上下文窗口的右边是模型选择,可以根据任务的复杂程度选择模型的思考强度。下面可以切换模型,这里一般我们就选择最新的模型,比如现在是 GPT-5.5 。 下面还有一个速度选项,可以选择标准还有快速。在快速模式下,会提升 50% 的 AI 推理速度,但是快速模式会消耗两倍的套餐用量。如果你的任务很急,但是套餐的余量还有很多,可以选择开启。 说到套餐余量,我们可以在左下角的设置剩余额度里面找到你现在的套餐余量。这里有两个限额,分别是 5 小时限额,还有周限额。这两个限额任意一个到达上限,Codex 都不能继续使用了。 两个限额都有对应的重置时间,时间到了以后,额度会重置成 100%。右边还有一个语音输入功能,可以让我们跟 AI 的交互从打字变成口喷,非常的好玩。 AI 生图 Codex 内置了 AI 画图功能,而且它使用的是当今最强的 AI 生图模型 GPT-Image-2 。这是刚才我让 Codex 为我们生成的宠物洗护的网站,我们看到它已经为我们配了一些图片。这里我看了一下,这些图片其实都是网络上的免费素材。这里有两个配图非常的不合适。首先这里的店内环境展示的都是一些宠物图片,它并不是一个真正的宠物洗护店的环境。第二点是门店信息,这里画的地图也太粗糙简陋了。 我们就针对这两个问题,让 Codex 帮我们来修改一下。我们来到 Codex ,新开一个对话,项目选择宠物洗护店那个。我让 Codex 调用 AI 绘图功能,绘制三个店内环境的轮播图,三个图应该分别展示店内的不同区域。 我们看到 Codex 为我们生成了三张图片,基本都保持了店内装修风格的一致性。 然后在网页这边也替换成了 3 张图片的轮播图,非常的不错。 接下来我们要改的是门店信息,这里的地图太简陋了。我们回到 Codex ,在宠物店应用这里新开一个对话,输入我的指令: 我们的店在陕西北路 1620 号,就是地图上标记的这个点。你按我发你的位置,用可爱清新的宠物风格的地图把我们的店标记上,然后修改网页里的门店位置信息。 这里我来到地图,我截个图,然后把我们的店用箭头标记上。接下来我们直接 Ctrl+V ,Mac 系统是 Command+V ,把截图粘贴过来,开始。 在 Codex 的执行过程中,我随时跟踪进度。这里我发现了一个问题,就是他画的这个地图是用 SVG 生成的,效果很差。我原本是想让他调用内置的 AI 生图模型来画。借着这个机会,我要介绍 Codex 的一个强大功能。它的英文名叫做 steer ,中文翻译过来是引导。这个词的英文原文的意思是打方向盘。当我们发现 AI 在执行过程中理解错了我们的意思,就不应该让它继续执行了,这时候应该及时接管方向盘,人工进行引导干预。 这里我截个图发送给 Codex 说:你这图不行,应该调用 AI 绘图能力。 在默认模式下,这个新的指令进入了指令队列排队,需要 AI 把上一轮全部执行完,才能执行我们新输入的指令。我们可以点击这里的引导按钮,英文版叫做 steer ,中途接管方向盘,引导干预 AI 的执行。 我们看到 Codex 这里显示已引导对话,然后回复我说味不对,我立即改用 AI 生图,重新生成一张。我们使用 Codex 的 steer 功能,在运行中途成功纠正了模型的运行方向。 在 Codex 的设置常规设置里面,有一个跟进行为。这里可以设置在执行过程中,我们输入的指令是在后面排队,还是直接进入引导。 这里我推荐还是默认选择排队,如果需要引导的话,我们直接点击那个引导按钮,或者按快捷键 Ctrl+回车。我们看到 Codex 为我们重新生成了一张图片,并且把它替换到了网页里面,标注出了我们店的位置,效果非常的棒。 计划模式与内置浏览器 在对话窗口这里有一个加号,里面有三个功能。首先是添加照片和文件,我们可以用照片或者文件给 AI 补充上下文信息,或者可以像刚才一样通过复制粘贴,直接把照片或者文件粘贴进对话窗口。下面是插件,目前预装了 4 个插件,分别对应办公三大件( Word,Excel,PPT ),还有浏览器自动化。 我们主要看这里的计划模式。开启了计划以后,Codex 就不会立即上手干活,而是先为我们输出一份完整的工作计划,跟我们进行了确认以后再干活。对于所有的复杂任务,建议都先开启计划模式,确保你能跟 AI 对齐颗粒度,让 AI 能够精准理解我们的意图。 我们在 Codex 里面打开计划模式,输入我们的需求: 把这个项目改造成 next js 框架 在计划模式里面,Codex 会很倾向于使用这种问题卡片的形式跟用户进行沟通。这里他询问我希望使用哪种项目形态,我选择 APP Router 加 TS 。然后样式迁移希望怎么处理,这里我选择改 Tailwind 。迁移完成要不要同时启动本地开发服务器验证,这里我选择构建加启动。Codex 为我们生成了一份完整的计划,我仔细阅读了一遍,没有发现问题。这里我们点击是,实施此计划。 代码编写完成以后,Codex 可以启动它内置的浏览器进行自动化的测试,这样任务就完成了,开发服务器也启动起来了。在右侧的多功能窗口,Codex 自动打开了浏览器。我们可以点击这里的展开面板按钮,看一下项目的完整状态。我们看到这次架构迁移非常的成功,页面上所有的元素都完整地保留了,非常的不错。 如果对某个部分不满意,我们可以点击这里的批注按钮,然后选中一个元素,在这里可以添加评论。比如这里我说为什么这个星星是空心的,然后在下面点击发送,让 AI 帮我们修改一下。 在下面也可以实时看到它的修改过程。我们刷新一下页面,这个星星就被修改成了实心的。这样我们就通过 Plan 模式配合 Codex 的内置浏览器,成功完成了项目架构的迁移,还顺手修改了一个小 bug 。 代码管理 Codex APP 并不是传统的 IDE ,它并不提供完整的代码编辑功能。我们可以在右上角点击切换文件树,这里虽然可以查看代码,但是没法直接编辑。我们只能点击某行代码来写批注,并不能直接修改代码。我们可以借助第三方的 IDE 来修改代码。 在进行代码管理之前,我们需要先把项目初始化成一个 git 工程。这里我们新开启一个对话,输入提示词: 把项目初始化成一个 git 工程,注意排除掉不需要的文件。 Codex 先为我们创建了 .gitignore 文件,把一些不需要提交的内容排除出去。Codex 帮我们把项目初始化成了 Git 仓库。 初始化成 Git 仓库以后,右上角又多了很多按钮。这里有一个 VSCode 按钮,我们点击一下,我们就可以快捷地使用 VSCode 来查看和修改代码。 除了使用 VSCode ,在这个下拉列表里面,还可以使用其他的 IDE 来打开项目。如果你的电脑上装过这些 IDE ,就可以在这里关联出来。我们也可以在设置常规设置里面选择默认打开的 IDE 。 我还可以要求 AI 把代码帮我提交到 Github 上面。Codex 需要我先在 Github 上面为它创建一个仓库。这里我来到 Github ,点击这个 new 按钮,仓库的名字还叫 pet_care ,点击创建。 创建出来以后把这个地址复制一下,我们回到 Codex 扔给他,成功帮我们把代码推送到了 Github 上面。我们点击这个链接,看到我们的代码已经备份到了 GitHub 的网站上面。我们可以使用对话的方式进行一切 Git 与 Github 操作,这都属于编程的基础知识,本期视频我就不展开讲了。 Git 回滚 本期视频我主要讲两个进阶技巧。第一个是使用 Git 对开发过程进行回滚,第二个技巧是 Git WorkTree 。 我们先看第一个回滚。这里我新开一个对话,我们打开侧边栏,点击加号,浏览器输入我们项目本地开发的地址,这样进入浏览器。我们还是在这里面进行一些批注。我让 Codex 在这里添加一个期望到店时间的功能,直接点击 Ctrl 加回车发送。Codex 为我们添加了期望到店时间这个字段。 当 AI 完成一个功能的开发以后,我们就使用 Git 把它备份保存一下。这里点击提交, 填写一个提交消息,点击继续。这样最新的代码改动就以 Git 的方式保存下来了。接下来我让 AI 把期望到店时间放到联系人的上面,开始。Codex 为我们完成了修改,我们还是从内置的浏览器看一下效果。这个字段跑到了最上面,不过这么一改,我觉得更难看了,我后悔了。我觉得还是把它放到原来的位置比较好。这里我想做的是把这一次的对话,包括这一次的代码改动,全部回滚掉,最好是当做无事发生。 这里我们先借助 Codex 的分叉功能,英文是 fork 。我们先把对话回滚掉。我们找到上一次对话结尾的位置,点击这个分叉按钮,选择派生到本地。 我们看到 Codex 的分叉功能,就是在我点击的这个位置,把对话复制了一份。这样复制出来的新对话,就已经剔除掉了我们刚才想删除的部分了。 不过分叉功能只能回退对话历史,它不能同步回退代码。所以这里我们要做的是把代码一同回退掉。我们可以在 VSCode 里面点击这个 source control 按钮,查看所有的 Git 提交。这里我需要把代码回退到生成期望到店时间的这个状态上。我们点击右键,点击这个 copy commit hash , 这样我们就把这次提交的 ID 复制下来了。我们回到 Codex ,先让 AI 把代码回退到这个状态,后面就是我们刚才复制的提交 ID 。 我们看到代码回退成功了,在浏览器里可以看到这个期望到店时间又变回了原来的位置。这样我们就使用了 Codex 的对话分岔功能,加上 Git 操作,成功地把这一次不需要的改动,从代码层面和对话历史层面进行了完全的回滚。 Git worktree 接下来我们来看下一个功能,就是 Git worktree 。WorkTree 这个名字听起来比较唬人,其实它本质上就是用 git 创建一个新的分支,然后把这个新分支的代码完整地复制到一个新的文件夹里面。这个新文件夹就是一个 WorkTree 。主文件夹和分支文件夹可以并行工作,我们可以在两个文件夹里面各自修改代码,互相不干扰。我们可以基于主干创建多个分支,它们在底层通过 git 关联在一起。分支文件夹的改动,随时都能轻松合并回主干。 找到我们的项目,右键创建永久工作树。这里起个名字,我想让第一个工作树专注优化客户评价这个部分,我给它加个后缀叫 customer rating 。Codex 把整个项目复制到了一个单独的文件夹里面,它跟主干已经不是同一个文件夹了。我们在分支里面做的操作不会影响到主干。这里我们再建一个工作树,第二个工作树主要用来负责优化下面的门店信息,还有这里的地图。我们给第二个树也起个名字。这样我们就拥有了两个工作树分支,它们都位于不同的文件夹下面,所以它们之间的并行工作不会影响到主干。 这里我们来测试一下。我们先打开第一个分支新对话,输入我们的需求: 优化一下客户评价部分,多写几个评价,做一个动画轮播效果, 开始。然后我们来到第二个分支,创建一个新的对话: 优化一下门店信息部分,让门店信息跟地图上下排列,不要左右排列,把地图展示全。 我们在两个分支上面进行并行开发,因为它们位于两个不同的文件夹,所以互相之间不会产生干扰。 两个分支在各自的文件夹里面都开发完毕了。接下来我们可以把它合并回主干。里直接输入合并回主干,两个分支都一样的操作,合并回主干。 两个分支都成功合并进了主干。我们在浏览器这边可以看到,客户评价已经优化过了,门店信息也从左右排布变成了上下排布,地图展示得更全了。这样我们使用 Git worktree 功能,高效并行开发了两个任务。当我们的分支使用完毕,我们可以直接右键移除,把两个临时的分支移除掉,然后回到主干继续工作。

v2ex.com · 2026-04-30 02:04:56+08:00 · tech

视频版: https://www.bilibili.com/video/BV1Kk9kBAEJv 最近 Codex APP 的能力越来越全面,变成了 Codex 四大产品形态里面最强的一个。Codex 比起 Claude Code ,额度更高,功能更全,上手更快,免费账户也能用,而且不会出现限速、封号、降智等问题,用过的小伙伴们直呼真香。本期视频带来一个 Codex APP 的完整教程,主要分为以下 12 个章节。 每个章节里面都会穿插一些重要的知识,对 Codex 的全部功能进行细致讲解。好,废话不多说,我们直接开始。 安装 在安装使用 Codex APP 之前,需要进行 3 个准备工作,也就是需要先把 Git 、Nodejs 还有 VSCode 安装一下。在我上期视频《从 0 开始用国内网络跑通一切 AI Agent 》里面,有详细的操作步骤,不熟悉的朋友们可以参考那一期视频。 接下来我们来到 Codex 的官网,Codex 支持 Windows 跟 Mac 两大操作系统。官网会根据你的操作系统,自动提供对应的安装包。本期视频我主要使用 Windows 来进行演示。Windows 跟 Mac 电脑的功能基本是一致的,唯一欠缺的功能是 computer use ,也就是自动操作电脑的能力。等需要演示这部分的时候,我会切换到 Mac 电脑进行演示。 然后我们一路点击下一步完成安装。接下来我们把 Codex APP 启动起来,选择 ChatGPT 账户完成登录。现在 ChatGPT 的免费账户也能使用 Codex 了,不过额度比较低。第一次进入软件要选一下希望 Codex 为你处理的工作,Codex 会根据你的选择预装一些内置的插件和 skills 。当然进入软件以后,我们还可以按需安装这些插件。然后选择主要的使用场景,是编程还是日常工作,这些都可以后续在设置里面进行修改。接下来点击设置沙盒按钮,完成沙盒的初始化。关于沙盒这部分的内容,我们下一个章节再来介绍。 项目与任务列表 我们点击右上角的按钮显示侧边栏,我们看到 Codex APP 是非常经典的三栏布局:左侧是任务列表,中间是对话窗口,右侧是多功能区域。 我们先创建两个项目文件夹,来展示一下它的基础使用。这里我在桌面新建了两个文件夹,作为两个项目文件夹。然后我们来到 Codex ,点击进入项目工作,使用现有文件夹。我们先选择第一个文件夹,这里我让它做一个 html 单页面的宠物洗护店的网页,开始。在左侧边栏里面增加了一个项目,项目的名称就是文件夹的名称,里面展示了正在运行的任务。 接下来我们点击左上角的新对话按钮。Windows 上的快捷键是 Ctrl+N ,Mac 系统的快捷键是 command+N ,来开启一个新的对话。我们可以选择新对话属于哪个项目。这里我准备开启一个新的项目,把第二个文件夹也添加进来,点击添加新项目,然后选择我们的第二个文件夹。 这里输入我第二个项目的需求:用 react 框架做一个网页版待办事项的提醒工具,回车开始执行。 在两个项目并行工作的同时,我们还可以开启更多的工作对话。比如这里我想询问 Codex 一个技术问题,我们把鼠标指向第二个项目,点击这个小按钮,在项目里面开启新的对话。 这里我询问 Codex:react 框架是什么,回车。这里看到我们开启了 3 个任务并行执行,有两个任务属于项目一,一个任务属于项目 2 。正在执行的任务上面都有一个转圈的小图标,表示 AI 正在工作。我们耐心等待一会。 过了一会状态就不一样了。有一个任务上面显示一个绿色标签,表示等待批准;有一个任务上面出现了一个蓝色小点,表示已经执行完毕了;还有一个任务继续转圈。我们来到这个等待批准的任务里面,发现 Codex 需要联网下载 Vite React 项目的模板,正在申请权限。 我们点击“是”批准,这个任务就继续执行了。又过了一会,三个任务上面都标记了蓝色的小圆点,表示三个任务都执行完毕了。Codex 任务列表非常的简洁美观好用,可以很方便地观察任务状态,可以并行开启多个工作任务,还能高效地从多个任务里面自由地切换。 我们再来看一下左侧边栏任务列表的其他功能。新对话按钮用来开启新的对话,在下面可以选择对应的项目,也可以选择不使用任何的项目,纯粹的闲聊。这种不属于任何项目的对话,都会被收录到任务列表的最下面,也就是对话这一栏里面。 左侧边栏第二个按钮,快捷键是 Ctrl+G ,Mac 电脑的快捷键是 command+G ,可以搜索近期的对话历史。不过我试了一下,这个功能只能搜索到对话的标题,它无法搜索到对话里面的内容。这里补充一下,每个对话标题都是 AI 根据对话内容自动摘要生成的。我们也可以选择某个对话,双击,对它进行一个重命名。如果我们不再需要某个对话了,可以点击这个归档对话的小按钮确认,然后我们的对话就在左侧边栏消失了。在设置已归档对话里面,可以找到我们删除的对话,点击取消归档就可以把它还原回来。左侧边栏还有两个按钮,插件与自动化,这个等我们在后面的章节再来看。 权限控制与沙箱 接下来我们来看一下中间的对话页面。这里最显眼的功能就是权限控制。 Codex 的权限控制全部是围绕沙箱来展开的,这点跟 Claude Code 有本质上的不同。Claude Code 的沙箱功能需要手动开启,Claude Code 的沙箱更像是一层可以额外开启的保护,而 Codex 的沙箱,它是整个权限系统运行的地基。 Codex 会把当前的项目文件夹作为一个沙箱进行管理。在默认权限下面,Codex 具有读取修改沙箱内所有文件的权限。在默认模式下,Codex APP 可以直接修改沙箱内,也就是项目文件夹的所有文件,它并不会一个个地跑来问你。我觉得这点非常的方便,也是符合正常的使用习惯的。当然我们也可以通过设置,改成逐个文件修改都需要审批,这个在视频的后半段高级设置这个我们再来讲。 Codex 的沙箱有两个默认限制。第一点是 Codex 不能修改沙箱外的文件,第二点是 Codex 的沙箱是禁止联网的。这两点硬性限制,它并不是靠模型自觉遵守,而是 Codex 使用操作系统底层功能实现的。不同操作系统的实现机制是不一样的,比如 MacOS 使用的是系统内置的 Seatbelt Sandbox 机制。 Codex 的沙箱功能是前阵爆火的 Harness engineering 概念的一个典型的工程实现,用操作系统级别的机制把 AI 的能力约束在一个可控的范围之内。这也很形象地体现了 Harness 这个词的原始含义,也就是马具。AI 就像一匹能力很强的马,而沙箱权限审批机制这些,就是套在它身上的马具。 如果 Codex 需要修改沙箱外文件,或者需要联网,可以向用户申请权限,这个操作叫做 escalate ,也就是提权操作。在默认情况下,提权操作都是需要人工审核同意的。Codex 为我们提供了第二个档位,也就是自动审查。启动了自动审查以后,Codex 会自动调用一个小模型,对提权操作进行安全性审查。如果发现是低风险的操作,就会直接放行。只有高风险的操作才会触发人工审查,这也是我最推荐的模式。自动审查使得绝大部分操作不需要人工审批,在获取了较高安全性的同时,还极大提升了使用的便利度。 所以一般情况下,在权限管理这里,我都推荐开启第二档,也就是自动审查。Codex 还有第三档,完全访问权限。开启了这个以后,Codex 完全无视沙箱的限制,可以在电脑上执行一切的操作。不过我们尝试开启的时候,这里出现了很醒目的风险提示,提示我们要谨慎使用。 上下文 在权限控制的右边有一个圆圈,展示的是当前上下文使用情况。这里翻译得不太好,准确的翻译应该是上下文使用量信息,显示的是这个对话里的历史对话内容占用了多少模型上下文空间。当上下文超过限制的时候,Codex 会自动对对话历史进行压缩,从而释放出更多的上下文空间。我们也可以输入斜杠,选择压缩选项,手动触发一次上下文压缩。压缩完成以后,Codex 会把之前对话的一些不重要的内容排除掉,可以有效提高 AI 的专注力,并且降低 TOKEN 消耗。 不过在 AI Agent 领域,有一个通用经验是清空好于压缩。因为过多的历史会话,会干扰 AI 的注意力。当我们让 AI 执行完一个任务以后,最好是开一个新的对话,清空上下文。这样有助于 AI 把注意力全部集中到新的任务上面来,从而提高任务的执行效果。 在上下文窗口的右边是模型选择,可以根据任务的复杂程度选择模型的思考强度。下面可以切换模型,这里一般我们就选择最新的模型,比如现在是 GPT-5.5 。 下面还有一个速度选项,可以选择标准还有快速。在快速模式下,会提升 50% 的 AI 推理速度,但是快速模式会消耗两倍的套餐用量。如果你的任务很急,但是套餐的余量还有很多,可以选择开启。 说到套餐余量,我们可以在左下角的设置剩余额度里面找到你现在的套餐余量。这里有两个限额,分别是 5 小时限额,还有周限额。这两个限额任意一个到达上限,Codex 都不能继续使用了。 两个限额都有对应的重置时间,时间到了以后,额度会重置成 100%。右边还有一个语音输入功能,可以让我们跟 AI 的交互从打字变成口喷,非常的好玩。 AI 生图 Codex 内置了 AI 画图功能,而且它使用的是当今最强的 AI 生图模型 GPT-Image-2 。这是刚才我让 Codex 为我们生成的宠物洗护的网站,我们看到它已经为我们配了一些图片。这里我看了一下,这些图片其实都是网络上的免费素材。这里有两个配图非常的不合适。首先这里的店内环境展示的都是一些宠物图片,它并不是一个真正的宠物洗护店的环境。第二点是门店信息,这里画的地图也太粗糙简陋了。 我们就针对这两个问题,让 Codex 帮我们来修改一下。我们来到 Codex ,新开一个对话,项目选择宠物洗护店那个。我让 Codex 调用 AI 绘图功能,绘制三个店内环境的轮播图,三个图应该分别展示店内的不同区域。 我们看到 Codex 为我们生成了三张图片,基本都保持了店内装修风格的一致性。 然后在网页这边也替换成了 3 张图片的轮播图,非常的不错。 接下来我们要改的是门店信息,这里的地图太简陋了。我们回到 Codex ,在宠物店应用这里新开一个对话,输入我的指令: 我们的店在陕西北路 1620 号,就是地图上标记的这个点。你按我发你的位置,用可爱清新的宠物风格的地图把我们的店标记上,然后修改网页里的门店位置信息。 这里我来到地图,我截个图,然后把我们的店用箭头标记上。接下来我们直接 Ctrl+V ,Mac 系统是 Command+V ,把截图粘贴过来,开始。 在 Codex 的执行过程中,我随时跟踪进度。这里我发现了一个问题,就是他画的这个地图是用 SVG 生成的,效果很差。我原本是想让他调用内置的 AI 生图模型来画。借着这个机会,我要介绍 Codex 的一个强大功能。它的英文名叫做 steer ,中文翻译过来是引导。这个词的英文原文的意思是打方向盘。当我们发现 AI 在执行过程中理解错了我们的意思,就不应该让它继续执行了,这时候应该及时接管方向盘,人工进行引导干预。 这里我截个图发送给 Codex 说:你这图不行,应该调用 AI 绘图能力。 在默认模式下,这个新的指令进入了指令队列排队,需要 AI 把上一轮全部执行完,才能执行我们新输入的指令。我们可以点击这里的引导按钮,英文版叫做 steer ,中途接管方向盘,引导干预 AI 的执行。 我们看到 Codex 这里显示已引导对话,然后回复我说味不对,我立即改用 AI 生图,重新生成一张。我们使用 Codex 的 steer 功能,在运行中途成功纠正了模型的运行方向。 在 Codex 的设置常规设置里面,有一个跟进行为。这里可以设置在执行过程中,我们输入的指令是在后面排队,还是直接进入引导。 这里我推荐还是默认选择排队,如果需要引导的话,我们直接点击那个引导按钮,或者按快捷键 Ctrl+回车。我们看到 Codex 为我们重新生成了一张图片,并且把它替换到了网页里面,标注出了我们店的位置,效果非常的棒。 计划模式与内置浏览器 在对话窗口这里有一个加号,里面有三个功能。首先是添加照片和文件,我们可以用照片或者文件给 AI 补充上下文信息,或者可以像刚才一样通过复制粘贴,直接把照片或者文件粘贴进对话窗口。下面是插件,目前预装了 4 个插件,分别对应办公三大件( Word,Excel,PPT ),还有浏览器自动化。 我们主要看这里的计划模式。开启了计划以后,Codex 就不会立即上手干活,而是先为我们输出一份完整的工作计划,跟我们进行了确认以后再干活。对于所有的复杂任务,建议都先开启计划模式,确保你能跟 AI 对齐颗粒度,让 AI 能够精准理解我们的意图。 我们在 Codex 里面打开计划模式,输入我们的需求: 把这个项目改造成 next js 框架 在计划模式里面,Codex 会很倾向于使用这种问题卡片的形式跟用户进行沟通。这里他询问我希望使用哪种项目形态,我选择 APP Router 加 TS 。然后样式迁移希望怎么处理,这里我选择改 Tailwind 。迁移完成要不要同时启动本地开发服务器验证,这里我选择构建加启动。Codex 为我们生成了一份完整的计划,我仔细阅读了一遍,没有发现问题。这里我们点击是,实施此计划。 代码编写完成以后,Codex 可以启动它内置的浏览器进行自动化的测试,这样任务就完成了,开发服务器也启动起来了。在右侧的多功能窗口,Codex 自动打开了浏览器。我们可以点击这里的展开面板按钮,看一下项目的完整状态。我们看到这次架构迁移非常的成功,页面上所有的元素都完整地保留了,非常的不错。 如果对某个部分不满意,我们可以点击这里的批注按钮,然后选中一个元素,在这里可以添加评论。比如这里我说为什么这个星星是空心的,然后在下面点击发送,让 AI 帮我们修改一下。 在下面也可以实时看到它的修改过程。我们刷新一下页面,这个星星就被修改成了实心的。这样我们就通过 Plan 模式配合 Codex 的内置浏览器,成功完成了项目架构的迁移,还顺手修改了一个小 bug 。 代码管理 Codex APP 并不是传统的 IDE ,它并不提供完整的代码编辑功能。我们可以在右上角点击切换文件树,这里虽然可以查看代码,但是没法直接编辑。我们只能点击某行代码来写批注,并不能直接修改代码。我们可以借助第三方的 IDE 来修改代码。 在进行代码管理之前,我们需要先把项目初始化成一个 git 工程。这里我们新开启一个对话,输入提示词: 把项目初始化成一个 git 工程,注意排除掉不需要的文件。 Codex 先为我们创建了 .gitignore 文件,把一些不需要提交的内容排除出去。Codex 帮我们把项目初始化成了 Git 仓库。 初始化成 Git 仓库以后,右上角又多了很多按钮。这里有一个 VSCode 按钮,我们点击一下,我们就可以快捷地使用 VSCode 来查看和修改代码。 除了使用 VSCode ,在这个下拉列表里面,还可以使用其他的 IDE 来打开项目。如果你的电脑上装过这些 IDE ,就可以在这里关联出来。我们也可以在设置常规设置里面选择默认打开的 IDE 。 我还可以要求 AI 把代码帮我提交到 Github 上面。Codex 需要我先在 Github 上面为它创建一个仓库。这里我来到 Github ,点击这个 new 按钮,仓库的名字还叫 pet_care ,点击创建。 创建出来以后把这个地址复制一下,我们回到 Codex 扔给他,成功帮我们把代码推送到了 Github 上面。我们点击这个链接,看到我们的代码已经备份到了 GitHub 的网站上面。我们可以使用对话的方式进行一切 Git 与 Github 操作,这都属于编程的基础知识,本期视频我就不展开讲了。 Git 回滚 本期视频我主要讲两个进阶技巧。第一个是使用 Git 对开发过程进行回滚,第二个技巧是 Git WorkTree 。 我们先看第一个回滚。这里我新开一个对话,我们打开侧边栏,点击加号,浏览器输入我们项目本地开发的地址,这样进入浏览器。我们还是在这里面进行一些批注。我让 Codex 在这里添加一个期望到店时间的功能,直接点击 Ctrl 加回车发送。Codex 为我们添加了期望到店时间这个字段。 当 AI 完成一个功能的开发以后,我们就使用 Git 把它备份保存一下。这里点击提交, 填写一个提交消息,点击继续。这样最新的代码改动就以 Git 的方式保存下来了。接下来我让 AI 把期望到店时间放到联系人的上面,开始。Codex 为我们完成了修改,我们还是从内置的浏览器看一下效果。这个字段跑到了最上面,不过这么一改,我觉得更难看了,我后悔了。我觉得还是把它放到原来的位置比较好。这里我想做的是把这一次的对话,包括这一次的代码改动,全部回滚掉,最好是当做无事发生。 这里我们先借助 Codex 的分叉功能,英文是 fork 。我们先把对话回滚掉。我们找到上一次对话结尾的位置,点击这个分叉按钮,选择派生到本地。 我们看到 Codex 的分叉功能,就是在我点击的这个位置,把对话复制了一份。这样复制出来的新对话,就已经剔除掉了我们刚才想删除的部分了。 不过分叉功能只能回退对话历史,它不能同步回退代码。所以这里我们要做的是把代码一同回退掉。我们可以在 VSCode 里面点击这个 source control 按钮,查看所有的 Git 提交。这里我需要把代码回退到生成期望到店时间的这个状态上。我们点击右键,点击这个 copy commit hash , 这样我们就把这次提交的 ID 复制下来了。我们回到 Codex ,先让 AI 把代码回退到这个状态,后面就是我们刚才复制的提交 ID 。 我们看到代码回退成功了,在浏览器里可以看到这个期望到店时间又变回了原来的位置。这样我们就使用了 Codex 的对话分岔功能,加上 Git 操作,成功地把这一次不需要的改动,从代码层面和对话历史层面进行了完全的回滚。 Git worktree 接下来我们来看下一个功能,就是 Git worktree 。WorkTree 这个名字听起来比较唬人,其实它本质上就是用 git 创建一个新的分支,然后把这个新分支的代码完整地复制到一个新的文件夹里面。这个新文件夹就是一个 WorkTree 。主文件夹和分支文件夹可以并行工作,我们可以在两个文件夹里面各自修改代码,互相不干扰。我们可以基于主干创建多个分支,它们在底层通过 git 关联在一起。分支文件夹的改动,随时都能轻松合并回主干。 找到我们的项目,右键创建永久工作树。这里起个名字,我想让第一个工作树专注优化客户评价这个部分,我给它加个后缀叫 customer rating 。Codex 把整个项目复制到了一个单独的文件夹里面,它跟主干已经不是同一个文件夹了。我们在分支里面做的操作不会影响到主干。这里我们再建一个工作树,第二个工作树主要用来负责优化下面的门店信息,还有这里的地图。我们给第二个树也起个名字。这样我们就拥有了两个工作树分支,它们都位于不同的文件夹下面,所以它们之间的并行工作不会影响到主干。 这里我们来测试一下。我们先打开第一个分支新对话,输入我们的需求: 优化一下客户评价部分,多写几个评价,做一个动画轮播效果, 开始。然后我们来到第二个分支,创建一个新的对话: 优化一下门店信息部分,让门店信息跟地图上下排列,不要左右排列,把地图展示全。 我们在两个分支上面进行并行开发,因为它们位于两个不同的文件夹,所以互相之间不会产生干扰。 两个分支在各自的文件夹里面都开发完毕了。接下来我们可以把它合并回主干。里直接输入合并回主干,两个分支都一样的操作,合并回主干。 两个分支都成功合并进了主干。我们在浏览器这边可以看到,客户评价已经优化过了,门店信息也从左右排布变成了上下排布,地图展示得更全了。这样我们使用 Git worktree 功能,高效并行开发了两个任务。当我们的分支使用完毕,我们可以直接右键移除,把两个临时的分支移除掉,然后回到主干继续工作。

v2ex.com · 2026-04-29 22:46:36+08:00 · tech

视频版: https://www.bilibili.com/video/BV1Kk9kBAEJv 最近 Codex APP 的能力越来越全面,变成了 Codex 四大产品形态里面最强的一个。Codex 比起 Claude Code ,额度更高,功能更全,上手更快,免费账户也能用,而且不会出现限速、封号、降智等问题,用过的小伙伴们直呼真香。本期视频带来一个 Codex APP 的完整教程,主要分为以下 12 个章节。 每个章节里面都会穿插一些重要的知识,对 Codex 的全部功能进行细致讲解。好,废话不多说,我们直接开始。 安装 在安装使用 Codex APP 之前,需要进行 3 个准备工作,也就是需要先把 Git 、Nodejs 还有 VSCode 安装一下。在我上期视频《从 0 开始用国内网络跑通一切 AI Agent 》里面,有详细的操作步骤,不熟悉的朋友们可以参考那一期视频。 接下来我们来到 Codex 的官网,Codex 支持 Windows 跟 Mac 两大操作系统。官网会根据你的操作系统,自动提供对应的安装包。本期视频我主要使用 Windows 来进行演示。Windows 跟 Mac 电脑的功能基本是一致的,唯一欠缺的功能是 computer use ,也就是自动操作电脑的能力。等需要演示这部分的时候,我会切换到 Mac 电脑进行演示。 然后我们一路点击下一步完成安装。接下来我们把 Codex APP 启动起来,选择 ChatGPT 账户完成登录。现在 ChatGPT 的免费账户也能使用 Codex 了,不过额度比较低。第一次进入软件要选一下希望 Codex 为你处理的工作,Codex 会根据你的选择预装一些内置的插件和 skills 。当然进入软件以后,我们还可以按需安装这些插件。然后选择主要的使用场景,是编程还是日常工作,这些都可以后续在设置里面进行修改。接下来点击设置沙盒按钮,完成沙盒的初始化。关于沙盒这部分的内容,我们下一个章节再来介绍。 项目与任务列表 我们点击右上角的按钮显示侧边栏,我们看到 Codex APP 是非常经典的三栏布局:左侧是任务列表,中间是对话窗口,右侧是多功能区域。 我们先创建两个项目文件夹,来展示一下它的基础使用。这里我在桌面新建了两个文件夹,作为两个项目文件夹。然后我们来到 Codex ,点击进入项目工作,使用现有文件夹。我们先选择第一个文件夹,这里我让它做一个 html 单页面的宠物洗护店的网页,开始。在左侧边栏里面增加了一个项目,项目的名称就是文件夹的名称,里面展示了正在运行的任务。 接下来我们点击左上角的新对话按钮。Windows 上的快捷键是 Ctrl+N ,Mac 系统的快捷键是 command+N ,来开启一个新的对话。我们可以选择新对话属于哪个项目。这里我准备开启一个新的项目,把第二个文件夹也添加进来,点击添加新项目,然后选择我们的第二个文件夹。 这里输入我第二个项目的需求:用 react 框架做一个网页版待办事项的提醒工具,回车开始执行。 在两个项目并行工作的同时,我们还可以开启更多的工作对话。比如这里我想询问 Codex 一个技术问题,我们把鼠标指向第二个项目,点击这个小按钮,在项目里面开启新的对话。 这里我询问 Codex:react 框架是什么,回车。这里看到我们开启了 3 个任务并行执行,有两个任务属于项目一,一个任务属于项目 2 。正在执行的任务上面都有一个转圈的小图标,表示 AI 正在工作。我们耐心等待一会。 过了一会状态就不一样了。有一个任务上面显示一个绿色标签,表示等待批准;有一个任务上面出现了一个蓝色小点,表示已经执行完毕了;还有一个任务继续转圈。我们来到这个等待批准的任务里面,发现 Codex 需要联网下载 Vite React 项目的模板,正在申请权限。 我们点击“是”批准,这个任务就继续执行了。又过了一会,三个任务上面都标记了蓝色的小圆点,表示三个任务都执行完毕了。Codex 任务列表非常的简洁美观好用,可以很方便地观察任务状态,可以并行开启多个工作任务,还能高效地从多个任务里面自由地切换。 我们再来看一下左侧边栏任务列表的其他功能。新对话按钮用来开启新的对话,在下面可以选择对应的项目,也可以选择不使用任何的项目,纯粹的闲聊。这种不属于任何项目的对话,都会被收录到任务列表的最下面,也就是对话这一栏里面。 左侧边栏第二个按钮,快捷键是 Ctrl+G ,Mac 电脑的快捷键是 command+G ,可以搜索近期的对话历史。不过我试了一下,这个功能只能搜索到对话的标题,它无法搜索到对话里面的内容。这里补充一下,每个对话标题都是 AI 根据对话内容自动摘要生成的。我们也可以选择某个对话,双击,对它进行一个重命名。如果我们不再需要某个对话了,可以点击这个归档对话的小按钮确认,然后我们的对话就在左侧边栏消失了。在设置已归档对话里面,可以找到我们删除的对话,点击取消归档就可以把它还原回来。左侧边栏还有两个按钮,插件与自动化,这个等我们在后面的章节再来看。 权限控制与沙箱 接下来我们来看一下中间的对话页面。这里最显眼的功能就是权限控制。 Codex 的权限控制全部是围绕沙箱来展开的,这点跟 Claude Code 有本质上的不同。Claude Code 的沙箱功能需要手动开启,Claude Code 的沙箱更像是一层可以额外开启的保护,而 Codex 的沙箱,它是整个权限系统运行的地基。 Codex 会把当前的项目文件夹作为一个沙箱进行管理。在默认权限下面,Codex 具有读取修改沙箱内所有文件的权限。在默认模式下,Codex APP 可以直接修改沙箱内,也就是项目文件夹的所有文件,它并不会一个个地跑来问你。我觉得这点非常的方便,也是符合正常的使用习惯的。当然我们也可以通过设置,改成逐个文件修改都需要审批,这个在视频的后半段高级设置这个我们再来讲。 Codex 的沙箱有两个默认限制。第一点是 Codex 不能修改沙箱外的文件,第二点是 Codex 的沙箱是禁止联网的。这两点硬性限制,它并不是靠模型自觉遵守,而是 Codex 使用操作系统底层功能实现的。不同操作系统的实现机制是不一样的,比如 MacOS 使用的是系统内置的 Seatbelt Sandbox 机制。 Codex 的沙箱功能是前阵爆火的 Harness engineering 概念的一个典型的工程实现,用操作系统级别的机制把 AI 的能力约束在一个可控的范围之内。这也很形象地体现了 Harness 这个词的原始含义,也就是马具。AI 就像一匹能力很强的马,而沙箱权限审批机制这些,就是套在它身上的马具。 如果 Codex 需要修改沙箱外文件,或者需要联网,可以向用户申请权限,这个操作叫做 escalate ,也就是提权操作。在默认情况下,提权操作都是需要人工审核同意的。Codex 为我们提供了第二个档位,也就是自动审查。启动了自动审查以后,Codex 会自动调用一个小模型,对提权操作进行安全性审查。如果发现是低风险的操作,就会直接放行。只有高风险的操作才会触发人工审查,这也是我最推荐的模式。自动审查使得绝大部分操作不需要人工审批,在获取了较高安全性的同时,还极大提升了使用的便利度。 所以一般情况下,在权限管理这里,我都推荐开启第二档,也就是自动审查。Codex 还有第三档,完全访问权限。开启了这个以后,Codex 完全无视沙箱的限制,可以在电脑上执行一切的操作。不过我们尝试开启的时候,这里出现了很醒目的风险提示,提示我们要谨慎使用。 上下文 在权限控制的右边有一个圆圈,展示的是当前上下文使用情况。这里翻译得不太好,准确的翻译应该是上下文使用量信息,显示的是这个对话里的历史对话内容占用了多少模型上下文空间。当上下文超过限制的时候,Codex 会自动对对话历史进行压缩,从而释放出更多的上下文空间。我们也可以输入斜杠,选择压缩选项,手动触发一次上下文压缩。压缩完成以后,Codex 会把之前对话的一些不重要的内容排除掉,可以有效提高 AI 的专注力,并且降低 TOKEN 消耗。 不过在 AI Agent 领域,有一个通用经验是清空好于压缩。因为过多的历史会话,会干扰 AI 的注意力。当我们让 AI 执行完一个任务以后,最好是开一个新的对话,清空上下文。这样有助于 AI 把注意力全部集中到新的任务上面来,从而提高任务的执行效果。 在上下文窗口的右边是模型选择,可以根据任务的复杂程度选择模型的思考强度。下面可以切换模型,这里一般我们就选择最新的模型,比如现在是 GPT-5.5 。 下面还有一个速度选项,可以选择标准还有快速。在快速模式下,会提升 50% 的 AI 推理速度,但是快速模式会消耗两倍的套餐用量。如果你的任务很急,但是套餐的余量还有很多,可以选择开启。 说到套餐余量,我们可以在左下角的设置剩余额度里面找到你现在的套餐余量。这里有两个限额,分别是 5 小时限额,还有周限额。这两个限额任意一个到达上限,Codex 都不能继续使用了。 两个限额都有对应的重置时间,时间到了以后,额度会重置成 100%。右边还有一个语音输入功能,可以让我们跟 AI 的交互从打字变成口喷,非常的好玩。 AI 生图 Codex 内置了 AI 画图功能,而且它使用的是当今最强的 AI 生图模型 GPT-Image-2 。这是刚才我让 Codex 为我们生成的宠物洗护的网站,我们看到它已经为我们配了一些图片。这里我看了一下,这些图片其实都是网络上的免费素材。这里有两个配图非常的不合适。首先这里的店内环境展示的都是一些宠物图片,它并不是一个真正的宠物洗护店的环境。第二点是门店信息,这里画的地图也太粗糙简陋了。 我们就针对这两个问题,让 Codex 帮我们来修改一下。我们来到 Codex ,新开一个对话,项目选择宠物洗护店那个。我让 Codex 调用 AI 绘图功能,绘制三个店内环境的轮播图,三个图应该分别展示店内的不同区域。 我们看到 Codex 为我们生成了三张图片,基本都保持了店内装修风格的一致性。 然后在网页这边也替换成了 3 张图片的轮播图,非常的不错。 接下来我们要改的是门店信息,这里的地图太简陋了。我们回到 Codex ,在宠物店应用这里新开一个对话,输入我的指令: 我们的店在陕西北路 1620 号,就是地图上标记的这个点。你按我发你的位置,用可爱清新的宠物风格的地图把我们的店标记上,然后修改网页里的门店位置信息。 这里我来到地图,我截个图,然后把我们的店用箭头标记上。接下来我们直接 Ctrl+V ,Mac 系统是 Command+V ,把截图粘贴过来,开始。 在 Codex 的执行过程中,我随时跟踪进度。这里我发现了一个问题,就是他画的这个地图是用 SVG 生成的,效果很差。我原本是想让他调用内置的 AI 生图模型来画。借着这个机会,我要介绍 Codex 的一个强大功能。它的英文名叫做 steer ,中文翻译过来是引导。这个词的英文原文的意思是打方向盘。当我们发现 AI 在执行过程中理解错了我们的意思,就不应该让它继续执行了,这时候应该及时接管方向盘,人工进行引导干预。 这里我截个图发送给 Codex 说:你这图不行,应该调用 AI 绘图能力。 在默认模式下,这个新的指令进入了指令队列排队,需要 AI 把上一轮全部执行完,才能执行我们新输入的指令。我们可以点击这里的引导按钮,英文版叫做 steer ,中途接管方向盘,引导干预 AI 的执行。 我们看到 Codex 这里显示已引导对话,然后回复我说味不对,我立即改用 AI 生图,重新生成一张。我们使用 Codex 的 steer 功能,在运行中途成功纠正了模型的运行方向。 在 Codex 的设置常规设置里面,有一个跟进行为。这里可以设置在执行过程中,我们输入的指令是在后面排队,还是直接进入引导。 这里我推荐还是默认选择排队,如果需要引导的话,我们直接点击那个引导按钮,或者按快捷键 Ctrl+回车。我们看到 Codex 为我们重新生成了一张图片,并且把它替换到了网页里面,标注出了我们店的位置,效果非常的棒。 计划模式与内置浏览器 在对话窗口这里有一个加号,里面有三个功能。首先是添加照片和文件,我们可以用照片或者文件给 AI 补充上下文信息,或者可以像刚才一样通过复制粘贴,直接把照片或者文件粘贴进对话窗口。下面是插件,目前预装了 4 个插件,分别对应办公三大件( Word,Excel,PPT ),还有浏览器自动化。 我们主要看这里的计划模式。开启了计划以后,Codex 就不会立即上手干活,而是先为我们输出一份完整的工作计划,跟我们进行了确认以后再干活。对于所有的复杂任务,建议都先开启计划模式,确保你能跟 AI 对齐颗粒度,让 AI 能够精准理解我们的意图。 我们在 Codex 里面打开计划模式,输入我们的需求: 把这个项目改造成 next js 框架 在计划模式里面,Codex 会很倾向于使用这种问题卡片的形式跟用户进行沟通。这里他询问我希望使用哪种项目形态,我选择 APP Router 加 TS 。然后样式迁移希望怎么处理,这里我选择改 Tailwind 。迁移完成要不要同时启动本地开发服务器验证,这里我选择构建加启动。Codex 为我们生成了一份完整的计划,我仔细阅读了一遍,没有发现问题。这里我们点击是,实施此计划。 代码编写完成以后,Codex 可以启动它内置的浏览器进行自动化的测试,这样任务就完成了,开发服务器也启动起来了。在右侧的多功能窗口,Codex 自动打开了浏览器。我们可以点击这里的展开面板按钮,看一下项目的完整状态。我们看到这次架构迁移非常的成功,页面上所有的元素都完整地保留了,非常的不错。 如果对某个部分不满意,我们可以点击这里的批注按钮,然后选中一个元素,在这里可以添加评论。比如这里我说为什么这个星星是空心的,然后在下面点击发送,让 AI 帮我们修改一下。 在下面也可以实时看到它的修改过程。我们刷新一下页面,这个星星就被修改成了实心的。这样我们就通过 Plan 模式配合 Codex 的内置浏览器,成功完成了项目架构的迁移,还顺手修改了一个小 bug 。 代码管理 Codex APP 并不是传统的 IDE ,它并不提供完整的代码编辑功能。我们可以在右上角点击切换文件树,这里虽然可以查看代码,但是没法直接编辑。我们只能点击某行代码来写批注,并不能直接修改代码。我们可以借助第三方的 IDE 来修改代码。 在进行代码管理之前,我们需要先把项目初始化成一个 git 工程。这里我们新开启一个对话,输入提示词: 把项目初始化成一个 git 工程,注意排除掉不需要的文件。 Codex 先为我们创建了 .gitignore 文件,把一些不需要提交的内容排除出去。Codex 帮我们把项目初始化成了 Git 仓库。 初始化成 Git 仓库以后,右上角又多了很多按钮。这里有一个 VSCode 按钮,我们点击一下,我们就可以快捷地使用 VSCode 来查看和修改代码。 除了使用 VSCode ,在这个下拉列表里面,还可以使用其他的 IDE 来打开项目。如果你的电脑上装过这些 IDE ,就可以在这里关联出来。我们也可以在设置常规设置里面选择默认打开的 IDE 。 我还可以要求 AI 把代码帮我提交到 Github 上面。Codex 需要我先在 Github 上面为它创建一个仓库。这里我来到 Github ,点击这个 new 按钮,仓库的名字还叫 pet_care ,点击创建。 创建出来以后把这个地址复制一下,我们回到 Codex 扔给他,成功帮我们把代码推送到了 Github 上面。我们点击这个链接,看到我们的代码已经备份到了 GitHub 的网站上面。我们可以使用对话的方式进行一切 Git 与 Github 操作,这都属于编程的基础知识,本期视频我就不展开讲了。 Git 回滚 本期视频我主要讲两个进阶技巧。第一个是使用 Git 对开发过程进行回滚,第二个技巧是 Git WorkTree 。 我们先看第一个回滚。这里我新开一个对话,我们打开侧边栏,点击加号,浏览器输入我们项目本地开发的地址,这样进入浏览器。我们还是在这里面进行一些批注。我让 Codex 在这里添加一个期望到店时间的功能,直接点击 Ctrl 加回车发送。Codex 为我们添加了期望到店时间这个字段。 当 AI 完成一个功能的开发以后,我们就使用 Git 把它备份保存一下。这里点击提交, 填写一个提交消息,点击继续。这样最新的代码改动就以 Git 的方式保存下来了。接下来我让 AI 把期望到店时间放到联系人的上面,开始。Codex 为我们完成了修改,我们还是从内置的浏览器看一下效果。这个字段跑到了最上面,不过这么一改,我觉得更难看了,我后悔了。我觉得还是把它放到原来的位置比较好。这里我想做的是把这一次的对话,包括这一次的代码改动,全部回滚掉,最好是当做无事发生。 这里我们先借助 Codex 的分叉功能,英文是 fork 。我们先把对话回滚掉。我们找到上一次对话结尾的位置,点击这个分叉按钮,选择派生到本地。 我们看到 Codex 的分叉功能,就是在我点击的这个位置,把对话复制了一份。这样复制出来的新对话,就已经剔除掉了我们刚才想删除的部分了。 不过分叉功能只能回退对话历史,它不能同步回退代码。所以这里我们要做的是把代码一同回退掉。我们可以在 VSCode 里面点击这个 source control 按钮,查看所有的 Git 提交。这里我需要把代码回退到生成期望到店时间的这个状态上。我们点击右键,点击这个 copy commit hash , 这样我们就把这次提交的 ID 复制下来了。我们回到 Codex ,先让 AI 把代码回退到这个状态,后面就是我们刚才复制的提交 ID 。 我们看到代码回退成功了,在浏览器里可以看到这个期望到店时间又变回了原来的位置。这样我们就使用了 Codex 的对话分岔功能,加上 Git 操作,成功地把这一次不需要的改动,从代码层面和对话历史层面进行了完全的回滚。 Git worktree 接下来我们来看下一个功能,就是 Git worktree 。WorkTree 这个名字听起来比较唬人,其实它本质上就是用 git 创建一个新的分支,然后把这个新分支的代码完整地复制到一个新的文件夹里面。这个新文件夹就是一个 WorkTree 。主文件夹和分支文件夹可以并行工作,我们可以在两个文件夹里面各自修改代码,互相不干扰。我们可以基于主干创建多个分支,它们在底层通过 git 关联在一起。分支文件夹的改动,随时都能轻松合并回主干。 找到我们的项目,右键创建永久工作树。这里起个名字,我想让第一个工作树专注优化客户评价这个部分,我给它加个后缀叫 customer rating 。Codex 把整个项目复制到了一个单独的文件夹里面,它跟主干已经不是同一个文件夹了。我们在分支里面做的操作不会影响到主干。这里我们再建一个工作树,第二个工作树主要用来负责优化下面的门店信息,还有这里的地图。我们给第二个树也起个名字。这样我们就拥有了两个工作树分支,它们都位于不同的文件夹下面,所以它们之间的并行工作不会影响到主干。 这里我们来测试一下。我们先打开第一个分支新对话,输入我们的需求: 优化一下客户评价部分,多写几个评价,做一个动画轮播效果, 开始。然后我们来到第二个分支,创建一个新的对话: 优化一下门店信息部分,让门店信息跟地图上下排列,不要左右排列,把地图展示全。 我们在两个分支上面进行并行开发,因为它们位于两个不同的文件夹,所以互相之间不会产生干扰。 两个分支在各自的文件夹里面都开发完毕了。接下来我们可以把它合并回主干。里直接输入合并回主干,两个分支都一样的操作,合并回主干。 两个分支都成功合并进了主干。我们在浏览器这边可以看到,客户评价已经优化过了,门店信息也从左右排布变成了上下排布,地图展示得更全了。这样我们使用 Git worktree 功能,高效并行开发了两个任务。当我们的分支使用完毕,我们可以直接右键移除,把两个临时的分支移除掉,然后回到主干继续工作。

v2ex.com · 2026-04-29 20:56:14+08:00 · tech

视频版: https://www.bilibili.com/video/BV1Kk9kBAEJv 最近 Codex APP 的能力越来越全面,变成了 Codex 四大产品形态里面最强的一个。Codex 比起 Claude Code ,额度更高,功能更全,上手更快,免费账户也能用,而且不会出现限速、封号、降智等问题,用过的小伙伴们直呼真香。本期视频带来一个 Codex APP 的完整教程,主要分为以下 12 个章节。 每个章节里面都会穿插一些重要的知识,对 Codex 的全部功能进行细致讲解。好,废话不多说,我们直接开始。 安装 在安装使用 Codex APP 之前,需要进行 3 个准备工作,也就是需要先把 Git 、Nodejs 还有 VSCode 安装一下。在我上期视频《从 0 开始用国内网络跑通一切 AI Agent 》里面,有详细的操作步骤,不熟悉的朋友们可以参考那一期视频。 接下来我们来到 Codex 的官网,Codex 支持 Windows 跟 Mac 两大操作系统。官网会根据你的操作系统,自动提供对应的安装包。本期视频我主要使用 Windows 来进行演示。Windows 跟 Mac 电脑的功能基本是一致的,唯一欠缺的功能是 computer use ,也就是自动操作电脑的能力。等需要演示这部分的时候,我会切换到 Mac 电脑进行演示。 然后我们一路点击下一步完成安装。接下来我们把 Codex APP 启动起来,选择 ChatGPT 账户完成登录。现在 ChatGPT 的免费账户也能使用 Codex 了,不过额度比较低。第一次进入软件要选一下希望 Codex 为你处理的工作,Codex 会根据你的选择预装一些内置的插件和 skills 。当然进入软件以后,我们还可以按需安装这些插件。然后选择主要的使用场景,是编程还是日常工作,这些都可以后续在设置里面进行修改。接下来点击设置沙盒按钮,完成沙盒的初始化。关于沙盒这部分的内容,我们下一个章节再来介绍。 项目与任务列表 我们点击右上角的按钮显示侧边栏,我们看到 Codex APP 是非常经典的三栏布局:左侧是任务列表,中间是对话窗口,右侧是多功能区域。 我们先创建两个项目文件夹,来展示一下它的基础使用。这里我在桌面新建了两个文件夹,作为两个项目文件夹。然后我们来到 Codex ,点击进入项目工作,使用现有文件夹。我们先选择第一个文件夹,这里我让它做一个 html 单页面的宠物洗护店的网页,开始。在左侧边栏里面增加了一个项目,项目的名称就是文件夹的名称,里面展示了正在运行的任务。 接下来我们点击左上角的新对话按钮。Windows 上的快捷键是 Ctrl+N ,Mac 系统的快捷键是 command+N ,来开启一个新的对话。我们可以选择新对话属于哪个项目。这里我准备开启一个新的项目,把第二个文件夹也添加进来,点击添加新项目,然后选择我们的第二个文件夹。 这里输入我第二个项目的需求:用 react 框架做一个网页版待办事项的提醒工具,回车开始执行。 在两个项目并行工作的同时,我们还可以开启更多的工作对话。比如这里我想询问 Codex 一个技术问题,我们把鼠标指向第二个项目,点击这个小按钮,在项目里面开启新的对话。 这里我询问 Codex:react 框架是什么,回车。这里看到我们开启了 3 个任务并行执行,有两个任务属于项目一,一个任务属于项目 2 。正在执行的任务上面都有一个转圈的小图标,表示 AI 正在工作。我们耐心等待一会。 过了一会状态就不一样了。有一个任务上面显示一个绿色标签,表示等待批准;有一个任务上面出现了一个蓝色小点,表示已经执行完毕了;还有一个任务继续转圈。我们来到这个等待批准的任务里面,发现 Codex 需要联网下载 Vite React 项目的模板,正在申请权限。 我们点击“是”批准,这个任务就继续执行了。又过了一会,三个任务上面都标记了蓝色的小圆点,表示三个任务都执行完毕了。Codex 任务列表非常的简洁美观好用,可以很方便地观察任务状态,可以并行开启多个工作任务,还能高效地从多个任务里面自由地切换。 我们再来看一下左侧边栏任务列表的其他功能。新对话按钮用来开启新的对话,在下面可以选择对应的项目,也可以选择不使用任何的项目,纯粹的闲聊。这种不属于任何项目的对话,都会被收录到任务列表的最下面,也就是对话这一栏里面。 左侧边栏第二个按钮,快捷键是 Ctrl+G ,Mac 电脑的快捷键是 command+G ,可以搜索近期的对话历史。不过我试了一下,这个功能只能搜索到对话的标题,它无法搜索到对话里面的内容。这里补充一下,每个对话标题都是 AI 根据对话内容自动摘要生成的。我们也可以选择某个对话,双击,对它进行一个重命名。如果我们不再需要某个对话了,可以点击这个归档对话的小按钮确认,然后我们的对话就在左侧边栏消失了。在设置已归档对话里面,可以找到我们删除的对话,点击取消归档就可以把它还原回来。左侧边栏还有两个按钮,插件与自动化,这个等我们在后面的章节再来看。 权限控制与沙箱 接下来我们来看一下中间的对话页面。这里最显眼的功能就是权限控制。 Codex 的权限控制全部是围绕沙箱来展开的,这点跟 Claude Code 有本质上的不同。Claude Code 的沙箱功能需要手动开启,Claude Code 的沙箱更像是一层可以额外开启的保护,而 Codex 的沙箱,它是整个权限系统运行的地基。 Codex 会把当前的项目文件夹作为一个沙箱进行管理。在默认权限下面,Codex 具有读取修改沙箱内所有文件的权限。在默认模式下,Codex APP 可以直接修改沙箱内,也就是项目文件夹的所有文件,它并不会一个个地跑来问你。我觉得这点非常的方便,也是符合正常的使用习惯的。当然我们也可以通过设置,改成逐个文件修改都需要审批,这个在视频的后半段高级设置这个我们再来讲。 Codex 的沙箱有两个默认限制。第一点是 Codex 不能修改沙箱外的文件,第二点是 Codex 的沙箱是禁止联网的。这两点硬性限制,它并不是靠模型自觉遵守,而是 Codex 使用操作系统底层功能实现的。不同操作系统的实现机制是不一样的,比如 MacOS 使用的是系统内置的 Seatbelt Sandbox 机制。 Codex 的沙箱功能是前阵爆火的 Harness engineering 概念的一个典型的工程实现,用操作系统级别的机制把 AI 的能力约束在一个可控的范围之内。这也很形象地体现了 Harness 这个词的原始含义,也就是马具。AI 就像一匹能力很强的马,而沙箱权限审批机制这些,就是套在它身上的马具。 如果 Codex 需要修改沙箱外文件,或者需要联网,可以向用户申请权限,这个操作叫做 escalate ,也就是提权操作。在默认情况下,提权操作都是需要人工审核同意的。Codex 为我们提供了第二个档位,也就是自动审查。启动了自动审查以后,Codex 会自动调用一个小模型,对提权操作进行安全性审查。如果发现是低风险的操作,就会直接放行。只有高风险的操作才会触发人工审查,这也是我最推荐的模式。自动审查使得绝大部分操作不需要人工审批,在获取了较高安全性的同时,还极大提升了使用的便利度。 所以一般情况下,在权限管理这里,我都推荐开启第二档,也就是自动审查。Codex 还有第三档,完全访问权限。开启了这个以后,Codex 完全无视沙箱的限制,可以在电脑上执行一切的操作。不过我们尝试开启的时候,这里出现了很醒目的风险提示,提示我们要谨慎使用。 上下文 在权限控制的右边有一个圆圈,展示的是当前上下文使用情况。这里翻译得不太好,准确的翻译应该是上下文使用量信息,显示的是这个对话里的历史对话内容占用了多少模型上下文空间。当上下文超过限制的时候,Codex 会自动对对话历史进行压缩,从而释放出更多的上下文空间。我们也可以输入斜杠,选择压缩选项,手动触发一次上下文压缩。压缩完成以后,Codex 会把之前对话的一些不重要的内容排除掉,可以有效提高 AI 的专注力,并且降低 TOKEN 消耗。 不过在 AI Agent 领域,有一个通用经验是清空好于压缩。因为过多的历史会话,会干扰 AI 的注意力。当我们让 AI 执行完一个任务以后,最好是开一个新的对话,清空上下文。这样有助于 AI 把注意力全部集中到新的任务上面来,从而提高任务的执行效果。 在上下文窗口的右边是模型选择,可以根据任务的复杂程度选择模型的思考强度。下面可以切换模型,这里一般我们就选择最新的模型,比如现在是 GPT-5.5 。 下面还有一个速度选项,可以选择标准还有快速。在快速模式下,会提升 50% 的 AI 推理速度,但是快速模式会消耗两倍的套餐用量。如果你的任务很急,但是套餐的余量还有很多,可以选择开启。 说到套餐余量,我们可以在左下角的设置剩余额度里面找到你现在的套餐余量。这里有两个限额,分别是 5 小时限额,还有周限额。这两个限额任意一个到达上限,Codex 都不能继续使用了。 两个限额都有对应的重置时间,时间到了以后,额度会重置成 100%。右边还有一个语音输入功能,可以让我们跟 AI 的交互从打字变成口喷,非常的好玩。 AI 生图 Codex 内置了 AI 画图功能,而且它使用的是当今最强的 AI 生图模型 GPT-Image-2 。这是刚才我让 Codex 为我们生成的宠物洗护的网站,我们看到它已经为我们配了一些图片。这里我看了一下,这些图片其实都是网络上的免费素材。这里有两个配图非常的不合适。首先这里的店内环境展示的都是一些宠物图片,它并不是一个真正的宠物洗护店的环境。第二点是门店信息,这里画的地图也太粗糙简陋了。 我们就针对这两个问题,让 Codex 帮我们来修改一下。我们来到 Codex ,新开一个对话,项目选择宠物洗护店那个。我让 Codex 调用 AI 绘图功能,绘制三个店内环境的轮播图,三个图应该分别展示店内的不同区域。 我们看到 Codex 为我们生成了三张图片,基本都保持了店内装修风格的一致性。 然后在网页这边也替换成了 3 张图片的轮播图,非常的不错。 接下来我们要改的是门店信息,这里的地图太简陋了。我们回到 Codex ,在宠物店应用这里新开一个对话,输入我的指令: 我们的店在陕西北路 1620 号,就是地图上标记的这个点。你按我发你的位置,用可爱清新的宠物风格的地图把我们的店标记上,然后修改网页里的门店位置信息。 这里我来到地图,我截个图,然后把我们的店用箭头标记上。接下来我们直接 Ctrl+V ,Mac 系统是 Command+V ,把截图粘贴过来,开始。 在 Codex 的执行过程中,我随时跟踪进度。这里我发现了一个问题,就是他画的这个地图是用 SVG 生成的,效果很差。我原本是想让他调用内置的 AI 生图模型来画。借着这个机会,我要介绍 Codex 的一个强大功能。它的英文名叫做 steer ,中文翻译过来是引导。这个词的英文原文的意思是打方向盘。当我们发现 AI 在执行过程中理解错了我们的意思,就不应该让它继续执行了,这时候应该及时接管方向盘,人工进行引导干预。 这里我截个图发送给 Codex 说:你这图不行,应该调用 AI 绘图能力。 在默认模式下,这个新的指令进入了指令队列排队,需要 AI 把上一轮全部执行完,才能执行我们新输入的指令。我们可以点击这里的引导按钮,英文版叫做 steer ,中途接管方向盘,引导干预 AI 的执行。 我们看到 Codex 这里显示已引导对话,然后回复我说味不对,我立即改用 AI 生图,重新生成一张。我们使用 Codex 的 steer 功能,在运行中途成功纠正了模型的运行方向。 在 Codex 的设置常规设置里面,有一个跟进行为。这里可以设置在执行过程中,我们输入的指令是在后面排队,还是直接进入引导。 这里我推荐还是默认选择排队,如果需要引导的话,我们直接点击那个引导按钮,或者按快捷键 Ctrl+回车。我们看到 Codex 为我们重新生成了一张图片,并且把它替换到了网页里面,标注出了我们店的位置,效果非常的棒。 计划模式与内置浏览器 在对话窗口这里有一个加号,里面有三个功能。首先是添加照片和文件,我们可以用照片或者文件给 AI 补充上下文信息,或者可以像刚才一样通过复制粘贴,直接把照片或者文件粘贴进对话窗口。下面是插件,目前预装了 4 个插件,分别对应办公三大件( Word,Excel,PPT ),还有浏览器自动化。 我们主要看这里的计划模式。开启了计划以后,Codex 就不会立即上手干活,而是先为我们输出一份完整的工作计划,跟我们进行了确认以后再干活。对于所有的复杂任务,建议都先开启计划模式,确保你能跟 AI 对齐颗粒度,让 AI 能够精准理解我们的意图。 我们在 Codex 里面打开计划模式,输入我们的需求: 把这个项目改造成 next js 框架 在计划模式里面,Codex 会很倾向于使用这种问题卡片的形式跟用户进行沟通。这里他询问我希望使用哪种项目形态,我选择 APP Router 加 TS 。然后样式迁移希望怎么处理,这里我选择改 Tailwind 。迁移完成要不要同时启动本地开发服务器验证,这里我选择构建加启动。Codex 为我们生成了一份完整的计划,我仔细阅读了一遍,没有发现问题。这里我们点击是,实施此计划。 代码编写完成以后,Codex 可以启动它内置的浏览器进行自动化的测试,这样任务就完成了,开发服务器也启动起来了。在右侧的多功能窗口,Codex 自动打开了浏览器。我们可以点击这里的展开面板按钮,看一下项目的完整状态。我们看到这次架构迁移非常的成功,页面上所有的元素都完整地保留了,非常的不错。 如果对某个部分不满意,我们可以点击这里的批注按钮,然后选中一个元素,在这里可以添加评论。比如这里我说为什么这个星星是空心的,然后在下面点击发送,让 AI 帮我们修改一下。 在下面也可以实时看到它的修改过程。我们刷新一下页面,这个星星就被修改成了实心的。这样我们就通过 Plan 模式配合 Codex 的内置浏览器,成功完成了项目架构的迁移,还顺手修改了一个小 bug 。 代码管理 Codex APP 并不是传统的 IDE ,它并不提供完整的代码编辑功能。我们可以在右上角点击切换文件树,这里虽然可以查看代码,但是没法直接编辑。我们只能点击某行代码来写批注,并不能直接修改代码。我们可以借助第三方的 IDE 来修改代码。 在进行代码管理之前,我们需要先把项目初始化成一个 git 工程。这里我们新开启一个对话,输入提示词: 把项目初始化成一个 git 工程,注意排除掉不需要的文件。 Codex 先为我们创建了 .gitignore 文件,把一些不需要提交的内容排除出去。Codex 帮我们把项目初始化成了 Git 仓库。 初始化成 Git 仓库以后,右上角又多了很多按钮。这里有一个 VSCode 按钮,我们点击一下,我们就可以快捷地使用 VSCode 来查看和修改代码。 除了使用 VSCode ,在这个下拉列表里面,还可以使用其他的 IDE 来打开项目。如果你的电脑上装过这些 IDE ,就可以在这里关联出来。我们也可以在设置常规设置里面选择默认打开的 IDE 。 我还可以要求 AI 把代码帮我提交到 Github 上面。Codex 需要我先在 Github 上面为它创建一个仓库。这里我来到 Github ,点击这个 new 按钮,仓库的名字还叫 pet_care ,点击创建。 创建出来以后把这个地址复制一下,我们回到 Codex 扔给他,成功帮我们把代码推送到了 Github 上面。我们点击这个链接,看到我们的代码已经备份到了 GitHub 的网站上面。我们可以使用对话的方式进行一切 Git 与 Github 操作,这都属于编程的基础知识,本期视频我就不展开讲了。 Git 回滚 本期视频我主要讲两个进阶技巧。第一个是使用 Git 对开发过程进行回滚,第二个技巧是 Git WorkTree 。 我们先看第一个回滚。这里我新开一个对话,我们打开侧边栏,点击加号,浏览器输入我们项目本地开发的地址,这样进入浏览器。我们还是在这里面进行一些批注。我让 Codex 在这里添加一个期望到店时间的功能,直接点击 Ctrl 加回车发送。Codex 为我们添加了期望到店时间这个字段。 当 AI 完成一个功能的开发以后,我们就使用 Git 把它备份保存一下。这里点击提交, 填写一个提交消息,点击继续。这样最新的代码改动就以 Git 的方式保存下来了。接下来我让 AI 把期望到店时间放到联系人的上面,开始。Codex 为我们完成了修改,我们还是从内置的浏览器看一下效果。这个字段跑到了最上面,不过这么一改,我觉得更难看了,我后悔了。我觉得还是把它放到原来的位置比较好。这里我想做的是把这一次的对话,包括这一次的代码改动,全部回滚掉,最好是当做无事发生。 这里我们先借助 Codex 的分叉功能,英文是 fork 。我们先把对话回滚掉。我们找到上一次对话结尾的位置,点击这个分叉按钮,选择派生到本地。 我们看到 Codex 的分叉功能,就是在我点击的这个位置,把对话复制了一份。这样复制出来的新对话,就已经剔除掉了我们刚才想删除的部分了。 不过分叉功能只能回退对话历史,它不能同步回退代码。所以这里我们要做的是把代码一同回退掉。我们可以在 VSCode 里面点击这个 source control 按钮,查看所有的 Git 提交。这里我需要把代码回退到生成期望到店时间的这个状态上。我们点击右键,点击这个 copy commit hash , 这样我们就把这次提交的 ID 复制下来了。我们回到 Codex ,先让 AI 把代码回退到这个状态,后面就是我们刚才复制的提交 ID 。 我们看到代码回退成功了,在浏览器里可以看到这个期望到店时间又变回了原来的位置。这样我们就使用了 Codex 的对话分岔功能,加上 Git 操作,成功地把这一次不需要的改动,从代码层面和对话历史层面进行了完全的回滚。 Git worktree 接下来我们来看下一个功能,就是 Git worktree 。WorkTree 这个名字听起来比较唬人,其实它本质上就是用 git 创建一个新的分支,然后把这个新分支的代码完整地复制到一个新的文件夹里面。这个新文件夹就是一个 WorkTree 。主文件夹和分支文件夹可以并行工作,我们可以在两个文件夹里面各自修改代码,互相不干扰。我们可以基于主干创建多个分支,它们在底层通过 git 关联在一起。分支文件夹的改动,随时都能轻松合并回主干。 找到我们的项目,右键创建永久工作树。这里起个名字,我想让第一个工作树专注优化客户评价这个部分,我给它加个后缀叫 customer rating 。Codex 把整个项目复制到了一个单独的文件夹里面,它跟主干已经不是同一个文件夹了。我们在分支里面做的操作不会影响到主干。这里我们再建一个工作树,第二个工作树主要用来负责优化下面的门店信息,还有这里的地图。我们给第二个树也起个名字。这样我们就拥有了两个工作树分支,它们都位于不同的文件夹下面,所以它们之间的并行工作不会影响到主干。 这里我们来测试一下。我们先打开第一个分支新对话,输入我们的需求: 优化一下客户评价部分,多写几个评价,做一个动画轮播效果, 开始。然后我们来到第二个分支,创建一个新的对话: 优化一下门店信息部分,让门店信息跟地图上下排列,不要左右排列,把地图展示全。 我们在两个分支上面进行并行开发,因为它们位于两个不同的文件夹,所以互相之间不会产生干扰。 两个分支在各自的文件夹里面都开发完毕了。接下来我们可以把它合并回主干。里直接输入合并回主干,两个分支都一样的操作,合并回主干。 两个分支都成功合并进了主干。我们在浏览器这边可以看到,客户评价已经优化过了,门店信息也从左右排布变成了上下排布,地图展示得更全了。这样我们使用 Git worktree 功能,高效并行开发了两个任务。当我们的分支使用完毕,我们可以直接右键移除,把两个临时的分支移除掉,然后回到主干继续工作。

v2ex.com · 2026-04-29 20:42:51+08:00 · tech

视频版: https://www.bilibili.com/video/BV1Kk9kBAEJv 最近 Codex APP 的能力越来越全面,变成了 Codex 四大产品形态里面最强的一个。Codex 比起 Claude Code ,额度更高,功能更全,上手更快,免费账户也能用,而且不会出现限速、封号、降智等问题,用过的小伙伴们直呼真香。本期视频带来一个 Codex APP 的完整教程,主要分为以下 12 个章节。 每个章节里面都会穿插一些重要的知识,对 Codex 的全部功能进行细致讲解。好,废话不多说,我们直接开始。 安装 在安装使用 Codex APP 之前,需要进行 3 个准备工作,也就是需要先把 Git 、Nodejs 还有 VSCode 安装一下。在我上期视频《从 0 开始用国内网络跑通一切 AI Agent 》里面,有详细的操作步骤,不熟悉的朋友们可以参考那一期视频。 接下来我们来到 Codex 的官网,Codex 支持 Windows 跟 Mac 两大操作系统。官网会根据你的操作系统,自动提供对应的安装包。本期视频我主要使用 Windows 来进行演示。Windows 跟 Mac 电脑的功能基本是一致的,唯一欠缺的功能是 computer use ,也就是自动操作电脑的能力。等需要演示这部分的时候,我会切换到 Mac 电脑进行演示。 然后我们一路点击下一步完成安装。接下来我们把 Codex APP 启动起来,选择 ChatGPT 账户完成登录。现在 ChatGPT 的免费账户也能使用 Codex 了,不过额度比较低。第一次进入软件要选一下希望 Codex 为你处理的工作,Codex 会根据你的选择预装一些内置的插件和 skills 。当然进入软件以后,我们还可以按需安装这些插件。然后选择主要的使用场景,是编程还是日常工作,这些都可以后续在设置里面进行修改。接下来点击设置沙盒按钮,完成沙盒的初始化。关于沙盒这部分的内容,我们下一个章节再来介绍。 项目与任务列表 我们点击右上角的按钮显示侧边栏,我们看到 Codex APP 是非常经典的三栏布局:左侧是任务列表,中间是对话窗口,右侧是多功能区域。 我们先创建两个项目文件夹,来展示一下它的基础使用。这里我在桌面新建了两个文件夹,作为两个项目文件夹。然后我们来到 Codex ,点击进入项目工作,使用现有文件夹。我们先选择第一个文件夹,这里我让它做一个 html 单页面的宠物洗护店的网页,开始。在左侧边栏里面增加了一个项目,项目的名称就是文件夹的名称,里面展示了正在运行的任务。 接下来我们点击左上角的新对话按钮。Windows 上的快捷键是 Ctrl+N ,Mac 系统的快捷键是 command+N ,来开启一个新的对话。我们可以选择新对话属于哪个项目。这里我准备开启一个新的项目,把第二个文件夹也添加进来,点击添加新项目,然后选择我们的第二个文件夹。 这里输入我第二个项目的需求:用 react 框架做一个网页版待办事项的提醒工具,回车开始执行。 在两个项目并行工作的同时,我们还可以开启更多的工作对话。比如这里我想询问 Codex 一个技术问题,我们把鼠标指向第二个项目,点击这个小按钮,在项目里面开启新的对话。 这里我询问 Codex:react 框架是什么,回车。这里看到我们开启了 3 个任务并行执行,有两个任务属于项目一,一个任务属于项目 2 。正在执行的任务上面都有一个转圈的小图标,表示 AI 正在工作。我们耐心等待一会。 过了一会状态就不一样了。有一个任务上面显示一个绿色标签,表示等待批准;有一个任务上面出现了一个蓝色小点,表示已经执行完毕了;还有一个任务继续转圈。我们来到这个等待批准的任务里面,发现 Codex 需要联网下载 Vite React 项目的模板,正在申请权限。 我们点击“是”批准,这个任务就继续执行了。又过了一会,三个任务上面都标记了蓝色的小圆点,表示三个任务都执行完毕了。Codex 任务列表非常的简洁美观好用,可以很方便地观察任务状态,可以并行开启多个工作任务,还能高效地从多个任务里面自由地切换。 我们再来看一下左侧边栏任务列表的其他功能。新对话按钮用来开启新的对话,在下面可以选择对应的项目,也可以选择不使用任何的项目,纯粹的闲聊。这种不属于任何项目的对话,都会被收录到任务列表的最下面,也就是对话这一栏里面。 左侧边栏第二个按钮,快捷键是 Ctrl+G ,Mac 电脑的快捷键是 command+G ,可以搜索近期的对话历史。不过我试了一下,这个功能只能搜索到对话的标题,它无法搜索到对话里面的内容。这里补充一下,每个对话标题都是 AI 根据对话内容自动摘要生成的。我们也可以选择某个对话,双击,对它进行一个重命名。如果我们不再需要某个对话了,可以点击这个归档对话的小按钮确认,然后我们的对话就在左侧边栏消失了。在设置已归档对话里面,可以找到我们删除的对话,点击取消归档就可以把它还原回来。左侧边栏还有两个按钮,插件与自动化,这个等我们在后面的章节再来看。 权限控制与沙箱 接下来我们来看一下中间的对话页面。这里最显眼的功能就是权限控制。 Codex 的权限控制全部是围绕沙箱来展开的,这点跟 Claude Code 有本质上的不同。Claude Code 的沙箱功能需要手动开启,Claude Code 的沙箱更像是一层可以额外开启的保护,而 Codex 的沙箱,它是整个权限系统运行的地基。 Codex 会把当前的项目文件夹作为一个沙箱进行管理。在默认权限下面,Codex 具有读取修改沙箱内所有文件的权限。在默认模式下,Codex APP 可以直接修改沙箱内,也就是项目文件夹的所有文件,它并不会一个个地跑来问你。我觉得这点非常的方便,也是符合正常的使用习惯的。当然我们也可以通过设置,改成逐个文件修改都需要审批,这个在视频的后半段高级设置这个我们再来讲。 Codex 的沙箱有两个默认限制。第一点是 Codex 不能修改沙箱外的文件,第二点是 Codex 的沙箱是禁止联网的。这两点硬性限制,它并不是靠模型自觉遵守,而是 Codex 使用操作系统底层功能实现的。不同操作系统的实现机制是不一样的,比如 MacOS 使用的是系统内置的 Seatbelt Sandbox 机制。 Codex 的沙箱功能是前阵爆火的 Harness engineering 概念的一个典型的工程实现,用操作系统级别的机制把 AI 的能力约束在一个可控的范围之内。这也很形象地体现了 Harness 这个词的原始含义,也就是马具。AI 就像一匹能力很强的马,而沙箱权限审批机制这些,就是套在它身上的马具。 如果 Codex 需要修改沙箱外文件,或者需要联网,可以向用户申请权限,这个操作叫做 escalate ,也就是提权操作。在默认情况下,提权操作都是需要人工审核同意的。Codex 为我们提供了第二个档位,也就是自动审查。启动了自动审查以后,Codex 会自动调用一个小模型,对提权操作进行安全性审查。如果发现是低风险的操作,就会直接放行。只有高风险的操作才会触发人工审查,这也是我最推荐的模式。自动审查使得绝大部分操作不需要人工审批,在获取了较高安全性的同时,还极大提升了使用的便利度。 所以一般情况下,在权限管理这里,我都推荐开启第二档,也就是自动审查。Codex 还有第三档,完全访问权限。开启了这个以后,Codex 完全无视沙箱的限制,可以在电脑上执行一切的操作。不过我们尝试开启的时候,这里出现了很醒目的风险提示,提示我们要谨慎使用。 上下文 在权限控制的右边有一个圆圈,展示的是当前上下文使用情况。这里翻译得不太好,准确的翻译应该是上下文使用量信息,显示的是这个对话里的历史对话内容占用了多少模型上下文空间。当上下文超过限制的时候,Codex 会自动对对话历史进行压缩,从而释放出更多的上下文空间。我们也可以输入斜杠,选择压缩选项,手动触发一次上下文压缩。压缩完成以后,Codex 会把之前对话的一些不重要的内容排除掉,可以有效提高 AI 的专注力,并且降低 TOKEN 消耗。 不过在 AI Agent 领域,有一个通用经验是清空好于压缩。因为过多的历史会话,会干扰 AI 的注意力。当我们让 AI 执行完一个任务以后,最好是开一个新的对话,清空上下文。这样有助于 AI 把注意力全部集中到新的任务上面来,从而提高任务的执行效果。 在上下文窗口的右边是模型选择,可以根据任务的复杂程度选择模型的思考强度。下面可以切换模型,这里一般我们就选择最新的模型,比如现在是 GPT-5.5 。 下面还有一个速度选项,可以选择标准还有快速。在快速模式下,会提升 50% 的 AI 推理速度,但是快速模式会消耗两倍的套餐用量。如果你的任务很急,但是套餐的余量还有很多,可以选择开启。 说到套餐余量,我们可以在左下角的设置剩余额度里面找到你现在的套餐余量。这里有两个限额,分别是 5 小时限额,还有周限额。这两个限额任意一个到达上限,Codex 都不能继续使用了。 两个限额都有对应的重置时间,时间到了以后,额度会重置成 100%。右边还有一个语音输入功能,可以让我们跟 AI 的交互从打字变成口喷,非常的好玩。 AI 生图 Codex 内置了 AI 画图功能,而且它使用的是当今最强的 AI 生图模型 GPT-Image-2 。这是刚才我让 Codex 为我们生成的宠物洗护的网站,我们看到它已经为我们配了一些图片。这里我看了一下,这些图片其实都是网络上的免费素材。这里有两个配图非常的不合适。首先这里的店内环境展示的都是一些宠物图片,它并不是一个真正的宠物洗护店的环境。第二点是门店信息,这里画的地图也太粗糙简陋了。 我们就针对这两个问题,让 Codex 帮我们来修改一下。我们来到 Codex ,新开一个对话,项目选择宠物洗护店那个。我让 Codex 调用 AI 绘图功能,绘制三个店内环境的轮播图,三个图应该分别展示店内的不同区域。 我们看到 Codex 为我们生成了三张图片,基本都保持了店内装修风格的一致性。 然后在网页这边也替换成了 3 张图片的轮播图,非常的不错。 接下来我们要改的是门店信息,这里的地图太简陋了。我们回到 Codex ,在宠物店应用这里新开一个对话,输入我的指令: 我们的店在陕西北路 1620 号,就是地图上标记的这个点。你按我发你的位置,用可爱清新的宠物风格的地图把我们的店标记上,然后修改网页里的门店位置信息。 这里我来到地图,我截个图,然后把我们的店用箭头标记上。接下来我们直接 Ctrl+V ,Mac 系统是 Command+V ,把截图粘贴过来,开始。 在 Codex 的执行过程中,我随时跟踪进度。这里我发现了一个问题,就是他画的这个地图是用 SVG 生成的,效果很差。我原本是想让他调用内置的 AI 生图模型来画。借着这个机会,我要介绍 Codex 的一个强大功能。它的英文名叫做 steer ,中文翻译过来是引导。这个词的英文原文的意思是打方向盘。当我们发现 AI 在执行过程中理解错了我们的意思,就不应该让它继续执行了,这时候应该及时接管方向盘,人工进行引导干预。 这里我截个图发送给 Codex 说:你这图不行,应该调用 AI 绘图能力。 在默认模式下,这个新的指令进入了指令队列排队,需要 AI 把上一轮全部执行完,才能执行我们新输入的指令。我们可以点击这里的引导按钮,英文版叫做 steer ,中途接管方向盘,引导干预 AI 的执行。 我们看到 Codex 这里显示已引导对话,然后回复我说味不对,我立即改用 AI 生图,重新生成一张。我们使用 Codex 的 steer 功能,在运行中途成功纠正了模型的运行方向。 在 Codex 的设置常规设置里面,有一个跟进行为。这里可以设置在执行过程中,我们输入的指令是在后面排队,还是直接进入引导。 这里我推荐还是默认选择排队,如果需要引导的话,我们直接点击那个引导按钮,或者按快捷键 Ctrl+回车。我们看到 Codex 为我们重新生成了一张图片,并且把它替换到了网页里面,标注出了我们店的位置,效果非常的棒。 计划模式与内置浏览器 在对话窗口这里有一个加号,里面有三个功能。首先是添加照片和文件,我们可以用照片或者文件给 AI 补充上下文信息,或者可以像刚才一样通过复制粘贴,直接把照片或者文件粘贴进对话窗口。下面是插件,目前预装了 4 个插件,分别对应办公三大件( Word,Excel,PPT ),还有浏览器自动化。 我们主要看这里的计划模式。开启了计划以后,Codex 就不会立即上手干活,而是先为我们输出一份完整的工作计划,跟我们进行了确认以后再干活。对于所有的复杂任务,建议都先开启计划模式,确保你能跟 AI 对齐颗粒度,让 AI 能够精准理解我们的意图。 我们在 Codex 里面打开计划模式,输入我们的需求: 把这个项目改造成 next js 框架 在计划模式里面,Codex 会很倾向于使用这种问题卡片的形式跟用户进行沟通。这里他询问我希望使用哪种项目形态,我选择 APP Router 加 TS 。然后样式迁移希望怎么处理,这里我选择改 Tailwind 。迁移完成要不要同时启动本地开发服务器验证,这里我选择构建加启动。Codex 为我们生成了一份完整的计划,我仔细阅读了一遍,没有发现问题。这里我们点击是,实施此计划。 代码编写完成以后,Codex 可以启动它内置的浏览器进行自动化的测试,这样任务就完成了,开发服务器也启动起来了。在右侧的多功能窗口,Codex 自动打开了浏览器。我们可以点击这里的展开面板按钮,看一下项目的完整状态。我们看到这次架构迁移非常的成功,页面上所有的元素都完整地保留了,非常的不错。 如果对某个部分不满意,我们可以点击这里的批注按钮,然后选中一个元素,在这里可以添加评论。比如这里我说为什么这个星星是空心的,然后在下面点击发送,让 AI 帮我们修改一下。 在下面也可以实时看到它的修改过程。我们刷新一下页面,这个星星就被修改成了实心的。这样我们就通过 Plan 模式配合 Codex 的内置浏览器,成功完成了项目架构的迁移,还顺手修改了一个小 bug 。 代码管理 Codex APP 并不是传统的 IDE ,它并不提供完整的代码编辑功能。我们可以在右上角点击切换文件树,这里虽然可以查看代码,但是没法直接编辑。我们只能点击某行代码来写批注,并不能直接修改代码。我们可以借助第三方的 IDE 来修改代码。 在进行代码管理之前,我们需要先把项目初始化成一个 git 工程。这里我们新开启一个对话,输入提示词: 把项目初始化成一个 git 工程,注意排除掉不需要的文件。 Codex 先为我们创建了 .gitignore 文件,把一些不需要提交的内容排除出去。Codex 帮我们把项目初始化成了 Git 仓库。 初始化成 Git 仓库以后,右上角又多了很多按钮。这里有一个 VSCode 按钮,我们点击一下,我们就可以快捷地使用 VSCode 来查看和修改代码。 除了使用 VSCode ,在这个下拉列表里面,还可以使用其他的 IDE 来打开项目。如果你的电脑上装过这些 IDE ,就可以在这里关联出来。我们也可以在设置常规设置里面选择默认打开的 IDE 。 我还可以要求 AI 把代码帮我提交到 Github 上面。Codex 需要我先在 Github 上面为它创建一个仓库。这里我来到 Github ,点击这个 new 按钮,仓库的名字还叫 pet_care ,点击创建。 创建出来以后把这个地址复制一下,我们回到 Codex 扔给他,成功帮我们把代码推送到了 Github 上面。我们点击这个链接,看到我们的代码已经备份到了 GitHub 的网站上面。我们可以使用对话的方式进行一切 Git 与 Github 操作,这都属于编程的基础知识,本期视频我就不展开讲了。 Git 回滚 本期视频我主要讲两个进阶技巧。第一个是使用 Git 对开发过程进行回滚,第二个技巧是 Git WorkTree 。 我们先看第一个回滚。这里我新开一个对话,我们打开侧边栏,点击加号,浏览器输入我们项目本地开发的地址,这样进入浏览器。我们还是在这里面进行一些批注。我让 Codex 在这里添加一个期望到店时间的功能,直接点击 Ctrl 加回车发送。Codex 为我们添加了期望到店时间这个字段。 当 AI 完成一个功能的开发以后,我们就使用 Git 把它备份保存一下。这里点击提交, 填写一个提交消息,点击继续。这样最新的代码改动就以 Git 的方式保存下来了。接下来我让 AI 把期望到店时间放到联系人的上面,开始。Codex 为我们完成了修改,我们还是从内置的浏览器看一下效果。这个字段跑到了最上面,不过这么一改,我觉得更难看了,我后悔了。我觉得还是把它放到原来的位置比较好。这里我想做的是把这一次的对话,包括这一次的代码改动,全部回滚掉,最好是当做无事发生。 这里我们先借助 Codex 的分叉功能,英文是 fork 。我们先把对话回滚掉。我们找到上一次对话结尾的位置,点击这个分叉按钮,选择派生到本地。 我们看到 Codex 的分叉功能,就是在我点击的这个位置,把对话复制了一份。这样复制出来的新对话,就已经剔除掉了我们刚才想删除的部分了。 不过分叉功能只能回退对话历史,它不能同步回退代码。所以这里我们要做的是把代码一同回退掉。我们可以在 VSCode 里面点击这个 source control 按钮,查看所有的 Git 提交。这里我需要把代码回退到生成期望到店时间的这个状态上。我们点击右键,点击这个 copy commit hash , 这样我们就把这次提交的 ID 复制下来了。我们回到 Codex ,先让 AI 把代码回退到这个状态,后面就是我们刚才复制的提交 ID 。 我们看到代码回退成功了,在浏览器里可以看到这个期望到店时间又变回了原来的位置。这样我们就使用了 Codex 的对话分岔功能,加上 Git 操作,成功地把这一次不需要的改动,从代码层面和对话历史层面进行了完全的回滚。 Git worktree 接下来我们来看下一个功能,就是 Git worktree 。WorkTree 这个名字听起来比较唬人,其实它本质上就是用 git 创建一个新的分支,然后把这个新分支的代码完整地复制到一个新的文件夹里面。这个新文件夹就是一个 WorkTree 。主文件夹和分支文件夹可以并行工作,我们可以在两个文件夹里面各自修改代码,互相不干扰。我们可以基于主干创建多个分支,它们在底层通过 git 关联在一起。分支文件夹的改动,随时都能轻松合并回主干。 找到我们的项目,右键创建永久工作树。这里起个名字,我想让第一个工作树专注优化客户评价这个部分,我给它加个后缀叫 customer rating 。Codex 把整个项目复制到了一个单独的文件夹里面,它跟主干已经不是同一个文件夹了。我们在分支里面做的操作不会影响到主干。这里我们再建一个工作树,第二个工作树主要用来负责优化下面的门店信息,还有这里的地图。我们给第二个树也起个名字。这样我们就拥有了两个工作树分支,它们都位于不同的文件夹下面,所以它们之间的并行工作不会影响到主干。 这里我们来测试一下。我们先打开第一个分支新对话,输入我们的需求: 优化一下客户评价部分,多写几个评价,做一个动画轮播效果, 开始。然后我们来到第二个分支,创建一个新的对话: 优化一下门店信息部分,让门店信息跟地图上下排列,不要左右排列,把地图展示全。 我们在两个分支上面进行并行开发,因为它们位于两个不同的文件夹,所以互相之间不会产生干扰。 两个分支在各自的文件夹里面都开发完毕了。接下来我们可以把它合并回主干。里直接输入合并回主干,两个分支都一样的操作,合并回主干。 两个分支都成功合并进了主干。我们在浏览器这边可以看到,客户评价已经优化过了,门店信息也从左右排布变成了上下排布,地图展示得更全了。这样我们使用 Git worktree 功能,高效并行开发了两个任务。当我们的分支使用完毕,我们可以直接右键移除,把两个临时的分支移除掉,然后回到主干继续工作。

linux.do · 2026-04-24 11:51:16+08:00 · tech

提示词: 你是一名精通图形学算法与 Web 交互的前端专家。请仅用一个 HTML 文件,基于 Three.js (ES Modules) 实现一个物理级高保真、支持自然手势的 3x3 魔方。 一、 交付规范 单文件架构:HTML/CSS/JS 必须合并在一个文件中。 依赖管理:必须通过 importmap 从 unpkg 或 cdn.skypack 引入 Three.js 及其 OrbitControls、Tween.js。 零素材依赖:禁止加载任何外部图片/贴图,所有材质纹理必须使用 HTML5 Canvas API 程序化动态生成。 二、 视觉与物理标准 模型构建: 场景需包含 27 个独立的小方块(Cubies)。 物理间隙:小方块之间必须保留微小的物理间距(Spacing),不可紧贴。 倒角质感:通过 Canvas 绘制带有圆角矩形(Rounded Rect)的贴纸纹理,模拟真实魔方的塑料黑边与贴纸高光效果。 光影环境: 必须开启 ShadowMap。 配置环境光(Ambient)与平行光(Directional),确保魔方有清晰的立体感和阴影投射。 三、 核心逻辑考点(数据结构与变换) 禁止维护复杂的 3D 状态数组,请使用基于“空间位置”的动态计算方案: 动态层级筛选: 不要写死索引。当需要旋转某一层时,遍历所有方块,根据其在世界坐标系(World Position)下的 x, y, z 值与阈值(Epsilon)来判断它是否属于当前旋转层。 Pivot 变换机制(关键考点): 实现旋转时,必须创建一个临时的 Pivot(轴心对象)。 核心API:使用 pivot.attach(object) 将选中的方块挂载到轴心,旋转轴心,动画结束后使用 scene.attach(object) 将方块放回场景。 作用:利用 attach 自动计算世界矩阵变换,避免手动处理复杂的四元数乘法。 坐标清洗: 每次旋转结束后,必须对所有方块的位置(Position)和旋转(Rotation)进行 Math.round() 取整处理,消除浮点数累积误差,防止魔方“散架”。 四、 交互系统考点(算法重难点) 这是区分初级与高级开发者的核心点,请实现类似原生 App 的自然手势体验: 操作分离: 左键拖拽:旋转魔方的某一层。 右键拖拽:旋转视角(OrbitControls)。 基于投影向量的手势识别算法: 射线检测:点击时获取被点击方块的“表面法线(Face Normal)”。 意图判断: 根据法线,锁定潜在的两个旋转轴(例如点击前面,潜在轴为 X 或 Y)。 将这两个 3D 轴的向量**投影(Project)**到 2D 屏幕空间。 计算用户鼠标滑动的 2D 向量与这两个投影向量的点积(Dot Product),选择匹配度最高的轴作为旋转轴。 方向修正与实时跟随: 实现1:1 实时跟手:鼠标移动多少像素,魔方层转动对应角度。 符号修正:通过叉乘(Cross Product)或投影符号判断,确保无论从魔方正面、背面还是顶面操作,鼠标向右划动始终对应“向右转”的视觉逻辑(解决方向反转 bug)。 磁吸效果: 松开鼠标后,自动计算最近的 90 度倍数,使用 Tween.js 播放回弹动画并对齐网格。 五、 代码质量 代码需包含清晰的注释,解释“手势投影算法”和“Pivot 挂载逻辑”。 具备 Scramble(打乱)和 Reset(重置)功能按钮。 测试结果 https://imgbed.snemc.cn/i/2ba0883a5353.gif (图片大于 4 MB) 概述: 有颜色错乱和转动轴向错乱问题 打乱按钮无效 测试花费 0.6元 思考时间(不含输出答案时间) 346.7s 测试轮数: 1 轮 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>3x3 魔方 - 物理级高保真手势交互</title> <style> :root { --bg: #1a1a2e; --panel-bg: #16213e; --text: #e0e0e0; --accent: #e94560; --accent2: #0f3460; --gold: #d4a574; } * { margin: 0; padding: 0; box-sizing: border-box; } body { background: var(--bg); font-family: 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif; overflow: hidden; height: 100vh; width: 100vw; user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent; cursor: default; } #canvas-container { position: fixed; inset: 0; z-index: 1; } #canvas-container canvas { display: block; } #canvas-container.grabbing canvas { cursor: grabbing; } #canvas-container.right-drag canvas { cursor: grab; } /* 底部控制面板 */ .control-panel { position: fixed; bottom: 28px; left: 50%; transform: translateX(-50%); z-index: 10; display: flex; gap: 16px; align-items: center; } .btn { padding: 12px 28px; border: none; border-radius: 30px; font-size: 15px; font-weight: 600; letter-spacing: 0.5px; cursor: pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); outline: none; position: relative; overflow: hidden; } .btn-scramble { background: rgba(233, 68, 96, 0.85); color: #fff; box-shadow: 0 8px 24px rgba(233, 68, 96, 0.35); } .btn-scramble:hover { background: rgba(245, 80, 108, 0.95); box-shadow: 0 12px 32px rgba(233, 68, 96, 0.5); transform: translateY(-3px); } .btn-scramble:active { transform: translateY(0); box-shadow: 0 4px 12px rgba(233, 68, 96, 0.3); } .btn-reset { background: rgba(255, 255, 255, 0.12); color: #e0e0e0; border: 1.5px solid rgba(255, 255, 255, 0.25); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2); } .btn-reset:hover { background: rgba(255, 255, 255, 0.2); border-color: rgba(255, 255, 255, 0.45); box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35); transform: translateY(-3px); } .btn-reset:active { transform: translateY(0); } .btn:disabled { opacity: 0.45; cursor: not-allowed; pointer-events: none; transform: none !important; } /* 提示标签 */ .hint-tag { position: fixed; top: 24px; left: 50%; transform: translateX(-50%); z-index: 10; background: rgba(0, 0, 0, 0.55); color: #ccc; font-size: 13px; padding: 8px 20px; border-radius: 20px; letter-spacing: 0.4px; pointer-events: none; transition: opacity 0.5s; } /* 响应式 */ @media (max-width: 600px) { .btn { padding: 10px 20px; font-size: 13px; border-radius: 24px; } .control-panel { gap: 10px; bottom: 18px; } .hint-tag { font-size: 11px; top: 12px; padding: 6px 14px; } } </style> </head> <body> <div id="canvas-container"></div> <div class="hint-tag" id="hint-tag">🖱️ 左键拖拽旋转层 | 右键拖拽旋转视角 | 滚轮缩放</div> <div class="control-panel"> <button class="btn btn-scramble" id="btn-scramble" title="随机打乱魔方">🔀 打乱</button> <button class="btn btn-reset" id="btn-reset" title="重置魔方到初始状态">↺ 重置</button> </div> <!-- Import Map:ES Modules 依赖 --> <script type="importmap"> { "imports": { "three": "https://unpkg.com/[email protected]/build/three.module.js", "three/addons/": "https://unpkg.com/[email protected]/examples/jsm/", "@tweenjs/tween.js": "https://unpkg.com/@tweenjs/[email protected]/dist/tween.esm.js" } } </script> <script type="module"> import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import * as TWEEN from '@tweenjs/tween.js'; // ==================== DOM 元素 ==================== const container = document.getElementById('canvas-container'); const hintTag = document.getElementById('hint-tag'); const btnScramble = document.getElementById('btn-scramble'); const btnReset = document.getElementById('btn-reset'); // ==================== 常量与配置 ==================== const CUBIE_SIZE = 0.9; // 小方块边长 const GRID_SPACING = 1.0; // 格点间距 const GAP = GRID_SPACING - CUBIE_SIZE; // 物理间隙 ≈ 0.1 const EPSILON = 0.15; // 层级筛选阈值 const ANGLE_PER_NDC = Math.PI; // NDC距离→弧度映射系数(1 NDC ≈ 180°) const MAGNETIC_DURATION = 280; // 磁吸动画时长(ms) const SCRAMBLE_STEPS = 20; // 打乱步数 const SCRAMBLE_STEP_DURATION = 160; // 打乱每步动画时长(ms) // 魔方标准颜色(贴纸颜色) const STICKER_COLORS = { right: '#E53935', // +X 红 left: '#FB8C00', // -X 橙 top: '#FAFAFA', // +Y 白 bottom: '#FDD835', // -Y 黄 front: '#43A047', // +Z 绿 back: '#1E88E5', // -Z 蓝 }; const PLASTIC_COLOR = '#1a1a1a'; // 塑料黑边颜色 // ==================== Three.js 初始化 ==================== const scene = new THREE.Scene(); scene.background = new THREE.Color('#1a1a2e'); scene.fog = new THREE.Fog('#1a1a2e', 6, 22); // 渲染器 const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: false }); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMappingExposure = 1.2; renderer.outputColorSpace = THREE.SRGBColorSpace; container.appendChild(renderer.domElement); const canvas = renderer.domElement; // 相机 const camera = new THREE.PerspectiveCamera(48, window.innerWidth / window.innerHeight, 0.5, 40); camera.position.set(5.5, 3.8, 6.5); camera.lookAt(0, 0, 0); // OrbitControls —— 仅响应右键旋转 & 中键缩放 const controls = new OrbitControls(camera, canvas); controls.target.set(0, 0, 0); controls.enableDamping = true; controls.dampingFactor = 0.12; controls.minDistance = 4; controls.maxDistance = 14; controls.maxPolarAngle = Math.PI * 0.75; // 关键:左键=null(留给魔方操作),中键=缩放,右键=旋转 controls.mouseButtons = { LEFT: null, MIDDLE: THREE.MOUSE ? THREE.MOUSE.DOLLY : 1, RIGHT: THREE.MOUSE ? THREE.MOUSE.ROTATE : 0, }; controls.touches = { ONE: THREE.TOUCH ? THREE.TOUCH.ROTATE : 0, TWO: THREE.TOUCH ? THREE.TOUCH.DOLLY_PAN : 1, }; controls.update(); // ==================== 光照与阴影 ==================== // 环境光 —— 提供基础照明 const ambientLight = new THREE.AmbientLight('#8899bb', 1.6); scene.add(ambientLight); // 半球光 —— 模拟天空/地面散射 const hemiLight = new THREE.HemisphereLight('#bcc8e8', '#3a3040', 1.0); scene.add(hemiLight); // 主平行光 —— 投射阴影 const sunLight = new THREE.DirectionalLight('#fffef5', 5.5); sunLight.position.set(8, 14, 6); sunLight.castShadow = true; sunLight.shadow.mapSize.width = 2048; sunLight.shadow.mapSize.height = 2048; sunLight.shadow.camera.near = 0.5; sunLight.shadow.camera.far = 50; sunLight.shadow.camera.left = -10; sunLight.shadow.camera.right = 10; sunLight.shadow.camera.top = 10; sunLight.shadow.camera.bottom = -10; sunLight.shadow.bias = -0.00025; sunLight.shadow.normalBias = 0.02; scene.add(sunLight); // 补光 —— 减少暗面过黑 const fillLight = new THREE.DirectionalLight('#c8d0ff', 2.2); fillLight.position.set(-3, 2, -4); scene.add(fillLight); // ==================== 地面(接收阴影) ==================== const groundGeo = new THREE.PlaneGeometry(20, 20); const groundMat = new THREE.MeshStandardMaterial({ color: '#2a2a35', roughness: 0.65, metalness: 0.05, }); const ground = new THREE.Mesh(groundGeo, groundMat); ground.position.y = -3.5; ground.rotation.x = -Math.PI / 2; ground.receiveShadow = true; ground.name = 'ground'; scene.add(ground); // 微妙的网格辅助线(装饰) const gridHelper = new THREE.PolarGridHelper(9, 48, 32, 64, '#333344', '#222233'); gridHelper.position.y = -3.49; scene.add(gridHelper); // ==================== 贴纸纹理生成(Canvas API) ==================== /** * 使用 HTML5 Canvas 程序化生成带圆角矩形的高光贴纸纹理 * @param {string} colorHex - 贴纸颜色 * @returns {THREE.CanvasTexture} */ function createStickerTexture(colorHex) { const size = 256; const canvas = document.createElement('canvas'); canvas.width = size; canvas.height = size; const ctx = canvas.getContext('2d'); // 1. 塑料黑底(模拟魔方塑料边框) ctx.fillStyle = PLASTIC_COLOR; ctx.fillRect(0, 0, size, size); // 2. 圆角矩形贴纸 const margin = 22; const radius = 34; const x = margin; const y = margin; const w = size - margin * 2; const h = size - margin * 2; ctx.beginPath(); ctx.moveTo(x + radius, y); ctx.lineTo(x + w - radius, y); ctx.quadraticCurveTo(x + w, y, x + w, y + radius); ctx.lineTo(x + w, y + h - radius); ctx.quadraticCurveTo(x + w, y + h, x + w - radius, y + h); ctx.lineTo(x + radius, y + h); ctx.quadraticCurveTo(x, y + h, x, y + h - radius); ctx.lineTo(x, y + radius); ctx.quadraticCurveTo(x, y, x + radius, y); ctx.closePath(); // 填充贴纸颜色 ctx.fillStyle = colorHex; ctx.fill(); // 3. 高光渐变(模拟贴纸表面的微妙光泽) const highlightGrad = ctx.createLinearGradient(x, y, x, y + h); highlightGrad.addColorStop(0, 'rgba(255,255,255,0.22)'); highlightGrad.addColorStop(0.25, 'rgba(255,255,255,0.06)'); highlightGrad.addColorStop(0.55, 'rgba(0,0,0,0.0)'); highlightGrad.addColorStop(0.8, 'rgba(0,0,0,0.04)'); highlightGrad.addColorStop(1, 'rgba(0,0,0,0.14)'); ctx.fillStyle = highlightGrad; ctx.fill(); // 4. 贴纸边缘微妙的暗线(模拟贴纸厚度) ctx.beginPath(); ctx.moveTo(x + radius, y); ctx.lineTo(x + w - radius, y); ctx.quadraticCurveTo(x + w, y, x + w, y + radius); ctx.lineTo(x + w, y + h - radius); ctx.quadraticCurveTo(x + w, y + h, x + w - radius, y + h); ctx.lineTo(x + radius, y + h); ctx.quadraticCurveTo(x, y + h, x, y + h - radius); ctx.lineTo(x, y + radius); ctx.quadraticCurveTo(x, y, x + radius, y); ctx.closePath(); ctx.strokeStyle = 'rgba(0,0,0,0.18)'; ctx.lineWidth = 2.5; ctx.stroke(); const texture = new THREE.CanvasTexture(canvas); texture.colorSpace = THREE.SRGBColorSpace; texture.minFilter = THREE.LinearMipmapLinearFilter; texture.magFilter = THREE.LinearFilter; texture.generateMipmaps = true; return texture; } // 预生成6种颜色的贴纸纹理(缓存复用) const stickerTextureCache = {}; for (const [key, colorHex] of Object.entries(STICKER_COLORS)) { stickerTextureCache[key] = createStickerTexture(colorHex); } // 塑料面材质(无贴纸,纯黑) const plasticMaterial = new THREE.MeshStandardMaterial({ color: 0x1a1a1a, roughness: 0.55, metalness: 0.08, }); // ==================== 构建魔方 ==================== /** * 所有27个小方块的引用数组 * @type {THREE.Mesh[]} */ const allCubies = []; /** * 每个cubie的初始状态(用于Reset) * @type {Map<THREE.Mesh, {position: THREE.Vector3, rotation: THREE.Euler}>} */ const initialStates = new Map(); /** * 根据cubie的初始格点位置判断某个面是否外露 * @param {number} gridX - 格点X坐标 (-1, 0, 1) * @param {number} gridY - 格点Y坐标 (-1, 0, 1) * @param {number} gridZ - 格点Z坐标 (-1, 0, 1) * @returns {Object} 6个面是否外露的布尔映射 */ function getExposedFaces(gridX, gridY, gridZ) { return { posX: Math.abs(gridX - 1) < 0.01, // +X面外露(右面,红) negX: Math.abs(gridX + 1) < 0.01, // -X面外露(左面,橙) posY: Math.abs(gridY - 1) < 0.01, // +Y面外露(顶面,白) negY: Math.abs(gridY + 1) < 0.01, // -Y面外露(底面,黄) posZ: Math.abs(gridZ - 1) < 0.01, // +Z面外露(前面,绿) negZ: Math.abs(gridZ + 1) < 0.01, // -Z面外露(后面,蓝) }; } /** * 为单个cubie创建6个面的材质数组 * BoxGeometry的面顺序:+X(0), -X(1), +Y(2), -Y(3), +Z(4), -Z(5) */ function createCubieMaterials(gridX, gridY, gridZ) { const exposed = getExposedFaces(gridX, gridY, gridZ); const faceConfigs = [ { exposed: exposed.posX, stickerKey: 'right' }, // +X → 右面红 { exposed: exposed.negX, stickerKey: 'left' }, // -X → 左面橙 { exposed: exposed.posY, stickerKey: 'top' }, // +Y → 顶面白 { exposed: exposed.negY, stickerKey: 'bottom' }, // -Y → 底面黄 { exposed: exposed.posZ, stickerKey: 'front' }, // +Z → 前面绿 { exposed: exposed.negZ, stickerKey: 'back' }, // -Z → 后面蓝 ]; return faceConfigs.map((config) => { if (config.exposed) { const tex = stickerTextureCache[config.stickerKey]; return new THREE.MeshStandardMaterial({ map: tex, roughness: 0.32, metalness: 0.02, color: 0xffffff, }); } else { return plasticMaterial.clone(); } }); } // 创建27个cubie const cubieGroup = new THREE.Group(); // 用于组织所有cubie cubieGroup.name = 'cubieGroup'; scene.add(cubieGroup); for (let gx = -1; gx <= 1; gx++) { for (let gy = -1; gy <= 1; gy++) { for (let gz = -1; gz <= 1; gz++) { const geo = new THREE.BoxGeometry(CUBIE_SIZE, CUBIE_SIZE, CUBIE_SIZE); const materials = createCubieMaterials(gx, gy, gz); const mesh = new THREE.Mesh(geo, materials); mesh.position.set(gx * GRID_SPACING, gy * GRID_SPACING, gz * GRID_SPACING); mesh.rotation.set(0, 0, 0); mesh.castShadow = true; mesh.receiveShadow = true; mesh.name = `cubie_${gx}_${gy}_${gz}`; // 存储初始格点坐标(用于调试和初始状态判断) mesh.userData = { initialGrid: { x: gx, y: gy, z: gz }, }; cubieGroup.add(mesh); allCubies.push(mesh); initialStates.set(mesh, { position: mesh.position.clone(), rotation: mesh.rotation.clone(), }); } } } // ==================== 交互状态机 ==================== const InteractionState = Object.freeze({ IDLE: 'idle', DRAGGING: 'dragging', ANIMATING: 'animating', SCRAMBLING: 'scrambling', }); let interactionState = InteractionState.IDLE; let activePivot = null; // 当前旋转轴心(THREE.Group) let activeAxisWorld = null; // 当前旋转轴(世界空间Vector3) let activeLayerValue = null; // 当前旋转层的坐标值 let activeAxisIndex = null; // 轴索引:0=X, 1=Y, 2=Z let dragStartNDC = null; // 鼠标按下时的NDC坐标 let projectedAxisScreen = null; // 投影到屏幕空间的轴方向(归一化Vector2) let currentDragAngle = 0; // 当前拖拽累积角度 let selectedCubies = []; // 当前选中的cubie列表 // ==================== 工具函数 ==================== /** * 将3D世界坐标投影到NDC空间 */ function worldToNDC(worldPos) { const ndc = worldPos.clone().project(camera); return new THREE.Vector2(ndc.x, ndc.y); } /** * 获取鼠标事件的NDC坐标 */ function mouseToNDC(event) { return new THREE.Vector2( (event.clientX / window.innerWidth) * 2 - 1, -(event.clientY / window.innerHeight) * 2 + 1 ); } /** * 将3D世界轴向量投影到屏幕空间,返回归一化的2D方向 * @param {THREE.Vector3} worldAxis - 世界空间中的轴向量(如(1,0,0)) * @param {THREE.Vector3} referencePoint - 参考点(用于投影) * @returns {THREE.Vector2} 屏幕空间中的归一化方向 */ function projectAxisToScreen(worldAxis, referencePoint) { const p1 = worldToNDC(referencePoint); const p2 = worldToNDC(referencePoint.clone().add(worldAxis)); const dir = new THREE.Vector2(p2.x - p1.x, p2.y - p1.y); const len = dir.length(); if (len < 1e-9) return new THREE.Vector2(1, 0); // 退化情况 return dir.normalize(); } /** * 坐标清洗:消除浮点数累积误差 * - position 四舍五入到整数 * - rotation 欧拉角四舍五入到最接近的 π/2 倍数 */ function snapCubieTransform(cubie) { // 清洗位置 cubie.position.x = Math.round(cubie.position.x); cubie.position.y = Math.round(cubie.position.y); cubie.position.z = Math.round(cubie.position.z); // 清洗旋转(欧拉角 → 最接近的 π/2 倍数) const halfPi = Math.PI / 2; cubie.rotation.x = Math.round(cubie.rotation.x / halfPi) * halfPi; cubie.rotation.y = Math.round(cubie.rotation.y / halfPi) * halfPi; cubie.rotation.z = Math.round(cubie.rotation.z / halfPi) * halfPi; } /** * 对所有cubie执行坐标清洗 */ function snapAllCubies() { allCubies.forEach(snapCubieTransform); } /** * 动态层级筛选:根据世界坐标和轴索引,找出属于同一旋转层的所有cubie * @param {number} axisIndex - 轴索引 0=X, 1=Y, 2=Z * @param {number} layerValue - 该层的坐标值 * @returns {THREE.Mesh[]} */ function getCubiesInLayer(axisIndex, layerValue) { const result = []; const axisKey = ['x', 'y', 'z'][axisIndex]; for (const cubie of allCubies) { // 获取cubie在世界空间中的位置 const worldPos = new THREE.Vector3(); cubie.getWorldPosition(worldPos); if (Math.abs(worldPos[axisKey] - layerValue) < EPSILON) { result.push(cubie); } } return result; } /** * 获取cubie当前世界坐标在指定轴上的值 */ function getCubieWorldAxisValue(cubie, axisIndex) { const worldPos = new THREE.Vector3(); cubie.getWorldPosition(worldPos); return ['x', 'y', 'z'][axisIndex] === 'x' ? worldPos.x : ['x', 'y', 'z'][axisIndex] === 'y' ? worldPos.y : worldPos.z; } // ==================== Pivot 旋转机制 ==================== /** * 创建轴心对象并挂载选中的cubie * @param {THREE.Mesh[]} cubies - 要挂载的cubie列表 * @returns {THREE.Group} pivot */ function createPivotAndAttach(cubies) { const pivot = new THREE.Group(); pivot.name = 'rotationPivot'; // Pivot放在世界原点,旋转轴通过原点 scene.add(pivot); for (const cubie of cubies) { // pivot.attach() 保持世界变换,将cubie挂载到pivot下 pivot.attach(cubie); } return pivot; } /** * 释放pivot:将所有cubie放回场景,然后移除pivot * @param {THREE.Group} pivot */ function releasePivot(pivot) { const children = [...pivot.children]; // 复制数组(遍历时会被修改) for (const cubie of children) { // scene.attach() 保持世界变换,将cubie放回场景 scene.attach(cubie); // 放回cubieGroup以保持组织结构 cubieGroup.attach(cubie); } scene.remove(pivot); if (pivot.geometry) pivot.geometry.dispose(); if (pivot.material) { if (Array.isArray(pivot.material)) { pivot.material.forEach(m => m.dispose()); } else { pivot.material.dispose(); } } } /** * 执行完整的层旋转(带磁吸动画) * @param {THREE.Group} pivot * @param {THREE.Vector3} axisWorld - 世界空间旋转轴 * @param {number} targetAngle - 目标角度(弧度) * @param {number} duration - 动画时长(ms) * @returns {Promise<void>} */ function animatePivotToTarget(pivot, axisWorld, targetAngle, duration) { return new Promise((resolve) => { // 获取pivot当前绕该轴的角度 const axisKey = ['x', 'y', 'z'][activeAxisIndex]; const startAngle = pivot.rotation[axisKey]; // 使用Tween.js const tweenData = { angle: startAngle }; const tween = new TWEEN.Tween(tweenData) .to({ angle: targetAngle }, duration) .easing(TWEEN.Easing.Cubic.Out) .onUpdate(() => { pivot.rotation[axisKey] = tweenData.angle; }) .onComplete(() => { pivot.rotation[axisKey] = targetAngle; resolve(); }) .start(); }); } // ==================== 手势投影算法(核心考点) ==================== /** * 根据面法线确定两个潜在旋转轴 * 原理:用户可以绕与法线垂直的任意轴旋转 * @param {THREE.Vector3} worldNormal - 世界空间中的面法线 * @returns {{axisA: THREE.Vector3, axisB: THREE.Vector3, indexA: number, indexB: number}} */ function getPotentialAxes(worldNormal) { const absX = Math.abs(worldNormal.x); const absY = Math.abs(worldNormal.y); const absZ = Math.abs(worldNormal.z); // 法线的主要分量决定了两个潜在旋转轴 if (absX >= absY && absX >= absZ) { // 法线接近X轴 → 潜在旋转轴为Y和Z return { axisA: new THREE.Vector3(0, 1, 0), axisB: new THREE.Vector3(0, 0, 1), indexA: 1, indexB: 2, }; } else if (absY >= absX && absY >= absZ) { // 法线接近Y轴 → 潜在旋转轴为X和Z return { axisA: new THREE.Vector3(1, 0, 0), axisB: new THREE.Vector3(0, 0, 1), indexA: 0, indexB: 2, }; } else { // 法线接近Z轴 → 潜在旋转轴为X和Y return { axisA: new THREE.Vector3(1, 0, 0), axisB: new THREE.Vector3(0, 1, 0), indexA: 0, indexB: 1, }; } } /** * 计算鼠标滑动向量与两个投影轴的点积,选择匹配度最高的轴 * @param {THREE.Vector2} dragVector - 鼠标滑动2D向量(NDC空间) * @param {THREE.Vector2} projA - 轴A在屏幕空间的投影方向 * @param {THREE.Vector2} projB - 轴B在屏幕空间的投影方向 * @returns {{chosenIndex: number, dotProduct: number, chosenProj: THREE.Vector2}} */ function selectBestAxis(dragVector, projA, projB, indexA, indexB) { const dotA = Math.abs(dragVector.dot(projA)); const dotB = Math.abs(dragVector.dot(projB)); if (dotA >= dotB) { return { chosenIndex: indexA, dotProduct: dragVector.dot(projA), chosenProj: projA, }; } else { return { chosenIndex: indexB, dotProduct: dragVector.dot(projB), chosenProj: projB, }; } } // ==================== 鼠标事件处理 ==================== let mouseDownWorldPoint = null; // 鼠标按下时的3D交点 let hasMovedSignificantly = false; // 是否产生了有效拖拽 const MIN_DRAG_THRESHOLD_NDC = 0.015; // 最小拖拽阈值(NDC单位) canvas.addEventListener('pointerdown', (event) => { // 仅处理左键(button === 0) if (event.button !== 0) return; // 非空闲状态不响应 if (interactionState !== InteractionState.IDLE) return; // 射线检测 const ndc = mouseToNDC(event); const raycaster = new THREE.Raycaster(); raycaster.setFromCamera(new THREE.Vector2(ndc.x, ndc.y), camera); const intersects = raycaster.intersectObjects(allCubies, false); if (intersects.length === 0) return; // 未命中魔方 const intersect = intersects[0]; const clickedCubie = intersect.object; const faceNormalLocal = intersect.face.normal.clone(); // 将面法线转换到世界空间 const worldNormal = faceNormalLocal.transformDirection(clickedCubie.matrixWorld).round(); // 获取交点世界位置 mouseDownWorldPoint = intersect.point.clone(); // 【手势投影算法】根据法线确定两个潜在旋转轴 const { axisA, axisB, indexA, indexB } = getPotentialAxes(worldNormal); // 将两个3D轴投影到屏幕空间 const projA = projectAxisToScreen(axisA, mouseDownWorldPoint); const projB = projectAxisToScreen(axisB, mouseDownWorldPoint); // 存储以备mousemove使用(此时尚未决定选哪个轴) dragStartNDC = ndc; hasMovedSignificantly = false; currentDragAngle = 0; selectedCubies = []; activePivot = null; activeAxisWorld = null; activeLayerValue = null; activeAxisIndex = null; projectedAxisScreen = null; // 暂存潜在轴信息 canvas._gestureData = { axisA, axisB, indexA, indexB, projA, projB, clickedCubie, worldNormal, }; interactionState = InteractionState.DRAGGING; container.classList.add('grabbing'); controls.enabled = false; // 拖拽期间禁用OrbitControls hintTag.style.opacity = '0.4'; }); canvas.addEventListener('pointermove', (event) => { if (interactionState !== InteractionState.DRAGGING) return; if (!canvas._gestureData) return; const currentNDC = mouseToNDC(event); const dragVector = new THREE.Vector2( currentNDC.x - dragStartNDC.x, currentNDC.y - dragStartNDC.y ); const dragLength = dragVector.length(); // 检查是否超过最小阈值 if (!hasMovedSignificantly && dragLength < MIN_DRAG_THRESHOLD_NDC) { return; // 微小移动,忽略 } const gd = canvas._gestureData; if (!hasMovedSignificantly) { // 首次显著移动:选择最佳旋转轴 hasMovedSignificantly = true; const selection = selectBestAxis(dragVector, gd.projA, gd.projB, gd.indexA, gd.indexB); activeAxisIndex = selection.chosenIndex; const rawDot = selection.dotProduct; // 确定世界旋转轴 const axisVectors = [ new THREE.Vector3(1, 0, 0), new THREE.Vector3(0, 1, 0), new THREE.Vector3(0, 0, 1), ]; activeAxisWorld = axisVectors[activeAxisIndex].clone(); projectedAxisScreen = selection.chosenProj.clone(); // 动态层级筛选:根据被点击cubie的世界坐标确定旋转层 const clickedCubie = gd.clickedCubie; const worldPos = new THREE.Vector3(); clickedCubie.getWorldPosition(worldPos); const axisKey = ['x', 'y', 'z'][activeAxisIndex]; activeLayerValue = Math.round(worldPos[axisKey]); // 筛选同一层的所有cubie selectedCubies = getCubiesInLayer(activeAxisIndex, activeLayerValue); // 创建Pivot并挂载选中的cubie activePivot = createPivotAndAttach(selectedCubies); activePivot.rotation.set(0, 0, 0); currentDragAngle = 0; // 更新gestureData gd._rawDotSign = rawDot; } // 计算旋转角度:鼠标滑动向量在投影轴上的投影(带符号) const projectionOnAxis = dragVector.dot(projectedAxisScreen); // 转换为弧度(1 NDC ≈ π 弧度 ≈ 180°) const angle = projectionOnAxis * ANGLE_PER_NDC; // 符号修正:确保"向右滑=向右转"的视觉逻辑 // 使用叉乘判断:dragVector × projectedAxisScreen 的符号决定旋转方向 const crossZ = dragVector.x * projectedAxisScreen.y - dragVector.y * projectedAxisScreen.x; const signCorrection = crossZ >= 0 ? 1 : -1; const correctedAngle = Math.abs(angle) * signCorrection; currentDragAngle = correctedAngle; // 实时更新pivot旋转(1:1跟手) const axisKey = ['x', 'y', 'z'][activeAxisIndex]; activePivot.rotation.set(0, 0, 0); activePivot.rotation[axisKey] = correctedAngle; }); window.addEventListener('pointerup', async (event) => { if (interactionState !== InteractionState.DRAGGING) return; container.classList.remove('grabbing'); hintTag.style.opacity = '1'; if (!hasMovedSignificantly || !activePivot || selectedCubies.length === 0) { // 无有效拖拽:清理 if (activePivot) { releasePivot(activePivot); } cleanupDragState(); controls.enabled = true; return; } // 【磁吸效果】:计算最近的90度倍数 const halfPi = Math.PI / 2; const rawAngle = currentDragAngle; const targetAngle = Math.round(rawAngle / halfPi) * halfPi; // 如果目标角度为0(即回到原位),直接释放 if (Math.abs(targetAngle) < 0.001) { releasePivot(activePivot); snapAllCubies(); cleanupDragState(); controls.enabled = true; return; } // 执行磁吸动画 interactionState = InteractionState.ANIMATING; btnScramble.disabled = true; btnReset.disabled = true; const pivotRef = activePivot; const axisRef = activeAxisWorld; const cubiesRef = selectedCubies; await animatePivotToTarget(pivotRef, axisRef, targetAngle, MAGNETIC_DURATION); // 动画完成:释放cubie回场景 releasePivot(pivotRef); // 【坐标清洗】:消除浮点数累积误差 snapAllCubies(); cleanupDragState(); controls.enabled = true; btnScramble.disabled = false; btnReset.disabled = false; interactionState = InteractionState.IDLE; }); /** * 清理拖拽状态 */ function cleanupDragState() { activePivot = null; activeAxisWorld = null; activeLayerValue = null; activeAxisIndex = null; dragStartNDC = null; projectedAxisScreen = null; currentDragAngle = 0; selectedCubies = []; hasMovedSignificantly = false; mouseDownWorldPoint = null; delete canvas._gestureData; if (interactionState === InteractionState.DRAGGING) { interactionState = InteractionState.IDLE; } container.classList.remove('grabbing'); } // 防止右键菜单弹出(在canvas上) canvas.addEventListener('contextmenu', (event) => { event.preventDefault(); }); // ==================== Scramble(打乱) ==================== /** * 执行打乱序列 * 随机选择层和轴,执行一系列90度旋转 */ async function scramble() { if (interactionState !== InteractionState.IDLE) return; interactionState = InteractionState.SCRAMBLING; btnScramble.disabled = true; btnReset.disabled = true; controls.enabled = false; hintTag.textContent = '🔀 正在打乱...'; hintTag.style.opacity = '1'; const axisVectors = [ new THREE.Vector3(1, 0, 0), // X轴 new THREE.Vector3(0, 1, 0), // Y轴 new THREE.Vector3(0, 0, 1), // Z轴 ]; const layerValues = [-1, 0, 1]; // 三层 const angleOptions = [-Math.PI / 2, Math.PI / 2]; // ±90° // 生成随机打乱序列(避免连续同轴旋转) const steps = []; let lastAxisIndex = -1; for (let i = 0; i < SCRAMBLE_STEPS; i++) { let axisIndex; do { axisIndex = Math.floor(Math.random() * 3); } while (axisIndex === lastAxisIndex && SCRAMBLE_STEPS > 3); lastAxisIndex = axisIndex; const layerValue = layerValues[Math.floor(Math.random() * 3)]; const angle = angleOptions[Math.floor(Math.random() * 2)]; steps.push({ axisIndex, layerValue, angle }); } for (let i = 0; i < steps.length; i++) { const { axisIndex, layerValue, angle } = steps[i]; const cubies = getCubiesInLayer(axisIndex, layerValue); if (cubies.length === 0) continue; const pivot = createPivotAndAttach(cubies); const axisKey = ['x', 'y', 'z'][axisIndex]; pivot.rotation.set(0, 0, 0); await animatePivotToTarget(pivot, axisVectors[axisIndex], angle, SCRAMBLE_STEP_DURATION); releasePivot(pivot); snapAllCubies(); // 小延迟让动画呼吸 if (i < steps.length - 1) { await new Promise(r => setTimeout(r, 40)); } } snapAllCubies(); controls.enabled = true; btnScramble.disabled = false; btnReset.disabled = false; interactionState = InteractionState.IDLE; hintTag.textContent = '🖱️ 左键拖拽旋转层 | 右键拖拽旋转视角 | 滚轮缩放'; hintTag.style.opacity = '1'; } // ==================== Reset(重置) ==================== /** * 重置所有cubie到初始状态(使用动画平滑过渡) */ async function resetCube() { if (interactionState !== InteractionState.IDLE) return; interactionState = InteractionState.ANIMATING; btnScramble.disabled = true; btnReset.disabled = true; controls.enabled = false; hintTag.textContent = '↺ 正在重置...'; hintTag.style.opacity = '1'; // 收集所有需要动画的cubie及其目标状态 const animations = []; for (const cubie of allCubies) { const initState = initialStates.get(cubie); if (!initState) continue; const targetPos = initState.position.clone(); const targetRot = initState.rotation.clone(); // 如果当前位置/旋转与目标相同,跳过 const posDist = cubie.position.distanceTo(targetPos); const rotDist = Math.abs(cubie.rotation.x - targetRot.x) + Math.abs(cubie.rotation.y - targetRot.y) + Math.abs(cubie.rotation.z - targetRot.z); if (posDist < 0.001 && rotDist < 0.001) continue; animations.push({ cubie, startPos: cubie.position.clone(), targetPos, startRot: { x: cubie.rotation.x, y: cubie.rotation.y, z: cubie.rotation.z, }, targetRot: { x: targetRot.x, y: targetRot.y, z: targetRot.z, }, }); } if (animations.length === 0) { // 无需动画 snapAllCubies(); finishReset(); return; } // 使用Tween并行动画所有cubie const tweenData = { progress: 0 }; const duration = 400; const tween = new TWEEN.Tween(tweenData) .to({ progress: 1 }, duration) .easing(TWEEN.Easing.Cubic.InOut) .onUpdate(() => { const t = tweenData.progress; for (const anim of animations) { anim.cubie.position.lerpVectors(anim.startPos, anim.targetPos, t); anim.cubie.rotation.x = anim.startRot.x + (anim.targetRot.x - anim.startRot.x) * t; anim.cubie.rotation.y = anim.startRot.y + (anim.targetRot.y - anim.startRot.y) * t; anim.cubie.rotation.z = anim.startRot.z + (anim.targetRot.z - anim.startRot.z) * t; } }) .onComplete(() => { for (const anim of animations) { anim.cubie.position.copy(anim.targetPos); anim.cubie.rotation.set(anim.targetRot.x, anim.targetRot.y, anim.targetRot.z); } snapAllCubies(); finishReset(); }) .start(); // 等待tween完成 await new Promise(resolve => { const check = setInterval(() => { if (tweenData.progress >= 1) { clearInterval(check); resolve(); } }, 50); // 安全超时 setTimeout(() => { clearInterval(check); resolve(); }, duration + 200); }); } function finishReset() { snapAllCubies(); controls.enabled = true; btnScramble.disabled = false; btnReset.disabled = false; interactionState = InteractionState.IDLE; hintTag.textContent = '🖱️ 左键拖拽旋转层 | 右键拖拽旋转视角 | 滚轮缩放'; hintTag.style.opacity = '1'; } // ==================== 按钮事件 ==================== btnScramble.addEventListener('click', () => { if (interactionState === InteractionState.IDLE) { scramble(); } }); btnReset.addEventListener('click', () => { if (interactionState === InteractionState.IDLE) { resetCube(); } }); // 键盘快捷键 window.addEventListener('keydown', (event) => { if (event.key === 's' || event.key === 'S') { if (interactionState === InteractionState.IDLE) scramble(); } if (event.key === 'r' || event.key === 'R') { if (interactionState === InteractionState.IDLE) resetCube(); } }); // ==================== 窗口大小适配 ==================== window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); // ==================== 渲染循环 ==================== function animate(timestamp) { requestAnimationFrame(animate); // 更新Tween动画 TWEEN.update(timestamp); // 更新OrbitControls(仅在非拖拽/非动画状态) if (interactionState === InteractionState.IDLE) { controls.enabled = true; controls.update(); } else if (interactionState === InteractionState.DRAGGING) { controls.enabled = false; } // 渲染 renderer.render(scene, camera); } // ==================== 启动 ==================== console.log('🧊 3x3 魔方已就绪'); console.log(' - 左键拖拽:手势旋转层(投影向量匹配算法)'); console.log(' - 右键拖拽:OrbitControls 旋转视角'); console.log(' - 滚轮:缩放'); console.log(' - 按钮/快捷键 S=打乱 R=重置'); console.log(' - Pivot挂载机制 + 坐标清洗 + 磁吸效果'); console.log(' - 物理间隙:', GAP.toFixed(2), '单位'); console.log(' - 倒角贴纸:Canvas程序化生成圆角矩形纹理'); requestAnimationFrame(animate); </script> </body> </html> 1 个帖子 - 1 位参与者 阅读完整话题