PAL MCP Server 接入新模型 Provider 完全指南:从 ProviderType 枚举到注册上线的完整链路 📅 发布时间:2026/9/15 21:53:51 👁 浏览次数: PAL MCP Server 接入新模型 Provider 完全指南从 ProviderType 枚举到注册上线的完整链路【免费下载链接】pal-mcp-serverThe power of Claude Code / GeminiCLI / CodexCLI [Gemini / OpenAI / OpenRouter / Azure / Grok / Ollama / Custom Model / All Of The Above] working as one.项目地址: https://gitcode.com/GitHub_Trending/ge/pal-mcp-server本文是 PAL MCP Server 官方扩展指南《Adding a New Provider》的深度技术解读。PAL MCP Server 通过一套可插拔的 Provider 架构将 Gemini、OpenAI、Azure OpenAI、OpenRouter、GrokX.AI、Ollama 等模型后端统一在一个注册表与能力模型之下。读完本文你将掌握如何从零新增一个自有 Provider原生 API 或 OpenAI 兼容 API理解ModelCapabilities能力声明、intelligence_score排序机制、环境变量驱动的激活逻辑以及如何把新 Provider 接入优先级级联并编写验证测试。一、扩展性架构总览每个 Provider 需要承担什么PAL MCP Server 的 Provider 系统设计目标非常明确新增一个模型后端时只写最少量的胶水代码其余全部复用共享管线。从 providers/base.py 的ModelProvider抽象基类可以看出任何一个 Provider 都必须满足以下四点约定继承ModelProvider基类或OpenAICompatibleProvider针对 OpenAI 兼容 API用ModelCapabilities对象声明支持的模型字段定义见 providers/shared/model_capabilities.py实现最小抽象钩子get_provider_type()和generate_content()定义于 providers/base.py 与 providers/base.py接入configure_providers()让环境变量控制其激活实现于 server.py可以借助现成的辅助子类如AzureOpenAIProvider——当你的 Provider 只是客户端接线方式不同时无需重写请求管线。基类把大量共性逻辑集中在了共享实现里具体子类只需要提供自己的目录和SDK 特有行为。这些共享能力包括共享能力说明源码位置温度校验通过validate_parameters()调用ModelCapabilities.temperature_constraint约束providers/base.py别名解析_resolve_model_name()把gpt解析为gpt-4这类短名providers/base.py限制策略感知list_models()/get_capabilities()都会经过utils.model_restrictions的 restriction service 过滤providers/base.py重试语义_run_with_retries()_is_error_retryable()钩子providers/base.pyintelligence_score 速查控制 auto 模式的确定性排序ModelCapabilities中的intelligence_score1–20是人类标注的模型能力分数。当你想让 auto 模式或listmodels输出有确定性的排序时就必须设置它。运行时排名capability rank以此为锚点再加上上下文窗口、扩展思考等小额加分项具体算法实现在 providers/shared/model_capabilities.pybase clamp(intelligence_score, 1, 20) * 5 ctx_bonus min(5, max(0, log10(context_window) - 3)) output_bonus 2 if max_output_tokens 65_000 else 1 if 32_000 else 0 feature_bonus ( (3 if supports_extended_thinking else 0) (1 if supports_function_calling else 0) (1 if supports_json_mode else 0) (1 if supports_images else 0) ) effective_rank clamp(base ctx_bonus output_bonus feature_bonus, 0, 100)从 docs/model_ranking.md 的评分参考看18–19 分对应前沿推理模型Gemini 2.5 Pro、GPT‑5.2 等15–17 分对应强通用大上下文模型12–14 分对应均衡助手9–11 分对应快速蒸馏模型6–8 分对应本地或效率型模型≤5 分对应实验性轻量模型。排名结果按 Provider 缓存并被工具 schema 的model参数描述、listmodels工具的top models区块以及模型不可用时的回退提示所消费。二、选择实现路径三种接线方式文档给出了三条清晰的接入路径选择依据是你的 API 与 OpenAI Chat Completions 格式的吻合程度Option A完整 ProviderModelProvider适用于具有独特特性或自定义认证方式的 API。你需要完全掌控 API 调用与响应处理填充MODEL_CAPABILITIES实现generate_content()与get_provider_type()。仅当你的模型目录来自注册表或远端源时才需要覆写get_all_model_capabilities()/_lookup_capabilities()仅当你拥有 Provider 级精确 tokenizer 时才覆写count_tokens()。Option BOpenAI 兼容 ProviderOpenAICompatibleProvider适用于遵循 OpenAI Chat Completion 格式的 API。你只需提供MODEL_CAPABILITIES、覆写get_provider_type()并视需要调整配置——基类自动接管别名解析、校验与请求接线API 处理全部继承。⚠️关键注意事项如果你实现了自定义的generate_content()在调用 SDK 之前必须调用_resolve_model_name()这样别名如gpt→gpt-4才能正确解析。共享实现OpenAI 兼容基类已经自动完成了这一步。这一点很重要但容易遗漏——从源码看providers/base.py 的_resolve_model_name()会依次做精确匹配、大小写不敏感匹配、别名表匹配最终找不到才原样返回。Option CAzure OpenAIAzureOpenAIProvider适用于 Azure 托管的 OpenAI 模型部署。它复用了 OpenAI 兼容管线但把客户端换成AzureOpenAI并引入规范模型名 → 部署 ID的映射providers/azure_openai.py。部署定义写在 conf/azure_models.json或AZURE_MODELS_CONFIG_PATH指向的文件中条目遵循ModelCapabilitiesschema 且必须包含deployment标识。完整配置流程见 docs/azure_openai.md。三、Step-by-Step从枚举到上线的完整五步步骤 1添加 Provider 类型在 providers/shared/provider_type.py 的ProviderType枚举中添加你的 Provider。当前仓库已内置的枚举值是GOOGLE、OPENAI、AZURE、XAI、OPENROUTER、CUSTOM、DIAL新增示例class ProviderType(Enum): GOOGLE google OPENAI openai EXAMPLE example # Add this这个枚举值贯穿整个系统API key 映射、限制策略restriction policy、模型路由都依赖它作为键。步骤 2创建 Provider 实现Option A完整 Provider原生实现创建providers/example.py。下面的示例完整展示了能力声明、客户端初始化和请求回包的标准写法与原文档示例一致并补充了关键字段注释Example model provider implementation. import logging from typing import Optional from .base import ModelProvider from .shared import ( ModelCapabilities, ModelResponse, ProviderType, RangeTemperatureConstraint, ) logger logging.getLogger(__name__) class ExampleModelProvider(ModelProvider): Example model provider implementation. MODEL_CAPABILITIES { example-large: ModelCapabilities( providerProviderType.EXAMPLE, model_nameexample-large, friendly_nameExample Large, intelligence_score18, # 1-20 人类评分驱动 auto 模式排序 context_window100_000, # 输入输出总 token 预算 max_output_tokens50_000, # 单次响应最大生成 token 数 supports_extended_thinkingFalse, # 是否支持扩展思考 token temperature_constraintRangeTemperatureConstraint(0.0, 2.0, 0.7), # 允许范围 默认值 descriptionLarge model for complex tasks, # 帮助 auto 模式选型 aliases[large, big], # 用户可输入短名 ), example-small: ModelCapabilities( providerProviderType.EXAMPLE, model_nameexample-small, friendly_nameExample Small, intelligence_score14, context_window32_000, max_output_tokens16_000, temperature_constraintRangeTemperatureConstraint(0.0, 2.0, 0.7), descriptionFast model for simple tasks, aliases[small, fast], ), } def __init__(self, api_key: str, **kwargs): super().__init__(api_key, **kwargs) # Initialize your API client here def get_all_model_capabilities(self) - dict[str, ModelCapabilities]: return dict(self.MODEL_CAPABILITIES) def get_provider_type(self) - ProviderType: return ProviderType.EXAMPLE def generate_content( self, prompt: str, model_name: str, system_prompt: Optional[str] None, temperature: float 0.7, max_output_tokens: Optional[int] None, **kwargs, ) - ModelResponse: resolved_name self._resolve_model_name(model_name) # 必须先解析别名 # Your API call logic here # response your_api_client.generate(...) return ModelResponse( contentGenerated response, usage{input_tokens: 100, output_tokens: 50, total_tokens: 150}, model_nameresolved_name, friendly_nameExample, providerProviderType.EXAMPLE, )关于这段代码背后的共享机制有几点值得展开get_capabilities()是完整的别名解析 → 查询 → 限制检查管线providers/base.py。它自动解析别名、强制执行共享的限制服务、并返回正确的ModelCapabilities实例。子类通常只需要覆写_lookup_capabilities()来对接注册表或远端源或覆写_finalise_capabilities()微调返回对象。count_tokens()默认使用4 字符 ≈ 1 token的估算providers/base.py保证 Provider 开箱即用只有当你能够调用 Provider 的真实 tokenizer 时才覆写它——例如 OpenAI 兼容基类集成了tiktokenproviders/openai_compatible.py。validate_model_name()委托给get_capabilities()providers/base.py所以大多数 Provider 可以依赖共享实现。validate_parameters()则校验温度是否落在temperature_constraint允许范围内providers/base.py。温度约束有多种形态providers/shared/temperature.py定义了RangeTemperatureConstraint连续范围、FixedTemperatureConstraint固定值如 O 系列推理模型、DiscreteTemperatureConstraint离散值集。对于未声明能力的模型还内置了基于名称模式如o1、o3、deepseek-r1、reasoner的infer_support()启发式推断providers/shared/temperature.py。重试机制开箱可用_run_with_retries()配合_is_error_retryable()providers/base.py默认对 timeout、connection、5xx 等瞬时错误重试但对 429 限流直接放弃OpenAI 兼容基类还覆写了结构化错误码解析能区分token 相关 429不可重试与速率限制 429可重试。Option BOpenAI 兼容 Provider简化版如果你的 API 走 OpenAI Chat Completions 格式代码量会大幅缩减Example OpenAI-compatible provider. from typing import Optional from .openai_compatible import OpenAICompatibleProvider from .shared import ( ModelCapabilities, ModelResponse, ProviderType, RangeTemperatureConstraint, ) class ExampleProvider(OpenAICompatibleProvider): Example OpenAI-compatible provider. FRIENDLY_NAME Example # Define models using ModelCapabilities (consistent with other providers) MODEL_CAPABILITIES { example-model-large: ModelCapabilities( providerProviderType.EXAMPLE, model_nameexample-model-large, friendly_nameExample Large, context_window128_000, max_output_tokens64_000, temperature_constraintRangeTemperatureConstraint(0.0, 2.0, 0.7), aliases[large, big], ), } def __init__(self, api_key: str, **kwargs): kwargs.setdefault(base_url, https://api.example.com/v1) super().__init__(api_key, **kwargs) def get_provider_type(self) - ProviderType: return ProviderType.EXAMPLEOpenAICompatibleProvider已通过MODEL_CAPABILITIES暴露声明的模型、经由共享基类管线解析别名、并执行限制策略——大多数子类只需提供上面展示的类元数据即可。它的共享实现还包含不少免费能力接新 Provider 时值得了解providers/openai_compatible.pyProvider 级 allowlist读取{PROVIDER_TYPE}_ALLOWED_MODELS环境变量例如EXAMPLE_ALLOWED_MODELS在默认限制检查之外再做一层白名单过滤_ensure_model_allowed覆写见 providers/openai_compatible.py智能超时配置本地 localhost 端点使用 60s 连接 30 分钟读/写超时远端自定义端点 45s 15 分钟还支持CUSTOM_CONNECT_TIMEOUT/CUSTOM_READ_TIMEOUT等环境变量覆盖providers/openai_compatible.py安全防护_validate_base_url()仅允许 http/https scheme、校验 hostname 与端口client属性在创建时显式屏蔽HTTP_PROXY等代理环境变量避免代理冲突providers/openai_compatible.py推理模型支持当ModelCapabilities.use_openai_response_apiTrue时自动走/v1/responses端点如 o3-pro并根据default_reasoning_effort注入 reasoning 参数对 OpenRouter 的/responses调用还会省略其不支持的store参数providers/openai_compatible.py多模态支持supports_imagesTrue时通过_process_image()把本地图片转成 data URL 随请求发送并经过utils/image_utils.validate_image校验。步骤 3注册你的 Provider注册涉及两处代码改动外加一处优先级配置3.1 在 providers/registry.py 中添加环境变量映射位置是_get_api_key_for_provider()的key_mapping字典providers/registry.py# In _get_api_key_for_provider (providers/registry.py), add: ProviderType.EXAMPLE: EXAMPLE_API_KEY,3.2 在 server.py 的configure_providers()中注册。参照现有实现如 Gemini 的注册代码在 server.py新增# 1. Import your provider from providers.example import ExampleModelProvider # 2. Add to configure_providers() function # Check for Example API key example_key os.getenv(EXAMPLE_API_KEY) if example_key: ModelProviderRegistry.register_provider(ProviderType.EXAMPLE, ExampleModelProvider) logger.info(Example API key found - Example models available)3.3 加入 Provider 优先级。编辑ModelProviderRegistry.PROVIDER_PRIORITY_ORDERproviders/registry.py把新 Provider 插入到原生 → 自定义 → 兜底级联的合适位置。当前仓库的实际顺序是PROVIDER_PRIORITY_ORDER [ ProviderType.GOOGLE, # Direct Gemini access ProviderType.OPENAI, # Direct OpenAI access ProviderType.AZURE, # Azure-hosted OpenAI deployments ProviderType.XAI, # Direct X.AI GROK access ProviderType.DIAL, # DIAL unified API access ProviderType.CUSTOM, # Local/self-hosted models ProviderType.OPENROUTER, # Catch-all for cloud models ]这条顺序决定了get_provider_for_model()providers/registry.py的遍历顺序当用户请求某个模型名时注册表按优先级依次询问每个 Provider你是否认识这个模型validate_model_name()第一个应答的 Provider 负责处理。这保证了当多个 Provider 提供同名模型时如 OpenRouter 也有gpt-4原生 API 优先于 OpenRouter。注册表本身是一个单例__new__实现register_provider()注册类的同时会使已缓存的实例失效get_provider()则负责按类型实例化、缓存并处理特殊初始化Custom 需要CUSTOM_API_URL、Gemini 支持GEMINI_BASE_URL自定义端点、Azure 需要AZURE_OPENAI_ENDPOINT API 版本等见 providers/registry.py。步骤 4环境配置在.env文件中添加# Your providers API key EXAMPLE_API_KEYyour_api_key_here # Optional: Disable specific tools DISABLED_TOOLSdebug,tracer # Optional (OpenAI-compatible providers): Restrict accessible models EXAMPLE_ALLOWED_MODELSexample-model-large,example-model-smallEXAMPLE_ALLOWED_MODELS会被OpenAICompatibleProvider._parse_allowed_models()读取环境变量名 {PROVIDER_TYPE 大写}_ALLOWED_MODELS以逗号分隔、大小写不敏感未配置时记录一条提示日志并放行全部模型providers/openai_compatible.py。Azure OpenAI 部署的环境变量AZURE_OPENAI_API_KEYyour_azure_openai_key_here AZURE_OPENAI_ENDPOINThttps://your-resource.openai.azure.com/ # Models are defined in conf/azure_models.json (or AZURE_MODELS_CONFIG_PATH) # AZURE_OPENAI_API_VERSION2024-02-15-preview # AZURE_OPENAI_ALLOWED_MODELSgpt-4o,gpt-4o-mini # AZURE_MODELS_CONFIG_PATH/absolute/path/to/custom_azure_models.jsonAzure 的模型也可以在 conf/azure_models.json 中定义仓库自带的文件模型列表为空可以安全复制使用。每个条目镜像ModelCapabilitiesschema且必须包含deployment字段。AzureOpenAIProvider在初始化时会加载注册表条目把规范模型名映射到部署 ID请求时把部署名填入model字段回包时再归一化为规范模型名providers/azure_openai.py。如果你在仓库外维护自定义副本设置AZURE_MODELS_CONFIG_PATH指向绝对路径即可。注意ModelCapabilities的description字段会在 auto 模式下帮助 Claude 选择最合适的模型因此每个模型都应写上清晰的能力描述。步骤 5测试你的 Provider创建基础测试验证实现正确性# Test capabilities provider ExampleModelProvider(test-key) capabilities provider.get_capabilities(large) assert capabilities.context_window 0 assert capabilities.provider ProviderType.EXAMPLE仓库中的测试为如何编写 Provider 级测试提供了大量参照tests/test_providers.py、tests/test_custom_provider.py、tests/test_azure_openai_provider.py、tests/test_openrouter_provider.py、tests/test_xai_provider.py分别覆盖各内置 Providertests/test_provider_routing_bugs.py专门验证模型路由与限制过滤的边界情况tests/test_openrouter_fallback.py验证兜底路由。此外 simulator_tests/ 下还有一批基于通信模拟的端到端测试如test_openrouter_fallback.py、test_cross_tool_comprehensive.py可以观察请求在完整工具链中的流转。如果使用 HTTP 录制回放可参照 tests/http_transport_recorder.py 与 tests/CASSETTE_MAINTENANCE.md。四、关键概念优先级、校验与别名Provider 优先级Provider Priority用户请求模型时Provider 按以下顺序被检查原生 ProviderGemini、OpenAI、Example 等——处理各自的专属模型Custom Provider——处理本地/自托管模型OpenRouter——其余一切的兜底。这对应注册表中的PROVIDER_PRIORITY_ORDER从源码层面看优先级不仅是文档约定而是get_provider_for_model()实际遍历的顺序因此新 Provider 的插入位置直接决定同名模型的路由胜负。模型校验Model ValidationModelProvider.validate_model_name()委托给get_capabilities()providers/base.py因此大多数 Provider 依赖共享实现。只有当你需要跳出这条管线时才覆写它——例如CustomProvider会拒绝 OpenRouter 模型让它们落到专用的 OpenRouter Provider 上参见 providers/custom.py。模型别名Model AliasesModelCapabilities上声明的aliases会经由_resolve_model_name()自动生效providers/base.py校验流程和请求流程都会在触碰你的 SDK 之前调用它。只有你的 Provider 需要超越共享行为的额外别名处理时才需要覆写generate_content()。五、最佳实践与注意事项原文档给出的最佳实践清单结合仓库实现可以做如下落地解读模型校验要具体——只接受你真正支持的模型。validate_model_name()默认走get_capabilities()管线如果能力目录里没有该模型就会返回False随后注册表会继续尝试下一个 Provider一致地使用ModelCapabilities对象——参考 Gemini Providerproviders/gemini.py的做法所有能力元数据统一声明避免散落的特殊逻辑提供描述性别名——好的别名直接改善用户体验例如 OpenRouter 目录中opus→anthropic/claude-opus-4.1、flash→google/gemini-2.5-flash见 conf/openrouter_models.json添加错误处理与日志——generate_content()抛出的异常会被_run_with_retries()包装为RuntimeError同时保留最后一次原始异常链便于排查用真实 API 调用测试——能力元数据正确 ≠ 请求管线正确务必用真实凭据验证端到端行为遵循既有模式——以 providers/gemini.py 和 providers/custom.py 为模板它们分别是完整 Provider与OpenAI 兼容 注册表驱动能力两种形态的参考实现。六、快速检查清单接入新 Provider 后逐项核对已添加到ProviderType枚举providers/shared/provider_type.py已创建包含全部必需方法的 Provider 类已在 providers/registry.py 中添加 API key 映射已加入 providers/registry.py 的 Provider 优先级顺序已在 server.py 中导入并在configure_providers()注册基础测试验证了模型校验与能力元数据已使用真实 API 调用验证七、参考实现速览接入前建议快速浏览这些真实实现理解三种形态的差异完整 Provider 范例providers/gemini.py原生 SDK 接线 完整能力目录OpenAI 兼容范例providers/custom.pyCUSTOM_API_URL驱动、能力来自 conf/custom_models.json 注册表与 providers/openrouter.py兜底路由基类与共享类型providers/base.py、providers/openai_compatible.py、providers/shared/model_capabilities.py、providers/shared/provider_type.pyAzure 部署形态providers/azure_openai.py、providers/registries/azure.py、conf/azure_models.json注册与激活providers/registry.py 的PROVIDER_PRIORITY_ORDER与 server.py 的configure_providers()模型排序机制docs/model_ranking.md 与 providers/shared/model_capabilities.py 的get_effective_capability_rank()【免费下载链接】pal-mcp-serverThe power of Claude Code / GeminiCLI / CodexCLI [Gemini / OpenAI / OpenRouter / Azure / Grok / Ollama / Custom Model / All Of The Above] working as one.项目地址: https://gitcode.com/GitHub_Trending/ge/pal-mcp-server创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考