Cherry Studio 应用版本(Edition)与 Provider 可用性跟随机制:全局版/中国版数据共享下的模型可见性实践
人工智能大模型AI 应用交互助手本地部署【免费下载链接】cherry-studio Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端项目地址https://gitcode.com/CherryHQ/cherry-studio点击查看免费下载导读Cherry Studio 提供全局版global与中国版cn两种应用版本二者共享同一份本地用户数据但每个版本只暴露其官方支持的 Provider 与模型。本篇基于仓库中的 breaking change 文档v2-refactor-temp/docs/breaking-changes/2026-09-02-edition-provider-availability.md并结合源码实现完整讲解版本如何被识别、Provider 与模型的可用性如何按版本过滤、切换版本后数据为何不丢失、用户遇到不可用模型时应如何处理以及发布管理人员需要关注的风险点。变更概述Provider 可用性跟随应用版本自 2026-09-02PR #19776起Cherry Studio 引入了Provider 可用性跟随应用版本的破坏性变更breaking change核心行为如下全局版与中国版共享本地用户数据两份版本共用同一份 SQLite 本地数据库Provider、模型、助手、会话等数据落盘位置一致。每个版本只暴露其支持的 Provider 与模型当前版本不支持的 Provider/模型记录在读取与使用层面会被视为不可用不再出现在运行时可见的数据集合中。不可用记录仍然保留这些记录不会被删除、不会被迁移、不会被覆写依旧完整存储在本地数据库中当用户切换回支持这些记录的其他版本后记录会重新变为可用。这一变更的本质是可用性判定发生在读取/使用的边界上而非存储的边界上——数据层永不丢失过滤只发生在运行时暴露层。版本Edition机制在仓库中的实现AppEdition 类型版本类型在 src/shared/types/appEdition.ts 中定义只有两个合法取值import type { ProviderEdition } from cherrystudio/provider-registry export const APP_EDITIONS [global, cn] as const satisfies readonly ProviderEdition[] export type AppEdition (typeof APP_EDITIONS)[number]注意这里AppEdition直接约束自 provider-registry 包的ProviderEdition类型说明应用版本与Provider 注册表中的版本声明共用同一套枚举语义保证两侧判定一致。版本解析与缓存版本的实际解析逻辑位于 src/main/utils/appEdition.tsconst APPLICATION_IDS { global: com.kangfenmao.CherryStudio, cn: com.cherryai.cherrystudio.cn } as const satisfies RecordAppEdition, string解析顺序为开发环境覆盖若应用未打包!app.isPackaged且设置了环境变量CHERRY_EDITION则以其为准parseAppEdition会做小写 trim 并校验打包环境读取元数据读取应用根目录package.json中的cherryEdition字段未定义时默认回退为global非法值非global/cn会直接抛出Unsupported application edition错误。解析结果通过getAppEdition()惰性缓存cachedAppEdition ?? resolveAppEdition()进程内只解析一次getApplicationId()则根据版本返回对应的应用标识CN 版使用独立的com.cherryai.cherrystudio.cn这保证了两版本可共存安装但共享用户数据目录的边界设计。Provider 注册表中的版本声明Provider 是否在某个版本可用由 provider-registry 包中的静态元数据availableInEditions声明。其 Schema 定义在 packages/provider-registry/src/schemas/provider.tsexport const ProviderEditionSchema z.enum([global, cn]) export type ProviderEdition z.infertypeof ProviderEditionSchema // ... availableInEditions: looseArray(ProviderEditionSchema, { min: 1 }).optional(),availableInEditions为可选字段缺省时语义上是对所有版本可用。仓库内实际声明示例packages/provider-registry/src/providers 目录双版本可用deepseek[global, cn]、dashscope、doubao、moonshot、minimax、new-api、modelscope、baichuan、baidu-cloud、cherryin、lmstudio、gpustack等仅全局版anthropic、gemini、grok、mistral、cerebras、fireworks、huggingface、azure-openai、aws-bedrock、copilot等。也就是说切换中国版后某些 Provider 不可见并非运行时临时屏蔽而是注册表数据中本来就只声明了global。Provider 可用性判定的核心逻辑ProviderService可用性判定的入口在 src/main/data/services/ProviderService.ts核心函数function isProviderAvailableInCurrentEdition(provider: PickProvider, availableInEditions): boolean { const availableInEditions provider.availableInEditions return isMigratedFromV1() || !availableInEditions || availableInEditions.includes(getAppEdition()) }判定规则任一成立即可用v1 迁移来源豁免isMigratedFromV1()为真用户数据来自 v1 迁移时全部放行——避免老用户升级后被瞬间隐藏全部 Provider无版本声明注册表未声明availableInEditionsundefined/空视为全版本可用显式包含当前版本availableInEditions数组包含当前getAppEdition()。再向上封装为getAvailableProviderMetadata退役retiredProvider 先行排除function getAvailableProviderMetadata(row: ProviderIdentity): ProviderDisplayMetadata | null { if (isRetiredProvider(row.providerId, row.presetProviderId)) return null const metadata getDataService(ProviderRegistryService).getProviderDisplayMetadata(...) return isProviderAvailableInCurrentEdition(metadata) ? metadata : null }并导出isProviderIdentityAvailable(row)它只依赖身份列 静态注册表 构建期版本 v1 来源标记即可判定便于在其他事务中调用而不需要新开数据库连接。读取路径列表与详情都做版本过滤list(query)遍历userProviderTable全部行逐行调用getAvailableProviderMetadata不可用行直接跳过不进运行时返回结果getByProviderId(providerId)先assertProviderAvailable(row, providerId)断言当前版本不可用时抛出DataApiErrorFactory.notFound(Provider, providerId)即对调用方表现为该 Provider 不存在。写入路径显式拒绝创建create(dto)在落库前会校验注册表元数据if (!isProviderAvailableInCurrentEdition(presetMetadata)) { throw DataApiErrorFactory.invalidOperation( create provider ${dto.providerId}, provider is unavailable in the current application edition ) }即当前版本不支持时新建 Provider 会被直接拒绝错误信息明确为在当前应用版本中不可用避免用户在当前版本下配置一个永远无法使用的 Provider。运行时断言供其他服务调用ProviderService 还暴露了三个运行时检查接口供上游Agent、Assistant、消息发送等使用listAvailableProviderIds(providerIds?)批量返回当前版本可用的 Provider ID 集合isAvailableByProviderId(providerId)单项可用性检查assertAvailable(providerId)不可用时抛 not-found 断言。这些方法保证了Provider 可用性在请求发送链路上被统一执行而不是只在前端 UI 层面做隐藏。模型层同样按版本过滤ModelService模型与 Provider 是强关联的每个user_model行都通过外键挂在某个 Provider 之下ON DELETE CASCADE。src/main/data/services/ModelService.ts 在查询时通过内连接把 Provider 的身份列一并取出function selectWithProviderIdentity(tx: PickDbType, select) { return tx .select({ model: userModelTable, providerId: userProviderTable.providerId, presetProviderId: userProviderTable.presetProviderId }) .from(userModelTable) .innerJoin(userProviderTable, eq(userProviderTable.providerId, userModelTable.providerId)) }然后在模型读取处复用 Provider 的判定findByIdTx(tx, id): Model | null { const [row] selectWithProviderIdentity(tx).where(eq(userModelTable.id, id)).limit(1).all() return row isProviderIdentityAvailable(row) ? this.enrichRowsFromRegistry([row.model])[0] : null } existsByIdTx(tx, id): boolean { const [row] selectWithProviderIdentity(tx).where(eq(userModelTable.id, id)).limit(1).all() return row ! undefined isProviderIdentityAvailable(row) }由于模型查询采用innerJoin而 Provider 行不会被删除因此不会因 join 丢失行当前版本不可用完全由isProviderIdentityAvailable在读取边界上拦截。从源码注释可见这一设计意图Providers unavailable in the current edition are treated as missing before the row is enriched——在当前版本中不可用的 Provider 下的模型在富化enrich之前就被当作缺失处理。这正是文档中assistants and agents bound to an unavailable provider or model cannot send requests的底层原因当用户把 Assistant/Agent 绑定到某个模型后若切换版本导致该模型变为不可用请求发送链路在解析模型时即失败直到用户重新选择模型。数据保留语义为什么切换回原版本数据原样归来这是本次变更最关键的破坏性行为也是用户最关心的点。从源码结构可以确认其数据层语义没有任何删除操作ProviderService/ModelService中所有 edition 过滤都发生在查询/读取边界没有任何delete、update语句针对不可用记录存储与展示解耦userProviderTable、userModelTable中的行、API Key、端配置endpointConfigs、Auth 配置authConfig、默认模型设置等全部保留切换回来即恢复由于过滤条件availableInEditions.includes(getAppEdition())是纯函数判定当getAppEdition()切回支持该 Provider 的版本时同一行数据立即重新满足条件恢复可用。因此文档中的承诺——No provider, model, assistant, or conversation data is deleted——在实现层面是成立的数据是看不见而非被删除。对用户的实际影响与操作建议影响场景从全局版切换到中国版时所有availableInEditions仅含global的 Provider如 Anthropic、Gemini、Grok、Mistral 等及其下模型将变为不可用绑定在这些模型上的 Assistant、Agent 无法再发起请求请求发送在模型解析阶段即失败会话历史、消息内容、Provider 配置数据均不受影响仍然完整保留。用户的应对方式文档明确给出两条路径在当前版本内重新选择为受影响的 Assistant/Agent 重新选择一个当前版本支持的 Provider 与模型例如切换至 DeepSeek、通义千问 DashScope、豆包 Doubao、Moonshot 等双版本 Provider 的模型切回原版本如果现有配置对中国版不可用且无法替换切换回支持该配置的全局版即可恢复全部可用性无需重新配置任何数据。给发布管理人员的提示文档的 release notes 指引值得特别留意留在全局版的用户完全不受影响不必在发布说明中制造恐慌切换至中国版的用户需要明确提示需要重新选择模型这是本次变更唯一需要用户主动操作的事项应在发布公告中单独强调。测试覆盖版本行为的自动化验证仓库为这一行为提供了专门的测试文件src/main/data/services/tests/ProviderService.edition.test.ts通过vi.mock分别控制getAppEdition()如固定为cn与isMigratedFromV1()并 mock 注册表仅提供availableInEditions: [global]的global-onlyProvider验证中国版下已持久化的 global-only Provider 在所有运行时读取与变更路径上均不可用src/main/data/services/tests/ModelService.edition.test.ts对应模型层的版本过滤验证。从测试结构可以推断版本判定是可 mock、可独立验证的纯逻辑便于后续新增 Provider 时快速补充版本声明与回归用例。此外 packages/provider-registry/src/tests/catalog-source-sync.test.ts 中还有对注册表目录数据的校验如断言cherryin声明了cn、默认 Provider 声明了global保证静态数据与双版本策略一致。小结Provider 可用性跟随应用版本是 Cherry Studio 在双版本global / cn产品策略下的关键边界设计共享一份数据按版本差异化暴露能力。本文梳理了从版本解析CHERRY_EDITION/cherryEdition→ 注册表声明availableInEditions→ 读取过滤isProviderAvailableInCurrentEdition→ 写入拦截create抛错→ 模型层复用判定的完整调用链。对开发者而言新增 Provider 时应正确声明availableInEditions对用户而言切换版本前应确认自己的模型绑定是否在该版本可用切换后若发现模型消失只需重新选择模型或切回原版本即可数据始终安全。赞分享人工智能大模型AI 应用交互助手本地部署【免费下载链接】cherry-studio Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端项目地址https://gitcode.com/CherryHQ/cherry-studio点击查看免费下载相关推荐WrenAI wren-core-base 版本演进全解析MDL 语义层共享 Manifest 类型与布局版本机制WrenAI wren core base 版本演进全解析MDL 语义层共享 Manifest 类型与布局版本机制 本篇文章以 WrenAI 仓库中 core后端人工智能AI Agent数据分析Machine Learning Yearning 中文版数据可用性对模型性能的影响分析Machine Learning Yearning 中文版数据可用性对模型性能的影响分析 你是否曾遇到过这样的困境明明投入了大量资源收集数据模型性能却停滞文档教程SchemaSpy多数据库支持深度测评MySQL、PostgreSQL、Oracle对比分析SchemaSpy多数据库支持深度测评MySQL、PostgreSQL、Oracle对比分析 SchemaSpy作为一款专业的数据库文档生成工具其强大的多数创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

OneUptime 状态页资源与分组完全指南:从单条监控到多级分组与 Grid 矩阵布局

OneUptime 状态页资源与分组完全指南:从单条监控到多级分组与 Grid 矩阵布局

OneUptime 状态页资源与分组完全指南:从单条监控到多级分组与 Grid 矩阵布局 【免费下载链接】oneuptime Complete open-source monitoring and observability platform. 项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime 本篇指南聚焦 OneUptim…

2026/9/20 19:58:44 阅读更多 →
pandoc 的 opendocument 交叉引用扩展(xrefs_name / xrefs_number)源码级解析

pandoc 的 opendocument 交叉引用扩展(xrefs_name / xrefs_number)源码级解析

pandoc 的 opendocument 交叉引用扩展(xrefs_name / xrefs_number)源码级解析 【免费下载链接】pandoc Universal markup converter 项目地址: https://gitcode.com/gh_mirrors/pa/pandoc 本篇文章基于 pandoc 官方命令行测试 test/command/6774.…

2026/9/20 19:57:43 阅读更多 →
具身智能开发入门:从感知决策到边缘部署

具身智能开发入门:从感知决策到边缘部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 19:57:43 阅读更多 →

最新新闻

MATLAB晶粒生长模拟:蒙特卡洛Potts模型实现与应用

MATLAB晶粒生长模拟:蒙特卡洛Potts模型实现与应用

1. 项目背景与核心价值在材料科学研究领域,晶粒组织的演化过程直接影响着金属、陶瓷等材料的力学性能和物理特性。传统实验方法需要耗费大量时间和资源进行金相制备、热处理和显微观察,而计算机模拟技术为研究者提供了一种高效、低成本的替代方案。这个M…

2026/9/22 0:07:44 阅读更多 →
5年大厂面试官揭秘:奇拿面试题新手避坑指南

5年大厂面试官揭秘:奇拿面试题新手避坑指南

5年大厂面试官揭秘:奇拿面试题新手避坑指南 官方文档翻了三遍还是像看天书?别慌,这就是典型的【奇拿】场景。很多【新手避坑】指南只讲理论,却忽略了大厂面试官真正想听的那句人话。今天我就把底裤都扒了,带你用最短时间抓住【奇拿】考点的核心,让你下…

2026/9/22 0:07:44 阅读更多 →
qq恢复网站入门到精通:3步避坑,选型不踩雷

qq恢复网站入门到精通:3步避坑,选型不踩雷

qq恢复网站入门到精通:3步避坑,选型不踩雷 官方文档翻了三遍还是晕?别急,谁第一次看QQ找回账号的后台逻辑不是这样。官方流程太冗长,关键节点藏得深,导致你卡在“验证方式”和“数据同步”上,根本抓不住重点。今天咱们不念经,直接拆解从0到1搭…

2026/9/22 0:07:44 阅读更多 →
Excel VBA中Range.Value数组特性解析与应用

Excel VBA中Range.Value数组特性解析与应用

1. 深入理解VBA中Range.Value返回的数组特性在Excel VBA开发中,Range对象的Value属性是最基础也是最常用的功能之一。但许多开发者(包括我在早期)都曾在这个看似简单的操作上栽过跟头。今天我们就来彻底剖析这个日常操作背后的机制。关键发现…

2026/9/22 0:07:44 阅读更多 →
3个坑解决版本升级API全变:手写实现如何打广告核心逻辑

3个坑解决版本升级API全变:手写实现如何打广告核心逻辑

3个坑解决版本升级API全变:手写实现如何打广告核心逻辑 版本升级后 API 全变了,你写的代码直接报 AttributeError ,是不是瞬间血压飙升?别慌,这种时候硬啃新文档不如 手写实现 底层逻辑来得快。…

2026/9/22 0:07:44 阅读更多 →
ISO9001体系高频面试题:3年实战避坑指南与代码级解析

ISO9001体系高频面试题:3年实战避坑指南与代码级解析

ISO9001体系高频面试题:3年实战避坑指南与代码级解析 昨天刚带一个新人做审计,他手里拿着从网上复制的《质量手册》草稿,问我在“4.1…

2026/9/22 0:06:44 阅读更多 →

日新闻

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天

3台商务办公笔记本实测:手写实现环境配置,告别卡半天 配置环境就卡半天?别怪机器慢,多半是你没选对工具链。在Java、Go或Python的项目现场, 手写实现…

2026/9/22 0:00:41 阅读更多 →
剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑

剑帝加点速查手册:3分钟搞懂核心逻辑 面试被问原理答不上来,是不是常态?别慌。很多开发者对着 GitHub 开源仓库里的代码发呆,看似简单实则暗藏玄机。今天这份【剑帝加点】速查手册,直接带你拆解核心实现,把面试必考的原理讲透。…

2026/9/22 0:00:41 阅读更多 →
手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优

手写实现图片压缩网站核心:搞定WebP转换与质量调优 复制来的代码跑不通不知道怎么调?别慌,这种“复制粘贴地狱”在开发圈太常见了。尤其是做 图片压缩网站…

2026/9/22 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/21 15:36:51 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/21 15:36:51 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →