安装
本页介绍怎样把 HybridInference 网关跑起来:用 Docker 服务栈,或者直接从源码运行、方便自己修改。
如果想先什么都不配、看网关实际应答一次请求,那就先看快速开始。它用一个固定回复的假 provider,不需要 provider 账号,不需要 API key,连 .env 都不用。本页是下一步:用你自己的 provider,搭你自己的部署。
需要准备什么
运行方式 |
要求 |
|---|---|
Docker 服务栈 |
Docker Engine 24+ 与 Docker Compose v2+ |
从源码运行 |
Python 3.10–3.13(推荐 3.12,以 |
在 Docker 之外运行控制台 |
Node.js 22(CI 安装的版本) |
Linux 或 macOS。
用 Docker 运行
git clone https://github.com/HarvardMadSys/hybridInference.git hybridinference
cd hybridinference
cp .env.example .env
第一次 make up 之前,在 .env 里填好数据库登录信息:DB_USER 和 DB_PASSWORD 默认是空的,DB_NAME 已经设成了 hybridinference。三个都有值之前,Compose 拒绝启动。.env 里别的都不是必填的。网关的其他设置项——provider key、SMTP、代理信任等——都存在它的数据库里,第一次启动后在控制台里填写。
然后启动这套服务栈:
make up # creates the external volume, then brings up Compose
make ps # show the services and their health
curl -s http://localhost:8080/health
第一次 make up 还会创建存放数据库的 Docker 卷 hybridinference_postgres_data。docker compose down -v 不会删除它;如果需要干净的数据库,见重置这套服务栈。
.env 里只保留数据库连接和容器相关的设置。之后如果改了其中某项,要重新运行 make up,而不是 make restart:容器只在创建时读取 .env,所以重启后用的还是旧值。
会启动三个容器:
服务 |
宿主机地址 |
说明 |
|---|---|---|
|
|
FastAPI 网关;用 |
|
|
Next.js 控制台;用 |
|
|
用 |
这些端口默认可从宿主机访问。同机运行的反向代理可以使用回环地址;从其他机器访问则需要显式覆盖监听地址。控制台也会转发 API 请求,公开它之前请先阅读部署指南。
Compose 文件中也包含 pgAdmin,通过可选的 admin profile 启动。
首次运行设置
第一次连着空数据库启动时,后端会生成它运行所必需的两个密钥——签发登录 token 的 JWT_SECRET_KEY,以及保护 API key 的 API_KEY_SECRET——并把它们存进数据库。然后它等待创建管理员:生成一个一次性的设置码,保存在数据库里,并打印在日志里:
docker logs hybridinference-backend 2>&1 | grep 'setup code'
打开控制台 http://localhost:3001,它会把你带到设置页面,然后:
输入设置码。在设置完成之前它保持不变,不管
LOG_LEVEL设成什么,后端每次启动都会再把它记进日志。设置完成之前,后端也拒绝一切注册,所以别人抢不走第一个账号。创建管理员:一个用户名和一个密码。这个账号没有邮箱地址,用用户名登录。选一个难猜的用户名,不要用
admin:登录对每个用户名每 15 分钟只允许尝试五次,而且在检查密码之前就计数,所以知道用户名的人就能把这个账号锁住。填写页面列出的设置项。默认情况下,网关提供
config/examples/models.openrouter.yaml里的三个示例模型,它们都走 OpenRouter(其中一个会先尝试本地的 Ollama 服务器),所以OPENROUTER_API_KEY会被列为缺失:设置好它,这些模型就能用。要换成你自己的模型,见添加新模型。完成。模型注册表在后端启动时读取 provider 凭据,所以只要你保存的内容需要重启,最后一步就会提供 Restart backend。
这里设置的所有内容,之后都可以在管理控制台的 Configuration 标签页上修改,做法见存储在数据库中的设置项。创建管理员的其他方式,以及怎样重置它的密码,见第一个管理员账号。
备注
密钥和数据库要放在一起保管。API_KEY_SECRET 一旦设置就不能再改,因为新值会让现有的所有 API key 失效;改 JWT_SECRET_KEY 则会让所有用户退出登录。保护已删除账号记录的 ERASURE_FENCE_SECRET,除非你在第一次启动前就在 .env 里设置它,否则会沿用 API_KEY_SECRET 的值,而且之后同样不能再改;见数据库。数据库的 dump 里带着这些密钥和每一个 provider key。
没有数据库的网关(DB_ENABLED=false)没有设置步骤,也没有存储的设置项:它从环境变量读取所有设置项;打开用户认证时,JWT_SECRET_KEY 和 API_KEY_SECRET 也要放在环境变量里。只有既没有数据库、也没有账号的网关才能不要它们——即 DB_ENABLED=false 并且 USER_AUTH_ENABLED=false,就像快速开始的阶段 1 那样。
本地开发(不用 Docker)
git clone https://github.com/HarvardMadSys/hybridInference.git hybridinference
cd hybridinference
make setup-dev
make setup-dev 会用 Python 3.12 创建 .venv(如果已有的 .venv 是别的次版本,它会拒绝继续),以可编辑方式安装本项目,同步 dev 依赖组,并装好 pre-commit hooks。手动来做的话:
uv venv -p 3.12
source .venv/bin/activate
uv sync --group dev
请在仓库根目录下运行网关,因为默认的配置路径都相对于仓库根目录:
cp .env.example .env # edit as above; a process started here reads it
uv run uvicorn serving.servers.app:app --no-proxy-headers --host 127.0.0.1 --port 8080
有数据库时,首次运行设置里说的设置码会出现在这个终端的日志里。
在另一个终端里运行控制台:
cd apps/frontend
npm ci
BACKEND_INTERNAL_URL=http://127.0.0.1:8080 npm run dev -- --hostname 127.0.0.1
打开 http://localhost:3001。控制台会把 API 路径转发给网关,BACKEND_INTERNAL_URL 告诉它网关在哪。这个变量的默认值 http://backend:8080 只在 Docker 内部有效,而控制台又不读仓库里的 .env,所以每次启动控制台都要设置它。用 curl http://localhost:3001/health 检查整条链路。
如果想连着 Postgres 开发、又不想启动整套服务栈,可以只起数据库容器:
make docker-volumes
docker compose -f deploy/docker/docker-compose.yml --env-file .env up -d postgres
如果本地网关不需要账号或数据库,在 .env 中同时设置 DB_ENABLED=false 和 USER_AUTH_ENABLED=false。它仍能路由请求,/health 会报告 "database_configured": false。账号、API key、请求历史以及存储在数据库中的设置项,都需要数据库。
配置
环境变量
仓库根目录的 .env 里放的是后端连上数据库之前就需要的东西,以及描述容器而不是应用本身的东西:数据库连接(DB_*)、宿主机端口和绑定地址、配置文件路径,以及少量进程和控制台的取值。.env.example 列出了它们。从仓库根目录启动后端时,后端会读取 .env;Compose 也会把它传给容器。
其他所有设置项都存在数据库里,在管理控制台的 Configuration 标签页上编辑,那里对每一项都有说明;USER_AUTH_ENABLED 这类运行时开关在 Settings 标签页上。环境变量里的值只是起点:启动时,如果数据库里还没有这个值,后端会把它复制进去,此后以存储的值为准。见存储在数据库中的设置项。
你最可能要用到的设置项:
设置项 |
作用 |
|---|---|
|
|
|
|
|
管理控制台可以按 provider 添加的路由类型,写成逗号分隔的 |
|
|
|
|
|
用户在验证邮件和重置邮件里点击的绝对 URL |
|
本网关自己对外的 origin,用来拼装注册和密码重置邮件里的绝对链接。请设置它:服务器不解析 |
|
日志详细程度,以及 |
|
进程内告警,默认关闭 |
|
信任 |
|
可选,直接从私有网络连入的客户端所在网段(CIDR);不会因此信任转发头 |
|
信任所列对端发来的 Cloudflare |
按你的部署方式该设上面哪几项代理设置,见可信代理与客户端 IP。
Provider 凭据
模型注册表自己指定要用哪些凭据。它的 api_key、api_keys、base_url 和 provider_model_id 字段都可以写成 ${VAR},在加载注册表时解析:先取数据库里存储的同名设置项,没有再用环境变量。所以一个部署需要哪些 provider key,就看它的注册表写了哪些变量,变量名随你起。
route:
- kind: openrouter
base_url: https://openrouter.ai/api/v1
api_keys:
- ${OPENROUTER_API_KEY}
只有整个值才会被替换:${VAR:-default},以及嵌在更长字符串里的 ${VAR},都不会被替换。详见配置。
Configuration 标签页会在 Providers 下列出当前注册表引用的每个变量,标出哪些是模型加载必不可少的,并保存它们的值;自带的默认注册表只需要 OPENROUTER_API_KEY。标签页还没列出的名字(比如你即将切换过去的那份注册表要用的)可以用 Add variable 添加。注册表在启动时读取这些值,所以改了之后要重启后端。没有数据库的网关则从 .env 读取它们。
也可以在管理控制台(Providers → Keys)里添加 key,无需重启;这些 key 和注册表里指定的 key 放在同一个池子里。见从管理控制台做运行时配置。
配置文件在哪里
网关通过环境变量或发行版的 manifest 找到自己的模型注册表、路由配置文件和告警规则;两者都没有指定时,就回退到 config/examples/ 下的示例。具体规则见网关如何找到自己的配置,文件里该写什么,那一页后面都有讲。
Compose 文件把 config/ 和 distributions/ 都以只读方式挂载进后端,所以在宿主机上改了其中任何一个,重启后端就行——不用重新构建镜像。
备注
直接跑在宿主机上的后端,可以通过 localhost 访问宿主机上的推理服务器。跑在 Docker 里的后端则必须用 Docker 内能访问到的地址,例如 host.docker.internal,并且要在模型注册表里显式写出来;HybridInference 不会替你改写 provider 的 URL。
验证安装
对着运行中的网关执行:
curl -s http://localhost:8080/v1/models
curl -s http://localhost:8080/v1/chat/completions \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer ${HYBRIDINFERENCE_API_KEY}" \
-d '{"model":"<model-id>","messages":[{"role":"user","content":"Say hello."}]}'
如果设了 USER_AUTH_ENABLED=0,就去掉 Authorization 头。模型 id 要用 /v1/models 真的列出来的那些。
同一个调用,用 OpenAI 的 Python SDK 来发——网关就是那个 base_url,现有客户端别的什么都不用改:
from openai import OpenAI
client = OpenAI(api_key="<your-api-key>", base_url="http://localhost:8080/v1")
response = client.chat.completions.create(
model="<model-id>",
messages=[{"role": "user", "content": "Say hello."}],
)
print(response.choices[0].message.content)
本地开发时,make check 会运行 linter 和默认测试套件;其他检查见贡献指南。
故障排查
required variable DB_USER is missing a value: DB_USER must be set in .env file——Compose 还没启动任何东西就停了。按上文的做法,在 .env 里填上 DB_USER 和 DB_PASSWORD。
启动时出现 Authentication configuration incomplete: set JWT_SECRET_KEY, API_KEY_SECRET——后端没能从数据库读到它的设置项,退回到了环境变量,而环境变量里没有密钥。更早的一行 Configuration load failed after 3 attempts 会说明原因;应该修好数据库连接,而不是往 .env 里加密钥。
设置页面不接受设置码——从 docker logs 命令输出的最后一行重新复制;更早的行可能属于你后来重置掉的数据库。输错的设置码会按客户端地址限流,但正确的设置码总会被接受。如果日志里根本没有设置码,说明设置已经完成;直接登录,或者按第一个管理员账号里的做法重置管理员密码。
缺少必填的设置项——已登录的用户会看到一条横幅,它指的那些设置项在 Configuration 标签页上标着 Missing。在那里把它们填上;provider 凭据要在 Restart backend 之后才生效。如果部署有意不设置某个模型的凭据,就改为在模型注册表里给那条路由标上 optional: true,这样这个变量就不再是必填的。
改了设置项之后登录失败——用命令行把这个设置项改回来,这不需要登录;见不通过控制台。
env file ... .env not found——在 make up 之前先用 cp .env.example .env 创建它。
从源码运行时报导入错误——运行 make setup-dev(或 uv sync --group dev),把后端装进 .venv,然后用 uv run 启动网关,或者先激活 .venv 再启动。
所有请求都 404,且 /v1/models 为空——说明注册表什么都没加载进来。启动时后端要么打印 Registered N routes from <path>,要么打印一条错误,指出它找不到的注册表路径;把这个路径和配置里的优先级列表对照一下。
端口已被占用——在 .env 里覆盖 BACKEND_PORT、FRONTEND_PORT 或 DB_PORT。