.gitignore 掉了。这层抽象要解决的问题不只是「请求格式不同」。真正难的是三件事:认证方式各不相同(API key / OAuth / 订阅账号 / 云厂商 IAM)、流式事件语义不同、以及模型能力矩阵每周都在变(上下文窗口、价格、是否支持 thinking、是否支持工具)。
前两件靠代码解决,第三件靠不把它当代码——生成、不入库、构建时刷新。
// This file is auto-generated by scripts/generate-models.ts
// Do not edit manually - run 'npm run generate-models' to update
import values from "./data/anthropic.json" with { type: "json" };
import { flattenModelCatalog, type ModelCatalog } from "../model-catalog.ts";
export const ANTHROPIC_MODELS: ModelCatalog<typeof values, "anthropic"> =
flattenModelCatalog("anthropic", values);
后果直接写在 README 的开发命令里:npm run build 会先刷新模型数据再构建;想不联网构建必须用 build:offline。README.md:56
发布用的源码归档里则包含这份生成数据,这样打包者能离线复现官方二进制。README.md:74
库只收支持 tool calling 的模型。ai/README.md:5 这一句把 pi-ai 从「通用 LLM SDK」区分了出来——它是 agent 的基础设施,不是中立的多家封装。
调 models.stream() 时,认证经由所属 provider 解析并合并进请求;每次请求里显式给的值永远优先(环境变量、存储的凭证、OAuth token 都排在后面)。ai/README.md:330
并且解析结果可以不发请求就查——models.getAuth(provider) 或 getAuth(model)。对一个要同时支持 API key、OAuth 订阅、云厂商凭证的库来说,「能单独查认证怎么解析出来的」是必要的可调试性。
这也解释了 第 03 章里循环为什么要 getApiKey 回调:OAuth token 会过期,而一个 run 可能跑很久,认证必须在每次 LLM 调用时重新解析,不能在构造时固定。
好处:模型清单每周都在变(新模型、改价、改窗口),入库会让 git 历史里塞满与代码无关的数据变更,而且永远滞后。构建时刷新意味着发版时的清单总是新的。
代价有三条,都很实在:
build:offline)。与 第 16 章那套「依赖精确锁版本、拒绝同日发布」的谨慎相比,这里的取舍是反向的:依赖代码要钉死,模型数据要最新。区分依据是——依赖代码会执行,模型元数据只是数据。
5.8 万行是很大的投入。从收录标准(只要支持 tool calling 的模型)和认证设计(订阅账号、OAuth)能看出理由:通用库优化的是「换 provider 容易」,agent 需要的是「工具调用、流式、成本、thinking 级别在所有 provider 上语义一致」——后者要深入到每家的细节里去抹平,而不是找最大公约数。
这个判断是否值 5.8 万行,取决于你要支持几家。支持 2 家不值,支持 39 家大概值。
上游讲这条理由,是在仓库之外:Earendil《What is a Harness?》(2026-08-20),比 ac4ac9e 晚 13 天。文中的理由是用户侧的选择权,直说是为了 “take power and leverage away from the AI labs and into the hands of end users”。
*.models.ts 文件数统计的,其中若干是同一家的不同接入方式(如 openai / openai-codex / azure-openai-responses),也包含若干区域变体(minimax / minimax-cn)。真实的「厂商数」小于 39。docs/custom-provider.md),不是等它被收录。这条证据的级别与本书其余部分不同。《What is a Harness?》是第一方立场文,能证明的只有「上游对外这么讲」,不能证明「代码这么跑」——它不是代码,也不是仓库文档,没有行号,也不该有。本条同样不进漂移记录:那里收的是同一 SHA 内「文档 vs 代码」的双向举证,这里有一侧根本不在仓库里。
场景同一个 commit,你在相隔两周的两天各跑一次 npm run build。两次产物一致吗?
B。模型元数据被当作构建产物而非源码。.gitignore:11 想复现官方发布要用发布归档里附带的数据快照 + build:offline。
场景你想在 pi 里接一个不支持 tool calling 的纯对话模型。可行路径是什么?
B。收录标准明确只收支持 tool calling 的模型——A 不会发生,这是设计选择而非疏漏;绕开目录的路径是自定义 provider。
ac4ac9e(2026-08-07 快照)。