首次启动空数据库时会生成并只打印一次 bootstrap API key,需立即保存;临时 Docker 容器内用 SQLite,停止即丢数据,持久化要用 Compose;通过仪表盘存提供商密钥需先设置 OTARI_SECRET_KEY 为 Fernet 密钥,Compose 还需在 .env 中配置 OTARI_PROVIDER_ACCOUNT_PEPPER。
otari
mozilla-aiApache-2.0活跃维护自托管的开源 AI 网关,把 40 多家模型提供商统一到一个接口,并自带虚拟密钥、预算控制和用量统计,省去多平台对接与成本管理麻烦。
Open-source AI gateway you run yourself. One endpoint for 40+ providers, with virtual keys, budgets, and usage tracking.
docker run --rm -p 8000:8000 -e OPENAI_API_KEY=YOUR_OPENAI_KEY -e OTARI_CONFIG_YAML='default_pricing: true
providers:
openai:
api_key: ${OPENAI_API_KEY}
' mzdotai/otari:latest otari serveREADME 未说明具体硬件要求;提供 Docker 镜像与 Compose 部署,Compose 默认使用 PostgreSQL,本地开发可改用 SQLite。
自托管的 AI 网关,用一个端点接入 40+ 模型提供商,统一管理密钥、预算与用量
自托管的开源 AI 网关,把 40 多家模型提供商统一到一个接口,并自带虚拟密钥、预算控制和用量统计,省去多平台对接与成本管理麻烦。
核心能力
- 用单一 OpenAI/Anthropic 兼容端点路由 40+ 提供商
- 签发可撤销虚拟密钥,按用户、工作区和模型限定范围
- 派发前校验预算,结算后记录用量
- 本地路由策略支持故障转移、条件选择、流量拆分与限流溢出
- 可选代码执行、联网搜索、MCP、推理护栏与文件理解
容易踩的坑
- v0.41.0最新正式版2026-11-09 · 2026-11-09 16:27 UTC
0.41.0 - 2026-11-09
Bug Fixes
- web: Mint the setup guide's key on a press and offer the guide once in #3003 by @daavoo (
8b9a896) - search: Use the organization key when no search tool can be picked in #2987 by @daavoo (
2d1bfc7) - hook: Flag every registration and honor CLAUDE_CONFIG_DIR in #2975 by @peteski22 (
c3a48ca) - budgets: Name service-key end users by external_id in budget refusals in #3006 by @LBCron (
497e07b) - web: Keep the refusal's error code on apiFetch errors in #2912 by @jigjigjig (
fcb11c0) - guardrails: Fail closed when a block guardrail gives no verdict in #2966 by @hitakshiA (
3c1f78d) - web: Offer org provider keys in member model restrictions in #2536 by @jigjigjig (
949102b) - web: Use Select for visible-label choices inside forms in #2891 by @jigjigjig (
4cd0864) - web: Say why a span has no input, and how to keep it in #2658 by @jigjigjig (
98ceaca) - gateway: Bill a stream the provider cuts mid-response on an estimate in #2886 by @jigjigjig (
b941f68) - usage: Count every round of a gateway tool loop in #2952 by @hitakshiA (
5eeb98b) - tenancy: Name the workspace_member foreign keys by @tbille (
59c41c5) - tenancy: Rename the workspace_member keys and check FK parity in #2601 by @tbille (
6930094) - guardrails: Read a # right after a command substitution as part of its word in #2751 by @theluckystrike (
887a13d) - batches: Price a recorded batch under the instance and model it was created with in #2663 by @pcbeingused333
- web: Mint the setup guide's key on a press and offer the guide once in #3003 by @daavoo (
- v0.40.02026-11-06 · 2026-11-06 18:57 UTC
查看更新说明
0.40.0 - 2026-11-06
Bug Fixes
- web: Open the public catalog filtered on the list a link names in #2923 by @jigjigjig (
bba566a) - routing: Stop optional params from failing every policy candidate in #2914 by @daavoo (
063083f) - web: Save a retried budget's edits and refuse rounded counts in #2927 by @daavoo (
f62c64e) - providers: Address review on key request prefixes in #2934 by @daavoo (
56125e2) - key: Address review on the key budget read by @daavoo (
b4d4857) - search: Drop the unused SearXNG client and document the adapter in #2943 by @aittalam (
eca744c) - guardrails: Keep a guardrails service's answer out of the gateway log in #2906 by @hitakshiA (
08e5a35) - web: Send the auth Help link to the configured documentation by @jigjigjig (
07d707d) - web: Share the welcome guide link between Help and the onboarding quickstart by @jigjigjig (
d135417) - otlp: Price imported prompt cache once and keep each OTel trace in one priced session in #2866 by @agpituk (
bc43068)
Features
- pricing: Price a pass-through report at its rate's slot by @dpoulopoulos (
8e44bd0) - pricing: Price a catalog model that has no text price by @dpoulopoulos (
ed11706) - api: Measure what each pass-through endpoint bills by @dpoulopoulos (
ea070e2) - pricing: Price a provider-run search at the model's own rate by @dpoulopoulos (
997bb95) - web: Set a budget's token and request limits from the dashboard by @daavoo (
0f6ec30) - BREAKING: providers: Name an organization key with its own endpoint by a request prefix by @daavoo (
f7fa290) - key: Let an API key read its own budget and usage by [
- web: Open the public catalog filtered on the list a link names in #2923 by @jigjigjig (
- v0.39.02026-11-05 · 2026-11-05 13:35 UTC
查看更新说明
0.39.0 - 2026-11-05
Bug Fixes
- upload: Authenticate before parsing multipart bodies in #2796 by @mikemikimike (
2bdfeca) - gateway: Write an estimated usage row when a client abandons a stream in #2869 by @jigjigjig (
38f7dd7) - files: Read an image in a file block as an image in #2848 by @daavoo (
a9a8b74) - welcome: Show the Otari router in the chat completion example by @jigjigjig (
47f2450) - welcome: Use a catalog id this gateway serves and explain the router by @jigjigjig (
8dbb82b) - welcome: Put the model listing command in its own block in #2884 by @jigjigjig (
51b55db) - web: Name every add-provider picker option from the dashboard's own map first by @jigjigjig (
ef54a14) - web: Keep the gateway's provider name searchable in the picker in #2885 by @jigjigjig (
408595e) - web: Match the catalog header lockup to the sign-in size in #2887 by @jigjigjig (
ab91361) - web: Keep edit dialogs mounted so they animate out on close by @jigjigjig (
d4c7450) - web: Release an edit dialog's row once its exit is over in #2888 by @jigjigjig (
5454bb9) - usage: Keep the model's pricing rules through a manual reprice by @jigjigjig (
6186334) - usage: Always qualify the manual reprice key so a colon in the model id is not read as a provider in #2890 by @jigjigjig (
076b584) - pricing: Read a Bedrock version suffix as part of the model id when judging Claude by @jigjigjig (
b6827e5) - pricing: Cover a Bedrock context-window suffix and tighten the version match in #2892 by @jigjigjig (
a3b41a9) - web: Give a filter chip's dismiss a 44px touch target on touch screens by [@jigjigjig](https://github.com/jigjig
- upload: Authenticate before parsing multipart bodies in #2796 by @mikemikimike (
- v0.38.02026-11-04 · 2026-11-04 15:36 UTC
查看更新说明
0.38.0 - 2026-11-04
Bug Fixes
- health-checks: Switch off a model its provider refuses during a run in #2846 by @daavoo (
11e2b45) - web: Give Amazon Bedrock its own provider mark in #2828 by @jigjigjig (
afa6284) - web: Keep focus in the table after a confirmed delete in #2852 by @jigjigjig (
e3c089f)
Features
- BREAKING: pricing: Spell every price unit as models.dev does by @dpoulopoulos (
aad0587) - dashboard: Name a price unit as the API does in #2820 by @dpoulopoulos (
887ec8e) - tools: Bill the pages a search reads as fetches on the instance that read them in #2831 by @aittalam (
21296f1) - BREAKING: tools: Refuse a search whose pages an unpriced fetch tool would read in #2832 by @aittalam (
fa0876a) - traces: Keep the content of routed requests that ask for it in #2685 by @agpituk (
d849d42) - images: Add the image edit endpoint in #2868 by @KevinGallaccio (
bff9dab)
New Contributors
- @KevinGallaccio made their first contribution in #2868
Full Changelog: https://github.com/mozilla-ai/otari/compare/v0.37.0...v0.38.0
- health-checks: Switch off a model its provider refuses during a run in #2846 by @daavoo (
- v0.37.02026-11-04 · 2026-11-04 08:01 UTC
查看更新说明
0.37.0 - 2026-11-04
Bug Fixes
- dashboard: Stop a filter below the fold scrolling the shell away in #2817 by @peteski22 (
c96d0fa) - provider-endpoints: Point a private api_base at hosted providers in #2830 by @daavoo (
9030c46)
Features
- pricing: Name every price unit in one module by @dpoulopoulos (
dcfc6a3) - catalog: Note a v2 price unit the reader does not know by @dpoulopoulos (
a948107) - pricing: Accept every price unit on the pricing routes in #2812 by @dpoulopoulos (
8c2b6f9) - pricing: Give each stored search and fetch tool with no price the otari: price in force in #2808 by @aittalam (
91483b2) - any-search: Add the Serply adapter in #2341 by @googio (
39a2ae8) - BREAKING: pricing: Price each search and fetch tool by its own price alone in #2809 by @aittalam (
f9be6d4) - any-search,any-fetch: Send a User-Agent naming the library from every provider in #2825 by @aittalam (
bcc2f97) - dashboard: Show each search and fetch tool at its own price in #2810 by @aittalam (
7842259) - any-search,any-fetch: Give each library a version of its own in #2827 by @aittalam (
022679a)
Maintenance
Performance
New Contributors
Full Changelog: https://github.com/mozilla-ai/otari/compare/v0.36.0...v0.37.0
- dashboard: Stop a filter below the fold scrolling the shell away in #2817 by @peteski22 (
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
An AI gateway you own and run.
Route one endpoint to 40+ providers, issue virtual keys, enforce budgets, and track usage.
Docs · otari.ai · Launch blog · Discord
[!NOTE] Developers Wilding, our AI hackathon at MozFest, runs until November 11. Build something with Otari and open-weight models for a chance at the $1,000 prize (plus runner-up prizes) and dedicated time with our AI engineers. Details and submissions.
Otari sits between your applications and model providers. It authenticates requests, resolves provider credentials, enforces budgets before dispatch, and records usage afterwards. Provider calls go through any-llm.
Run Otari with your own database and provider keys.
Why Otari
- One OpenAI and Anthropic-compatible endpoint for many providers
- Provider credentials stay behind the gateway
- Revocable API keys with user, workspace, and model scope
- Budget checks before spend and usage records after settlement
- Local routing policies for failover, conditional selection, traffic splitting, and spill-over past a rate limit
- Optional code execution, web search, MCP, inference guardrails, and file understanding
Quickstart
Run an ephemeral gateway with Docker:
docker run --rm -p 8000:8000 \
-e OPENAI_API_KEY=YOUR_OPENAI_KEY \
-e OTARI_CONFIG_YAML='
default_pricing: true
providers:
openai:
api_key: ${OPENAI_API_KEY}
' \
mzdotai/otari:latest \
otari serve
On the first empty database, Otari creates an API key and prints it once:
No API keys found. Created bootstrap key for first run. Save this key now:
tk-...
Send a request with that key:
curl http://localhost:8000/api/v1/chat/completions \
-H "Authorization: Bearer tk-..." \
-H "Content-Type: application/json" \
-d '{
"model": "openai:gpt-4o-mini",
"messages": [{"role": "user", "content": "Say hello."}]
}'
OpenAI clients work by setting base_url to
http://localhost:8000/api/v1.
This container uses SQLite inside the container and is deleted when it stops. Use the Compose setup below for persistent data.
The command a developer runs next to a coding agent (otari hook,
otari import claude-code) installs on its own, without the server:
brew install mozilla-ai/tap/otari
See Agent Guardrails and Use with Claude Code.
Run the full stack
git clone https://github.com/mozilla-ai/otari
cd otari
cp config.example.yml config.yml
# Set a master key, provider credentials, and pricing in config.yml.
# Provider copies of attached files are off until they have a pepper of their own. Compose reads .env.
grep -qs OTARI_PROVIDER_ACCOUNT_PEPPER .env || echo "OTARI_PROVIDER_ACCOUNT_PEPPER=$(openssl rand -base64 32)" >> .env
docker compose pull
docker compose up -d
Compose runs Otari with PostgreSQL. Optional profiles add the code sandbox, web search, and guardrail services:
docker compose --profile code-exec --profile web-search --profile guardrails up -d
The dashboard is served at http://localhost:8000/. To store provider keys
through the dashboard, set OTARI_SECRET_KEY to a Fernet key generated by
otari gen-secret-key.
A one-click deployment template is available for Railway.
API and dashboard
The core completion routes are:
POST /api/v1/chat/completionsPOST /api/v1/messagesPOST /api/v1/responses
Otari also serves the broader OpenAI-compatible and management APIs. The
running server publishes Swagger UI at /api/v1/docs and OpenAPI at
/api/v1/openapi.json. See API reference.
The dashboard manages providers, models, routing, tools, keys, members, budgets, settings, activity, and usage. Its navigation adapts to the signed-in person's authority. See Admin dashboard.
Development
git clone https://github.com/mozilla-ai/otari
cd otari
uv sync --dev
cp config.example.yml config.yml
uv run otari serve --config config.yml
For local development without PostgreSQL, change database_url to
sqlite+aiosqlite:///./otari.db.
Common checks:
make test
make lint
make typecheck
See CONTRIBUTING.md before opening a pull request.
Documentation
- Quickstart
- Deployment
- Configuration
- Models
- Routing
- Access control
- Built-in tools
- Agent Guardrails
- SDK and agent integrations
- Architecture
License
Apache 2.0. See LICENSE.