【AI Agent基础 | 第六篇】LLM多厂商接入:区分provider、protocol、base_url、adapter

前言
  此文是我近期学习星哥的Agent项目遇到的问题,结合AI整理总结而来,分享给大家。一是为了记录,二是用于日后的回顾,三也是希望能其给他初学者带来一点点帮助。

特别鸣谢 UP主:氪金氪氪氪氪


目录

  • [1. 先说结论](#1. 先说结论)
  • [2. 一个常见的 Model 结构](#2. 一个常见的 Model 结构)
  • [3. provider 是什么?](#3. provider 是什么?)
  • [4. api / protocol 是什么?](#4. api / protocol 是什么?)
  • [5. base_url 是什么?](#5. base_url 是什么?)
  • [6. adapter 是什么?](#6. adapter 是什么?)
  • [7. 为什么不把阿里模型直接放进 openai-standard?](#7. 为什么不把阿里模型直接放进 openai-standard?)
  • [8. 更推荐的模型表结构](#8. 更推荐的模型表结构)
  • [9. 注册协议适配器](#9. 注册协议适配器)
  • [10. 常见主流协议有哪些?](#10. 常见主流协议有哪些?)
  • [11. 最终推荐命名](#11. 最终推荐命名)
  • [12. 一句话总结](#12. 一句话总结)

在接入多个大模型厂商时,经常会遇到这些词:

  • provider
  • api
  • protocol
  • base_url
  • adapter
  • OpenAI-compatible

如果这些概念没分清,代码很容易变成这样:

python 复制代码
Model(
    id="qwen-plus",
    api="openai-standard",
    provider="openai-standard",
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)

这段配置可能能跑,但读起来很混乱:这到底是 OpenAI,还是阿里百炼?

这篇文章用一个简单的 LLM 项目结构,解释这些概念应该怎么拆。

1. 先说结论

推荐把概念分成四层:

text 复制代码
provider/vendor = 谁提供服务,比如 openai / anthropic / dashscope
api/protocol    = 接口协议,比如 openai-standard / anthropic-messages
base_url        = 服务地址,比如 https://api.openai.com/v1
adapter         = 适配器代码,比如 stream_openai_compatible

一句话理解:

text 复制代码
provider = 跟谁打交道
api      = 用什么协议说话
base_url = 去哪里说话
adapter  = 负责翻译这门协议的代码

2. 一个常见的 Model 结构

假设项目里有这样一个模型定义:

python 复制代码
from dataclasses import dataclass

@dataclass
class Model:
    id: str
    name: str
    api: str
    provider: str
    base_url: str
    max_tokens: int

这里最容易混的是 apiprovider

推荐含义是:

python 复制代码
Model(
    id="qwen-plus",
    name="Qwen Plus",
    api="openai-standard",       # 协议:OpenAI Chat Completions
    provider="dashscope",        # 厂商:阿里百炼
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    max_tokens=8192,
)

这表示:

text 复制代码
使用阿里百炼的 qwen-plus 模型
但请求格式复用 OpenAI 兼容协议
请求地址是 DashScope 的 base_url

3. provider 是什么?

provider 更适合表示"厂商"或"配置来源"。

例如:

text 复制代码
openai
anthropic
dashscope
deepseek
openrouter
azure

它通常决定:

text 复制代码
1. API Key 从哪个环境变量读取
2. 默认 base_url 是什么
3. 日志、错误归属、用量统计属于哪个厂商
4. 后续厂商特有能力如何扩展

例如:

python 复制代码
import os

def get_env_api_key(provider: str) -> str | None:
    if provider == "anthropic":
        return os.getenv("ANTHROPIC_API_KEY")

    if provider == "openai":
        return os.getenv("OPENAI_API_KEY")

    if provider == "dashscope":
        return os.getenv("DASHSCOPE_API_KEY")

    return None

这样配置会比较清楚:

powershell 复制代码
$env:OPENAI_API_KEY = "OpenAI 的 Key"
$env:DASHSCOPE_API_KEY = "阿里百炼的 Key"

而不是把阿里百炼的 Key 塞进 OPENAI_API_KEY

4. api / protocol 是什么?

很多项目不一定叫 protocol,可能叫 api

它表示"接口协议",也就是请求和响应长什么样。

例如:

text 复制代码
openai-standard
anthropic-messages
gemini-generate-content
bedrock-converse

api 决定调用哪个适配器:

python 复制代码
def stream(model: Model, context, options=None):
    adapter = get_api_adapter(model.api)
    return adapter.stream(model, context, options)

如果:

python 复制代码
model.api == "openai-standard"

就走 OpenAI Chat Completions 格式:

text 复制代码
POST /chat/completions
Authorization: Bearer xxx
messages: [...]
tools: [...]
stream: true

如果:

python 复制代码
model.api == "anthropic-messages"

就走 Anthropic Messages 格式:

text 复制代码
POST /v1/messages
x-api-key: xxx
anthropic-version: 2023-06-01
messages: [...]
tools: [...]
stream: true

5. base_url 是什么?

base_url 是接口地址的前半截。

它不是 protocol。

简单理解:

text 复制代码
protocol = 怎么说话
base_url = 跟谁说话

同一个 OpenAI 协议,可以有不同的 base_url

text 复制代码
OpenAI:
https://api.openai.com/v1/chat/completions

阿里百炼:
https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions

OpenRouter:
https://openrouter.ai/api/v1/chat/completions

DeepSeek:
https://api.deepseek.com/chat/completions

对应代码可能是:

python 复制代码
url = f"{model.base_url.rstrip('/')}/chat/completions"

所以:

python 复制代码
Model(
    api="openai-standard",
    provider="dashscope",
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)

最后请求的是:

text 复制代码
https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions

6. adapter 是什么?

adapter 是适配器代码。

它负责把项目内部的统一格式,转换成某个外部协议需要的格式;再把外部响应转换回内部格式。

例如项目内部统一调用是:

python 复制代码
stream(model, context, options)

对于 OpenAI 协议,适配器可能是:

python 复制代码
def stream_openai_compatible(model, context, options=None):
    api_key = get_env_api_key(model.provider)

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    }

    payload = {
        "model": model.id,
        "messages": to_openai_messages(context),
        "stream": True,
    }

    url = f"{model.base_url.rstrip('/')}/chat/completions"

    # 发请求、解析 SSE、转换成内部 AssistantMessage

对于 Anthropic 协议,适配器可能是:

python 复制代码
def stream_anthropic(model, context, options=None):
    api_key = get_env_api_key(model.provider)

    headers = {
        "x-api-key": api_key,
        "anthropic-version": "2023-06-01",
        "Content-Type": "application/json",
    }

    payload = {
        "model": model.id,
        "messages": to_anthropic_messages(context),
        "max_tokens": model.max_tokens,
        "stream": True,
    }

    url = f"{model.base_url.rstrip('/')}/v1/messages"

    # 发请求、解析 event/data、转换成内部 AssistantMessage

所以:

text 复制代码
adapter = 代码层面的协议翻译器

阿里百炼兼容 OpenAI 接口,因此不需要单独写 stream_dashscope,可以复用:

text 复制代码
stream_openai_compatible

7. 为什么不把阿里模型直接放进 openai-standard?

当然可以。

比如:

python 复制代码
MODELS = {
    "openai-standard": {
        "qwen-plus": Model(
            id="qwen-plus",
            name="Qwen Plus",
            api="openai-standard",
            provider="openai-standard",
            base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
            max_tokens=8192,
        ),
    }
}

然后:

powershell 复制代码
$env:OPENAI_API_KEY = "你的阿里百炼 Key"
$env:XINGCLAW_PROVIDER = "openai-standard"
$env:XINGCLAW_MODEL_ID = "qwen-plus"

这样能跑。

但问题是语义混乱:

text 复制代码
provider 叫 openai-standard
base_url 却是 dashscope.aliyuncs.com
OPENAI_API_KEY 里装的是阿里百炼 Key

短期学习没问题,长期维护会变麻烦。

比如你以后同时使用 OpenAI 和阿里百炼:

powershell 复制代码
$env:OPENAI_API_KEY = "OpenAI Key"
$env:DASHSCOPE_API_KEY = "DashScope Key"

如果都塞进 OPENAI_API_KEY,就没法干净切换。

8. 更推荐的模型表结构

更清晰的写法是:

python 复制代码
MODELS = {
    "openai": {
        "gpt-4o-mini": Model(
            id="gpt-4o-mini",
            name="GPT-4o mini",
            api="openai-standard",
            provider="openai",
            base_url="https://api.openai.com/v1",
            max_tokens=16384,
        ),
    },
    "dashscope": {
        "qwen-plus": Model(
            id="qwen-plus",
            name="Qwen Plus",
            api="openai-standard",
            provider="dashscope",
            base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
            max_tokens=8192,
        ),
    },
    "anthropic": {
        "claude-sonnet-4-5": Model(
            id="claude-sonnet-4-5",
            name="Claude Sonnet 4.5",
            api="anthropic-messages",
            provider="anthropic",
            base_url="https://api.anthropic.com",
            max_tokens=8192,
        ),
    },
}

这里:

text 复制代码
openai 和 dashscope 是不同 provider
但它们都复用 api="openai-standard"

这才是重点。

不是说百炼不兼容 OpenAI,而是:

text 复制代码
兼容 OpenAI 协议,不等于它就是 OpenAI provider。

9. 注册协议适配器

可以用一个注册表,把 api 映射到适配器函数:

python 复制代码
from dataclasses import dataclass
from typing import Callable

@dataclass
class ApiAdapter:
    api: str
    stream: Callable

_REGISTRY: dict[str, ApiAdapter] = {}

def register_api_adapter(adapter: ApiAdapter) -> None:
    _REGISTRY[adapter.api] = adapter

def get_api_adapter(api: str) -> ApiAdapter:
    return _REGISTRY[api]

注册内置协议:

python 复制代码
def register_builtin_api_adapters() -> None:
    register_api_adapter(
        ApiAdapter(
            api="anthropic-messages",
            stream=stream_anthropic,
        )
    )

    register_api_adapter(
        ApiAdapter(
            api="openai-standard",
            stream=stream_openai_compatible,
        )
    )

注意这里更推荐叫 ApiAdapter,而不是 ApiProvider

因为这里注册的是:

text 复制代码
协议 -> 适配器实现

不是:

text 复制代码
厂商 -> 厂商配置

10. 常见主流协议有哪些?

不止两个。

常见的有:

text 复制代码
1. OpenAI Chat Completions
   /v1/chat/completions
   很多厂商兼容它,比如阿里百炼、DeepSeek、OpenRouter、Groq 等。

2. OpenAI Responses API
   /v1/responses
   OpenAI 新一代统一接口。

3. Anthropic Messages API
   /v1/messages
   Claude 原生接口。

4. Google Gemini API
   generateContent / streamGenerateContent
   Gemini 原生接口。

5. AWS Bedrock Converse API
   AWS Bedrock 的统一对话接口。

6. Azure OpenAI API
   接近 OpenAI,但 endpoint、deployment、api-version、鉴权方式有 Azure 特有差异。

7. 本地模型服务
   Ollama、vLLM、llama.cpp、TGI 等,有些兼容 OpenAI,有些有原生接口。

所以一个项目早期只有:

text 复制代码
openai-standard
anthropic-messages

很正常。

它们能覆盖大量场景,尤其是 OpenAI-compatible 生态。

11. 最终推荐命名

推荐:

text 复制代码
provider:
  openai
  anthropic
  dashscope
  deepseek
  openrouter

api/protocol:
  openai-standard
  anthropic-messages
  openai-responses
  gemini-generate-content
  bedrock-converse

adapter:
  stream_openai_compatible
  stream_anthropic
  stream_openai_responses
  stream_gemini

不推荐:

text 复制代码
provider = openai-standard

因为 openai-standard 更像协议,不像厂商。

12. 一句话总结

在 LLM 多厂商接入里,最重要的是把这几个概念拆开:

text 复制代码
provider/vendor = 谁提供服务
api/protocol    = 请求响应格式
base_url        = 服务入口地址
adapter         = 负责协议转换的代码

阿里百炼兼容 OpenAI 接口,所以它应该是:

python 复制代码
Model(
    id="qwen-plus",
    provider="dashscope",
    api="openai-standard",
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)

而不是把它伪装成:

python 复制代码
provider="openai-standard"

这样做的好处是:

text 复制代码
1. Key 不混乱
2. 日志更清楚
3. 后续扩展更容易
4. 多厂商可以并存
5. 协议复用和厂商配置互不影响

上述内容也同步在我的飞书,欢迎访问

https://my.feishu.cn/wiki/QLauws6lWif1pnkhB8IcAvkhncc?from=from_copylink

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,你们的支持就是我坚持下去的动力!

相关推荐
AI技术增长1 小时前
第 2 集:环境搭建:安装 Claude Code、GitHub CLI 与项目初始化
人工智能·自动化·github
老哥不老1 小时前
ChatGPT Image2 实测全解析:AI图像生成,从“能看”到“能用”的质变
人工智能·gpt
qyhua2 小时前
AgentCode 深度技术解析:极简架构下的 AI 编程代理设计哲学
人工智能·架构
逻辑君2 小时前
认知神经科学研究报告【20260016】
人工智能
快乐非自愿2 小时前
SpringAI入门指南
大数据·人工智能·spring
新知图书2 小时前
通过阿里云百炼平台调用DeepSeek大模型
人工智能·阿里云·云计算·langchian
TokenByte-AI导航小贴士2 小时前
Claude 4.5 Sonnet / Opus / Haiku:新手选型指南
人工智能·ai·云计算·aigc·claude·aws
实习僧企业版2 小时前
AI 重构校招效率,释放 HR 核心价值
人工智能·重构
真上帝的左手2 小时前
26. AI-大语言模型-Token
人工智能·语言模型·自然语言处理·token