用 Codex 修改项目时,有一种问题特别容易让人困惑:

本地明明已经测试通过,代码一提交到 CI,却又失败了。

常见情况包括:

  • 本地 npm test 全部通过,CI却报错;

  • 本地能正常构建,GitHub Actions里却失败;

  • Windows电脑没问题,Linux环境直接报错;

  • Codex已经修好代码,但CI提示依赖版本不一致;

  • 本地环境变量齐全,CI里却提示变量不存在;

  • 同一份代码,本地和云端得到完全不同的结果。

遇到这种情况,不一定是 Codex 又把代码改错了。

更常见的原因其实是:

本地环境和CI环境不是同一个环境。

所以排查重点不要只盯着代码本身。

更应该先比较:

版本、依赖、环境变量、操作系统和执行命令。


一、先确认CI失败的具体阶段

看到CI红了以后,先不要直接告诉Codex:

CI失败了,继续修。

因为一次CI流程可能包含很多阶段:

安装依赖
↓
Lint
↓
类型检查
↓
Build
↓
单元测试
↓
集成测试
↓
打包

如果连依赖都没装成功,继续改业务代码没有意义。

第一步应该先看:

到底是哪一步第一次失败。

例如:

npm install 失败

和:

npm test 失败

完全是两个不同问题。

所以可以先让Codex只做分析:

先不要修改代码。

请分析CI日志中第一个真正失败的位置,
判断属于依赖、构建、测试还是环境配置问题。

找到第一个失败点,比盯着最后一行错误更重要。


二、本地和CI使用的Node或Python版本可能不一样

这是非常常见的原因。

例如本地使用:

Node.js 22

但CI配置还是:

Node.js 20

你本地使用的新API,在旧版本环境里可能根本不存在。

Python项目也是一样。

例如:

本地:Python 3.12
CI:Python 3.10

某些语法、依赖和标准库行为就可能出现差异。

所以遇到“本地过、CI挂”,建议先检查:

本地运行时版本
CI运行时版本
项目声明版本

最好让三者保持一致。

如果项目里已经有:

.nvmrc
.node-version
.python-version

或者 CI 配置中明确写了版本,就应该优先对齐。


三、依赖锁文件有没有一起提交

Codex修改项目时,有时候会新增或者升级依赖。

本地执行完:

npm install

项目可以正常运行。

但如果只提交了:

package.json

却漏掉:

package-lock.json

或者:

pnpm-lock.yaml
yarn.lock

CI重新安装依赖时,拿到的具体版本就可能和本地不一样。

结果就是:

你本地测试的是A版本,CI实际装的是B版本。

所以看到CI依赖相关错误时,优先检查:

git status

看看锁文件是不是有变化却没有提交。

尤其是Codex修改 package.json 后,一定要顺手确认锁文件。


四、本地node_modules可能掩盖了问题

这是一个很隐蔽的情况。

你的电脑可能已经使用这个项目半年了。

node_modules 里存在很多历史安装留下来的依赖。

于是即使:

package.json

里漏掉了某个包,本地仍然可能正常运行。

但CI通常会从一个干净环境重新安装。

它只认:

项目真正声明的依赖。

于是出现:

Cannot find module

或者:

Module not found

这种情况下,本地“能跑”并不能证明项目依赖是完整的。

可以尝试用更接近CI的方式验证:

rm -rf node_modules
npm ci

然后重新:

npm test
npm run build

如果干净安装以后本地也失败,就说明之前是旧环境把问题隐藏了。


五、CI更推荐使用锁定依赖的安装方式

Node项目里,本地开发经常使用:

npm install

但CI通常更适合:

npm ci

因为 npm ci 会更严格地按照锁文件安装。

这样能减少:

今天CI装一套版本,明天又装另一套。

如果使用 pnpm 或 yarn,也应该确保CI按照项目已有锁文件执行固定安装。

核心思路就是:

CI环境应该尽量可重复。

不然同一份代码每次安装出来的依赖都可能不同。


六、环境变量是另一个高频原因

本地项目可能有:

.env
.env.local

里面包含:

DATABASE_URL
API_KEY
JWT_SECRET

所以本地运行没有问题。

但这些文件通常不会提交到Git。

CI环境里如果没有单独配置,就会直接报:

environment variable not found

或者应用启动以后出现:

undefined

所以可以先让Codex检查:

当前代码运行至少依赖哪些环境变量,只列变量名,不要输出真实密钥。

然后和CI里的Secret或环境变量配置逐项核对。

重点是:

不要为了修CI,把真实密钥直接写进代码或提交到仓库。

正确做法应该是补CI配置,而不是把敏感值硬编码进去。


七、Windows和Linux的文件大小写差异很容易踩坑

很多开发者本地使用Windows。

Windows某些文件系统对文件名大小写并不敏感。

例如文件真实名称是:

UserService.ts

代码却写成:

import "./userservice"

本地可能还能运行。

但CI通常使用Linux。

Linux会严格区分:

UserService.ts
userservice.ts

于是直接报找不到文件。

这种问题特别容易出现在:

  • 重命名文件;

  • Git提交;

  • import路径;

  • 大小写混用。

所以出现:

Module not found

但本地明明存在文件时,要重点检查文件名大小写。


八、路径分隔符也可能造成平台差异

还有一种情况是代码里直接写:

src\config\app.json

这更偏Windows路径。

到了Linux CI里,可能出现异常。

更稳定的方式通常是使用语言或框架提供的路径处理工具。

例如Node.js里的:

path.join()

而不是手动拼接:

\

或者:

/

如果Codex修改了文件路径逻辑,而本地测试通过、CI失败,就应该检查:

是不是写死了操作系统相关路径。


九、本地和CI执行的命令可能根本不一样

这也是非常容易忽略的一点。

你本地测试可能只执行:

npm test

但CI实际上执行:

npm run lint
npm run typecheck
npm run build
npm test

于是本地看起来一切正常。

CI却在:

typecheck

阶段就挂了。

所以真正要模拟CI,不是只运行你平时最常用的命令。

而应该打开CI配置,看看它到底执行了什么。

然后在本地尽量按同样顺序执行:

安装
↓
Lint
↓
类型检查
↓
Build
↓
测试

这样很多问题可以在提交前直接发现。


十、测试数据和数据库环境也可能不同

如果项目包含集成测试,CI里经常使用:

独立数据库;

临时容器;

测试数据库;

Mock服务。

而本地可能直接连接:

开发数据库。

这就可能造成:

本地有某条测试数据;

CI没有;

本地数据库已经手动初始化;

CI数据库还是空的。

于是同一条测试,本地通过,CI失败。

这种情况下,要检查:

  • Migration有没有执行;

  • Seed数据是否一致;

  • 测试是否依赖固定数据;

  • 数据库版本是否相同;

  • 测试有没有正确清理状态。

真正稳定的测试应该尽量:

自己准备数据,自己执行,自己清理。

而不是依赖“我本地刚好有这条数据”。


十一、缓存会让CI问题变得更难判断

很多CI系统会缓存:

依赖;

构建产物;

工具链。

缓存能明显加速流程,但也可能带来一个问题:

旧缓存和新代码不兼容。

例如升级了依赖,但CI仍然恢复旧缓存。

结果出现非常奇怪的报错。

如果CI错误和代码完全对不上,或者:

重新运行偶尔成功;

某次升级后持续异常;

可以尝试检查缓存Key或者临时禁用缓存做一次对照。

但不要一看到CI失败就先清缓存。

缓存应该属于后面的排查项,而不是第一步。


十二、不要为了CI变绿直接修改测试

这点和本地调试一样重要。

假设:

本地测试通过;

CI某个测试失败。

不要第一反应就让Codex:

把这个CI测试修到通过。

因为真正的问题可能是:

环境不同;

版本不同;

时区不同;

路径不同;

测试数据不同。

如果直接改测试预期,就可能把真正的问题掩盖掉。

更好的方式是:

先比较本地和CI环境差异,
不要修改测试预期。

找出为什么同一个测试在两个环境结果不同。

先解释差异,再决定要不要改代码。


十三、时区也是非常容易被忽略的差异

比如本地电脑是:

Asia/Shanghai

CI环境可能使用:

UTC

如果测试里涉及:

日期;

凌晨;

时间戳;

过期时间;

当天数据;

就可能出现:

本地全部通过,CI固定失败。

例如:

new Date()

在不同环境下得到的日期边界可能不一样。

所以只要CI失败和时间相关,就应该检查:

是不是时区差异。

长期来说,服务端逻辑最好尽量明确使用统一时区或UTC。


十四、让Codex先做“环境对比”,不要急着改

遇到本地过、CI挂,可以直接用这种任务:

当前情况:

本地:
Node 22
npm 10
测试全部通过

CI:
Node 20
npm 10
Build失败

要求:
1. 暂时不要修改代码;
2. 比较本地与CI运行环境;
3. 找出所有可能产生行为差异的地方;
4. 先给出最高概率原因;
5. 确认后再修改。

这样Codex会先从环境差异出发。

比直接:

CI又失败了,修一下。

更容易找到真正根因。


十五、一个稳定的CI失败排查顺序

以后遇到这种问题,可以固定按下面顺序:

第一步:找到第一个失败步骤

不要只看最后一行日志。

第二步:对比运行时版本

Node、Python、Java等是否一致。

第三步:检查锁文件

确认依赖版本一致。

第四步:做一次干净安装

排除本地旧依赖干扰。

第五步:检查环境变量

确认CI配置完整。

第六步:检查系统差异

大小写、路径、时区。

第七步:本地执行CI同样命令

尽量复现。

第八步:最后再改代码

只有定位到真正问题以后才修改。

整个逻辑就是:

先复现环境差异,再处理代码差异。


最后

Codex本地测试通过,但CI失败,并不一定说明:

“AI这次又写错代码了。”

真正高频的问题反而是:

两个环境根本不一样。

可以优先检查六项:

运行时版本;

依赖锁文件;

环境变量;

操作系统差异;

测试命令;

测试数据。

真实项目里,本地“能运行”只代表第一步。

真正可靠的修改,应该能够在:

干净环境 + 固定依赖 + 标准构建 + 自动测试

下重复通过。

所以遇到CI报错以后,不要马上让Codex继续重写代码。

先问清楚一个更重要的问题:

“为什么同一份代码,在两个环境里的结果不一样?”

找到这个差异,通常比连续修改业务代码更有效。


持续更新 Codex、大模型开发与 AI 编程实战内容,更多技术内容欢迎搜索关注「仙逆GPT」。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐