A unified interface for local Large Language Models(LLM) and online LLM providers.
ullm 希望能为本地模型以及众多在线 LLM 服务提供统一的调用方式,使得开发者能够无痛地在不同模型或 LLM 服务之间切换,而无需更改代码。
Note
本项目只专注于为不同 LLM 模型或服务的基础生成功能提供统一接口,包括通用的生成、聊天接口以及最基础的工具调用、视觉理解功能,在此之外的其他相关功能如 Finetuning、Prompt Engineering、Emebedding、RAG、Agent、TTS、ASR 本项目目前并不支持,将来也不会支持。
Warning
本项目会尽可能地遵循语义版本,但在 1.0 版本前可能会发生不兼容的接口变动。
- 支持 OpenAI 等 23 个在线 LLM 服务,详见「在线服务」一节
- 支持和 OpenAI 接口兼容的自建服务
- 支持 Ollama API
- 配置化的使用方式,为所有不同模型及服务提供统一的初始化方式,详见「使用」一节
- 本地模型支持
- 归一化模型名称
- 为所有模型支持工具调用(对原本不支持的通过自定义 prompt 模板实现)
- 为不同模型适配对应的 tokenizer,以获得 tokens 数量解决某些 remote model 不返回 tokens 数量的问题
- 模型配置的管理
- 多模型路由
- 单元测试
- 完善文档
- 实现流式接口
TBD
平台 | Provider ID | 模型数量 | 视觉模型数量 | 支持工具调用的模型数量 | 联网模型数量 |
---|---|---|---|---|---|
零一万物 | 01ai | 9 | 1 | 1 | 2 |
阿里巴巴 | alibaba | 101 | 17 | 13 | 9 |
Anthropic | anthropic | 8 | 8 | 8 | 0 |
Azure OpenAI | azure-openai | 20 | 4 | 11 | 0 |
百川智能 | baichuan | 12 | 0 | 5 | 6 |
百度 | baidu | 52 | 0 | 24 | 14 |
字节跳动豆包 | bytedance | 7 | 0 | 7 | 0 |
Cloudflare Workers AI | cloudflare | 36 | 0 | 1 | 0 |
Cohere | cohere | 12 | 0 | 6 | 0 |
DeepSeek | deepseek | 1 | 0 | 1 | 0 |
15 | 15 | 15 | 0 | ||
Groq | groq | 16 | 2 | 9 | 0 |
科大讯飞 | iflytek | 12 | 0 | 5 | 6 |
MiniMax | minimax | 7 | 0 | 3 | 1 |
Moonshot | moonshot | 3 | 0 | 3 | 0 |
OpenAI | openai | 21 | 8 | 12 | 0 |
OpenRouter | openrouter | 195 | 33 | 195 | 4 |
Perplexity | perplexity | 7 | 0 | 0 | 3 |
天工 | skywork | 1 | 0 | 0 | 0 |
阶跃星辰 | stepfun | 14 | 3 | 10 | 4 |
腾讯混元 | tencent | 20 | 1 | 3 | 9 |
Together AI | together | 59 | 0 | 59 | 0 |
智谱 | zhipu | 18 | 2 | 16 | 8 |
OpenAI 接口兼容的服务 | openai-compatible | ||||
Ollama API | ollama |
pip install ullm
示例:
model_config = {
# required fields
"type": 'remote',
"model": 'gpt-3.5-turbo',
"provider": 'openai',
"api_key": 'sk-************************************************',
# optional fields
"max_tokens": 4096,
"max_input_tokens": 1024,
"max_output_tokens": 1024,
"temperature": 0.8,
"top_p": 1.0,
"top_k": 50,
"stop_sequences": ['stop1', 'stop2'],
"http_proxy": 'https://example-proxy.com',
}
模型配置中必须指定这三个字段
-
type: 指定模型为本地模型(
local
)还是在线模型(remote
),目前仅实现了 remote -
provider: 指定模型提供方,见前面「支持模型」一节,或者你也可以通过命令行工具来或获取目前支持的在线服务提供方
ullm list-providers
会得到如下结果,使用其中的 name 作为配置文件中
provider
的值| name | models | visual_models | tool_models | online_models | |-------------------|----------|-----------------|---------------|-----------------| | 01ai | 3 | 1 | 0 | 0 | | alibaba | 44 | 4 | 6 | 6 | | anthropic | 3 | 3 | 3 | 0 | | azure-openai | 20 | 4 | 11 | 0 | | baichuan | 4 | 0 | 0 | 2 | | baidu | 46 | 0 | 24 | 12 | | cohere | 12 | 0 | 4 | 6 | | deepseek | 2 | 0 | 0 | 0 | | google | 3 | 2 | 2 | 0 | | groq | 4 | 0 | 4 | 0 | | iflytek | 4 | 0 | 2 | 0 | | minimax | 5 | 0 | 5 | 0 | | moonshot | 3 | 0 | 3 | 0 | | ollama | | | | | | openai | 20 | 4 | 11 | 0 | | openai-compatible | | | | | | openrouter | 127 | 13 | 127 | 4 | | perplexity | 7 | 0 | 0 | 2 | | stepfun | 3 | 1 | 0 | 0 | | zhipu | 5 | 1 | 4 | 2 |
-
model
: 指定要使用的模型名字
除这三个字段外,各不同平台的模型可能会有各自的一些必需字段(如 api_key
),这些必需字段都在每个模型类的 META 中定义,如 OpenAIModel
class OpenAIModel(OpenAICompatibleModel):
META = RemoteLanguageModelMetaInfo(
api_url="https://api.openai.com/v1/chat/completions",
language_models=[
# ......
],
visual_language_models=[
# ......
],
# https://platform.openai.com/docs/guides/function-calling
tool_models=[
# ......
],
required_config_fields=["api_key"],
)
由于支持的平台众多,为方便起见,ullm 在命令行接口中提供了工具来生成示例代码供您修改
ullm print-example --provider openai
会得到如下输出
from ullm import LanguageModel
config = {
# required fields
"type": 'remote',
"model": 'gpt-3.5-turbo',
"provider": 'openai',
"api_key": 'sk-************************************************',
# optional fields
"max_tokens": 4096,
"max_input_tokens": 1024,
"max_output_tokens": 1024,
"temperature": 0.8,
"top_p": 1.0,
"Top_k": 50,
"stop_sequences": ['stop1', 'stop2'],
"http_proxy": 'https://example-proxy.com',
}
model = LanguageModel.from_config(config)
messages = [{"role": "user", "content": "Hello!"}]
res = model.chat(messages)
messages.append(res.to_message())
messages.append({"role": "user", "content": "Tell me a joke please!"})
res = model.chat(messages)
生成的示例代码中 required_fields
下方的配置项就是必须配置的。
所有模型的实例化统一通过 LanguageModel
这个类来进行,您不必关心不同模型的具体类名。
from ullm import LanguageModel
model = LanguageModel.from_config(model_config)
如果配置不符合要求,这个过程中可能会报错,具体来说
- 如果配置中缺失了一些必需字段,会报错
- 如果模型名称不在支持的模型列表里,会报错
ullm
实现了 ModelHub
来提供简易的模型管理,使用它可以
-
将模型实例的配置注册到
ModelHub
中from ullm import LanguageModel, ModelHub config = { # required fields "type": 'remote', "model": 'gpt-3.5-turbo', "provider": 'openai', "api_key": 'sk-************************************************', # optional fields "max_tokens": 4096, "max_input_tokens": 1024, "max_output_tokens": 1024, "temperature": 0.8, "top_p": 1.0, "Top_k": 50, "stop_sequences": ['stop1', 'stop2'], "http_proxy": 'https://example-proxy.com', } model = LanguageModel.from_config(config) hub = ModelHub() hub.register_model(model, "openai:gpt-3.5-turbo")
或者也可以使用命令行工具来注册模型
ullm register-model --model-id "openai:gpt-3.5-turbo" --model-config-file openai.json
-
通过注册时分配的唯一性 Model ID 从
ModelHub
中获取一个模型实例来进行聊天model = hub.get_model("openai:gpt-3.5-turbo") model.chat([{"role": "user", "content": "Hello"}])
默认情况下 ModelHub
会生成一个 SQLite3
的数据库文件 $HOME/.ullm.db
,并在这个数据库中存储已注册的模型实例配置,若希望更改数据库文件路径或使用其他存储后端(如 MySQL
或 PostPostgres
或),可以通过不同方法来自定义存储类型和 URL:
-
实例化时直接指定存储类型和 URL
-
使用
SQLite3
并更改数据库文件路径为/home/user/mymodels.db
hub = ModelHub(hub_backend="rds", hub_db_url="sqlite:////home/user/my.db")
-
使用
MySQL
hub = ModelHub(hub_backend="rds", hub_db_url="mysql://user:passwd@ip:port/my_db")
-
使用
Postgres
hub = ModelHub(hub_backend="rds", hub_db_url="postgresql://postgres:my_password@localhost:5432/my_db")
-
使用
Redis
hub = ModelHub(hub_backend="redis", hub_db_url="redis://localhost:6379/0", hub_redis_prefix="/ullm/model_hub/")
-
-
设置环境变量
-
使用
SQLite3
并更改数据库文件路径为/home/user/mymodels.db
export ULLM_HUB_BACKEND=rds export ULLM_HUB_DB_URL=sqlite:////home/user/my.db
-
使用
MySQL
export ULLM_HUB_BACKEND=rds export ULLM_HUB_DB_URL=mysql://user:passwd@ip:port/my_db
-
使用
Postgres
export ULLM_HUB_BACKEND=rds export ULLM_HUB_DB_URL=postgresql://postgres:my_password@localhost:5432/my_db
-
使用
Redis
export ULLM_HUB_BACKEND=redis export ULLM_HUB_DB_URL=redis://localhost:6379/0 export ULLM_HUB_REDIS_PREFIX=/ullm/model_hub/
-
-
设置
.env
环境变量文件-
使用
SQLite3
并更改数据库文件路径为/home/user/mymodels.db
ULLM_HUB_BACKEND=rds ULLM_HUB_DB_URL=sqlite:////home/user/my.db
-
使用
MySQL
ULLM_HUB_BACKEND=rds ULLM_HUB_DB_URL=mysql://user:passwd@ip:port/my_db
-
使用
Postgres
ULLM_HUB_BACKEND=rds ULLM_HUB_DB_URL=postgresql://postgres:my_password@localhost:5432/my_db
-
使用
Redis
ULLM_HUB_BACKEND=redis ULLM_HUB_DB_URL=redis://localhost:6379/0 ULLM_HUB_REDIS_PREFIX=/ullm/model_hub/
-
示例:
generate_config = {
"temperature": 0.7,
"max_tokens": None,
"max_input_tokens": None,
"max_output_tokens": 1024,
"top_p": None,
"top_k": None,
"stop_sequences": ["stop1", "stop2"],
"frequency_penalty": None,
"presence_penalty": None,
"repetition_penalty": None,
"tools": None,
"tool_choice": None,
}
ullm 支持在生成时指定部分生成参数以覆盖模型初始化时指定的一些生成参数,目前的生成参数支持这些
temperature
: 指定模型使用温度采样生成方法,并控制生成随机程度max_tokens
: 指定模型单次计算时支持的最大窗口(输入与输出之和)长度,目前并不生效max_input_tokens
: 指定模型支持的最大输入长度,目前仅cohere
和ollama
支持max_output_tokens
: 指定模型生成结果的最大长度top_p
: 指定模型采样方法为 Nucleus 采样,并指定采样百分位,与temperature
冲突top_k
: 指定模型生成时采样概率最高的 k 个 token,对部分 LLM 服务如OpenAI
不生效stop_sequences
: 指定模型生成的停止标识frequency_penalty
/presence_penalty
/repetition_penalty
: 用于对模型生成中一些重复行为的惩罚的设置,各家实现并不一致,若需使用请查阅对应 LLM 服务文档tools
/tool_choice
: 指定模型要调用的工具,目前工具方面的支持还不完善,暂不建议使用
生成参数共有三层,从上到下分别是:运行时生成参数、模型配置指定的参数、LLM 服务自身的默认参数。一个参数若运行时不指定,那么会尝试从模型配置中获取,如果模型配置中也未设置则将使用服务自身的默认值(由外部 LLM API 自身决定)。
示例:
model.generate(""补全句子:白日依山尽", config=generate_config)
会得到如下结果
GenerationResult(
model='qwen-turbo',
stop_reason='stop',
content='黄河入海流。',
tool_calls=None,
input_tokens=29,
output_tokens=5,
total_tokens=34,
original_result='{"output":{"choices":[{"finish_reason":"stop","message":{"role":"assistant","content":"黄河入海流。"}}]},"usage":{"total_tokens":34,"output_tokens":5,"input_tokens":29},"request_id":"00ccdb48-74a3-9873-851c-79dbfb4b5a8c"}'
)
示例:
system = "你是孙悟空,我是叫作小钻风的小妖怪,现在请你按照以上设定和我进行对话。"
messages = [{"role": "user", "content": "大王叫我来巡山啊,巡完南山巡北山啊"}]
model.chat(messages, system=system, config=generate_config)
会得到如下结果
GenerationResult(
model='qwen-turbo',
stop_reason='stop',
content='嘿,小钻风,你这巡山的勤快劲儿倒也不赖。不过咱们这花果山水帘洞,可不比寻常山头,有啥新鲜事儿没?别告诉我你只找找有没有偷吃桃子的家伙。',
tool_calls=None,
input_tokens=50,
output_tokens=55,
total_tokens=105,
original_result='{"output":{"choices":[{"finish_reason":"stop","message":{"role":"assistant","content":"嘿,小钻风,你这巡山的勤快劲儿倒也不赖。不过咱们这花果山水帘洞,可不比寻常山头,有啥新鲜事儿没?别告诉我你只找找有没有偷吃桃子的家伙。"}}]},"usage":{"total_tokens":105,"output_tokens":55,"input_tokens":50},"request_id":"774dcfa1-27be-955a-872a-94d8c0eeca2c"}'
)
如果想继续对话下去,可以将结果转换为 message 对象加入到 messages
里去
response = model.chat(messages, system=system, config=generate_config)
messages.append(response.to_message())
messages.append({"role": "user", "content": "啊!孙悟空打上门啦!"})
model.chat(messages, system=system, config=generate_config)
会得到如下结果
GenerationResult(
model='qwen-turbo',
stop_reason='stop',
content='哈哈,你这消息还挺灵通的嘛,小钻风。孙悟空那猴子,本事大得很,来找茬儿肯定是为了些过节。你准备好迎战了吗?咱们花果山的兄弟们可不能示弱,得让他见识见识我们妖族的厉害!',
tool_calls=None,
input_tokens=122,
output_tokens=60,
total_tokens=182,
original_result='{"output":{"choices":[{"finish_reason":"stop","message":{"role":"assistant","content":"哈哈,你这消息还挺灵通的嘛,小钻风。孙悟空那猴子,本事大得很,来找茬儿肯定是为了些过节。你准备好迎战了吗?咱们花果山的兄弟们可不能示弱,得让他见识见识我们妖族的厉害!"}}]},"usage":{"total_tokens":182,"output_tokens":60,"input_tokens":122},"request_id":"3de256d0-23bd-93a5-93a6-7bb6e859f9d9"}'
)
Usage: ullm list-providers [OPTIONS]
List all remote LLM providers
Options:
-h, --help Show this message and exit.
Usage: ullm list-supported-models [OPTIONS]
List all remote models
Options:
--providers TEXT List models of these providers, separate multi providers
with commas
--only-visual
--only-online
--only-tool
-h, --help Show this message and exit.
Usage: ullm print-example [OPTIONS]
Print code example for a specified remote LLM provider
Options:
--provider TEXT [required]
-h, --help Show this message and exit.
Usage: ullm chat [OPTIONS]
A simple chat demo
Options:
--model TEXT Model ID registered in hub, or a model
config file [required]
--model-hub-backend [rds|redis]
Model hub backend
--model-hub-db-url TEXT Model hub database url
--system TEXT
--temperature FLOAT
--max-output-tokens INTEGER
--keep-turns-num INTEGER
-h, --help Show this message and exit.
Usage: ullm register-model [OPTIONS]
Register a new model to hub
Options:
--model-hub-backend [rds|redis]
Model hub backend
--model-hub-db-url TEXT Model hub database url
--model-id TEXT
--model-config-file TEXT
-h, --help Show this message and exit.
Usage: ullm list-models [OPTIONS]
List all registered models
Usage: python -m ullm.cli list-models [OPTIONS]
List all registered models
Options:
--model-hub-backend [rds|redis]
Model hub backend
--model-hub-db-url TEXT Model hub database url