3 · 每个选择的代价
前两章讲了差异和共识。这一章讲一件更少被谈论的事:每一个设计选择放弃了什么。
为什么必须单独讲代价?
技术文章通常只讲「这个设计好在哪」。但在真实的架构决策里,你要判断的从来不是「这个设计好不好」,而是「它的代价我能不能承受」。
一个你付不起代价的好设计,等于一个坏设计。
3.1 Claude Code 的代价
代价 1 · 固定的上下文策略换不掉
| 得到 | 失去 |
|---|---|
五级阶梯针对编程场景做到了极致优化,配合私有的 cache_edits 能力,能在压缩的同时保住缓存前缀 | 如果你的工作负载不是编程,你没有出路。五级阶梯的每一级都对「什么信息可以丢」有隐含假设 —— 而那个假设是围绕代码工作流建立的 |
举个具体的:五级阶梯里的「剪裁」优先丢弃最老的工具结果。在编程场景这通常没问题(你读过的文件内容,需要时可以再读一遍)。但如果你的场景是长期的、有状态的对话(比如一个持续几周的项目管理助手),最老的信息可能恰恰是最重要的约束条件。
代价 2 · 编译期特性开关的双刃
89 个 feature() 开关 + 死代码消除
→ 关掉的功能【物理上不进二进制文件】
| 得到 | 失去 |
|---|---|
| 体积更小、攻击面更小、没有「关掉的功能还残留代码」的风险。而且有「排除字符串检查」这样的构建时验证,确保被禁用的功能真的没漏出来 | 用户不能在运行时开启任何东西。要一个不同的功能组合,就要重新构建一个二进制文件。 而且这套机制本身有复杂度成本 —— 源码里能看到「排除字符串检查」逼出了一个奇怪的回调注入( snipReplay),只为了绕过构建时校验 |
代价 3 · 单一入口形态
Claude Code 是终端工具。它有 4 种启动形式,但都在终端里。没有聊天平台集成、没有 webhook、没有定时任务。
这换来的是:整套交互设计可以假设「有一个 TTY、有一个人在看、支持 ANSI 转义序列、支持 Ctrl-C」。那 347 KB 的输入框组件之所以能存在,正是因为它只需要服务一种终端。
代价 4 · 闭源
这是最实际的一条:你不能在自己的产品里用它的实现。
本系列的分析基于泄漏的源码,性质是架构学习,不是可复用的代码资产。你能学到设计思路,但要自己重新实现。
而且其中一些关键能力(比如 cache_edits)是 Anthropic 的私有服务端能力,外部开发者根本拿不到。照着抄一个「压缩时不破坏缓存」的实现,是做不到的。
3.2 Hermes 的代价
代价 1 · 抽象层的重量
ContextEngine 抽象基类:490 行接口定义
内置 compressor 实现: 419 KB
→ 接口与实现的比例:490 行 : 419 KB
490 行接口不是「一堆方法签名」,它包含了大量必须遵守的契约说明:
· 生命周期是「不是每轮一次」
· select_context() 的输出必须在所有校验器之前
· 缓存不变式:你的实现不能破坏前缀
· usage 字典的版本演进规则
· protect_first_n 的语义在某个版本变过
一个第三方要写出一个正确的上下文引擎,需要读懂并遵守全部这些约定。这个门槛非常高 —— 高到实践中可能几乎没有人真的换掉默认实现。
那么这 490 行的抽象成本值不值?这是一个真实的、没有标准答案的问题。
代价 2 · 默认不安全
| 得到 | 失去 |
|---|---|
| 本机执行最快、最简单、没有文件同步问题。开箱即用 | 默认安装等于给模型一个完整权限的终端。审计报告的头号「严重」问题 而且这个风险是隐性的 —— 用户不会主动去改一个「已经能正常工作」的默认配置 |
「安全的默认值」和「好用的默认值」在这里直接冲突。
如果默认是 Docker:新用户第一次跑要等镜像下载,要处理文件同步,可能因为 Docker 没装而直接失败。大量用户会在第一次尝试时流失。
如果默认是本机:所有人都能立刻跑起来,代价是所有人默认处在无隔离状态。
这个权衡没有正确答案,只有明确的取舍。但至少应该在首次运行时明确告知用户当前处于无隔离模式 —— 让风险是「用户知情后接受的」,而不是「用户不知道的」。
代价 3 · 22 个平台的持续维护负担
相关的还有一条隐性成本:测试。22 个平台每一个都需要真实的测试账号、测试工作区、测试凭据。全量回归测试的成本极高,实践中很可能做不到。
代价 4 · Python 的分发问题
| Claude Code | Hermes |
|---|---|
| Bun 编译成单个可执行文件(296 MB)。下载即用,没有依赖问题 | Python 包。用户要有正确版本的 Python、要装依赖、要处理虚拟环境、要面对依赖冲突 |
296 MB 听起来很大,但它换来的是「一个文件,双击就跑」。而任何做过 Python 应用分发的人都知道,「在我机器上是好的」这句话有多常见。
3.3 两边共有的代价
共同代价 1 · 复杂度是不可逆的
Claude Code 的 10 步权限级联、Hermes 的 5,802 行红线 —— 这些复杂度一旦加进去,就再也拿不出来了。
因为每一条规则都对应一个曾经发生过的问题。删掉它,那个问题就会回来。而且删规则的人通常不知道它为什么存在(写它的人可能已经离职了)。
结论:加规则要慎重,因为你是在给系统加一笔永久负债。每一条规则最好都带上「它防的是什么」的注释 —— Hermes 那条记录了 gh pr create --title 事故的注释就是正面例子。
共同代价 2 · 对模型行为的强依赖
两个系统都在提示词里写了大量「你必须这样做」的约束:
- Claude Code 的「思考三定律」、压缩时的「不许调用任何工具」(穷举点名 + 说明后果)
- Hermes 的注入检测、技能描述的匹配
这些约束是「劝说」,不是「强制」。
模型可能不听。而且换一个模型版本,服从度就会变化 —— 一段在旧版本上 99% 有效的提示词,在新版本上可能只有 90% 有效,而那 10% 会变成线上事故。
Claude Code 的源码里能看到这个演进痕迹:那条「不许调用工具」的指令原来放在结尾,后来移到了开头,因为发现模型对开头指令的服从度明显更高。
这类依赖是智能体系统特有的技术债:它不在你的代码里,而在模型的权重里,你无法测试也无法控制。
共同代价 3 · 可观测性的成本
Claude Code 有 660 个事件类型、1,093 个埋点。这些代码本身要写、要维护、要在重构时同步更新。Hermes 有事件系统、投递台账、技能使用统计、执行历史。
但这个代价是必须付的 —— 因为智能体系统的失败往往是「行为不对」而不是「报错了」,没有埋点就完全无法排查。
3.4 代价对照总表
| 维度 | Claude Code 付出的 | Hermes 付出的 |
|---|---|---|
| 灵活性 | 上下文策略换不掉;只服务终端场景 | — |
| 复杂度 | 编译期开关体系(89 个 + 死代码消除 + 排除检查) | 抽象基类矩阵(6 类扩展点,每个都有完整契约) |
| 安全 | — | 默认无隔离(审计头号问题) |
| 维护 | — | 22 个平台的永久负债 |
| 分发 | — | Python 依赖地狱 |
| 可复用 | 闭源 + 依赖私有服务端能力 | — |
| 共有 | 复杂度不可逆 · 依赖模型服从度 · 可观测性成本 | |
看完这张表你会发现一件事:两边的代价几乎是互补的。
Claude Code 用「灵活性」换「极致优化和分发便利」。
Hermes 用「安全默认值和维护成本」换「无处不在和可替换」。
没有一个选择是免费的,也没有一个是错的 —— 只有「跟你的约束匹配」和「不匹配」。下一章讲怎么判断你的约束是什么。
3 · The Cost of Every Choice
The first two chapters covered differences and consensus. This one covers something that gets talked about far less: what each design choice gave up.
Why does cost need its own chapter?
Technical articles usually only explain “what's good about this design.” But in a real architecture decision, the question you're answering is never “is this design good,” it's “can I afford its cost.”
A good design whose cost you can't pay is the same thing as a bad design.
3.1 What Claude Code Pays
Cost 1 · A fixed context strategy you can't swap out
| Gained | Lost |
|---|---|
The five-rung ladder is tuned to the limit for the coding scenario, and with the private cache_edits capability it can compact while preserving the cache prefix | If your workload isn't coding, there's no way out. Every rung of the ladder carries an implicit assumption about “which information is safe to drop” — and that assumption was built around code workflows |
A concrete example: the “snip” rung drops the oldest tool results first. In a coding scenario that's usually fine (a file you already read can be read again when needed). But if your scenario is a long-lived, stateful conversation (say, a project-management assistant that runs for weeks), the oldest information may be exactly the most important constraint.
Cost 2 · The double edge of compile-time feature flags
89 feature() flags + dead-code elimination
→ a disabled feature is [physically absent from the binary]
| Gained | Lost |
|---|---|
| Smaller size, smaller attack surface, no risk of “the feature is off but its code is still lying around.” There are also build-time verifications like the “excluded-string check” to make sure disabled features really didn't leak through | Users can't turn anything on at runtime. A different combination of features means rebuilding the binary. And the mechanism has its own complexity cost — the source shows the “excluded-string check” forcing an odd callback injection ( snipReplay) purely to get around the build-time validation |
Cost 3 · A single form of entry
Claude Code is a terminal tool. It has 4 launch forms, but all of them live in the terminal. No chat-platform integrations, no webhooks, no scheduled tasks.
What that buys: the entire interaction design can assume “there is a TTY, a human is watching, ANSI escape sequences work, Ctrl-C works.” The 347 KB input-box component can exist precisely because it only has to serve one kind of terminal.
Cost 4 · Closed source
This is the most practical one: you can't use its implementation in your own product.
This series is based on leaked source; its nature is architecture study, not a reusable code asset. You can learn the design thinking, but you'll have to re-implement it yourself.
And some of the key capabilities (cache_edits, for one) are Anthropic's private server-side features that outside developers simply can't get. Copying an implementation of “compact without breaking the cache” is not something you can do.
3.2 What Hermes Pays
Cost 1 · The weight of the abstraction layer
ContextEngine abstract base class: 490 lines of interface definition
Built-in compressor implementation: 419 KB
→ Interface-to-implementation ratio: 490 lines : 419 KB
Those 490 lines of interface aren't “a pile of method signatures”; they hold a lot of contract text that must be obeyed:
· The lifecycle is “not once per turn”
· The output of select_context() must come before all validators
· The cache invariant: your implementation must not break the prefix
· The versioning rules for the usage dict
· The semantics of protect_first_n changed in some version
For a third party to write a correct context engine, they have to read and honor all of these conventions. That bar is very high — high enough that in practice almost nobody may actually swap out the default implementation.
So is the cost of those 490 lines of abstraction worth it? That's a real question with no standard answer.
Cost 2 · Insecure by default
| Gained | Lost |
|---|---|
| Local execution is the fastest and simplest, with no file-sync problems. Works out of the box | A default install hands the model a terminal with full permissions. The number one “critical” finding in the audit report And the risk is invisible — users don't go out of their way to change a default that “already works” |
“Safe defaults” and “usable defaults” collide head-on here.
If the default is Docker: a new user's first run waits on an image download, has to deal with file sync, and may fail outright because Docker isn't installed. A large share of users would leave on their first attempt.
If the default is local: everyone can run it immediately, at the price of everyone being unisolated by default.
There is no correct answer to this trade-off, only an explicit choice. But at minimum, the first run should tell the user plainly that they're in unisolated mode — so the risk is one “the user knew about and accepted,” not one “the user didn't know about.”
Cost 3 · The ongoing maintenance burden of 22 platforms
There's a related hidden cost: testing. Each of the 22 platforms needs a real test account, test workspace, and test credentials. Full regression testing is extremely expensive and very likely infeasible in practice.
Cost 4 · Python's distribution problem
| Claude Code | Hermes |
|---|---|
| Bun compiles it into a single executable (296 MB). Download and run; no dependency problems | A Python package. The user needs the right Python version, has to install dependencies, deal with virtual environments, and face dependency conflicts |
296 MB sounds big, but what it buys is “one file, double-click, it runs.” And anyone who has ever shipped a Python application knows how often you hear “it works on my machine.”
3.3 Costs Both Sides Share
Shared cost 1 · Complexity is irreversible
Claude Code's 10-step permission cascade, Hermes's 5,802 lines of red lines — once this complexity goes in, it never comes back out.
Because every rule corresponds to a problem that actually happened once. Delete it and that problem comes back. And the person deleting the rule usually doesn't know why it exists (the person who wrote it may have left).
Conclusion: add rules with care, because you're adding a permanent liability to the system. Ideally every rule carries a comment saying “what this guards against” — the Hermes comment recording the gh pr create --title incident is the positive example.
Shared cost 2 · Heavy dependence on model behavior
Both systems write lots of “you must do it this way” constraints into their prompts:
- Claude Code's “three laws of thinking,” and the “do not call any tool” rule during compaction (every tool named exhaustively, plus the consequences spelled out)
- Hermes's injection detection, and its skill-description matching
These constraints are “persuasion,” not “enforcement.”
The model may not listen. And switch model versions and compliance shifts — a prompt that worked 99% of the time on the old version may work 90% of the time on the new one, and that 10% becomes a production incident.
The Claude Code source shows the trail of this evolution: the “do not call tools” instruction originally sat at the end and was later moved to the beginning, because the model turned out to obey instructions at the start noticeably more.
This kind of dependence is technical debt unique to agent systems: it lives not in your code but in the model's weights, where you can neither test it nor control it.
Shared cost 3 · The cost of observability
Claude Code has 660 event types and 1,093 instrumentation points. That code has to be written, maintained, and kept in sync during refactors. Hermes has an event system, a delivery ledger, skill-usage statistics, and execution history.
But this is a cost that must be paid — because agent systems fail mostly by “behaving wrong” rather than “throwing an error,” and without instrumentation there is no way to investigate at all.
3.4 Cost Comparison Summary
| Dimension | What Claude Code pays | What Hermes pays |
|---|---|---|
| Flexibility | Context strategy can't be swapped; serves only the terminal scenario | — |
| Complexity | The compile-time flag system (89 flags + dead-code elimination + exclusion checks) | The abstract-base-class matrix (6 kinds of extension points, each with a full contract) |
| Safety | — | No isolation by default (the audit's number one finding) |
| Maintenance | — | The permanent liability of 22 platforms |
| Distribution | — | Python dependency hell |
| Reusability | Closed source + depends on private server-side capabilities | — |
| Shared | Irreversible complexity · dependence on model compliance · the cost of observability | |
Read this table and one thing jumps out: the two sides' costs are almost complementary.
Claude Code trades “flexibility” for “extreme optimization and easy distribution.”
Hermes trades “safe defaults and maintenance cost” for “being everywhere and being replaceable.”
No choice is free, and none is wrong — there is only “matches your constraints” and “doesn't.” The next chapter is about how to figure out what your constraints are.