Codex SDK 编程式 Agent 接口:Thread 与 Per-Turn 沙箱控制

交互式终端 CLI 能够极大提升单人开发时的编码效率,但当团队需要把 Agent 嵌入流水线时,交互式界面就显得捉襟见肘了:

  • 在 CI/CD 流程中自动审查 Pull Request 并留下行级建议;
  • 定时自动化扫描代码库中的弃用 API 并发起批量迁移;
  • 构造复杂的多阶段(Phase)代码重构工作流。

这些任务需要的是编程式接口(Programmatic SDK)。OpenAI 围绕 Codex 提供了 @openai/codex-sdk。其最核心的架构创新在于Thread(会话线程)抽象,以及支持按轮次(Per-Turn)动态调整沙箱权限。


核心抽象:Thread 与 Per-Turn 沙箱机制

在传统的 Agent 运行时中,权限通常在会话启动时一次性固定(例如给定了“写权限”,则整个运行周期都拥有写权限)。但真实业务中最安全的做法是“最小权限原则(Principle of Least Privilege)”:分析阶段坚决只读,只有到了真正的覆写阶段才临时提权,改完后立即降权回只读。

Codex SDK 原生支持这种 Per-Turn 粒度的沙箱动态控制:

核心概念分工

  1. Thread(线程/会话):
    代表一个持久化的交互单元,拥有唯一的 threadId,维护完整的模型上下文、对话历史和文件观察状态。Thread 支持持久化序列化与跨进程唤醒恢复。
  2. Turn(轮次):
    Thread 中的一次原子级执行。从传入一条 Prompt 开始,到模型完成一系列工具调用并生成最终结果为止。每一个 Turn 都可以独立传入 sandbox 模式与特定的 writable_roots。

SDK 基本用法与渐进式提权实战

以下是一个完整的 TypeScript 示例,演示如何使用 Codex SDK 在单个会话中完成“只读分析 → 受限写入”的渐进提权:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import { Codex } from "@openai/codex-sdk";

const codex = new Codex({
apiKey: process.env.OPENAI_API_KEY,
});

async function runAuditedRefactor() {
// 1. 创建一个新的重构 Thread
const thread = await codex.threads.create({
model: "o3",
instructions: "你是一个严格遵循 TypeScript 最佳实践的代码重构专家。",
});

console.log(`[Codex] Thread 初始化完成, ID: ${thread.id}`);

// 2. 第一阶段:使用严格 read_only 模式执行安全排查
const analysisTurn = await thread.turn({
message: "检查 src/services/ 目录下是否存在未经捕获的全局 Promise 抛错。",
sandbox: "read_only",
});

console.log("[Codex] 分析结果:", analysisTurn.output);

// 3. 业务代码校验:如果确实存在风险,才申请升级沙箱写权限
if (analysisTurn.output.includes("存在潜在漏洞")) {
console.log("[Codex] 检测到隐患,提升沙箱权限至 workspace_write 进行单点修复...");

const fixTurn = await thread.turn({
message: "将发现漏洞的文件进行 try-catch 规范封装,不要改动其他任何逻辑。",
sandbox: "workspace_write",
// 将写权限精确锁定在单个模块,坚决不开放全目录
writable_roots: ["src/services/payment.ts"],
});

console.log("[Codex] 修复执行完毕:", fixTurn.output);
}

// 4. 第三阶段:权限收回,再次执行只读测试审查
const verifyTurn = await thread.turn({
message: "检查最新的变更,确认没有产生循环依赖。",
sandbox: "read_only",
});

console.log("[Codex] 验证收尾:", verifyTurn.output);
}

runAuditedRefactor().catch(console.error);

跨进程会话恢复(Thread Resumption)

对于大型重构任务,往往无法在一个临时的脚本进程中连续跑完,可能需要人工在中间环节进行业务审阅或触发外部流水线检查。Codex SDK 支持通过 ID 随时唤醒 Thread:

1
2
3
4
5
6
7
8
9
10
// 在前一个任务中保存 thread.id
const savedThreadId = "th_98a7bc12e4f0";

// 在后续的 Webhook 任务或新脚本中无缝恢复
const resumedThread = await codex.threads.resume(savedThreadId);

await resumedThread.turn({
message: "人工审批已通过,请继续执行第二阶段的单元测试补充。",
sandbox: "workspace_write",
});

典型自动化工程场景

1. 批量安全迁移(Batch Migration)

针对包含上百个文件的庞大单体仓库,如果让模型一口气全盘修改,极易发生上下文丢失或不可控的错误连锁反应。利用 SDK 可以实现严格隔离的单文件循环:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import glob from "glob";

const targetFiles = glob.sync("src/modules/**/*.ts");

for (const filePath of targetFiles) {
// 每个文件开启一个独立隔离的 Thread
const thread = await codex.threads.create({ model: "o3" });

await thread.turn({
message: `将 ${filePath} 中的传统回调异步模式重构为 async/await。`,
sandbox: "workspace_write",
// 强制限制模型只能碰这一个文件
writable_roots: [filePath],
});

console.log(`[Batch] 完成重构: ${filePath}`);
}

2. CI/CD PR 门禁拦截

将 SDK 包装为 GitHub Action 自动化脚本:

1
2
3
4
5
6
7
8
9
10
11
const reviewThread = await codex.threads.create({ model: "o3" });

const result = await reviewThread.turn({
message: `仔细审查此 PR 的 Diff 内容,若发现 SQL 注入风险,明确返回 'SECURITY_RISK':\n${prDiff}`,
sandbox: "read_only", // 保证审查任务绝不修改仓库状态
});

if (result.output.includes("SECURITY_RISK")) {
console.error("检测到安全红线,阻断流水线合并!");
process.exit(1);
}

编程式接口横向对比

评估维度 OpenAI Codex SDK OpenAI Assistants API Claude Code (CLI JSON 模式)
执行载体 本地工作区 + OS 原生沙箱 OpenAI 云端托管沙箱 本地宿主机器
文件系统直接访问 支持(直接操作本地源码) 不支持(需上传文件) 支持
Per-Turn 动态权限 原生支持(轮次级切换) 无本地概念 不支持(全局统一配置)
会话断点续传 支持(基于 threadId) 支持 仅支持 CLI --resume 标志
适合业务场景 本地代码自动化、CI/CD 修复 云端问答、文档智能体 交互式终端日常辅助

下一步

Codex 展现了极强的底层架构设计与 SDK 编排能力,但在真实的社区评估中,它的体验到底如何?为什么在 ThoughtWorks 2026 年的技术雷达上,它没有进入 Adopt 环而是被定在 Trial 环?下一篇将深度剖析:Codex-06-开发者体验与生态评估Trial环归因。