安装

本页介绍怎样把 HybridInference 网关跑起来:用 Docker 服务栈,或者直接从源码运行、方便自己修改。

如果想先什么都不配、看网关实际应答一次请求,那就先看快速开始。它用一个固定回复的假 provider,不需要 provider 账号,不需要 API key,连 .env 都不用。本页是下一步:用你自己的 provider,搭你自己的部署。

需要准备什么

运行方式

要求

Docker 服务栈

Docker Engine 24+ 与 Docker Compose v2+

从源码运行

Python 3.10–3.13(推荐 3.12,以 pyproject.toml 为准)与 uv

在 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 里填好三样东西:

  1. 数据库登录信息。DB_USER 和 DB_PASSWORD 默认是空的,DB_NAME 已经设为 hybridinference。三个都有值之前,Compose 不会启动。

  2. 三个密钥。JWT_SECRET_KEY 用来给登录 token 签名,API_KEY_SECRET 是网关对 API key 做哈希时用的密钥,ERASURE_FENCE_SECRET 用来保护已删除账号的记录。没有前两个,后端会拒绝启动;第三个留空时,会悄悄沿用 API_KEY_SECRET 的值。三个要分别生成:

    python3 -c "import secrets; print(secrets.token_urlsafe(48))"
    
  3. 模型要用的凭据。默认情况下,网关提供 config/examples/models.openrouter.yaml 里的三个示例模型,它们都走 OpenRouter(其中一个会先尝试本地的 Ollama 服务器)。设置好 OPENROUTER_API_KEY 就能用。要换成你自己的模型,见添加新模型。

把这些密钥和部署的其他配置放在一起,并且一直保留:每次重启、每个副本都用同一组,升级时也原样带过去。改了 JWT_SECRET_KEY,已经签发的访问 token 会全部失效;改了 API_KEY_SECRET,所有现有的 API key 都将无法使用。改了 ERASURE_FENCE_SECRET(或者在它留空时代替它的 API_KEY_SECRET),后端会直接拒绝启动,见数据库。网关从不替你生成或轮换这些密钥。

备注

只有不带数据库、也没有账号体系的网关才能不设这些密钥:DB_ENABLED=false 并且 USER_AUTH_ENABLED=false,就像快速开始的阶段 1 那样。ADMIN_TOKEN 是可选的;留空只会关闭旧式的管理员 token 访问方式。

然后启动这套服务栈:

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,所以重启后用的还是旧值。

会启动三个容器:

服务

宿主机地址

说明

backend

127.0.0.1:8080

FastAPI 网关;用 BACKEND_HOST / BACKEND_PORT 覆盖监听地址

frontend

127.0.0.1:3001

Next.js 控制台;用 FRONTEND_HOST / FRONTEND_PORT 覆盖

postgres

127.0.0.1:5432

用 DB_PORT 覆盖

这些端口默认可从宿主机访问。同机运行的反向代理可以使用回环地址;从其他机器访问则需要显式覆盖监听地址。控制台也会转发 API 请求,公开它之前请先阅读部署指南。

Compose 文件中也包含 pgAdmin,通过可选的 admin profile 启动。

本地开发(不用 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。从仓库根目录启动后端时,它会读取这个文件;Compose 也会把它传给各个容器。

除了上面 Docker 步骤里的这些变量(DB_NAME、DB_USER、DB_PASSWORD、JWT_SECRET_KEY、API_KEY_SECRET、ERASURE_FENCE_SECRET),以及默认注册表需要的 OPENROUTER_API_KEY,.env.example 里的其他变量都是可选的。最可能用得上的是这些:

变量

作用

USER_AUTH_ENABLED

1(默认)要求推理请求携带用户 API key;0 允许匿名推理,但不会关闭账号登录或管理员鉴权

ADMIN_TOKEN

/admin/* 端点使用的可选旧式 bearer token;留空只会禁用这一访问方式

PROVIDER_ROUTE_TYPES

管理控制台可以按 provider 添加的路由类型,写成逗号分隔的 provider=type[|type] 条目(例如 chutes=quota,openrouter=concurrency|on_demand);留空则每个 provider 都不受限

DB_ENABLED

false 让网关不带数据库运行

DB_STORE_FULL_CONTENT

false(默认)完全不存储 prompt 和响应;true 则完整存储。见请求日志与隐私

FRONTEND_URL

用户在验证邮件和重置邮件里点击的绝对 URL

BASE_URL

本网关自己对外的 origin,用来拼装注册和密码重置邮件里的绝对链接。请设置它:服务器不解析 X-Forwarded-*,所以留空的话,即便在 TLS 反代后面,也会从请求里推导出 http://…。见可信代理与客户端 IP

LOG_LEVEL, LOG_FORMAT

日志详细程度,以及 json/纯文本输出

ALERTS_ENABLED, SLACK_ALERTS_WEBHOOK_URL

进程内告警,默认关闭

TRUST_PROXY_HEADERS, TRUSTED_PROXIES

信任 TRUSTED_PROXIES 中所列代理发来的 X-Forwarded-For;下面的 Cloudflare 设置也需要打开这个开关

TRUSTED_DIRECT_CLIENT_NETWORKS

可选,直接从私有网络连入的客户端所在网段(CIDR);不会因此信任转发头

TRUST_CLOUDFLARE_HEADERS, TRUSTED_CLOUDFLARE_NETWORKS

信任所列对端发来的 Cloudflare CF-Connecting-IP;还需要同时设置 TRUST_PROXY_HEADERS=1

按你的部署方式该设上面哪几项代理设置,见可信代理与客户端 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},都不会被替换。详见配置。

.env.example 里为本项目已有 adapter 或示例的 provider 预留了空的占位变量;你也可以随意添加自己的变量名。内置的默认注册表只需要 OPENROUTER_API_KEY。

配置了数据库之后,也可以在管理控制台(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 还没启动任何东西就停了。按上面第 1 步,在 .env 里填上 DB_USER 和 DB_PASSWORD。

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。