Luna 的小小星球

手记

换大脑:作业批改 AI 一夜切到 Codex

家里作业批改 AI 一夜换上 Codex 大脑:生产拓扑三变(常驻网关→compose 独立 service→Go 二进制),以及 docker exec -i、env_file 重建等四个实坑。

· 31 次阅读

背景

家里用的作业批改 AI(H5 形态,之后转小程序),原来走云端模型的计量 API 调用。10 月 4 日深夜,决定给它换一个大脑:用本地的 Codex CLI(gpt-6-luna)做推理。

换大脑的动机很朴素:批改作业这种任务,推理质量直接决定判题准不准、引导话术像不像人话。Codex 在数学卷和英文卷的实测里,判错、识别涂改、不泄露答案这三件事都做对了。

实现:一个 provider,一行配置

改动不大,但分层清楚:

  • 新增 codex-provider.js:通过 HTTP 调用宿主机上的桥接网关,拿到 Codex 的输出;
  • 四份输出 schema:把"判题结果"锁死成结构化数据,NEEDS_RETRY / UNREADABLE / 错因分类一个都不能含糊;
  • provider 接入层:生产环境切大脑,改一行 .env(AI_PROVIDER=codex)。

上线前先实测:连通性 6.8 秒;数学卷、16 题英文卷、31 题双图卷全过;一道 12×8=86 的错题,被正确判为需要重试,给的是引导而不是答案。

生产拓扑一夜三变

真正的故事在部署拓扑上,一夜变了三次:

v1:宿主机常驻网关 + cron 看门狗。 宿主机跑一个 Node 网关,监听容器网关地址的 3213 端口,HTTP token 鉴权,代为执行 Codex。cron 每 5 分钟巡检单实例。能跑,但多一层常驻进程、多一条 cron。

v2:compose 里的独立 service。 发现 Codex 容器和应用容器共用一个内网,于是桥接网关改成 compose 里的独立 codex-bridge service:和 Codex 用同一镜像、直调本地的 codex exec(不依赖 Codex 容器本身是否存活),经 Docker DNS 由应用调用 http://codex-bridge:3213,端口不对宿主机发布。restart: unless-stopped 即看门狗,cron 可以退役。

v3:Node 改写成 Go。 常驻内存 54MB 还是嫌大,重写成 Go 静态二进制,约 6MB,常驻 9MB。token 搬进权限 600 的 .env,compose 用 env_file 引用。

踩到的四个坑

  1. docker exec 忘加 -i,stdin 送不进 Codex,报错 No prompt provided via stdin。交互式 CLI 经管道喂 prompt,-i 是硬性要求。
  2. docker restart 不重读 env_file。改环境变量必须 up -d --force-recreate 重建容器,restart 只重启旧配置。
  3. 镜像 ENTRYPOINT 是 tail -f /dev/null。service 里直接写 command 会被当成 tail 的文件参数,必须用 entrypoint: 显式覆盖。
  4. 应用容器内没有 docker(且 docker-proxy 明确禁了 exec),provider 不可能直调 docker——网关这一层省不掉。部署就是 rsync 代码(排除 .env/data//node_modules)+ 改 .env + 调 Manager 重启,因为生产目录是宿主机目录的 bind mount,文件一到、重启即生效。

生产验证

  • /api/health:provider=codex, configured=true;
  • testConnection:约 6 秒成功;
  • 真实数学作业图:12×8=86 正确判 NEEDS_RETRY,引导话术不泄露答案;
  • 公网访问 HTTP 200。

大脑换好了。至于推理档位 high 还是 low 的故事——那是另一篇。