4 · 你自己做系统时怎么选

这一章把前面所有内容转成可操作的判断。不是「学哪个」,而是「在你的约束下,哪个设计是对的」。

4.1 第一个问题:用户在不在场

这是分水岭。先回答它,后面一半的决策会自动确定。

你的智能体运行时,有人在看着屏幕吗? ┌─ 是(交互式)─────────────────────────────────┐ │ · 危险操作 → 弹确认框 │ │ · 权限系统的终点可以是"问人" │ │ · 上下文可以提示用户手动处理 │ │ · 投入应该向【交互体验】倾斜 │ │ · 参考 Claude Code │ └────────────────────────────────────────────────┘ ┌─ 否(自主运行)───────────────────────────────┐ │ · 危险操作 → 必须有自动决策规则 │ │ · 必须有告警 + 事件系统 │ │ · 必须有注入检测 │ │ · 必须有执行隔离 │ │ · 投入应该向【可靠性和安全】倾斜 │ │ · 参考 Hermes │ └────────────────────────────────────────────────┘ ┌─ 都有 ────────────────────────────────────────┐ │ ★ 最常见的真实情况 │ │ → 【按触发源分层】:同一个循环,不同的权限 │ │ (这正是 Hermes 第 12 章那张图的结论) │ └────────────────────────────────────────────────┘

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 面试场景:怎么把这些讲出来

如果被问「你怎么设计一个 Agent 系统」

不要从「有一个循环,模型调工具,工具返回结果」开始讲。这是所有人都会说的,说明不了什么。

从约束开始讲:

「首先要确定两件事:用户在不在场,以及工作负载是单一还是多样

用户在场,安全的终点可以是问人;不在场,就必须有自动决策规则、告警系统和执行隔离,因为出了问题没人会发现。

工作负载单一,就把策略写死做深度优化;多样,就需要抽象基类 —— 但要区分哪些是可叠加的能力,哪些是必须单选的策略。

然后是三个跑不掉的约束:上下文是最稀缺的资源,所以一切设计围绕渐进式披露;安全必须分层,因为每一层都不可靠;默认值必须是 fail-closed。」

如果被追问细节,这些是有分量的具体例子
被问到可以举的例子
上下文管理五级阶梯(每级的信息损失递增,从最轻的开始);select_contextcompress 的正交(读 vs 写,那个误用故事)
提示词缓存前缀匹配,一个字节不同就全部失效;分叉子智能体为了共享缓存做到字节级一致
安全_CMDPOS 命令位置锚定和那次 gh pr create --title 误拦事故;绕过免疫检查放在模式判断之前
多智能体MAX_DEPTH = 1(用硬限制消灭指数爆炸);set_spawn_paused(区分「停止接受新工作」和「终止现有工作」)
可靠性孤儿 tool_use 必须在每条中止路径合成结果;try_register_running_job 防定时任务堆叠
重试凭据池按 HTTP 状态码决定冷却时长(429 短、401 长、5xx 极短)

4.6 最后:一个可以带走的判断框架

面对任何一个智能体系统的设计决策,依次问: ① 这个决定会往常驻上下文里加东西吗? → 加多少 token?每轮都要付吗?值吗? → 能不能改成"目录 + 按需加载"? ② 这个决定涉及安全吗? → 它是哪一层?还有别的层吗? → 如果这一层失效,会怎样? ③ 这里有没有一个"理论上不会太大"的量? → 加个上限。现在就加。 ④ 这里在判断"你是谁"吗? → 改成判断"你能做什么"。 ⑤ 出错时会发生什么? → 是放行还是拒绝?(应该是拒绝) → 是哪一类错误?(决定重试策略) ⑥ 这是一个两段式操作吗? → "声明了但没完成"怎么办? ⑦ 我现在要加的抽象,有第二个真实实现吗? → 没有的话,先写死。

这七个问题不需要你记住任何一个具体实现。

它们是从 Claude Code 的 176,391 字分析和 Hermes 的 141,079 字分析里提炼出来的、真正可迁移的部分。

具体的实现会过时 —— 模型会变、API 会变、框架会变。但这些约束来自「智能体」这个形态本身,它们不会变。