big-AGI 模型域自动解析(Editorial Auto-Picks)机制解析:三层降级链、编辑表与编译期类型安全
【免费下载链接】big-AGIAI suite powered by state-of-the-art models and providing advanced AI/AGI functions. Includes AI personas, AGI functions, world-class Beam multi-model chats, text-to-image, voice, response streaming, code highlighting and execution, PDF import, presets for developers, much more. Deploy on-prem or in the cloud.项目地址: https://gitcode.com/GitHub_Trending/bi/big-AGI
导读
big-AGI 中每个"模型域"(Domain,如primaryChat、codeApply、fastUtil、imageCaption)都需要一个可用的 LLM;当用户没有手动固定(Pin)某个模型时,系统会自动解析一个默认模型。本文基于 LLM-editorial-auto-picks.md 与仓库源码,完整剖析这条自动解析链路:用户固定(Pin)→ 编辑表推荐(Editorial pick)→ ELO/成本启发式(ELO/cost heuristic)的三层降级逻辑,并深入讲解"编辑表"(EditorialDefaults)如何以手工策展的跨厂商优先级提供可预测的默认值,以及整套机制如何借助 TypeScript 字面量联合实现编译期类型安全。读完后,你将能定位任意域模型的默认来源、理解编辑表条目的编写与匹配规则,并能在自己的模型选型模块中复用这套"策展优先 + 启发式兜底"的架构思路。
一、背景:什么是"模型域",为什么需要自动解析
big-AGI 将不同的模型用途抽象为若干域(Domain),每个域代表一类固定场景。域标识符定义在 model.domains.types.ts 的DModelDomainId联合中,共 4 个:
primaryChat:主聊天模型,用于 Chat 窗口,通常从对话历史推断或由 Persona 指定;codeApply:代码编辑器模型,用于应用代码变更及其他代码操作;fastUtil:快速工具模型,用于 Auto-Title、Summarize 等"快"特性,要求具备函数调用能力;imageCaption:图像描述模型,在把图片发送给主聊天模型之前先生成详细的文字描述。
每个域在 model.domains.registry.ts 中注册了规格(ModelDomainSpec),包括显示标签、autoStrategy(自动选择策略)、requiredInterfaces(必需接口列表)以及可选的fallbackDomain/editorialFallbackDomain。例如codeApply要求接口LLM_IF_OAI_Fn,imageCaption的自动策略是topVendorTopLlm并可在主域失败时回退到primaryChat。
当一个域需要模型、而用户没有显式固定时,系统调用llmsAssignmentsAutoModelId()(位于 store-llms-domains_slice.ts)解析默认模型。该函数按顺序尝试三层:Pin → Editorial pick → ELO/cost heuristic。
二、三层解析链(Resolution Layers)
第 1 层:Pin(用户固定)
modelAssignments[domainId]保存用户的显式固定。语义在assignDomainModelId()(store-llms-domains_slice.ts)中实现:
- 固定指向一个有效 LLM:直接使用;
- 固定为
null:用户显式选择"该域不要模型"; - 记录不存在:Auto 模式,进入第 2 层。
仓库中还配套实现了两条维护逻辑,保证 Pin 层始终干净:
llmsAssignmentsPruneStale()(store-llms-domains_slice.ts):当 LLM 全局列表(universe)发生变更或 store 重新水合时,剔除引用已不存在模型的固定项;被剔除的条目视同 Auto,在读取时重新解析;assignDomainModelAutoIfStale()(store-llms-domains_slice.ts):同步期的维护操作,若固定指向的模型已不可见(被隐藏),则清除固定并退回 Auto。
第 2 层:Editorial pick(编辑表推荐)
llmsEditorialPickForDomain(domainId, filteredLlms)遍历编辑表(见下文"编辑表"一节),返回第一个与用户本地 LLM 列表匹配的(vendor, modelId)对。这一层是手工策展的跨厂商默认值来源,提供不依赖 ELO 或成本启发式的可预测结果。
值得注意的是,该函数支持一个可选的第三参数fallbackEditorialDomainId:当主域没有编辑条目、或条目全部不匹配时,可以转而检查备选域的编辑表。这个参数由域的editorialFallbackDomain规格驱动(model.domains.registry.ts),并在解析器中被传入(store-llms-domains_slice.ts)。
第 3 层:ELO/成本启发式(ELO/cost heuristic)
当编辑表没有任何条目匹配时,系统回退到按域配置(ModelDomainsRegistry中的autoStrategy)的两种策略之一:
topVendorTopLlm:选择ELO 最高厂商中的 ELO 最高模型。实现见_strategyTopQuality()(store-llms-domains_slice.ts),直接取"厂商分组中第一个厂商的第一个模型"。被primaryChat、codeApply、imageCaption使用。topVendorLowestCost:在顶部厂商中选择成本最低(非免费)的模型,且优先选择带 ELO 评分的模型。实现见_strategyTopVendorLowestCost()(store-llms-domains_slice.ts)。被fastUtil使用。其设计假设是:最低非零成本通常落在最新模型上,而最新模型往往也是更好的模型。
两种策略共享同一套预处理:_groupLlmsByVendorRankedByElo()(store-llms-domains_slice.ts)把可见模型按厂商分组、组内按 ELO 降序、厂商之间按其最高 ELO 降序。成本排名costRank来自_getLlmCostBenchmarkFromPricing()(store-llms-domains_slice.ts),它基于一个假设性基准成本:10 万输入 token + 1 万输出 token的总价。注意 ELO 排序中cbaElo缺失的模型按 -1 处理(排最后),隐藏模型(isLLMHidden)直接不参与分组。
在进入三层解析之前,解析器还会先按域的requiredInterfaces收窄候选集:_allowedDomainLlms()(store-llms-domains_slice.ts)要求候选模型具备全部必需接口;但如果过滤后没有任何模型匹配,则放宽条件退回全量列表,避免"无模型可用"。
此外,同一文件中还提供了两个启发式入口:llmsHeuristicGetTopDiverseLlmIds()(按 ELO 跨厂商轮转取多样化的 Top 模型)与llmsHeuristicGetTopFastLlmIds()(按成本跨厂商轮转取低价模型,免费/0 成本模型被排到末尾)。它们体现了"多厂商多样性 + 兜底填充"的通用选型思路,与域解析共用同一套分组逻辑。
三、编辑表(Editorial Table)详解
编辑表位于 model.domains.editorial.ts,导出常量EditorialDefaults。
3.1 结构(Shape)
每个域映射到一个有序的{ vendor, modelId }数组。原文档的骨架如下:
export const EditorialDefaults = { primaryChat: [ { vendor: 'anthropic', modelId: 'claude-opus-4-7' }, { vendor: 'openai', modelId: 'gpt-5.5' }, { vendor: 'googleai', modelId: 'models/gemini-3.5-flash' }, // ... ], codeApply: [ /* ... */ ], // ... } as const satisfies _EditorialDefaultsTable;对照当前仓库实际内容(model.domains.editorial.ts),表内条目持续迭代并带有详尽注释:例如primaryChat当前以claude-fable-5-1打头(注释记录了 2026-09-01 解除冻结、Bedrock 停留 5.1 需账号授权等背景),随后是claude-opus-5(2026-07-24 发布,1M 上下文、默认开启思考)、claude-opus-4-8、OpenAI 的gpt-6-astra(2026-09-03 旗舰)、gpt-5.6-sol、Gemini 系列models/gemini-3.7-flash等,末尾总是 NVIDIA NIM 的免费试用条目。codeApply域则把 Gemini Flash 系列与gpt-5.3-codex排在前面,体现"代码优化模型优先"的域意图。这些注释本身就是维护者留下的决策记录,是理解编辑表演变的第一手资料。
3.2 关键性质
- 数组顺序即跨厂商优先级。picker 返回第一个匹配项,不查询任何外部 ELO 排名——一个 Gemini 模型可以夹在两个 Anthropic 条目之间,反之亦然。这在源码注释中反复强调:"Array order IS the cross-vendor precedence - any vendor's model can be sandwiched between picks from other vendors."
- 按域定制列表。每个域独立编排,反映域用途(如
codeApply偏好代码模型、fastUtil偏好廉价快速模型、imageCaption偏好视觉模型)。 - 没有条目的域直接落入第 3 层(ELO/成本启发式)。
- NVIDIA NIM 条目固定在每个域列表尾部:它是免费试用端点,所以只要配置了付费厂商,付费厂商一定先命中;只有完全没有付费厂商时 NIM 才作为兜底。注释同时记录了多次 EOL 清理(如
deepseek-v4-pro在 NVIDIA 上 410 Gone、z-ai/glm-5.2于 2026-08-24 EOL 被移除)。
3.3 匹配逻辑(宽容匹配)
_editorialMatch()(model.domains.editorial.ts)对llm.initialParameters.llmRef依次尝试三种匹配,以容忍日期后缀与 OpenRouter 的点号 ID:
- 精确匹配:
llmRef === editorialId; - 前缀匹配:
llmRef.startsWith(editorialId),用于处理厂商追加的日期后缀(如-20250514); - 点/横线等价匹配:
llmRef.replace(/\./g, '-') === editorialId.replace(/\./g, '-'),用于 OpenRouter 的anthropic/claude-fable-5.1与编辑表中的anthropic/claude-fable-5-1之间的对应。
注意匹配基于llmRef(模型的初始参数引用),而非DLLMId,注释明确指出了这一点(被注释掉的备选实现llm.id === editorialId有意未启用)。
3.4 picker 实现要点
llmsEditorialPickForDomain()(model.domains.editorial.ts)按声明顺序遍历EditorialDefaults[domainId],用llm.vId === vendor && _editorialMatch(llm, modelId)找第一个命中;无命中返回undefined,由调用方(自动解析器)落入 ELO/成本策略。主域无条目时按前述fallbackEditorialDomainId逻辑退到备选域。
3.5 域系统之外的编辑建议:视频输入提示
编辑表文件还额外承载了一个域系统之外的"能力建议":llmsEditorialVideoInputPick()(model.domains.editorial.ts)在用户粘贴视频 URL 且当前模型不支持视频输入时,推荐一个可看视频的模型。它只考虑 Gemini 家族(原生googleai或llmRef含gemini的服务,如 OpenRouter 的google/gemini-*),因为"URL 视频(YouTube 抓取)是 Gemini 的能力";排序规则为:可见优先于隐藏、pubDate最新优先、原生 Google AI 服务优先。对应的提示文案EditorialVideoInput由 composer 在视频粘贴场景下展示。
四、类型安全链(Type-Safety Chain)
编辑表的每个modelId都在编译期受限于该厂商已知模型 ID 的字面量联合,这是整套机制最重要的工程质量保障。
4.1 厂商模型 ID 类型如何派生
各厂商模型文件通过llmsDefineModels()(定义于 models.mappings.ts,OpenAI 风格厂商使用其预实例化版本llmsDefineManualMappings)导出一个const数组,再从数组推导字面量联合。例如 xAI:
// in xai.models.ts (L16) export type LlmsXAIModelId = typeof _knownXAIChatModels[number]['idPrefix'];llmsDefineModels<TElem>()工厂保留数组的 const 类型,因此联合会追踪数组中每个idPrefix(或id)字面量。在厂商文件中增删模型会自动更新联合类型,编辑表侧的旧 ID 随即在编译期报错。Anthropic 与 Gemini 因按id而非idPrefix组织,其类型推导分别见 anthropic.models.ts 与 gemini.models.ts。
4.2 编辑表的判别联合
model.domains.editorial.ts 声明了按vendor判别、将modelId绑定到对应厂商类型(或string)的联合:
type _EditorialPick = | { vendor: 'anthropic', modelId: LlmsAnthropicModelId } | { vendor: 'openai', modelId: LlmsOpenAIModelId } | { vendor: 'bedrock', modelId: `${'us.' | 'global.'}anthropic.${LlmsAnthropicModelId}${'' | '-thinking' | '-v1:0'}` } | { vendor: 'openrouter', modelId: `anthropic/${LlmsAnthropicModelId | 'claude-haiku-4-5'}` | `google/${string}` | `openai/${LlmsOpenAIModelId}` } // ... ;对比原文档的示意版本,当前源码对动态厂商也做了更精细的约束:Bedrock 的modelId被收窄为us./global.前缀 + Anthropic 模型 ID + 可选-thinking/-v1:0后缀的模板字符串类型;OpenRouter 则限定为anthropic/、google/、openai/三种前缀。这比单纯的string更严格,但依旧为运行时发现的模型保留余地。
同时存在一条编译期断言(model.domains.editorial.ts):
const _assertEditorialVendorsAreValid: [_EditorialPick['vendor']] extends [ModelVendorId] ? true : never = true;它保证联合中每个厂商字面量都必须是合法的ModelVendorId。
4.3 编译器能捕获什么
- 厂商名拼写错误(如
'oepnai'):触发_assertEditorialVendorsAreValid断言失败; - 厂商与模型不匹配(如
{ vendor: 'anthropic', modelId: 'gpt-5.5' }):判别联合收窄失败; - 厂商下线模型后编辑表残留旧 ID:
LlmsXxxModelId随厂商已知模型数组自动更新,旧 ID 不再属于联合,编译报错。
4.4 厂商覆盖范围
- 静态厂商(富字面量联合):Anthropic、OpenAI、Gemini(
googleai)、xAI、Z.AI、Moonshot、DeepSeek、NVIDIA NIM(nvidianim),提供最强的编译期保证; - 动态厂商:OpenRouter、Bedrock 的模型列表在运行时发现,
modelId用string或模板字符串放宽约束; - 其余已注册厂商(Alibaba、ArceeAI、Azure、ChutesAI、FastAPI、FireworksAI、Groq、LLMAPI、Novita、TogetherAI)同样通过
llmsDefineManualMappings导出LlmsXxxModelId类型,但其已知模型数组目前可能为空——llmsDefineModels的基元素类型退化为TElem而非never(models.mappings.ts 的注释解释了这一点),机制保持就绪,未来可直接补充编辑条目; - MiniMax、Perplexity 使用按
id键控的ModelDescriptionSchema[]数组,而非idPrefix,但同样的 const 追踪机制适用。
五、向外的纵深:pubDate 编辑轴与未策展标记
编辑表只是 big-AGI 对模型元数据编辑控制的一个维度。围绕"每模型元数据"还有另一条编辑轴——pubDate(发布时间)、策展描述、chatPrice、benchmark、parameterSpecs等字段的保证与取舍,详见同目录的 LLM-editorial-pubdate.md。简要关联如下:
pubDate('YYYYMMDD'格式字符串,字段定义见 llms.types.ts)在编辑条目中保证输出;Anthropic 与 Gemini 的 0-day 模型分别由llmsAntCreatePlaceholderModel()(anthropic.models.ts)与geminiModelToModelDescription()(gemini.models.ts,未知模型回退到formatPubDate())兜底填充;- 客户端侧,
getLLMPubDate()与isLLMRecentlyPublished()(llms.types.ts)驱动 "new" 徽标与排序(LLM_RECENTLY_PUBLISHED_DAYS = 45); [?]未策展标记(llmsLabelUncurated()/llmsIsLabelUncurated(),models.mappings.ts)用于标注"列表 API 无法确定该模型是什么"的 ID-only 目录,与"尚未策展"是不同的语义——它由llm-registry-sync等下游消费,避免把视频/TTS/Embedding ID 误当作聊天模型发布。
六、相关文件速查
| 文件 | 作用 |
|---|---|
| model.domains.editorial.ts | 编辑表EditorialDefaults+ pickerllmsEditorialPickForDomain+ 视频输入建议 |
| store-llms-domains_slice.ts | 三层解析器llmsAssignmentsAutoModelId、Pin 维护、ELO/成本策略实现 |
| model.domains.types.ts | DModelDomainId联合(四个域) |
| model.domains.registry.ts | 域规格(autoStrategy、requiredInterfaces、fallbackDomain、editorialFallbackDomain) |
| models.mappings.ts | llmsDefineModels/llmsDefineManualMappings类型推导工厂、fromManualMapping、formatPubDate、[?]标记 |
| LLM-editorial-pubdate.md | 同一编辑理念在 per-model 元数据(pubDate等)轴上的展开 |
七、结语:这套机制的工程价值
回顾整条链路,big-AGI 的域模型自动解析体现了三个可复用的设计原则:确定性优先——手工策展的编辑表让"默认模型"可预期、可解释,不依赖波动中的 ELO/成本数据;分层兜底——Pin → Editorial → Heuristic 逐级降级,任何一层失效都有下一层接住,且通过fallbackDomain/editorialFallbackDomain提供域间兜底;类型即文档——借助llmsDefineModels的 const 追踪与判别联合,把"厂商模型清单"与"编辑表"在编译期绑定,增删模型、拼写错误、跨厂商错配都在构建期暴露。理解这套机制后,无论是排查"为什么自动选了这个模型",还是为新增域编写编辑条目,都有明确的代码路径可循。
【免费下载链接】big-AGIAI suite powered by state-of-the-art models and providing advanced AI/AGI functions. Includes AI personas, AGI functions, world-class Beam multi-model chats, text-to-image, voice, response streaming, code highlighting and execution, PDF import, presets for developers, much more. Deploy on-prem or in the cloud.项目地址: https://gitcode.com/GitHub_Trending/bi/big-AGI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考