前幾天已經分別看過 Codex,以及 Anthropic 的 commerce-agents。
兩邊都有 Prompt、Skill、Tool、Memory,也都有自己的 Runtime。
所以這篇做最後一次橫向比較:
1. 多 Project 的 Config 怎麼處理?
2. Memory 怎麼從對話變成長期記憶?
3. Skill / Tool 怎麼決定這次 Agent 能用什麼?
4. Sandbox 到底什麼時候才需要?
假設現在有兩個商品:
flight-service
credit-card
並不需要因此開發兩個Agents,而是更換 Agent 使用的設定。
Codex 的 config loader 原始碼在:
codex-rs/config/src/loader/mod.rs
裡面直接定義 config layer 順序:
system
↓
user
↓
profile
↓
cwd
↓
.codex/config.toml
↓
runtime override
也就是同一個 Codex Runtime,可以因為 cwd 不同而載入不同 Project Config。
例如:
/workspace/flight-service/
└── .codex/config.toml
/workspace/card/
└── .codex/config.toml
而 Codex App Server 建立 Thread 時,也可以直接指定:
{
cwd,
sandbox,
config,
baseInstructions,
developerInstructions
}
來源:
codex-rs/app-server-protocol/
schema/typescript/v2/ThreadStartParams.ts
ThreadStartParams 本身就包含 cwd、sandbox 與 config。
所以:
Thread A
cwd = /workspace/flight-service
Thread B
cwd = /workspace/card
可以共用同一個 App Server。
commerce-agents 的做法比較像一般 Application。
Shopping Agent 有:
shopping-agent/core/shopping_agent/config.py
Merchant Agent 則有:
merchant-agent/core/merchant_agent/config.py
Repo 本身的執行方式就是:
agent = ShoppingAgent(
backend=your_backend,
skills_dir=Path("shopping-agent/skills"),
config=ShoppingAgentConfig(...)
)
也就是:
Backend
Skills Directory
Agent Config
↓
ShoppingAgent
都在建立 Agent instance 時決定。
Codex 的 Memory Pipeline 在:
codex-rs/memories/README.md
完整流程是:
Conversation
↓
Phase 1 Extract
↓
State DB
↓
Phase 2 Select
↓
Consolidation
↓
Long-term Memory
它先做 extraction。
每個 Thread 的 rollout 經過模型後產生:
raw_memory
rollout_summary
rollout_slug
然後先寫進 State DB。
接下來進入 Phase 2。
它會從已 Extract 的 Memory 中,依照:
usage_count
last_usage
generated_at
max_unused_days
選出值得繼續保留的內容,再送進 Consolidation Agent。
最後形成:
~/.codex/memories/
├── raw_memories.md
├── rollout_summaries/
└── consolidated memory
共用 Memory 實作在:
commerce-common/commerce_common/memory.py
主要流程是:
Conversation
↓
Extract Fact
↓
Validate
↓
Write Filter
↓
MemoryStore
它有兩條 Memory 寫入路徑:
使用者明確要求記住
↓
save_memory
以及:
一輪對話完成
↓
extract_and_store()
↓
模型 Extract Fact
但 Extract 出來的資料不能直接寫入,還要經過:
validate_fact()
↓
MemoryWriteFilter
↓
MemoryStore
針對 Fact 的寫入限制:
key ≤ 64 chars
value ≤ 200 chars
而且會拒絕 identifier-shaped value,以及符合 memory_blocked_patterns 的內容。
Agent Application 自己定義什麼值得記、什麼不能記,以及 Memory 怎麼保存。
Skill 與 Tool 前面都介紹過,這裡只比較 Runtime 到底怎麼決定:
這次 Model 看得到什麼?
Codex 對應的核心在:
codex-rs/core/src/tools/
├── registry.rs
└── router.rs
ToolRouter 本身就持有:
pub struct ToolRouter {
registry: ToolRegistry,
model_visible_specs: Arc<[ToolSpec]>,
...
}
也就是它把:
Runtime 裡有哪些 Tool
和:
這一次哪些 Tool 要暴露給 Model
分開。
流程大概是:
ToolRegistry
↓
ToolRouter
↓
model_visible_specs
↓
Model
↓
Tool Invocation
↓
Registry / Handler
它的結構很清楚:
Config
↓
Tool Registry
「這次有哪些 Tool」
↓
Model
↓
Tool Call
↓
Executor
「這個 Tool 實際怎麼執行」
↓
Backend
而且 Executor 不只是呼叫 function。
Tool list 由 deployment config 決定;Executor 會拒絕沒有被註冊的 Tool name。
也就是 Model 就算自己產生:
delete_everything
如果 Registry 沒有註冊:
Registry
✕
Executor refuses
不會因為 Model 說要執行就真的執行。
前面三項可以先收斂成:
| 面向 | Codex | commerce-agents |
|---|---|---|
| Config | Runtime / Project / Thread Config | Host 建立 Agent 時傳入 Config、Backend、Skills |
| Memory | Extract → DB → Select → Consolidate | Extract Fact → Validate → Filter → Store |
| Tool | ToolRegistry + ToolRouter |
registry.py + Executor + Backend |
| Skill | Harness 層統一 Discovery / Selection | 每個 Domain Agent 自己提供 Skills |
因為Codex是通用 Agent Harness,commerce-agents是已經組好的 Domain Agent
Sandbox 可以先用一句話理解:
當 Agent 要直接執行 Bash、Python、測試程式等 OS 操作時,限制這個 Process 可以讀寫哪些檔案、能不能連網。
例如 Agent 要執行:
python analyze.py
沒有 Sandbox:
Agent
↓
python analyze.py
↓
繼承目前 OS User 的權限
有 Sandbox:
Agent
↓
python analyze.py
↓
Sandbox
├─ /workspace 可以寫
├─ /home/user/.ssh 不可寫
└─ Network 不允許
兩邊目的相同,但設定方式不同。
| Codex | Claude Agent SDK | |
|---|---|---|
| Sandbox 定位 | Runtime 的執行政策 | 主要限制 Bash command |
| 預設行為 | Trusted Project 通常使用 workspace-write |
enabled=False,要使用需開啟 |
| Filesystem | read-only / workspace-write / danger-full-access |
Bash Process 的 filesystem isolation |
| 額外可寫目錄 | writable_roots |
不是主要 Sandbox config;一般檔案 Tool 走 Permission |
| Network | network_access |
network.allowedDomains / deniedDomains 等 |
| 特定 Command | 主要依整體 Sandbox Policy | 可用 excludedCommands 排除 |
| Sandbox 外執行 | danger-full-access |
allowUnsandboxedCommands |
| 主要使用情境 | Coding Agent 執行 Shell、修改 Code、跑 Test | 自己建立的 Agent 有開放 Bash 時 |
Codex 的 workspace-write 會允許讀取檔案,但只能修改:
cwd
+
writable_roots
Network 是否允許則另外由:
[sandbox_workspace_write]
network_access = false
控制。Codex 的設定定義也直接包含:
writable_roots
network_access
exclude_tmpdir_env_var
exclude_slash_tmp
因此一般 Coding Agent 最常見的設定就是:
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
network_access = false
代表:
可以修改目前 Project
但不能任意修改其他目錄
也不能讓 Shell 任意連 Internet
Claude Agent SDK 則比較明確把 Sandbox 定位在 Bash。
例如:
ClaudeAgentOptions(
tools=["Bash"],
sandbox={
"enabled": True,
"autoAllowBashIfSandboxed": True,
"network": {
"allowedDomains": [
"pypi.org"
]
}
}
)
代表 Agent 可以執行 Bash,但 Bash Process 會受到 Sandbox 的 filesystem / network 限制。
Claude SDK 目前可設定的主要項目包含:
enabled
autoAllowBashIfSandboxed
excludedCommands
allowUnsandboxedCommands
network
Network 還能設定:
allowedDomains
deniedDomains
可以直接用 Agent 擁有的能力判斷:
| Agent 使用情境 | Sandbox 是否重要 |
|---|---|
| 只有聊天 / Prompt | 幾乎沒有作用 |
| 只有 REST API / MCP Tool | 通常不是主要安全邊界 |
| 讀取資料 | 主要看 Tool Permission |
| 修改 Code | Codex 的 filesystem Sandbox 開始重要 |
| 執行 Python / Bash | Sandbox 很重要 |
跑 pytest / npm test |
Sandbox 很適合 |
pip install / npm install |
還需要考慮 Sandbox Network |
| Agent 可以任意執行 Shell | Sandbox 應該視為重要安全邊界 |
這也解釋了為什麼前面的 commerce-agents 幾乎沒有討論 Sandbox。
它使用 Claude Agent SDK 時,實際配置是:
tools=["Skill"]
mcp_servers={...}
而不是:
tools=[
"Bash",
"Read",
"Edit"
]
它的 Agent 主要透過已註冊的 Domain MCP Tool:
search_products
get_orders
add_to_cart
操作 Backend,因此安全邊界主要是:
Tool Registry
+
Executor
+
Gate
+
Backend Permission
沒有 Bash,自然也沒有太多 Bash Sandbox 需要設定。
openai/codex — codex-rs/memories/README.md:Phase 1 extraction 與 Phase 2 consolidation。anthropics/commerce-agents — docs/safety.md:Tool surface、Executor、Memory 與 Gate 的安全邊界。