由于大部分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_url 和 api_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
}
}
本地部署的
ollama和vllm不需要 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)
输出结果就不贴了,有兴趣可以在后面下载代码自己玩一下。
总结
从以上的代码实践可以看出,基于标准的魔力,实现一个通用的大模型客户端就变得比较简单了。
代码
本文涉及的所有代码以及相关资源都已经共享,参见:
为便于找到代码,程序文件名称最前面的编号与本系列文章的文档编号相同。
🪐感谢您观看,祝好运🪐