读了两份源码,跑了 150 次基准测试,Codex 和 DeepSeek Harness 的选型有了答案
2026 年 8 月,两件事前后脚发生。OpenAI 把驱动 Codex 的 harness 以 Apache-2.0 开源,DeepSeek 放出了 dsh v0.1(MIT)。随后网上冒出一批对比文章,结论高度一致:Codex 生态成熟,DeepSeek Harness 插件化更灵活。
这个说法没错,但它没法帮你做决定。
我把两边源码拉到本地逐行读了一遍。Codex 锁定 tag rust-v0.150.1;DeepSeek Harness 读的是安装目录里的 TypeScript 源码,版本 0.1.1-rc.2。读完源码又做了另一件事:把五个机制场景搬上测试环境,跑了 150 次真实 agent 运行,对沙箱拒绝和中途插话单独做了补充探针。
下面先讲源码分析的结果,再说基准测试跑出来的差距。
十个维度的胜负分布
先给总览。工具调度 dsh 更强。工具清单方面,Codex 更薄更锐,dsh 更全,取决于你认同哪种哲学。多智能体 Codex 明显更强。上下文管理两者平手,略微偏 dsh。沙箱 Codex 更强。可观测性与回放 dsh 更强。模型互操作 dsh 完胜。提示词与工作纪律 Codex 更强。扩展性(二次开发)dsh 更强。失败恢复 dsh 略强。
五五开。但真正决定选型的往往只有一两条。
多智能体:dsh 的宣传主场反而落后
外界印象里,dsh 是“可重组的 Agent 运行时”,多智能体理应是它的优势领域。源码给出的答案相反。
Codex 侧有 9 个已落地的 agent 控制工具,全部在同一个文件里定义:spawn_agent、send_input、send_message、followup_task、resume_agent、wait_agent、list_agents、close_agent、interrupt_agent。派生、送消息、追加任务、等待、列举、恢复、关闭、打断——一整套生命周期管理。在本地跑 codex features list,multi_agent 是 stable 且默认开启,goals 同样是 stable 默认开启。prompts/templates/goals/ 目录下有三个模板:budget_limit.md、continuation.md、objective_updated.md。“长目标 + 预算上限 + 续跑”已经被产品化了。
dsh 侧的控制面是 4 个工具:send_message、interrupt_agent、list_agents,加子智能体侧的 report。
但 dsh 有自己的亮点。子智能体分 fork 和 spawn 两种语义。fork 继承父会话已完成 turn 的前缀,spawn 是全新上下文——这个区别在代码里是 provider 上的一个布尔量 inheritsParentContext,一边 true 一边 false。还有递归深度预算,可以断言上限。ralph 工具做“每轮开一个结构化输出子智能体、带最大轮数和交接字数上限”的循环编排,workflow 做多阶段编排。
准确的说法是:成熟度 Codex 领先,语义清晰度和可编排性 dsh 领先。
Codex 没有 read_file 这个工具
检索 Codex 全部工具名字面量,没有 read_file,没有 grep,没有 list_dir。读文件和搜代码全走一个工具:exec_command。发行包里直接捆了一份 ripgrep 二进制。
dsh 完全相反:read、write、edit、glob、grep、read_image 各自独立成工具,再加 str_replace_editor。
这不是谁糙谁细的问题。Codex 相信“一个 shell 打通一切”,工具面窄,模型的选择负担小,代价是所有文件操作的正确性都压在命令行拼装上。dsh 相信“细粒度工具更可控”,每个工具的参数、错误、UI 呈现都能单独设计,代价是模型要在更多工具里做选择。
文件编辑原语也体现同一分歧。Codex 用 apply_patch 信封(*** Begin Patch / *** Update File: / *** Move to:),一次调用能跨多文件增删改移,吞吐高。dsh 用 old_str 唯一匹配,命中 0 次或多次都直接报错回灌给模型,单点精准、失败信息直白。
决定选型的可能只是一行枚举
这是源码里最硬的一处差异。
Codex 的 WireApi 枚举只有一个变体:Responses。wire_api = "chat" 在配置反序列化阶段就会报错,错误信息明确写着“不再支持”,连 ollama-chat 都被移除了。
dsh 这边,DeepSeek 适配器直接 POST 到 ${baseURL}/chat/completions,另有一个 pi-ai 适配器提供多提供方路由,配置里能直接写 openai、anthropic,或指向任意兼容服务并声明 api: openai-completions。
如果你的模型服务是 OpenAI 兼容的 chat completions 接口,dsh 零成本接入,Codex 必须自己加一层 Responses 转换代理。
基准跑完之后,这条结论需要修正。见后文“同模型比较终于跑起来了”。
工具并行的实现差异
同一条模型回复里出现多个工具调用时,怎么调度?
Codex 用一把读写锁。工具自己声明能不能并行,能并行的拿读锁并发跑,不能的拿写锁独占。声明缺失默认不能并行。简单可靠,代价是一个“不安全”的工具就能把整批调用退化成串行。
dsh 的做法更精细。独占调用形成屏障,并行调用进入有界滚动池。后续调用在启动前重新分类,独占重分类要等当前池排空。派发可以重叠,但策略判定、结果和结果上下文严格按模型给出的顺序提交。
还有一个细节能看出设计思路。中断时,dsh 会给那些还没派发的调用写入合成错误结果——目的是让事件日志回放依然合法。宁可造一条假的失败记录,也不允许日志里出现“有调用没结果”的空洞。
两种压缩,防的是两种故障
上下文压缩两边都有,目标不同。
Codex 关心的是不要超窗。压缩阈值算带缓冲的 token 上限,作用域能配“算全部上下文”还是“只算压缩窗口前缀之后新增的部分”。compaction_image_budget 默认开启,图片也计入压缩预算、按需裁掉旧图。这是一套贴着真实 API 计费口径做的工程。
dsh 关心的是压缩后历史不能坏。维护一个“工具调用/结果余额”,只允许在余额为零的位置切割历史。一旦发现某个 tool/result 找不到对应调用,直接抛错。溢出的大段文本走 spill:整体存盘,行内只留头尾预览加一个取回定位符。
Codex 防的是超限报错,dsh 防的是压缩把 tool_call/tool_result 拆散导致后续请求非法。两个都对,修的不是同一个 bug。
会话层也体现同一逻辑。dsh 的 append-only 事件日志加纯函数投影不是附加功能,而是架构约束——连中断和压缩都要为“可回放”让路。Codex 也有 JSONL rollout、resume、fork,但更像一套运维能力,不是所有机制都必须向它妥协。
沙箱:Codex 的实现深度更足
Codex 的 SandboxType 有四个变体:无沙箱、macOS Seatbelt、Linux seccomp、Windows 受限令牌。三平台都有独立实现文件,macOS 策略是四个单独的 .sbpl 文件,提权路径单独成了一个 crate。
dsh 的思路同源,权限词汇表也一样(read-only / workspace-write / danger-full-access)。实现是一张平台链表:Linux 走 bwrap 再退 landlock,macOS 走 seatbelt,Windows 走 ACL 受限令牌。多候选时用功能探针按顺序仲裁,所有探针都失败就拒绝,命令不跑。
一个必须说清楚的取舍。dsh 让沙箱也是插件,能换掉。这是灵活性,同时也是风险面——你的沙箱有多强,取决于你装了哪个插件。
工作纪律写在哪
这条直接决定同样的模型放进去,谁更会干活。
Codex 有 6 份按模型分版的基础提示词文件:gpt_5_2_prompt.md、gpt-5.2-codex_prompt.md、gpt-5.1-codex-max_prompt.md 等。开头声明身份和能力边界,后面是 How you work 这类长篇章节,把计划、沙箱审批、输出风格全规定死。
dsh 的内置身份声明只有一句话:You are an AI agent powered by DeepSeek Harness.
这不是没做完。提示词是有序 section 注册表,order 0 那个位置是留给部署方 persona 的空槽,官方明确把“你是谁、怎么干活”留白了。真正的行为约束下沉到每个工具自带的文本里——比如 jobs 工具告诉模型:记住每个后台 job id,不要忙等,收尾前用 job_output 收集,不再相关的用 job_kill 杀掉。
要拿来就用,Codex 有一套已调校好的工作纪律。要按自己业务定纪律,dsh 的结构更干净,不用跟内置提示词打架。
dsh 还有一个独有的东西:cordis_define / cordis_run / cordis_stop / cordis_undefine 加三个自省工具,让模型能在会话里定义、启动、停止插件——也就是让 agent 改自己的运行时。Codex 没有对等物。
同模型比较终于跑起来了
读完源码以为效果基准做不了。理由就是上面那行枚举:Codex 只认 Responses,dsh 说 chat completions,两边跑的模型很容易不同。测出来的是模型谁聪明,不是 harness 谁强。
这次测试用了 gpt-5.6-sol、DeepSeek-V4-Pro、Opus 4.8 和 GLM-5.3。实际使用的 API 同时支持 /v1/chat/completions 和 /v1/responses,所以 Codex 走 Responses、dsh 走 chat completions,指向同一个模型 id。
所以第三条结论修一下。不是“Codex 接不了你的模型”,而是“你的模型服务必须提供 Responses 兼容入口”。只有 chat completions 的服务,那条结论成立;同时提供两个协议时,Codex 能直接进来。
接入这一层有两个坑。
dsh 的零参数工具会被拒。job_list、get_goal 这类无参工具的 JSON Schema 缺 required 字段,API 映射成 null 后被校验器打回:Invalid schema for function 'job_list': null is not of type "array",请求直接 400。OpenAI 系模型能容忍,DeepSeek 路由不行。最后写了一个四十行的本地代理,在 wire 层补上 required: []。没有靠关掉工具,那会改变被测对象本身。
Responses 路由并非对所有模型都可用。DeepSeek 和 Anthropic 路由在五次重连后返回 high demand 错误,Codex 侧只能跑两个模型,八个组合缩成六个。
150 次基准测试怎么跑的
设计原则:不测智商,只测机制。判定必须确定性,不靠主观打分。
五个场景,各跑 5 次,六个 harness × 模型组合,共 150 次运行。
大输出:5MB 文件里埋一个标记,看截断/spill 之后还能不能取回。
并行吞吐:一次读 10 个互不依赖的小文件。
压缩后存活:60 个文件各含一个整数,求和,答案唯一。
死循环自愈:让它确认一个不存在的 token,看会不会反复搜。
顺序依赖:先写 a.txt,再据其内容推导 b.txt。
判定就是查文件内容、查最后一行输出、查墙钟时间,没有一处需要打分。
结果:149/150 通过。
五个正式场景里,两边都没有出现持续性的“跑不动”。差异主要落在成本和方差上。
同模型中位墙钟:
压缩那一行的五倍差距是全场最有意思的数据,恰好验证了“Codex 没有读文件工具”那一节。Codex 用一条 exec_command 把 60 个文件聚合算完,一次调用搞定;dsh 用 read 逐个读,工具调用序列长得多。
同一个哲学分歧在时间轴上的投影。一个 shell 打通一切确实快,代价是正确性压在命令行拼装上、中间过程不可审计。细粒度工具慢,但每一步都在事件日志里留痕。更在乎墙钟还是更在乎可回溯,源码里没答案,看你要做什么。
唯一那次真失败是 dsh + GLM-5.3 + 并行,跑了 121 秒没取到全部 10 个 token。1/100 的抖动,不足以支撑任何结论。但 dsh 在并行和大输出两个场景的标准差(23.7s、16.4s)明显高于 Codex(3.3s、7.9s)。单次跑赢不算赢,原因在这。
两个补充探针
沙箱拒绝和插话没有混进 150 次统计,单独报告。
沙箱拒绝这一步测成了,恢复路径没有测成。在终端里用 Codex 的真实 read-only 模式(没加任何 bypass 参数)让它写文件,系统拒绝了写操作,日志明确写出 patch rejected: writing is blocked by read-only sandbox,最终回复为 BLOCKED,目标文件确认没有创建。拒绝路径生效,但拒绝后能否通过审批或提权恢复,没验证。
dsh 补充探针没有到达模型执行,直接返回 dsh: TRANSPORT: Connection error。dsh 的拒绝行为、文件状态和恢复能力都不能从这次运行得出结论。源码仍有 read-only / workspace-write / danger-full-access 权限层,但源码能力不是运行证据。
中途插话没有真实运行结果。源码和已有测试确认两边都有实时入口:Codex 是 app-server 的 turn/steer,dsh 是 Agent Inbox / Web Host API 的 mode: "steer"。但这次没有完成两边对同一 active turn 的真实 API 驱动,不能把“接口存在”写成“插话成功”。
这两个补充探针不能加入 149/150 的正式通过率。尤其是中途插话,只能说实现入口已确认,实测尚未完成。
选哪个
按你的目的,不按名气。
选 Codex:想把仓库里的活干完;在 macOS/Linux 上跑不受信代码(内核级沙箱是硬边界);需要长目标、预算上限、多 agent 协同这类已产品化的流程;不想自己写工作纪律;在意墙钟——同模型下它在压缩类长上下文任务上快出五倍。
选 DeepSeek Harness:接非 Responses 协议的模型(除非模型服务自己提供 Responses 兼容入口);做自己的 agent 产品,需要换掉模型、工具、沙箱甚至 agent loop;需要完整轨迹回放做可观测性;能接受用更长的工具调用序列换每一步都可审计。
两个都装也不冲突。配置文件互不干扰,日常交付用 Codex,Web 和 headless 流程用 dsh 包一层。已有报道称 dsh 能把 Codex 当子代理调用——harness 之间的边界本来就在模糊。
操作清单速览
-
读源码定位选型分歧点:Codex 锁 tag rust-v0.150.1,dsh 源码在~/.dsh/profiles/node_modules/@deepseek-ai/,每个包有 src/ 和中文 README。 -
检查模型服务的 API 协议:只有 chat completions 则 dsh 直接接入,只有 Responses 或两者兼有则 Codex 也能接入。Responses 路由并非对所有模型服务可用。 -
注意 dsh 零参数工具的 required 字段:无参工具缺 required: []会被部分模型服务拒掉,需要代理补正或修改工具定义。 -
性能差异看场景:压缩类长上下文任务 Codex 快五倍,但细粒度工具场景 dsh 的可回溯性更强。方差数据表明 dsh 单次运行波动更大。 -
沙箱能力验证:Codex read-only 拒绝路径已实测通过;dsh 沙箱是插件化架构,实际能力取决于所选插件和平台探针链。 -
多智能体成熟度:Codex 已产品化,dsh 的 fork/spawn 语义更清晰但工具数量少。 -
工作纪律:Codex 内置提示词已调校,dsh 的 persona 槽位留白,行为约束下沉到工具自描述文本。
常见问题
问:Codex 和 dsh 能不能同时安装?
能。配置文件互不干扰。日常交付用 Codex,Web 和 headless 流程用 dsh 包一层。已有报道 dsh 能把 Codex 当子代理调用。
问:我的模型服务只支持 chat completions,选哪个?
选 dsh。Codex 的 WireApi 枚举只有 Responses 变体,配置 wire_api = "chat" 在反序列化阶段就会报错。
问:dsh 零参数工具报错怎么修?
在 wire 层补上 required: []。原文用了一个四十行本地代理解决。不要关掉工具——那会改变被测对象本身。
问:哪个跑得更快?
分场景。压缩类长上下文任务 Codex 快约五倍。大输出、自愈、顺序依赖场景两者差距不大。但 dsh 在并行和大输出场景的方差显著高于 Codex。
问:沙箱怎么选?
Codex 三平台独立实现,macOS 有单独的 .sbpl 策略文件,提权路径单独成 crate。dsh 沙箱是插件,用平台链表按顺序仲裁。选 dsh 意味着你的沙箱强度取决于你装了哪个插件。
问:先读源码还是先跑基准?
先读源码。能告诉你机制是否存在、怎么设计的,帮你确定该测什么。再跑基准,才知道差多少。压缩那五倍墙钟差距,源码只读出“工具更薄 vs 更细”,读不出具体倍数。
问:Codex 不读文件只靠 exec_command,安全吗?
这是哲学问题。Codex 相信 shell 打通一切,发行包捆了 ripgrep。文件操作正确性压在命令行拼装上。dsh 用独立工具,每个操作可审计、错误信息直白,但调用序列更长。

