news 2026/9/28 2:47:00

Operit OpenCode Provider 协议隔离改造:公共 Provider 恢复与四协议专用路由实现解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Operit OpenCode Provider 协议隔离改造:公共 Provider 恢复与四协议专用路由实现解析
  • AI Agent
  • 人工智能
  • 大模型
  • AI 应用
  • 工具调用
  • 本地部署
  • MCP Clients
  • Agent 记忆

【免费下载链接】Operit

The most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent

项目地址:https://gitcode.com/gh_mirrors/op/Operit
点击查看免费下载

本指南围绕 Operit(Android 端 AI Agent / AI Chat 客户端)中 OpenCode(Zen / Go)接入的架构重构展开,讲解如何把路由、认证与思考参数从公共 Provider 中剥离、收敛到 OpenCode 专用实现,并逐一拆解 OpenAI Chat Completions、OpenAI Responses、Anthropic Messages、Gemini 四条协议路由的隔离边界与实现细节。读完本文,你将理解 Operit 的 LLM Provider 分层设计,掌握"以受控扩展点承载协议差异、不让公共请求路径承担特例"的改造方法,并能对照源码与测试完成同类多协议网关接入的隔离验证。

改造背景:OpenCode 特例侵入公共 Provider 的问题

OpenCode 首版接入时,把路由、认证和思考参数通过OpenCodeReasoningParametersmarker 直接注入到 Claude、Gemini、OpenAI 与 Responses 四个 provider 中。其结果是:这个只为 OpenCode 一个 provider 服务的 marker,进入了所有普通请求的构建路径,导致 ClaudeProvider、GeminiProvider、OpenAIProvider、OpenAIResponsesProvider 这些公共实现必须识别 OpenCode 特例,公共请求路径被迫承担了本不属于自身的协议差异。

从源码结构看,Operit 的 LLM 接入层集中在 llmprovider 目录 下,包含 ClaudeProvider.kt、GeminiProvider.kt、OpenAIProvider.kt、OpenAIResponsesProvider.kt、OpenCodeProvider.kt 等四十余个 provider 实现,以及 ThinkingQualityMapping.kt、ModelListFetcher.kt、AIServiceFactory.kt 等支撑模块。任何特例分支一旦写入公共文件,都会随公共路径被所有兼容 provider 共享,既增加维护成本,也容易在后续改动中互相干扰。

修正意图与作用域

本次重构的核心意图是:让 OpenCode 的协议适配完全留在 OpenCode 专用实现中;普通 provider 只保留自己的通用行为;必要的继承点只表达稳定的请求构建扩展,不引用 OpenCode 类型或分支判断。

官方作用域记录于 index.md:

  • 恢复公共 provider 的原有 reasoning、认证和端点行为;
  • 为 OpenCode 的 Chat Completions、Responses、Anthropic 和 Gemini 路由提供隔离实现;
  • 修正 OpenCode Gemini 的认证头和 SSE URL;
  • 保留现有设置、模型目录和路由测试,并补充隔离边界说明。

改造完成后,OpenCode Chat、Responses、Anthropic、Gemini 的专用实现已全部合并到 OpenCodeProvider.kt 单文件中,公共 Provider 不再包含 OpenCode marker、端点判断和认证分支。

公共 Provider 恢复边界

恢复边界记录在 01-public-provider-baseline.md:

  • 旧实现:公共 provider 通过OpenCodeReasoningParametersmarker 改变 reasoning 自动注入、参数过滤和 Gemini 请求端点,该 marker 进入所有普通请求构建路径;
  • 目标实现:公共 provider 不再导入或识别 OpenCode 类型;OpenCode 请求使用专用子类或专用请求构建钩子;普通请求的认证、端点和 thinking 行为保持原样;
  • 完成标准:ClaudeProvider.kt、GeminiProvider.kt、OpenAIProvider.kt、OpenAIResponsesProvider.kt不包含 OpenCode 特例判断;OpenCode 专用代码承担显式 reasoning 参数和 Geminix-goog-api-key/ SSE URL。

在现有源码中搜索OpenCode关键字,命中的文件仅剩OpenCodeProvider.kt、AIServiceFactory.kt、ModelListFetcher.kt与CodexProvider.kt(后者用于模型目录解析),四个公共 provider 文件均已不再引用 OpenCode 类型,与完成标准一致。公共 provider 的 thinking 注入统一走 ThinkingQualityMapping.kt 中的ThinkingConfigurationApplier.apply()通用机制——该机制按 providerTypeId + modelName + apiEndpoint 解析 thinking 配置,本身与 OpenCode 解耦。

OpenCode 路由隔离:单文件四协议

路由隔离记录于 02-opencode-routing.md:OpenCodeProvider负责根据模型选择协议,并把请求交给专用 provider 实现;专用实现可以复用通用 provider 的消息、工具和流处理,但通过受控扩展点覆盖请求体和请求 URL,不把 OpenCode 条件写回公共 provider。

总体结构

OpenCodeProvider.kt 内部包含三层:

  1. OpenCodeProvider(门面):class OpenCodeProvider(private val delegate: AIService, ...) : AIService by delegate,以委托方式持有协议专用实现,对外保持统一的AIService接口;sendMessage()中先调用ThinkingConfigurationApplier.modelParameters()把思考配置转成协议可见的显式参数,再转发给 delegate;
  2. OpenCodeRouting(路由器):负责协议判定、端点规范化与模型目录端点构造;
  3. 四个专用 Provider 子类:OpenCodeChatProvider、OpenCodeResponsesProvider、OpenCodeClaudeProvider、OpenCodeGeminiProvider,分别继承公共的OpenAIProvider、ClaudeProvider、GeminiProvider,通过 override 扩展点改写请求。

创建入口在 AIServiceFactory.kt:当ApiProviderType.OPENCODE时调用OpenCodeProvider.create()。create()内部先去除模型名opencode/、opencode-go/前缀,再依据端点与模型名路由到四个专用实现。

协议路由判定表

路由判定集中在OpenCodeRouting.protocolFor(),规则如下(按模型 ID 判定):

模型 ID 前缀路由协议
gemini-GEMINI_GENERIC
claude-、qwen3.;minimax-(Go 端点全量,非 Go 端点仅-free后缀)ANTHROPIC_GENERIC
gpt-、grok-、muse-spark-OPENAI_RESPONSES_GENERIC
非 Go 端点下的minimax-OPENAI_GENERIC
big-pickle-、deepseek-、glm-、hy3、hy4-、kimi-、ling-、longcat-、mimo-、nemotron-、omen-、qwen3-coder、ring-、north-、laguna-、trinity-、x-preview-OPENAI_GENERIC
其他抛出IllegalArgumentException("Unsupported OpenCode model protocol: ...")

端点构造由OpenCodeRouting.endpointFor()完成:先对 base 做规范化(去尾部/,若不以/v1结尾则补上),随后按协议拼接:

  • Responses:{base}/responses
  • Anthropic:{base}/messages
  • Gemini:{base}/models/{modelName}
  • 其余(Chat Completions):{base}/chat/completions

模型目录端点modelsEndpoint()为{base}/models;catalogProviderId()依据是否为 Go 端点返回opencode-go或opencode。Go 端点的判定isGo()检查 endpoint 是否以/zen/go或/zen/go/v1结尾。

各协议的请求边界与实现细节

OpenAI Chat Completions(OpenCodeChatProvider):继承OpenAIProvider,providerType = OPENAI_GENERIC。显式传入reasoning_effort;同时针对 OpenCode Chat 路由"后端透传 DeepSeek 风格 thinking 输出"的特性做了收敛处理——该协议要求历史 assistant 消息必须原样回传reasoning_content,否则模型完成工具调用后的下一轮请求会返回 400("The reasoning_content in the thinking mode must be passed back to the API.")。实现上:

  1. 强制preserveThinkInHistory = true,让父类的buildMessagesAndCountTokens保留历史 assistant 消息中的<think>内容;
  2. overridecustomizeFinalRequestObject()(公共基类 OpenAIProvider.kt 中为空实现、专供子类扩展的受控钩子),在 messagesArray 后处理阶段调用ChatUtils.extractThinkingContent()(见 ChatUtils.kt)将<think>内容拆分为reasoning_content字段并回填。该实现完全收敛在子类内部,不动通用OpenAIProvider。

OpenAI Responses(OpenCodeResponsesProvider):同样继承OpenAIProvider,useResponsesApi = true,providerType = OPENAI_RESPONSES_GENERIC。显式传入reasoning而不触发公共自动注入;在createRequestBody()中,当未开启 thinking 时调用ChatUtils.stripOpenAiResponsesReasoningMetaTurns()(ChatUtils.kt)剥离历史消息中的 Responses reasoning 元信息,避免关闭 thinking 后历史污染请求。

Anthropic Messages(OpenCodeClaudeProvider):继承ClaudeProvider,providerType = ANTHROPIC_GENERIC,传入空 thinking 配置"[]"(思考参数由 OpenCode 侧显式下发,不触发公共自动注入)。overrideaddParameters(),仅放行thinking、budget_tokens、output_config三类参数,并按ParameterValueType(OBJECT/STRING/INT/FLOAT/BOOLEAN)将参数值写入请求 JSON——OBJECT 类型的非法 JSON 会被runCatching捕获并记录警告而非抛错。

Gemini(OpenCodeGeminiProvider):继承GeminiProvider,providerType = GEMINI_GENERIC。overridecreateRequest(),与公共 GeminiProvider 的两处关键差异(即本次"修正认证头和 SSE URL"的直接落点):

  • 认证头:公共 GeminiProvider.kt 使用 URL 查询参数?key=...传递 API Key;OpenCode 网关要求x-goog-api-key请求头,因此OpenCodeGeminiProvider改为.addHeader("x-goog-api-key", opencodeApiKeyProvider.getApiKey());
  • SSE URL:公共实现使用streamGenerateContent/generateContent方法;OpenCode 在流式场景要求追加?alt=sse后缀。实现中method = if (isStreaming) "streamGenerateContent" else "generateContent",suffix = if (isStreaming) "?alt=sse" else "",最终 URL 为{apiBase}/models/{modelName}:{method}{suffix}(apiBase由OpenCodeRouting.apiBase()从 endpoint 中剥离/models/片段后规范化为/v1结尾)。

Go 端点专属头部

Go 端点(/zen/go)需要"agent 自有身份"以维持网关侧 prompt-cache 路由稳定,create()中对 routedHeaders 统一追加:

  • User-Agent: Operit/{VERSION_NAME}(所有 OpenCode 路由生效);
  • x-opencode-session: operit-{config.id}(仅 Go 端点)。

模型目录请求同样携带Authorization: Bearer {apiKey}与User-Agent: Operit/{VERSION_NAME}(见 ModelListFetcher.kt),且模型列表端点由OpenCodeRouting.modelsEndpoint()提供(ModelListFetcher.kt),与其他 provider 的/v1/models约定区分。

思考参数:从 marker 到协议显式参数

隔离改造的关键点之一是 thinking 表达方式。公共路径不再识别任何 OpenCode marker,改为:OpenCodeProvider.sendMessage()调用ThinkingConfigurationApplier.modelParameters()(ThinkingQualityMapping.kt),该方法把思考配置解析结果转成一组ModelParameter显式参数,随modelParameters + opencodeParameters传入 delegate;同时enableThinking = enableThinking || thinkingMapping.reasoningRequired,并在 Responses 协议下才把 enableThinking 透传(enableThinking && protocol == OPENAI_RESPONSES_GENERIC),避免其他协议触发公共自动注入。

各协议对应的思考参数由 ModelThinkingConfigDefaultsCollect.kt 中的默认配置声明,均为providers: ["OPENCODE"]下的规则:

配置规则 ID匹配范围参数标签档位
opencode-gemini-thinking-levelgoogle/gemini-*thinkingLevel(含thinkingConfig.includeThoughts)LOW/MEDIUM/HIGH
opencode-anthropic-effortanthropic、minimax/claude-*、minimax-*output_config.effort(含thinking.type=adaptive、thinking.display=summarized)low/medium/high
opencode-zhipu-glm-effortzhipu、zai-org、thudm/ 含glmreasoning_effort(含thinking.type=enabled/disabled)low/high/max
opencode-responses-effortopenai、azure、xai/ 含gpt-、grok-、codexreasoning.effort(含reasoning.summary=auto、include)low/medium/high/xhigh
opencode-chat-effort兜底(其他 Chat 模型)reasoning_effortlow/medium/high

用户可在模型配置中以自定义 thinkingConfigurations JSON 覆盖这些默认规则(customConfigurationControlsOpenCodeOptionCount测试用例即验证了自定义规则对档位数量的控制)。

静态验证与测试覆盖

验证记录见 03-verification.md:本次按仓库执行准则不运行构建、Gradle 或测试命令,完成后执行静态 diff 检查(git diff --check),并核对公共 provider 不再引用 OpenCode 专用类型。

仓库现有测试可从侧面印证隔离边界:

  • OpenCodeThinkingConfigurationTest.kt 覆盖 5 个用例:zhipu/glm-5.3与zai-org/glm-4.6走reasoning_effort(low/high/max)档位、google/gemini-2.5-pro走thinkingLevel(LOW/MEDIUM/HIGH)档位、未知 provider 兜底reasoning_effort(low/medium/high),以及自定义配置控制档位数量;
  • CodexModelListParserTest.kt 与 CodexModelPolicyTest.kt 覆盖 OpenCode 模型目录解析与显式模型放行策略。

配置视角:OpenCode 在 Operit 中的接入方式

从用户/配置视角看,OpenCode 以独立 Provider 类型注册于 ApiProviderConfigCollect.kt:

  • providerType = OPENCODE,默认端点https://opencode.ai/zen,端点选项含Zen(https://opencode.ai/zen)与Go(https://opencode.ai/zen/go)两种,Go 端点即路由表与x-opencode-session头部生效的前提;
  • 默认模型名为空,需从模型目录拉取(模型 ID 形如zhipu/glm-5.3、google/gemini-2.5-pro,去除opencode/或opencode-go/前缀后参与路由判定);
  • ApiProviderType.OPENCODE注释明确说明"按基础路径选择服务,按模型 ID 选择协议"(ModelConfigData.kt)。

隔离边界小结

本次改造形成的清晰边界可以概括为三层约定:

  1. 公共 provider 只保留通用行为:ClaudeProvider、GeminiProvider、OpenAIProvider、OpenAIResponsesProvider 不再出现 OpenCode 特例判断,thinking 注入统一走ThinkingConfigurationApplier通用机制;
  2. OpenCode 专用代码集中收敛:路由、端点、认证、思考参数、reasoning_content 回传等全部落在 OpenCodeProvider.kt 内,以继承 + override 公共基类中受控扩展点(createRequestBody、customizeFinalRequestObject、addParameters、createRequest)的方式实现,不修改父类公共逻辑;
  3. 可验证性:通过静态 grep 公共 provider 文件中的 OpenCode 引用、运行 OpenCodeThinkingConfigurationTest.kt 等既有测试、以及git diff --check静态检查,即可确认隔离边界未被破坏。

对于后续需要接入类似"一个网关、多协议后端"的 provider,这套"门面路由 + 路由表 + 四协议子类 + 受控扩展点"的架构可以直接复用:协议差异下沉到专用子类,公共请求路径永远只理解自身的协议语义。

  • AI Agent
  • 人工智能
  • 大模型
  • AI 应用
  • 工具调用
  • 本地部署
  • MCP Clients
  • Agent 记忆

【免费下载链接】Operit

The most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent

项目地址:https://gitcode.com/gh_mirrors/op/Operit
点击查看免费下载

相关推荐

上一篇:5分钟快速上手:用rmats2sashimiplot轻松实现RNA-seq剪接可视化
下一篇:Amazon Bedrock Workshop依赖项管理:Python环境隔离与版本控制

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 2:44:50

Arm Development Studio安装激活全攻略:从下载到调试一站式实操指南

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

作者头像 李华
网站建设 2026/9/28 2:43:19

RGB-D目标跟踪实战:数据对齐、梯度回传与深度敏感区域优化

简介&#xff1a;这是一份面向计算机视觉初学者与进阶学习者的多模态目标跟踪实践项目&#xff0c;聚焦RGB与Depth双模态融合技术&#xff0c;适用于课程设计、毕业设计及工程实训等场景。项目基于Python实现&#xff0c;采用边缘引导的单目深度估计网络EG-BTS构建COCO2017 RGB…

作者头像 李华