尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Cherry Studio 的 Adapter Family 机制:Endpoint 到 AI SDK 适配器的一对一映射

发布时间:2026/9/20 14:53:22

资讯中心
01
ARTICLE

Cherry Studio 的 Adapter Family 机制:Endpoint 到 AI SDK 适配器的一对一映射

Cherry Studio 的 Adapter Family 机制:Endpoint 到 AI SDK 适配器的一对一映射
Cherry Studio 的 Adapter Family 机制Endpoint 到 AI SDK 适配器的一对一映射【免费下载链接】cherry-studio Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端项目地址: https://gitcode.com/CherryHQ/cherry-studioadapterFamily是 Cherry Studio 中每个EndpointConfig上的可选字段它决定了某个 endpoint 协议由哪个ai-sdk/*包来实现是连接「用户配置的 Provider/Endpoint」与「运行时 AI SDK 适配器」之间的唯一路由信号。本文基于仓库文档 docs/references/ai/adapter-family.md 展开结合源码深入讲解该字段的运行时解析逻辑、两条写入路径目录种子与 v1→v2 迁移、Schema 约束与测试覆盖帮助你理解在多 LLM 提供商桌面客户端中如何做到「一套配置、多种协议、零启发式猜测」地选择正确的 SDK 适配器。什么是adapterFamily三层身份堆栈中的路由信号在 Cherry Studio 的 Provider 模型中一个 provider 的「身份」由三层构成adapterFamily位于最底层直接决定走哪个 SDK 实现层示例作用provider.idminimax、silicon、my-relay面向用户的身份标识、UI 标签、路由键endpointTypeopenai-chat-completions、anthropic-messagesURL 路径模板 协议家族adapterFamilyopenai-compatible、anthropic、azure-responses实现该协议的ai-sdk/*包关键设计点在于adapterFamily与provider.id不是一一对应的。多端点中继类提供商如 MiniMax、Silicon、AiHubMix在同一个provider.id下每个 endpoint 各携带一个adapterFamily——同一个 provider 的不同 endpoint 可以路由到不同的 SDK 包。例如 Silicon 在 providers.json 中同时声明了endpointConfigs: { anthropic-messages: { adapterFamily: anthropic, baseUrl: https://api.siliconflow.cn }, openai-chat-completions: { adapterFamily: openai-compatible, baseUrl: https://api.siliconflow.cn/v1 } }这意味着同一个 Silicon 账号走anthropic-messages端点时使用ai-sdk/anthropic走openai-chat-completions时则使用ai-sdk/openai-compatible。AiHubMix 甚至为四种端点分别声明了统一的aihubmix适配器家族见 providers.json由自定义适配器统一处理 Anthropic、Gemini、OpenAI 三种协议。运行时解析器单信号、无启发式adapterFamily在请求运行时只被读取从不被推断。核心解析函数位于 src/main/ai/provider/endpoint.tsexport function resolveAiSdkProviderId(provider: Provider, endpointType: EndpointType | undefined): AppProviderId { const adapterFamily endpointType ? provider.endpointConfigs?.[endpointType]?.adapterFamily : undefined if (adapterFamily adapterFamily in appProviderIds) { return resolveProviderVariant(appProviderIds[adapterFamily], endpointType) } if (endpointType ENDPOINT_TYPE.OPENAI_RESPONSES) { return appProviderIds[open-responses] } return appProviderIds[openai-compatible] }这段代码体现了几个重要设计决策解析完全基于adapterFamily这一个信号不参考provider.id、baseUrl等做任何启发式猜测heuristics。只要 endpoint 配置中存在adapterFamily且能命中已注册的appProviderIds就直接路由。变体variant解析resolveProviderVariant会基于 endpoint type 在基础 adapter 之上追加后缀。例如openai基础适配器遇到openai-chat-completions端点会映射到openai-chat变体遇到openai-responses会尝试映射到openai-responses变体见 endpoint.ts。azure-responses这类已经带变体的值会被幂等地原样传递。双终端兜底当没有adapterFamily或值无效时openai-responses端点落到通用open-responses适配器其余全部落到openai-compatible。注意对于未知的adapterFamily如totally-not-a-real-family解析器不做任何恢复尝试——它把adapterFamily的质量责任完全交给写入端UI / 迁移器 / 种子器。appProviderIds由 ai-core 的coreExtensions与 Cherry 应用扩展合并而来包含了基础 id、别名alias与变体variant的完整映射表见 src/main/ai/types/merged.ts。例如openai-response单数是openai的别名而非独立变体所以 OpenAI 的 Responses 端点最终解析回基础 idopenai由 ai-core 内部映射。端点解析完成后resolveProviderOptionsKey再根据解析出的适配器 id 推导providerOptions的命名空间如openai、anthropic、google、vertex、ollama供推理选项等 provider-option 写入方使用见 endpoint.ts。写入路径adapterFamily是派生值只在写行时计算adapterFamily被严格设计为行写入时row-write time计算、请求时request time从不计算的派生值。唯一的共享推断函数位于 packages/provider-registry/src/registry-utils.tsexport function inferAdapterFamily( endpointType: EndpointType, catalogConfig?: PickRegistryEndpointConfig, adapterFamily | ... | null ): string { if (catalogConfig?.adapterFamily) return catalogConfig.adapterFamily return ENDPOINT_TYPE_TO_DEFAULT_ADAPTER_FAMILY[endpointType] ?? openai-compatible }推断优先级是① 目录catalog中声明的adapterFamily优先编码了厂商专属的中继路由例如 AiHubMix 的anthropic-messages端点使用aihubmix而非anthropic② 否则按 endpoint type 的默认映射③ 最终兜底openai-compatible。Endpoint type 默认适配器映射当目录未指定时以下 endpoint type 有固定的默认适配器见 registry-utils.tsendpoint type默认 adapteranthropic-messagesanthropicgoogle-generate-contentgoogleollama-chat/ollama-generateollamajina-rerankjina-rerankopenai-responsesopenai其他所有openai-compatible终端兜底这套映射是纯协议推导的凡是讲 anthropic-messages 协议的端点就需要anthropic适配器凡是讲 google-generate-content 协议就需要google适配器与具体厂商无关。两个适配器服务openai-responses按实现完整度选择openaiai-sdk/openai与open-responsesai-sdk/open-responses都能说 OpenAI Responses 协议端点实现的完整度决定选哪个超集端点 —— 选openaiOpenAI、Azure以及忠实实现该协议的第三方DeepSeek、Ark/豆包、DashScope、各类中继。这些实现会完整消费 OpenAI 原生推理输入项{ id, summary }、store、加密 CoT还提供内置联网搜索带引用。只有openai适配器会解析 annotation、image、file-search 与response.created等事件路由到其他适配器会静默丢弃。厂商缺失特性是无害的未知字段会被忽略厂商怪癖也容易在此打补丁——例如 DeepSeek 的非规范事件response.reasoning_text.delta、Ark 要求而 OpenAI 容忍的 assistant 项上的status字段。子集端点 —— 选open-responses只实现核心协议、可能拒绝额外字段的精简服务器目前是 HuggingFace 路由LM Studio / vLLM / 自托管紧随其后。它们没有引用可丢中性的适配器发送最小请求体。经验法则一句话缺失的特性归openai冲突的字段归open-responses。两条写入路径目录种子与 v1→v2 迁移全项目只有两条路径会写入adapterFamily且都运行在main 进程的行写入时刻1. 目录种子新安装——packages/provider-registry/data/providers.json 为每个 provider 的每个 endpoint 声明adapterFamily种子器通过buildPersistedEndpointConfigs见 registry-utils.ts将其投影到持久化配置baseUrl、modelsApiUrls、adapterFamily与dialect中非默认的字段会被写入主进程专属的推理配置文件reasoning profiles则刻意留在 registry 内存中、不跨过这条边界。2. v1 → v2 迁移存量用户——src/main/data/migration/v2/migrators/mappings/ProviderModelMappings.ts 先按 legacy id 查目录命中则采用目录的更具体的adapterFamily未命中则调用inferAdapterFamily(endpointType)取 endpoint type 默认值。其中有两个值得注意的细节ProviderModelMigrator.ts在合并时会携带 preset 的adapterFamily前向传播ANTHROPIC_MESSAGES端点会跳过 legacy type 提示——因为 v1 的自定义 anthropic 中继即使端点讲的是 anthropic 协议其legacy.type也是openai中继协议本身是 openai 格式此时必须让端点协议胜出否则会把 anthropic 端点错误标记为openai-compatible。迁移器中还有一张LEGACY_TYPE_TO_ADAPTER_FAMILY映射表见 ProviderModelMappings.ts专门为目录无法覆盖的自定义 id v1 provider 服务如new-api→newapi、gateway→gateway让运行时解析器可以完全信任adapterFamily这一单一信号。渲染进程不写adapterFamily渲染进程的自定义 provider 表单不会设置该字段ProviderEditorDrawer.tsx只把baseUrl写入 endpoint config让字段保持缺失状态从而走解析器的openai-compatible兜底。相应地inferAdapterFamily在渲染进程没有任何调用者——它只被上面的迁移器调用。这与 provider.ts 中EndpointConfigOverrideSchema的设计一致行持久化子集只包含用户显式拥有的字段baseUrl、dialectregistry 拥有的字段modelsApiUrls、adapterFamily在读取时从 registry 解析避免渲染进程写死一份会过期的快照。Schema 约束可选字段与镜像定义adapterFamily在两个层面有 Schema 约束运行时行模型src/shared/data/types/provider.ts中的EndpointConfigSchemaexport const EndpointConfigSchema z.object({ baseUrl: z.string().optional(), modelsApiUrls: ModelsApiUrlsSchema.optional(), /** AI SDK adapter family that handles this endpoint. Carried over from the catalog */ adapterFamily: z.string().optional(), dialect: EndpointDialectSchema.optional() })见 provider.ts目录条目模型packages/provider-registry/src/schemas/provider.ts中的RegistryEndpointConfigSchema镜像了同样的结构保证目录声明与运行时读取的字段语义一致。由于 Schema 将字段声明为optional而解析器又有全量兜底openai-compatible所以没有任何写入路径被强制要求设置该字段——它是一套「写则不亏、不写也能跑」的渐进式配置。测试覆盖从推断到解析的完整链路adapterFamily的每个环节都有单测背书见下表目标文件用例数inferAdapterFamilypackages/provider-registry/src/__tests__/registry-utils.test.ts5迁移器回填src/main/data/migration/v2/migrators/mappings/__tests__/ProviderModelMappings.test.ts4运行时解析器src/main/ai/provider/__tests__/endpoint.test.ts54buildPersistedEndpointConfigspackages/provider-registry/src/__tests__/registry-utils.test.ts10其中 endpoint.test.ts 的 54 个用例值得重点研读它覆盖了目录adapterFamily优先级高于 provider.id 启发式如 Silicon 双端点分别路由到anthropic与openai-compatible见第 87-104 行变体后缀在基础 adapterFamily 之上的叠加如openai responses 端点、azure-responses直接存储未知 / 缺失adapterFamily时的终端兜底第 150-173 行自定义 provider 配置 Responses 端点无adapterFamily时落到通用open-responses第 175-194 行以及多端点中继 providerMiniMax 形态的回归保护——确保anthropic-messages端点绝不会被端点头endpoint-blind地发送 openai 格式请求第 299-309 行。延伸阅读运行时完整解析链路Provider Resolution配置状态归属设计Provider State Ownership目录数据源providers.json解析器实现src/main/ai/provider/endpoint.ts推断函数实现packages/provider-registry/src/registry-utils.tsv1→v2 迁移映射ProviderModelMappings.ts【免费下载链接】cherry-studio Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端项目地址: https://gitcode.com/CherryHQ/cherry-studio创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。