ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ChatGPT充值后Codex写的代码风格不统一?用ESLint+Prettier+Ruff自动检查规则减少人工返工

ChatGPT充值后Codex写的代码风格不统一?用ESLint+Prettier+Ruff自动检查规则减少人工返工 1. Codex 生成代码风格漂移的真实场景与返工成本ChatGPT 充值后开始用 Codex 改项目前几个文件通常很顺等到一次任务涉及五六个文件时问题就冒出来了user.ts用双引号order.ts用单引号新函数叫fetchUserData旧代码里全是getUserInfo有的文件两空格缩进有的四空格。代码能跑测试也过但 Review 时你得逐行盯着引号和缩进看真正该关注的业务逻辑反而被淹没。这种风格漂移不是 Codex 不会写代码而是它在读取项目上下文时看到的就是一套自相矛盾的写法。项目里同时存在const getUser async () { return await request(/user) }和async function fetchUser() { return request(/user); }Codex 无法判断哪个才是团队标准于是每次生成都可能跟随当前打开文件或最近修改文件的风格差异越滚越大。更麻烦的是很多人的应对方式是在提示词里反复写“用两个空格缩进、单引号、不要分号”。短期有效但每次任务都要重复输入而且人工后续修改照样可能破坏格式。真正稳定的做法是把风格规则从提示词里拿出来交给专门工具执行JavaScript/TypeScript 用 ESLint PrettierPython 用 RuffGo 用 gofmt多语言项目在 CI 里统一跑检查。Codex 负责逻辑工具负责风格分工清晰返工自然下降。我试过在一个中型 Node 项目里只靠提示词约束两周后git diff里仍然混着大量引号和缩进变化换成 ESLint Prettier 提交前钩子之后风格类 Review 意见基本归零。下面把可复制的配置和验证动作完整拆开你可以直接照着落地。2. TaoToken 前置准备让 Codex 稳定调用模型完成批量修改风格检查工具解决的是“改完之后的统一”但 Codex 要能稳定地读文件、改文件、跑命令前提是模型调用链路本身不中断。如果你在 Codex 里配置的是官方直连遇到限流或网络波动时任务跑到一半失败生成的文件可能只改了一半风格检查反而会报出一堆半成品错误。这时候用 TaoToken 做 API 接入层会更省心。TaoToken 是一个面向开发者的模型 API 聚合服务官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 。它的作用是让你用统一的 Base URL 和 Key 调用多个模型Codex、Cline、Claude Code 这类工具都能接。对于本篇场景你需要的不是花哨功能而是稳定的模型响应让 Codex 能连续完成“读文件 → 改代码 → 跑 lint → 修复”这一整条链路。适合谁用已经在用 Codex 或准备把 Codex 接入日常开发流程、希望减少调用中断导致半成品文件的开发者。如果你只是偶尔让 Codex 改一个函数官方直连也够但一旦进入多文件批量修改稳定接入层的价值就体现出来了。接入步骤不复杂核心是三件套Base URL、API Key、Model ID。以 Codex 的auth.json配置为例你需要把这三项写对。先到 TaoToken 控制台创建 API Key地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 创建后复制 Key。然后配置 Codex 的auth.json路径通常在~/.codex/auth.jsonLinux/macOS或%USERPROFILE%\.codex\auth.jsonWindows。写入以下内容{ base_url: https://taotoken.net/api, api_key: sk-你的TaoToken密钥, model: gpt-4o }注意base_url不要加 UTM 参数API 调用地址就是https://taotoken.net/api。Model ID 根据你实际使用的模型填写比如gpt-4o、claude-3-5-sonnet等。如果你用的是 Cline 或 Claude Code配置方式类似都是在设置里填 Base URL、Key、Model ID 这三项。Cline 的 MCP 配置里如果涉及模型调用同样走这个 Base URL。配置完成后先做一次最小验证让 Codex 读取一个文件并输出内容。如果返回正常说明接入层通了。这一步很重要因为后面 ESLint、Prettier、Ruff 的批量检查都依赖 Codex 能稳定读写文件。如果这里就报 401 或连接失败先排查 Key 和 Base URL不要急着往下配 lint。3. 可复制配置ESLint Prettier Ruff 三件套落地这一节是全文的核心直接给可复制的配置片段。分 JavaScript/TypeScript 和 Python 两条线你可以按项目技术栈取用。3.1 JavaScript/TypeScriptESLint Prettier 配置先安装依赖。在项目根目录执行npm install --save-dev eslint prettier eslint-config-prettier eslint-plugin-prettier typescript-eslint/parser typescript-eslint/eslint-plugin然后创建.eslintrc.json{ root: true, parser: typescript-eslint/parser, plugins: [typescript-eslint, prettier], extends: [ eslint:recommended, plugin:typescript-eslint/recommended, prettier ], rules: { prettier/prettier: error, quotes: [error, single], semi: [error, never], indent: [error, 2], typescript-eslint/no-unused-vars: [error, { argsIgnorePattern: ^_ }], typescript-eslint/no-explicit-any: warn }, ignorePatterns: [dist/, node_modules/, coverage/] }创建.prettierrc{ singleQuote: true, semi: false, tabWidth: 2, trailingComma: es5, printWidth: 100, arrowParens: always }创建.prettierignoredist node_modules coverage *.min.js在package.json里加脚本{ scripts: { lint: eslint . --ext .ts,.tsx,.js,.jsx, lint:fix: eslint . --ext .ts,.tsx,.js,.jsx --fix, format: prettier . --write, format:check: prettier . --check, type-check: tsc --noEmit } }这套配置的关键点eslint-config-prettier关掉 ESLint 里和 Prettier 冲突的规则eslint-plugin-prettier把 Prettier 的格式问题当成 ESLint 错误报出来这样你只需要跑npm run lint就能同时拿到风格和质量问题。quotes、semi、indent三条规则直接对应 Codex 最容易漂移的三个点。3.2 PythonRuff 配置Ruff 的优势是一个工具同时做 lint 和 format配置量比 flake8 black isort 少很多。安装pip install ruff在pyproject.toml里加配置[tool.ruff] line-length 100 target-version py311 exclude [venv, .venv, __pycache__, build, dist] [tool.ruff.lint] select [E, F, I, N, UP, B, SIM] ignore [E501] [tool.ruff.lint.isort] known-first-party [app, src] [tool.ruff.format] quote-style double indent-style spaceselect里的含义E/F是 pycodestyle 和 pyflakes 基础规则I是导入排序N是命名规范UP是 pyupgrade 现代化建议B是 bugbear 常见陷阱SIM是简化建议。这套组合能覆盖 Codex 在 Python 里最常犯的导入顺序乱、未使用变量、命名不一致、可简化代码没处理等问题。常用命令ruff check . ruff format --check . ruff check . --fix ruff format .注意ruff format --check只检查不修改适合在提交前跑ruff format .才会真正改写文件。建议在 Codex 任务里只对当前改动目录执行比如ruff check app/service/避免一次格式化整个旧项目。3.3 把规范写进 AGENTS.md工具解决可执行规则AGENTS.md 补充项目特有约定。在项目根目录创建AGENTS.md# 代码规范 - TypeScript 不使用 any特殊情况必须说明原因 - 优先复用 src/utils 中的已有工具 - API 请求统一放在 src/api - 公共类型放在 src/types - 不在页面组件中直接拼接请求地址 - 新增函数必须使用清晰的业务命名 - 不进行与当前任务无关的全局格式化 # 完成前检查 - npm run lint - npm run type-check - npm run test这样 Codex 不仅知道怎么格式化还知道代码该放哪、能不能新增依赖、是否允许改公共模块。配合前面的 ESLint/Prettier/Ruff 配置风格约束就从“每次口头提醒”变成了“项目里写死的规则”。4. 验证请求与成功结果提交前自动拦截风格不一致代码配置写完不等于生效必须验证。这一节给你完整的验证动作和预期结果。4.1 手动验证 lint 和 format先故意写一段风格不一致的代码比如在src/test-style.ts里写const getUser async () { return await request(/user) }注意这里用了四空格缩进、双引号、有分号。然后跑npm run lint预期输出会报出prettier/prettier、quotes、semi、indent四类错误并指出具体行号。再跑npm run format:check预期输出Code style issues found in the above file。这说明检查生效了。接着跑npm run lint:fix和npm run format再跑一次format:check应该通过。Python 侧同理写一段导入顺序乱的代码跑ruff check .会报I001导入排序问题跑ruff format --check .会报格式问题。4.2 用 Git 钩子自动拦截手动跑容易忘用 husky lint-staged 在提交前自动拦截。安装npm install --save-dev husky lint-staged npx husky init在package.json加{ lint-staged: { *.{ts,tsx,js,jsx}: [eslint --fix, prettier --write], *.py: [ruff check --fix, ruff format] } }在.husky/pre-commit里写npx lint-staged这样每次git commit时只对暂存区的文件跑检查和修复。如果修复后仍有错误提交会被拦截。这一步是“把风格返工降到接近零”的关键因为不合格的代码根本进不了提交历史。4.3 让 Codex 输出检查结果在 AGENTS.md 里加一条要求让 Codex 每轮任务结束时按固定格式总结# 任务结束输出格式 本轮修改文件 1. src/api/user.ts 2. src/types/user.ts 已执行检查 - npm run lint通过 - npm run type-check通过 - npm run test通过 规范说明 - 未新增第三方依赖 - 未修改任务范围之外的文件 - 已复用现有 request 工具这种输出比“已经修改完成”有用得多Review 时一眼能看出改了哪些文件、跑了哪些检查、有没有越界。如果 Codex 说 lint 通过但你本地跑失败说明它可能没真正执行命令这时候要检查它的工具调用权限。4.4 验证 Git 差异范围每次 Codex 任务结束后跑git diff --stat git diff如果--stat显示改了 200 个文件但你的任务只涉及一个接口说明自动格式化扩大了范围。这时候不要直接提交先确认原因。常见原因是跑了全局prettier . --write或ruff format .把整个旧项目都格式化了。正确做法是只对改动目录执行比如prettier src/api --write。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth配置过程中最容易卡在接入层和工具链的报错上。这一节按真实报错逐个排查。5.1 401 Unauthorized现象Codex 调用模型时返回 401或者 Cline 里提示认证失败。排查顺序第一检查auth.json里的api_key是否完整复制有没有多余空格或换行。第二检查base_url是否写成https://taotoken.net/api不要带 UTM 参数也不要写成https://taotoken.net/api/v1除非文档明确要求。第三到 TaoToken 控制台确认 Key 是否过期或被删除。第四如果用的是环境变量确认变量名和 Codex 读取的一致。401 基本都是 Key 或 Base URL 的问题和 ESLint 配置无关。5.2 local proxy failed现象Codex 或 Cline 报local proxy failed或连接本地代理失败。这个报错通常和工具自身的代理设置有关。检查 Codex 配置里有没有残留的proxy字段如果有确认它指向的地址是否还在运行。如果你没有主动配代理把相关字段删掉让请求直连 Base URL。另外检查系统环境变量HTTP_PROXY、HTTPS_PROXY是否被其他软件设置过这些变量会干扰 Codex 的请求。清理后重启 Codex 再试。5.3 reading choices 报错现象调用模型后返回reading choices相关错误或者解析响应失败。这通常是响应格式和客户端预期不一致导致的。排查第一确认 Model ID 填写正确比如gpt-4o不要写成gpt4o或gpt-4。第二确认 Base URL 没有多余路径。第三如果用的是 Cline检查它的模型提供商设置里选的是 OpenAI Compatible 还是其他选错会导致解析失败。第四升级 Codex 或 Cline 到最新版本旧版本可能不兼容新的响应结构。5.4 OAuth 相关报错现象提示 OAuth 登录失败或 token 刷新失败。如果你用的是 Codex 的 OAuth 登录方式而不是 API Key遇到这个报错先确认登录态是否过期。重新执行登录流程或者改用 API Key 方式接入 TaoToken。API Key 方式不依赖 OAuth配置更直接适合自动化场景。如果你同时配了 OAuth 和 API Key确认工具优先读取的是哪一个避免冲突。5.5 lint 通过但 CI 失败现象本地npm run lint通过CI 上却报格式错误。排查第一确认 CI 和本地用的 Node 版本、依赖版本一致package-lock.json要提交。第二确认 CI 里跑的命令和本地一致比如本地跑eslint . --ext .tsCI 里不能只跑eslint .。第三检查.eslintignore和.prettierignore是否一致。第四如果 CI 用了缓存清缓存重跑。版本不一致是最常见原因。5.6 Ruff 和 ESLint 规则冲突多语言项目里如果 Python 和 JS 文件混在一个仓库确认 Ruff 只处理.pyESLint 只处理.ts/.js。在pyproject.toml的exclude里排除前端目录在.eslintrc.json的ignorePatterns里排除 Python 目录。否则两边互相报错排查起来很费时间。6. 语义一致 CTA把风格检查接入你的 Codex 工作流配置和排查都走通之后下一步是把它变成日常习惯。我的建议是每次让 Codex 开始任务前先在 AGENTS.md 里确认检查命令是最新的任务结束后先跑git diff --stat看范围再跑 lint 和 format check最后让 Codex 输出检查结果。这套流程跑顺之后风格类返工基本不会再出现。如果你还没配置 TaoToken 接入层可以从 API Key 开始到 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 创建 Key然后按本文第 2 节的auth.json配置写入 Base URL 和 Model ID。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有各客户端的详细配置说明。想先验证模型响应是否正常可以用模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 发一条测试消息。如果你打算长期用 Codex 做多文件批量修改和 Agent 任务Coding Plan 页面 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 有适合高频场景的方案说明。最后提醒一个实操细节不要一次性给旧项目跑全局格式化。先在一个小目录里验证 ESLint Prettier Ruff 的配置确认规则符合团队习惯再逐步扩大范围。格式化提交和功能提交分开Review 时才能看清哪些是逻辑改动、哪些是风格改动。风格检查工具的价值不是让代码变好看而是让 Review 只关注真正重要的东西。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进