本章目录In this chapter
- 4 · How to Choose When You Build Your Own
- 4.1 The First Question: Is the User Present?
- 4.2 The Second Question: Is the Workload Uniform or Varied?
- 4.3 The Third Question: Who Will Extend It?
- 4.4 Eight Things You Must Do Whichever Road You Take
- 4.5 The Interview: How to Talk About All This
- 4.6 Finally: A Decision Framework You Can Take With You
4 · 你自己做系统时怎么选
这一章把前面所有内容转成可操作的判断。不是「学哪个」,而是「在你的约束下,哪个设计是对的」。
4.1 第一个问题:用户在不在场
这是分水岭。先回答它,后面一半的决策会自动确定。
4.2 第二个问题:工作负载是单一的还是多样的
| 单一工作负载 | 多样工作负载 |
|---|---|
| 例子:只做代码助手 / 只做客服 / 只做数据分析 | 例子:一个平台,上面跑各种各样的智能体 |
| 该做:把上下文策略、工具集、提示词全部针对这一种负载做死。深度优化 | 该做:抽象基类 + 可插拔。允许每种负载配自己的策略 |
| 不该做:过早抽象。你会为了一个永远不会有第二种实现的接口,付出永久的复杂度 | 不该做:把某一种负载的假设写进核心。它会在第二种负载出现时炸掉 |
最常见的错误是「预防性抽象」:还没有第二种实现,就先定义一个抽象基类。
代价:你的接口是凭想象设计的,而不是从两个真实实现里提炼的。等真的出现第二种实现时,你会发现接口不合适,然后要么改接口(破坏第一个实现),要么让第二个实现别扭地适配。
更好的做法:先写死。当出现第二个真实需求时,再从两个具体实现里提炼接口。那时你提炼出来的接口才是对的。
4.3 第三个问题:谁来扩展
| 扩展者 | 该提供的机制 | 不该提供的 |
|---|---|---|
| 只有你自己 | 直接改代码。也许加几个配置项 | 插件系统。你在给自己制造麻烦 |
| 你的团队 | 技能(Markdown) + 配置。零代码,人人可写 | 复杂的插件 API |
| 其他工程团队 | 工具注册 + 钩子 + MCP | 让他们能替换核心策略 |
| 不可信的第三方 | MCP(跨进程隔离) | 同进程插件。一个崩溃会拖垮你 |
记住 Hermes 第 9 章那个权限梯度:扩展的门槛应该和它能造成的破坏成正比。
技能(纯文本、人人可写、最多让智能体走错路)
→ MCP(跨进程、崩溃隔离、只能提供工具)
→ 插件(同进程、能挂钩子、但钩子只能追加不能替换)
→ 核心策略(能替换整个上下文,但单选,必须用户显式配置)
不要提供一个万能的插件接口让所有人都能做所有事。
4.4 无论选哪条路,都必须做的八件事
这是第 2 章八条共识的行动版本:
| # | 要做的事 | 具体动作 |
|---|---|---|
| 1 | 给上下文记账 | 算清楚:系统提示词多少 token、工具定义多少、每轮增长多少。任何常驻内容都要能说出它为什么值这个价 |
| 2 | 渐进式披露 | 工具、技能、文档、记忆 —— 全部改成「目录常驻 + 内容按需」。并且在描述质量上投入时间 |
| 3 | 至少两层安全 | 「能力收窄」(不给危险工具)+ 「执行隔离」(容器/沙箱)。规则匹配不算一层可靠的防御 |
| 4 | 默认失败即关闭 | 检查每一处 try/except:出异常时是放行还是拒绝?把所有「出错就跳过」改成「出错就拒绝」 |
| 5 | 加硬限制 | 委派深度、并发数、单次输出长度、遍历跳数、缓存条目数。每一个「理论上不会太大」的量都要有上限 |
| 6 | 能力查询而非身份判断 | 搜索代码里所有的 if xxx == "某个具体名字",改成 if xxx.supports_yyy() |
| 7 | 错误分类 | 至少分出三类:可重试的临时故障(短退避)/ 配置或凭据问题(长退避或告警)/ 逻辑错误(不重试,直接报告) |
| 8 | 两段式操作带租约 | 任何「先声明后完成」的操作(工具调用、任务认领、锁),都要处理「声明了但没完成」:补偿或超时 |
4.5 面试场景:怎么把这些讲出来
不要从「有一个循环,模型调工具,工具返回结果」开始讲。这是所有人都会说的,说明不了什么。
从约束开始讲:
「首先要确定两件事:用户在不在场,以及工作负载是单一还是多样。
用户在场,安全的终点可以是问人;不在场,就必须有自动决策规则、告警系统和执行隔离,因为出了问题没人会发现。
工作负载单一,就把策略写死做深度优化;多样,就需要抽象基类 —— 但要区分哪些是可叠加的能力,哪些是必须单选的策略。
然后是三个跑不掉的约束:上下文是最稀缺的资源,所以一切设计围绕渐进式披露;安全必须分层,因为每一层都不可靠;默认值必须是 fail-closed。」
| 被问到 | 可以举的例子 |
|---|---|
| 上下文管理 | 五级阶梯(每级的信息损失递增,从最轻的开始);select_context 与 compress 的正交(读 vs 写,那个误用故事) |
| 提示词缓存 | 前缀匹配,一个字节不同就全部失效;分叉子智能体为了共享缓存做到字节级一致 |
| 安全 | _CMDPOS 命令位置锚定和那次 gh pr create --title 误拦事故;绕过免疫检查放在模式判断之前 |
| 多智能体 | MAX_DEPTH = 1(用硬限制消灭指数爆炸);set_spawn_paused(区分「停止接受新工作」和「终止现有工作」) |
| 可靠性 | 孤儿 tool_use 必须在每条中止路径合成结果;try_register_running_job 防定时任务堆叠 |
| 重试 | 凭据池按 HTTP 状态码决定冷却时长(429 短、401 长、5xx 极短) |
4.6 最后:一个可以带走的判断框架
这七个问题不需要你记住任何一个具体实现。
它们是从 Claude Code 的 176,391 字分析和 Hermes 的 141,079 字分析里提炼出来的、真正可迁移的部分。
具体的实现会过时 —— 模型会变、API 会变、框架会变。但这些约束来自「智能体」这个形态本身,它们不会变。
4 · How to Choose When You Build Your Own
This chapter turns everything so far into decisions you can act on. Not “which one to learn from,” but “under your constraints, which design is right.”
4.1 The First Question: Is the User Present?
This is the dividing line. Answer it first and half the remaining decisions settle themselves.
4.2 The Second Question: Is the Workload Uniform or Varied?
| A single workload | Varied workloads |
|---|---|
| Examples: only a coding assistant / only customer support / only data analysis | Example: one platform running all kinds of agents |
| Do: take the context strategy, toolset, and prompts and hard-wire all of them for that one workload. Optimize deeply | Do: abstract base classes + pluggability. Let each workload bring its own strategy |
| Don't: abstract prematurely. You'll pay permanent complexity for an interface that will never have a second implementation | Don't: bake one workload's assumptions into the core. It blows up the moment a second workload shows up |
The most common mistake is “preventive abstraction”: defining an abstract base class before a second implementation exists.
The cost: your interface is designed from imagination, not distilled from two real implementations. When the second one actually arrives, you'll find the interface doesn't fit, and then you either change the interface (breaking the first implementation) or contort the second one to fit.
The better approach: hard-wire it first. When a second real need appears, distill the interface from the two concrete implementations. The interface you extract then is the one that's actually right.
4.3 The Third Question: Who Will Extend It?
| Extender | Mechanism to provide | Don't provide |
|---|---|---|
| Only you | Edit the code directly. Maybe add a few config options | A plugin system. You're making trouble for yourself |
| Your team | Skills (Markdown) + config. Zero code; anyone can write one | A complex plugin API |
| Other engineering teams | Tool registration + hooks + MCP | The ability to replace core strategies |
| Untrusted third parties | MCP (cross-process isolation) | In-process plugins. One crash takes you down with it |
Remember the permission gradient from Hermes Chapter 9: the barrier to extending should scale with the damage the extension can do.
Skills (plain text, anyone can write one, worst case the agent takes a wrong turn)
→ MCP (cross-process, crash-isolated, can only provide tools)
→ Plugins (in-process, can attach hooks, but hooks can only append, never replace)
→ Core strategies (can replace the entire context, but single-select and must be explicitly configured by the user)
Don't offer one universal plugin interface that lets everyone do everything.
4.4 Eight Things You Must Do Whichever Road You Take
This is the action version of the eight consensus points from Chapter 2:
| # | What to do | Concrete action |
|---|---|---|
| 1 | Account for context | Work out the numbers: how many tokens in the system prompt, how many in tool definitions, how much growth per turn. Anything resident must be able to justify its price |
| 2 | Progressive disclosure | Tools, skills, docs, memory — convert all of them to “catalog resident + contents on demand.” And put time into description quality |
| 3 | At least two layers of safety | “Capability narrowing” (don't hand out dangerous tools) + “execution isolation” (container/sandbox). Rule matching doesn't count as a reliable layer |
| 4 | Fail closed by default | Inspect every try/except: on exception, does it allow or refuse? Change every “on error, skip” to “on error, refuse” |
| 5 | Add hard limits | Delegation depth, concurrency, single-output length, traversal hops, cache entries. Every quantity that “shouldn't get too big in theory” needs a cap |
| 6 | Capability queries, not identity checks | Search the code for every if xxx == "some specific name" and change it to if xxx.supports_yyy() |
| 7 | Classify errors | At least three classes: retryable transient failures (short backoff) / config or credential problems (long backoff or alert) / logic errors (no retry; report immediately) |
| 8 | Two-phase operations carry leases | Any “declare first, complete later” operation (tool calls, task claims, locks) must handle “declared but never completed”: compensate or time out |
4.5 The Interview: How to Talk About All This
Don't open with “there's a loop, the model calls tools, the tools return results.” Everyone says that; it proves nothing.
Open with the constraints:
“First, two things need settling: whether the user is present, and whether the workload is uniform or varied.
If the user is present, safety can end in asking a human; if not, there have to be automatic decision rules, an alerting system, and execution isolation, because nobody will notice when something goes wrong.
If the workload is uniform, hard-wire the strategy and optimize deeply; if it's varied, you need abstract base classes — but distinguish the capabilities that can stack from the strategies that must be single-select.
Then come three constraints you can't escape: context is the scarcest resource, so everything is designed around progressive disclosure; safety must be layered, because no layer is reliable; and the default must be fail-closed.”
| If asked about | Examples you can give |
|---|---|
| Context management | The five-rung ladder (each rung loses more information; start with the gentlest); the orthogonality of select_context and compress (read vs. write, and the misuse story) |
| Prompt caching | Prefix matching — one differing byte invalidates all of it; forked subagents go byte-identical to share the cache |
| Safety | _CMDPOS command-position anchoring and the gh pr create --title false-block incident; bypass-immunity checks placed before the mode check |
| Multi-agent | MAX_DEPTH = 1 (a hard limit that kills exponential blowup); set_spawn_paused (separating “stop accepting new work” from “terminate existing work”) |
| Reliability | Orphaned tool_use must get a synthesized result on every abort path; try_register_running_job keeps scheduled tasks from piling up |
| Retries | The credential pool sets cooldown length by HTTP status code (short on 429, long on 401, very short on 5xx) |
4.6 Finally: A Decision Framework You Can Take With You
These seven questions don't require you to remember any specific implementation.
They are the genuinely transferable part, distilled from 176,391 characters of analysis of Claude Code and 141,079 characters of analysis of Hermes.
Specific implementations will go out of date — models change, APIs change, frameworks change. But these constraints come from the “agent” form itself, and they won't.