由于大部分AI平台提供的API/接口都兼容 OpenAI API ,所以我们可以使用 OpenAI SDK 实现通用的 LLM(大语言模型) 客户端。

关于 OpenAI API 更多内容,可参考 程序员应该熟悉的概念(2)OpenAI API

本文讲述了如何实现一个简单的大模型客户端

兼容 OpenAI API 的平台

平台名称 base_url
openai https://api.openai.com/v1
anthropic https://api.anthropic.com/v1
mistral https://api.mistral.ai/v1
gemini https://generativelanguage.googleapis.com/v1beta/openai
cohere https://api.cohere.com/v1
xai https://api.x.ai/v1
openrouter https://openrouter.ai/api/v1
ollama http://localhost:11434/v1
bailian https://dashscope.aliyuncs.com/compatible-mode/v1
vllm http://localhost:8000/v1

本地部署的 Ollama 也兼容 OpenAI API,使用时无需 api-key 。合理的标准大大提高生产力!

定义变量

我们先定义一个变量,存储不同平台的 base_urlapi_key,这样在访问不同的平台时,使用该平台独有的配置信息即可。

    PROVIDERS = {
        "openai": {
            "base_url": "https://api.openai.com/v1",
            "api_key_env": "OPENAI_API_KEY"
        },
        "anthropic": {
            "base_url": "https://api.anthropic.com/v1",
            "api_key_env": "ANTHROPIC_API_KEY"
        },
        "mistral": {
            "base_url": "https://api.mistral.ai/v1",
            "api_key_env": "MISTRAL_API_KEY"
        },
        "gemini": {
            "base_url": "https://generativelanguage.googleapis.com/v1beta/openai",
            "api_key_env": "GEMINI_API_KEY"
        },
        "cohere": {
            "base_url": "https://api.cohere.com/v1",
            "api_key_env": "COHERE_API_KEY"
        },
        "xai": {
            "base_url": "https://api.x.ai/v1",
            "api_key_env": "XAI_API_KEY"
        },
        "openrouter": {
            "base_url": "https://openrouter.ai/api/v1",
            "api_key_env": "OPENROUTER_API_KEY"
        },
        "ollama": {
            "base_url": "http://localhost:11434/v1",
            "api_key_env": None     # 使用任何字符串都可以
        },
        "bailian":{
            "base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
            "api_key_env": "DASHSCOPE_API_KEY"
        },
        "vllm": {
            "base_url": "http://localhost:8000/v1",
            "api_key_env": None
        }
    }

本地部署的 ollamavllm 不需要 api_key。
这里将api-key存储在环境变量中,当然也可改造让它存储在配置文件甚至数据库中。

实现通用客户端类:LLMClient

在使用 LLM(大语言模型) 时,temperature 是很常用的参数: 它的数值在 0-1 之间,数值越小,确定性越强,数值越大,随机性越强。如果我们需要更加稳定准确的答案,那么这个数值应该小一点,如果想模拟李白写诗,这个数值应该大一点。

class LLMClient:
    
    def __init__(self, provider="openai", api_key=None, temperature: float = 0.7):
        """
        初始化 LLM 客户端
        :param base_url: API 地址,例如 "http://localhost:8000/v1"
        :param api_key: API key(Ollama 等兼容实现可用任意字符串)
        :param model: 模型名称,例如 "qwen3" 或 "gpt-4o-mini"
        :param temperature: 采样温度([0-1],数值越大随机性越高)
        """
        if provider not in self.PROVIDERS:
            raise ValueError(f"Unsupported provider: {provider}")

        self.provider = provider
        self.temperature = temperature  # 保存默认 temperature
        config = self.PROVIDERS[provider]

        if not api_key and config["api_key_env"]:
            import os
            api_key = os.getenv(config["api_key_env"])
            if not api_key:
                raise ValueError(f"Missing API key, please set {config['api_key_env']}")

        if not api_key:
            api_key = "none"

        self.client = OpenAI(api_key=api_key, base_url=config["base_url"])

    def chat(self, model, messages, stream=False, **kwargs):
        """
        普通调用: 返回字符串
        流式调用: 返回生成器,每次 yield 新的 token
        """
        # 如果用户没有传 temperature,则用默认的
        # top_p、max_tokens 这些常用参数也可以通过kwargs设置
        if "temperature" not in kwargs:
            kwargs["temperature"] = self.temperature
        if stream:
            response = self.client.chat.completions.create(
                model=model,
                messages=messages,
                stream=True,
                **kwargs
            )
            def generator():
                for chunk in response:
                    delta = chunk.choices[0].delta.content
                    if delta:
                        yield delta
            return generator()
        else:
            resp = self.client.chat.completions.create(
                model=model,
                messages=messages,
                **kwargs
            )
            return resp.choices[0].message.content

kwargs 看起来怪怪的,但是其能力却很强,它可以传递任意数量的关键字参数。这些关键字参数会以字典的形式存储在 kwargs 中。
我们在 init 中设置了 temperature 的默认值,但是可以在调用 chat 方法时,通过 kwargs 覆盖它。

上面的类支持普通的调用,也支持流模式。下面使用本地部署的 ollama 测试一下:

if __name__ == '__main__':
    model_name = "qwen3"
    llm = LLMClient(provider="ollama")

    print("流式模式结果:", end="", flush=True)
    for token in llm.chat(
        model=model_name,
        messages=[{"role": "user", "content": "用少于1000个字总结《西游记》"}],
        stream=True
    ):
        print(token, end="", flush=True)

    print()  # 换行

    result = llm.chat(model_name, [{"role": "user", "content": "用李白的风格给我写一首描写饮酒的诗"}])
    print("普通模式结果:\n", result)

输出结果就不贴了,有兴趣可以在后面下载代码自己玩一下。

总结

从以上的代码实践可以看出,基于标准的魔力,实现一个通用的大模型客户端就变得比较简单了。


代码

本文涉及的所有代码以及相关资源都已经共享,参见:

为便于找到代码,程序文件名称最前面的编号与本系列文章的文档编号相同。

🪐感谢您观看,祝好运🪐