Claude Code + Codex + Copilot 在同一项目里协作,我一个下午的实录


前三篇分别展示了每个工具单独用是什么体验。但真正干活的时候,从来不是"今天用这个、明天用那个"。

同一个需求里,你可能五分钟前在终端让 Claude Code 写接口,两分钟前在 VS Code 里让 Copilot 修了个细节,现在又开个 Codex 沙箱试一个不确定的库。

这篇用一整个下午的真实工作流,把三个工具串起来。


需求

公司的内部后台(Express + SQLite)管着几百条物料记录。老板说:“能不能导出成 CSV,然后自动发邮件给采购?”

这个需求可以拆成三块:

  1. CSV 导出——已有查询接口,加个格式转换就行
  2. 定时任务——每周五下午跑一次
  3. 邮件发送——用公司内部的 SMTP 服务

前两个没啥问题。第三个有点麻烦——公司的 SMTP 服务器配置很奇葩,需要走 TLS+STARTTLS 的特殊组合。搞不好把邮件服务搞崩了,影响其他模块。

于是分工:Claude Code 负责全局、Copilot 负责细节、Codex 负责试探 SMTP。


第一步:Claude Code 开局

在项目根目录启动:

$ claude
• Scanning directory... Express app detected
  - app.js (main routes)
  - models/material.js (Material model)
  - services/ (business logic)
  - config/ (env config)
  - package.json (dependencies: express, sqlite3, better-sqlite3)

先让它了解现有结构,然后描述需求:

我需要一个物料记录导出功能:查询 material 表的所有记录,导出为 CSV
文件,然后通过公司 SMTP 服务器发送邮件。CSV 和邮件是两个独立
的服务层。先实现 CSV 导出部分,SMTP 邮件部分先预留接口但暂不
实现——我要先在沙箱里验证邮件方案。

Claude Code 开始动手:

• Reading models/material.js (found: id, name, quantity, unit, supplier, updated_at)
• Reading services/ (3 existing service files)
• Reading config/mail.js (existing SMTP config placeholder)

→ Plan:
  1. Create services/csv_exporter.js — query materials, generate CSV
  2. Add route POST /materials/export — trigger CSV export
  3. Create services/mailer.js — placeholder with send() interface
  4. Add tests for CSV exporter

→ Implementing:
  [+] services/csv_exporter.js (42 lines)
  [~] app.js — add /materials/export route
  [+] services/mailer.js (23 lines, placeholder)
  [+] tests/csv_exporter.test.js (55 lines)
  → npm test — 5 passed
  → curl test: POST /materials/export → 200, returns CSV content

几分钟,CSV 导出和邮件预留接口都好了。services/mailer.js 还写了清晰的 JSDoc 注释,标了 TODO:待验证 SMTP TLS+STARTTLS 配置。


第二步:切到 VS Code,Copilot 修细节

Claude Code 生成的代码跑通了,但扫一眼发现有东西要改。

services/csv_exporter.js 里有一行:

const csv = records.map(r => Object.values(r).join(',')).join('\n');

逻辑是对的,但如果物料名称里包含逗号,CSV 就炸了。我在这个文件里停下来,用 Cmd+I 唤起 Copilot Agent,在行内直接输入:

this CSV generation will break if values contain commas — use a proper escaping library

Copilot 在内联 diff 里直接替换了这一行:

- const csv = records.map(r => Object.values(r).join(',')).join('\n');
+ import { stringify } from 'csv-stringify/sync';
+ const csv = stringify(records, { header: true });

顺手还改了 package.json——加了 csv-stringify 到 dependencies。

这种小修补是 Copilot 最强的场景——不需要切终端、不需要描述上下文。你看着哪行有问题,光标停在那里,说一句话,改了。

十分钟的代码审查里,Copilot 帮我修了四个地方:CSV 转义、一个缺少的 try-catch、一个错误的 HTTP 状态码、还有一个注释拼写。


第三步:Codex 试水 SMTP

SMTP 这块我信不过。公司的邮件服务器配置让人头疼,之前手写邮件功能踩过两次坑。我不确定 nodemailer 的 TLS+STARTTLS 组合在当前的版本里能不能直接用。

开个 Codex 沙箱,单独验证邮件方案:

$ codex exec --sandbox danger-full-access \
  "用 nodemailer 连接一个 SMTP 服务器,要求:
   - host: smtp.company.local
   - port: 587
   - 使用 STARTTLS 升级到 TLS 连接
   - 不实际发送邮件,只验证连接是否成功
   - 把能用的配置模板打印出来"

注意这里用了 --sandbox danger-full-access——因为要装 npm 包,需要网络。日常用 Codex 沙箱的话默认是不通网的,有网络需求的实验得显式开。

沙箱里,Codex 用了一个很聪明的方法来避免对 SMTP 服务器的实际冲击——自己写了个迷你 server.js 监听端口 2525,模拟 SMTP 的 EHLOSTARTTLS 握手序列:

→ Tool: shell $ npm install nodemailer
→ Tool: write mock_smtp_server.js (25 lines, simulates EHLO+STARTTLS)
→ Tool: shell $ node mock_smtp_server.js &
→ Tool: write test_transport.js
→ Tool: shell $ node test_transport.js
→ Connection successful with config:
    {
      host: 'localhost',
      port: 2525,
      secure: false,
      requireTLS: true,
      tls: { rejectUnauthorized: false }
    }
→ Verified: nodemailer STARTTLS handshake works with this config shape

然后把 localhost:2525 换成公司的 smtp.company.local:587,配置结构一模一样。连同 rejectUnauthorized: false 的警告注释也保留——“仅内网使用,生产环境建议配置 CA 证书”。

回到项目里,把验证通过的配置填入 services/mailer.js,删掉 TODO 注释。整个过程公司邮件服务器零接触。


第四步:回到 Claude Code,收尾

SMTP 方案验证完了。再次启动 Claude Code,告诉它:

Codex 沙箱验证了 nodemailer 的 STARTTLS 配置可行。
现在把 services/mailer.js 从 placeholder 升级为完整实现,
用这套 SMTP 配置。sender 和 recipients 从 config/mail.js 读取。

Claude Code 读到 services/mailer.js 里我刚才从 Codex 拿来的配置,接着干活:

• Reading services/mailer.js (updated with verified SMTP config)
• Reading config/mail.js
• Updating services/mailer.js — replacing placeholder with full implementation
  [+] send() function with nodemailer transport
  [+] sendCSVReport() — exports CSV and attaches to email
• Re-reading services/csv_exporter.js (noticed Copilot's csv-stringify change)
  ✓ Compatible — mailer calls csv_exporter.generateCSV()
• Running tests: 7 passed

有意思的是它发现了 Copilot 改的 csv-stringify,自动调整了 mailer.js 里的调用方式——我之前用的是手动拼接的 CSV,它改成调 csv_exporter.generateCSV() 获取格式化好的内容。

最后生成 commit message:

feat: add material CSV export and email delivery

- Add CSV exporter service with proper escaping (csv-stringify)
- Add nodemailer-based mailer with SMTP STARTTLS support
- SMTP config verified in sandbox before integration
- Add POST /materials/export route
- Include tests for CSV export

扫一眼 message,准确描述了三个工具各自贡献的部分。确认,提交。


这个下午到底发生了什么

回头整理一下,三个工具各自干了什么:

阶段 工具 干的活 为什么用它
实现主体功能 Claude Code CSV 导出、路由、测试、邮件骨架 项目级上下文,一次搞定多文件
代码审查 Copilot CSV 转义修复、try-catch、状态码 光标停在有问题的那行,说一句话就改了
验证危险操作 Codex 沙箱里测试 SMTP 连接 不想拿公司邮件服务器当小白鼠
集成收尾 Claude Code 实现 mailer、对接配置、提交 它知道整个项目的变更上下文

没有哪个工具"更好"。是"这个环节最适合用哪个"。


怎么判断什么时候用哪个

几次实战下来,形成了一套判断逻辑,现在基本是条件反射了。

用 Claude Code 的时候:

  • 跨多个文件的功能。一个需求需要改三层代码——它一次性全改了
  • 需要用 git log 或项目历史来理解现有逻辑的时候
  • 写测试。它能自己跑、自己修,直到全绿
  • 生成 commit message。改了什么它最清楚

用 Copilot 的时候:

  • 代码审查阶段。看着 Claude Code 的输出,发现哪行不对,停在那行,说一句话
  • 写小函数、补全代码块——手写完函数签名,Tab 就出来了
  • 在代码中间插入逻辑——标好位置,Cmd+I 描述要加什么

用 Codex 的时候:

  • 不确定一个库能不能用、一个配置对不对。先在沙箱里试
  • 涉及外部依赖或可能有副作用的事情。邮件、短信、支付
  • 从零搭东西。新项目在沙箱里跑通了再落地
  • 学习/探索。沙箱里随便折腾,搞坏了就否决重来

改什么、写什么,这事 Claude Code 处理。一行代码对不对,Copilot 处理。不确定的事,Codex 处理。


三个工具的关系

像是台球桌上的三根杆——开球用重杆,角度球换轻杆,跳球还有专门的跳杆。你不会拿开球杆去打角度球,也不会只带一根杆打完整场。

从装上第一天我就把三个都放在手边。现在每天打开的项目里,Copilot 一直在后台,Claude Code 处理大任务,Codex 偶尔被喊来跑个实验。谁也不取代谁。


下一篇

快速上手阶段的最后一篇。接下来进入深度实战——从零用 Claude Code 重构一个真实项目,看看它在复杂场景下的表现。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐