arganzheng · 2026-10-04
模型 API 没有供应商替你写的规格书,应用工程师要自己写——失效模式、契约、账、选型判据、客户端纪律,五部分缺一不可。
%%{init: {"flowchart": {"wrappingWidth": 170}}}%%
flowchart TB
C1["01 失效模式"] --> C2["02 API 契约(一)"]
C2 --> C3["03 API 契约(二)"]
C2 & C3 --> C4["04 成本与延迟的账"]
C1 & C4 --> C5["05 选型"]
C1 & C2 & C4 --> C6["06 客户端工程"]
七条失效性质,每条可检测——每条对应后面某一层的应对
flowchart LR
CTX["组装上下文<br/>system·历史·检索·工具"] --> PRE["prefill<br/>读上下文"] --> SAMP["逐 token<br/>采样"] --> OUT["输出<br/>文本/JSON/tool_call"] --> ACT["执行动作"]
flowchart LR
PRE["prefill"] & SAMP["采样"] & ACT["执行"]
F4["④ 上下文标称 ≠ 有效"] -.-> PRE
F5["⑤ 知识截止"] -.-> PRE
F3["③ 指令遵循"] -.-> PRE
F1["① 非确定性"] -.-> SAMP
F2["② 幻觉"] -.-> SAMP
F6["⑥ 供应商变更"] -.-> PRE
F7["⑦ 越界"] -.-> ACT
classDef stage fill:#fff7e0,stroke:#c98a00,stroke-width:2px,color:#222
classDef fail fill:#fdecea,stroke:#c0392b,color:#222
class PRE,SAMP,ACT stage
class F1,F2,F3,F4,F5,F6,F7 fail
每条失效性质都有一个落在纸面上的数
| 性质 | 一个数 |
|---|---|
| 非确定性 | batch 不变性缺失:1000 次贪心 18 种结果 → 修好后 1 种;公开 API 做不到 |
| 上下文有效长度 | NoLiMa 32K 处 11/13 模型掉到基线一半以下;GPT-4o 99.3% → 69.7% |
| 幻觉的后果 | Air Canada 812.02 加元——源材料正确、输出编造、公司仍负责 |
| 越界 | PocketOS 9 秒删库;约 700 个 agent 入侵 Hugging Face |
块列表进出;工具调用是协议不是功能;结构化输出保证语法不保证语义
%%{init: {"flowchart": {"wrappingWidth": 200}}}%%
flowchart LR
App["应用"] -->|"req"| API["模型 API"]
API -->|"asst + tc"| CHK{"校验·权限"}
CHK -->|"执行"| Tool["工具"]
Tool -->|"res/err"| App
App -->|"hist+res"| API
API -->|"ans"| Done(["结束"])
CHK -->|"循环到无 tc<br/>或预算尽"| API
同骨架不同实现——字段、状态、缓存顺序各异
| 项 | OpenAI | Anthropic |
|---|---|---|
| 工具参数 | arguments 是字符串 |
input 是对象 |
| 服务端状态 | Responses 默认 store: true 30 天;Conversation 无 TTL |
无状态 |
| 缓存顺序 | tools → system → messages | 同 |
| 变更 | Assistants API 2026-08-26 关闭 |
思考按输出价计费且占 TTFT;effort 是倾向不是预算;思考是只搬运的跨轮状态
%%{init: {"flowchart": {"wrappingWidth": 200}}}%%
flowchart TB
IN["输入:完整历史<br/>(含上轮 thinking)"] --> THINK["思考阶段<br/>thinking 不可见<br/>输出价计费 · 占 TTFT"]
THINK --> OUT["可见输出<br/>文本 / tool_call"]
OUT --> STATE["返回状态<br/>thinking block 等"]
STATE --> NEXT["下轮必须携带<br/>(DeepSeek 例外)"]
EFF["effort"] -.->|"控制思考量级"| THINK
NEXT -.-> IN
classDef stage fill:#fff7e0,stroke:#c98a00,stroke-width:2px,color:#222
classDef ctl fill:#eef6ff,stroke:#5b8fd6,color:#222
class IN,THINK,OUT,STATE,NEXT stage
class EFF ctl
effort 一档 6 倍账单;历史也受校验约束
| 量 | 数 |
|---|---|
同任务 low → high |
账单 $0.0075 → $0.0445(6 倍) |
| 历史校验 | 校验 thinking block 之前的历史——编辑历史受约束 |
| Chat Completions | 自 GPT-5.4 起不支持带 effort 的工具调用 |
| DeepSeek | reasoning_content 不能送回 |
max_tokens 含思考输出价是输入的 4–6 倍、缓存读 0.1× 一次回本;TTFT 三段、总时长由输出主导
%%{init: {"flowchart": {"wrappingWidth": 170}}}%%
flowchart TB
Q["排队"] --> P["prefill<br/>∝ 未缓存输入"]
P --> T["思考<br/>∝ 思考 token"]
T --> F(["首个可见 token<br/>(TTFT)"])
F --> D["decode<br/>每 token 一步"]
D --> E(["最后 token<br/>(总时长)"])
classDef seg fill:#fff7e0,stroke:#c98a00,stroke-width:2px,color:#222
classDef mark fill:#f0f0f0,stroke:#888,color:#222
class Q,P,T,D seg
class F,E mark
输出 4–6×、缓存读 0.1×——输出主导账单
| 价 | 相对输入价 |
|---|---|
| 输出 | 4–6× |
| 缓存读 | 0.1×(Fable 5.1 0.025×、DeepSeek 0.02×) |
| 缓存写 | 1.25×(1 小时 TTL 2×) |
| 长上下文 | OpenAI > 272K:整个请求输入 2×、输出 1.5× |
| 峰时 / Batch | DeepSeek 峰时 ×2;Batch API 50% |
榜单只缩范围——选型用自己的评测集 30–50 条;级联不漏难题、弃用周期也是维度
%%{init: {"flowchart": {"wrappingWidth": 170}}}%%
flowchart TB
A["20+ 候选 → 硬约束"] -->|"榜单"| E["短名单"]
E --> F["自家评测集"]
F --> G{"过?"}
G -->|"否"| H["放宽约束"]
G -->|"是"| I["按每任务成本排"]
I --> K["选定 + 替代模型"]
classDef step fill:#fff7e0,stroke:#c98a00,stroke-width:2px,color:#222
classDef dec fill:#eef6ff,stroke:#5b8fd6,color:#222
class A,E,F,I,K,H step
class G dec
30–50 条自测集选型;弃用通知最短 4 天
| 量 | 数 |
|---|---|
| Arena 失真 | Llama 4 前 27 个私测变体;两家各约 20% Arena 数据 vs 83 个开源模型共 29.7% |
| 大小模型价差 | 5–20 倍;70% 简单请求级联省 63% |
| 自托管 | 满载 $0.8 / 百万;利用率 30% 时翻三倍 + Infra 团队 |
| 弃用通知 | OpenAI 3–6 个月、Anthropic ≥ 1 年、DeepSeek 4 天 |
错误只重试「再试可能不同」的四类;超时分四层;幂等责任在工具侧
%%{init: {"flowchart": {"wrappingWidth": 180}}}%%
flowchart TB
S(["业务层发起调用"]) --> CNT["数 token + 并发槽"]
CNT --> SEND["发送(四层超时)"]
SEND --> OK{"成功?"}
OK -->|"是"| PARSE["解析 · 读 usage"]
PARSE --> DONE(["返回 + 记 trace"])
OK -->|"否"| CLS["错误分类<br/>(下图)"]
classDef step fill:#fff7e0,stroke:#c98a00,stroke-width:2px,color:#222
classDef dec fill:#eef6ff,stroke:#5b8fd6,color:#222
classDef stop fill:#f0f0f0,stroke:#888,color:#222
class CNT,SEND,PARSE,CLS step
class OK dec
class S,DONE stop
可重试走「退避 + 预算」,不可重试看有没有 fallback——两条路最终都回到发送或失败
%%{init: {"flowchart": {"wrappingWidth": 180}}}%%
flowchart TB
CLS{"错误分类"} -->|"可重试"| BACK["退避<br/>指数 + 抖动"]
BACK -->|"预算未耗尽"| SEND["回到发送"]
BACK -->|"耗尽"| FB{"有 fallback?"}
CLS -->|"不可重试"| FB
FB -->|"换模型 / 降级"| SEND
FB -->|"无"| FAIL(["失败返回 + 记 trace"])
classDef step fill:#fff7e0,stroke:#c98a00,stroke-width:2px,color:#222
classDef dec fill:#eef6ff,stroke:#5b8fd6,color:#222
classDef stop fill:#f0f0f0,stroke:#888,color:#222
class BACK,SEND step
class CLS,FB dec
class FAIL stop
重试有预算、超时分四种、取消要传播
| 纪律 | 规则 |
|---|---|
| 重试 | full jitter \(t_n = \min(t_{max}, \text{random}(0, t_0 2^n))\);重试预算 10% |
insufficient_quota |
也是 429,不可重试 |
| 超时 | 连接 / 首字节 / 字节间 / 总——一个总超时不够 |
| 流式 | 超过一分钟的生成一律流式 |
| 计数 | Sonnet 5 同文本多 30% token;中文每字 1–2 token |
| 取消 | 用户关页面要传播到上游,否则供应商继续生成并计费 |
| 部分 | 一句话 | 篇 |
|---|---|---|
| 失效模式 | 七条性质,每条可检测 | 01 |
| 契约 | 块列表进出;工具调用是协议;思考是只搬运的状态 | 02、03 |
| 账 | 五项成本;读一次回本;TTFT 三段 | 04 |
| 选型判据 | 自己的评测集;级联;弃用周期 | 05 |
| 客户端纪律 | 四类错误、四层超时、预算、传播取消 | 06 |
insufficient_quota 不可重试/model-as-a-component.html;通关自测在系列总结