这一卷解决什么问题
把模型接进产品,技术上有无数种写法;真正难的是回答下面四个问题:
- 这项能力对外承诺了什么?质量、延迟、成本与失败语义分别是什么?
- 模型换了、供应商变了、区域调整了,业务代码要不要跟着改?
- 模型不可用时,产品是缺失、变弱,还是阻塞?
- 一次请求花了多少钱、为什么慢、失败在哪,能不能查到?
卷一把这四个问题拆成 13 章。每一章解决其中一小块,并在第 13 章组合成一条可以运行的基线。
如果你现在已经有“调通模型但不知道怎么上线”的状态,这一卷就是为你写的。
全书结构
卷一 45 篇,分为三部分:
- 前置 3 篇:序、本前言、目录与学习路径。
- 正文 39 篇:13 章,每章 3 节。
- 附录 3 篇:术语与判据速查、能力契约与错误码速查、AI 架构评审清单。
13 章的分工是:
| 章 | 主题 | 解决的问题 |
|---|---|---|
| 1 | AI 能力的产品化边界 | 什么算能力,什么只是模型调用 |
| 2 | 模型选型与能力矩阵 | 用哪些维度比较模型,怎样避免只看榜单 |
| 3 | 模型网关 | 哪些职责该放在产品与模型之间 |
| 4 | 多模型路由 | 一次请求怎样落到具体模型,结果怎样解释 |
| 5 | 流式输出与交互架构 | 首字延迟、取消、背压与半截响应 |
| 6 | 上下文与提示 | 提示怎样成为可版本化的产物 |
| 7 | 结构化输出与工具调用 | 模型输出怎样被校验与授权 |
| 8 | 延迟、成本与质量 | 预算怎样拆,取舍怎样记录 |
| 9 | 缓存与复用 | 什么能缓存,什么绝对不能 |
| 10 | 降级与兜底 | 模型不可用时产品做什么 |
| 11 | 安全与信任边界 | 密钥、租户、注入与输出审查 |
| 12 | 可观测与计量 | 一次请求最小要记录什么 |
| 13 | 卷一收口 | 前面的模块怎样组合成基线 |
前三章建立地基,第 4–12 章按“请求生命周期”展开,第 13 章收口。这个顺序不是唯一读法,目录篇给了三条按问题选择的路径。
每章怎么读
每章三节,通常按下面的节奏展开:
- 第一节定义问题。 用「回声」的一个具体场景说明“如果不这样设计,会发生什么”。
- 第二节给出判据。 把决策写成可比较的维度、阈值或分类,而不是“看情况”。
- 第三节落到代码。 用一段可运行的 TypeScript 把判断固定下来,并给出测试。
每篇的结尾固定是「小结」与「常见错误与边界」。如果你时间有限,先读每篇的这两节,再决定要不要回头看推导。
实验工程 ai-lab
卷一对应一个实验工程 ai-lab。它不是完整产品,而是一组可以单独运行、也可以组合运行的模块:
ai-lab/
src/
core/ 能力契约、错误模型、选型、路由、预算
protocol/ 统一请求/响应与流式协议
gateway/ 网关、阶段组合、mock provider
stream/ 流式管线、取消与错误
prompt/ 模板、上下文预算、版本
structured/ 结构化输出校验与修复
tools/ 工具白名单与授权
cost/ 延迟预算、token 成本、取舍
cache/ 缓存键、失效、命中率
degrade/ 降级计划、降级链、演练
security/ 出域、注入、输出审查
observe/ 观测字段、计量、质量信号
test/ 与 src 同构的测试目录
每一章对应其中一个目录。第 13 章会引用前面多个模块,但不会改写它们。
实验工程不需要安装依赖:Node 26 直接运行 .ts,测试使用内置的 node:test。如果你只想验证某一章,运行:
node --test test/<目录>/*.test.ts
注意通配符要落到具体文件;直接传目录会得到 MODULE_NOT_FOUND。
三级验证
书里的“可运行”分三级,口径必须说清楚:
| 级别 | 依赖 | 能证明什么 | 不能证明什么 |
|---|---|---|---|
| L1 | 无,纯 Node 内置模块 | 契约、路由、预算、缓存、降级等纯逻辑正确 | 真实模型的输出质量 |
| L2 | 进程内 HTTP / 本地端口 | 网关、流式、取消与错误路径可用 | 真实网络与供应商行为 |
| L3 | 真实模型或代理 | 端到端体验与成本 | 可复现性(模型会变) |
卷一的所有结论都在 L1 与 L2 可复现;L3 只用于团队自己的验收,不作为书稿的承诺。文中若出现 L3 的数字,一定来自读者环境,而不是本书的“实测”。
代码与命名约定
实验代码遵循以下约定:
- 运行时:Node 26.5.0,依赖原生类型剥离直接运行
.ts。 - 模块:只使用
node:内置模块,零第三方依赖。 - 导入:本地导入必须带
.ts后缀,例如import { AiError } from "../core/errors.ts"。 - 类型:禁用
enum、namespace与构造函数参数属性;用联合类型、interface与普通字段替代。 - 命名:能力用点号分层,例如
chat.reply、search.rerank;租户用tenant-a这类稳定标识。 - 成本:一律用整数微元(
costMicros),按百万 token 单价换算,向上取整。 - 时间:需要断言的地方注入
Clock,不直接依赖Date.now()。
这些限制不是风格偏好,而是为了让代码在没有任何工具链的环境里也能跑起来。读者clone 下来,只需要一个 Node 26。
错误处理口径
全书统一把错误收敛为九类:
| 类别 | 含义 | 是否可重试 |
|---|---|---|
auth | 密钥无效或权限不足 | 否 |
quota | 租户配额耗尽 | 否 |
rate-limit | 触发限流 | 是 |
timeout | 超过预算 | 是 |
unavailable | 模型或区域不可用 | 是 |
invalid-request | 请求结构错误 | 否 |
invalid-output | 输出不符合契约 | 是 |
content-blocked | 内容安全拦截 | 否 |
provider | 其他提供方错误 | 是 |
这张表的意义不在于分类本身,而在于它决定了重试、降级与用户提示。一个错误如果被归错类,后面的处理一定错。
为什么用 TypeScript 与 Node 26
AI 领域的主流示例多用 Python。本书选 TypeScript,有三个现实原因:
- 读者面更广。 产品前端、BFF 与服务端工程师都能直接运行,不需要配置虚拟环境与依赖。
- 类型适合表达契约。 能力契约、请求响应、错误分类、降级原因,用类型写出来比用文档写出来更难被忽略。
- 零依赖可复现。 没有
pip install、没有 CUDA、没有 API key,测试在任何机器上结果一致。
这本书不讨论模型训练与推理优化,所以不需要 Python 生态的数值库。网关、路由、预算、缓存与降级这些产品侧架构问题,与语言无关。
章间依赖
大部分章节可以独立阅读,但有几条依赖需要知道:
- 第 3 章的网关依赖第 1 章的能力契约与第 2 章的模型档案。
- 第 4 章的路由依赖第 2 章的档案与第 3 章的请求上下文。
- 第 9、10 章依赖第 3 章的统一错误模型。
- 第 12 章的观测字段依赖第 3、8 章的请求与预算结构。
- 第 13 章依赖前面所有模块,必须最后读。
如果只想解决一个具体问题,可以按目录篇的三条路径跳读;如果要完整评审一次接入方案,建议按顺序读。
数字口径
书里的数字分两类,正文会明确标注:
- 本机运行输出:附命令与输出,读者可以复现。例如测试通过数、编译耗时。
- 案例假设值:用于演示推导。例如“假设日活 100 万、人均 3 次调用、每次 800 token”。
案例假设值不是容量承诺。读者必须用自己的产品事实重新代入,才能得到有意义的结论。
成本计算的统一口径是:
costMicros = ceil(inputTokens × inputMicrosPerMTok / 1_000_000)
+ ceil(outputTokens × outputMicrosPerMTok / 1_000_000)
这个公式刻意简单:它忽略缓存折扣、批量折扣与阶梯价,因为这些因供应商而异。卷一关心的是“能不能算清”,而不是“算到小数点后几位”。
团队怎么用这一卷
这一卷不是读完就结束的。建议把它变成三个团队动作:
接入评审。 用第 1、3、8、10 章的判据,检查方案是否回答了能力契约、网关边界、预算与降级四个问题。答不上来的,不允许进入开发。
上线检查。 用第 9、11、12 章,检查缓存隔离、数据出域与观测字段。这三项在事故发生时决定你能不能定位。
故障复盘。 用第 5、7、10 章,区分问题出在流式语义、输出解析还是降级链。很多“模型不稳定”的结论,最后都落在其中一处。
附录 C 把这些判据整理成一份可以直接投影的评审清单。
三个动手练习
如果你只想动手,做这三个练习就够了:
练习一:给一个能力写契约。 选「回声」的“长文摘要”,写出输入、输出、质量、延迟、成本与失败语义。要求每一项都能被验证,而不是“尽量快”“尽量准”。
练习二:让网关拒绝一次请求。 给 POST /v1/chat 加租户配额,配额耗尽时返回 quota 错误,并确保失败请求也被计量。写测试证明超限后不会继续调用模型。
练习三:设计一次降级。 假设 frontier 模型整体不可用,写出智能回复的降级顺序:小模型 → 模板 → 隐藏入口。说明每一步的用户可见行为与恢复条件。
三个练习都不需要真实模型。做完以后,你会对“能力契约”有比读十篇文章更具体的理解。
自检清单
读完卷一,用下面十个问题自检:
- 你能不能说出「回声」的五个 AI 能力,以及每个能力的失败语义?
- 你能不能解释为什么网关不负责业务语义?
- 你能不能说清一次请求从进入到返回,经过哪些阶段?
- 你能不能说清路由为什么选了这个模型,而不是另一个?
- 你能不能描述首帧前后重试行为的差别?
- 你能不能算出一个能力的单次成本与月度上限?
- 你能不能说清缓存键包含什么,什么变更会让它失效?
- 你能不能列出模型不可用时,每个能力的产品行为?
- 你能不能说出一次请求至少要记录哪些字段?
- 你能不能给出一次接入的退出条件?
答不上来的问题,对应章节就是下一轮阅读的重点。
每章的产出物
卷一不要求读者记住所有细节,但要求每章结束时手里多一样东西:
- 第 1 章:能力清单。
- 第 2 章:选型矩阵与评测集。
- 第 3 章:网关骨架与错误模型。
- 第 4 章:路由策略与解释记录。
- 第 5 章:流式协议说明。
- 第 6 章:提示模板库与版本记录。
- 第 7 章:结构化输出契约与工具白名单。
- 第 8 章:预算表与取舍 ADR。
- 第 9 章:缓存键规范与失效规则。
- 第 10 章:能力降级表与演练记录。
- 第 11 章:数据出域与租户隔离说明。
- 第 12 章:最小观测字段与计量口径。
- 第 13 章:基线评审与风险清单。
产出物不需要一开始就完美。它们的价值在于把“我们讨论过”变成“我们写下来了”。
关于勘误与反馈
书中的代码与环境有关。Node 版本、Hugo 渲染或平台差异都可能导致示例行为不同。如果你发现代码无法运行,先确认三件事:
- Node 版本是否为 26.x,是否支持直接运行
.ts。 - 导入路径是否带
.ts后缀,大小写是否与文件名一致。 - 测试命令是否用了文件通配符,而不是目录。
如果仍然无法复现,请记录完整命令、输出与版本号。没有这些信息的反馈,很难定位。
小结
这一卷的目标不是让你成为模型专家,而是让你在把模型接进产品时,能回答四个问题:承诺了什么、边界在哪里、失败怎么办、成本怎么算。
能力契约是起点,网关是稳定层,路由与降级保证异常时可解释,缓存、计量与观测让承诺可以被验证。第 13 章会把它们组合起来,形成卷一基线。
下一章从「回声」的一次智能回复事故开始,说明为什么“能调通模型”和“能承诺一项能力”之间,还隔着整整一套架构。
常见错误与边界
- 把本前言当目录。真正的篇目顺序与阅读路径在目录篇。
- 跳过第 1 章直接看网关。没有能力契约,网关的每个设计决策都会失去依据。
- 把 L1 测试当成上线验收。L1 只证明逻辑正确,不证明真实模型可用。
- 把案例假设值当成容量承诺。所有数字都要按自己的产品重新代入。
- 只读代码不看判据。代码是判断的固化,判据才是可以迁移的部分。
- 认为零依赖意味着零工程。依赖少只降低了复现成本,不降低架构复杂度。
- 把错误分类表当成装饰。错误归错类,重试与降级一定跟着错。
- 只做接入不做退出条件。临时开关与临时降级会变成永久债务。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。