OGX 是什么 · 全景图 · 阅读地图
30 秒导读: OGX(Open GenAI Stack,前身 Llama Stack)是一个你能装在自己机器上跑的 agentic API 服务器。它对外长得和 OpenAI 的 API 一模一样——你把现有 OpenAI SDK 的
base_url指到http://localhost:8321/v1就能用;对内它把「用哪个模型、走哪个后端」做成了 可插拔的 Provider,还把 agent 的「思考—调工具—再思考」循环搬到了服务端。本章不进代码, 只帮你建立心智模型、看懂全 景、并告诉你六章各讲什么、该按什么顺序读。
1. 这是什么(零基础也能懂)
一句话定义: OGX 是一个自托管、OpenAI 兼容的 AI 后端服务器——你在本地或自己的服务器上 起一个进程,它对外暴露一套「和 OpenAI 完全一样」的 HTTP 接口,而背后接的是谁(Llama、GPT、 Gemini、Mistral,跑在 Ollama、vLLM、云服务……)由你配置,应用代码一个字都不用改。
它解决谁的什么问题。 想象你已经用 OpenAI 的 Python SDK 写好了一个应用。现在你想: 换成本地跑的开源模型、或换到公司自建的推理集群、或今天用 GPT 明天用 Llama——但不想重写代码。 OGX 就是夹在中间的那一层:应用照旧对着「OpenAI 的形状」说话,OGX 负责把话翻译并转发给真正的后端。
README 把这层定位讲得很直接:它是 "a drop-in replacement for the OpenAI API that you can run anywhere"(README.md:26)——可以跑在笔记本、机房或云上。
它给谁用。 后端工程师、应用开发者、平台团队——尤其是那些「已经在用 OpenAI/Anthropic SDK, 只想把请求指向另一个服务器就跑起来」的人。
它能做什么(功能一览):
| 能力 | 对外端点(OpenAI 形状) | 说明 |
|---|---|---|
| 聊天 / 补全 / 嵌入 | /v1/chat/completions、/v1/completions、/v1/embeddings | 任意 OpenAI 客户端可直连(README.md:40) |
| Responses API | /v1/responses | 服务端 agentic 编排:工具调用 + MCP + 内建 file search,一次调用搞定(README.md:41) |
| 向量库 / 文件 | /v1/vector_stores、/v1/files | 托管式文档存储与检索(RAG 的底座) |
| 批处理 | /v1/batches | 离线批量任务 |
| Skills | /v1alpha/skills | 版本化的技能包(带 SKILL.md 的 zip),agent 可调用 |
| 多 SDK 兼容 | /v1/messages(Anthropic)、/v1alpha/interactions(Google GenAI) | 除 OpenAI 外,原生支持另外两家 SDK(README.md:46) |
用起来什么样(最小示例)。 这段就是 README 首页那段——注意它是标准 OpenAI SDK,唯一的
改动是 base_url(README.md:28-36):
from openai import OpenAI
# 只改这一行:把 OpenAI 客户端指向本地的 OGX 服务器
client = OpenAI(base_url="http://localhost:8321/v1", api_key="fake")
response = client.chat.completions.create(
model="llama-3.3-70b", # 换成任意后端支持的模型名
messages=[{"role": "user", "content": "Hello"}],
)
启动服务器同样是一行(README.md:58-66,starter 发行版自带 Ollama):
uv run ogx stack run starter
一句话直觉 / 类比。 把 OGX 想成 AI 后端的 「USB 插座 + 交换机」:
- 插座(OpenAI 兼容层)——你的插头(应用代码)是固定形状的,插进去就通电;
- 交换机(Provider + 路由)——插座背后接的是哪台发电机(哪个模型 / 后端),由机房里的配线决定, 换发电机不用换插头。
本节到此 不涉及任何底层实现;你只要记住:对外一张固定的脸(OpenAI 形状),对内一堆可换的后端。
2. 顶层全景(它大概怎么转)
2.1 怎么读这张图
从上往下就是一个请求的旅程:客户端进来 → 先过 FastAPI 服务器的中间件栈(鉴权、租户、 路由授权)→ 到达 Router(某个 API 的门面)→ Router 查 RoutingTable(这个资源归谁管)→ 落到某个 Provider(在进程内跑,或转发给外部服务)。方向单一、命中即走。
Client(OpenAI / Anthropic / Google GenAI SDK,或裸 HTTP)
│ POST /v1/chat/completions { model: "ollama/llama3.2:3b" }
▼
┌──────────────────────────────────────────────────────────┐
│ FastAPI 服务器 (core/server/server.py: StackApp) │
│ 中间件栈(后加的先跑): │
│ ① 鉴权 AuthenticationMiddleware 提取 user+tenant │
│ ② 租户 TenancyMiddleware 注入/校验 tenant 模式 │
│ ③ 路由授权 RouteAuthorizationMiddleware 路由级访问策略 │
└───────────────────────────┬──────────────────────────────┘
▼ (路由分发,路由由 impls 自动发现登记)
┌──────────────────────────────────────────────────────────┐
│ Router (core/routers/inference.py: InferenceRouter) │
│ 「这个 model 归哪个 provider?」→ 问 RoutingTable │
└───────────────────────────┬──────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────┐
│ RoutingTable (core/routing_tables/common.py: │
│ CommonRoutingTableImpl) │
│ 查 DistributionRegistry:model → provider_id │
└───────────────────────────┬──────────────────────────────┘
▼
┌────────────────────────┐ ┌────────────────────────┐
│ Inline Provider │ 或 │ Remote Provider │
│ 进程内跑 │ │ 转发 外部服务 │
│ (meta-reference, │ │ (ollama/openai/vLLM, │
│ sqlite-vec …) │ │ 经 OpenAIMixin 适配) │
└────────────────────────┘ └───────────┬────────────┘
▼
外部服务 / 本地计算
这张图对应 ARCHITECTURE.md 的 "Request Flow"(ARCHITECTURE.md:16-47);中间件的实际添加顺序与 「后加先跑」的注释见
create_app()(core/server/server.py:397-436)。
2.2 核心部件一句话职责
下面这张表是整套系统的名词表——认全它们,后面每一章都在展开其中一格。符号名与位置均来自 源码(参 ARCHITECTURE.md:250-262 的 Key Classes 表,并已核对):
| 部件(符号名) | 位置 | 一句话职责 |
|---|---|---|
OGX / Stack | core/stack.py:69 / core/stack.py:739 | OGX 是把所有 API 协议拼在一起的复合门面;Stack 管初始化、资源注册与生命周期(Stack.initialize 在 core/stack.py:749) |
StackApp | core/server/server.py:126 | FastAPI 应用的包装:构造时先把 Stack 初始化好,再据此登记路由 |
resolve_impls() | core/resolver.py:147 | 启动装配引擎:校验配置里的 provider → 按依赖排序 → 逐个实例化 → 为可路由 API 装上 Router+RoutingTable |
get_provider_registry() | core/distribution.py:101 | 加载所有可用的 provider 规格(每个 API 一份清单),供上面的解析器挑选 |
CommonRoutingTableImpl | core/routing_tables/common.py:88 | 所有自动路由 API 的路由表基类:记「哪个资源(模型/向量库/工具组)归哪个 provider」,get_provider_impl 在 :130 |
InferenceRouter | core/routers/inference.py:73 | inference API 的门面/分发器:每次请求查路由表,把调用委派给正确的 provider |
OpenAIMixin | providers/utils/inference/openai_mixin.py:51 | 远程 provider 的共享底座:内部持一个 AsyncOpenAI 客户端,把请求转发给任何「说 OpenAI 话」的后端 |
OpenAIResponsesImpl | providers/inline/responses/builtin/responses/openai_responses.py:106 | 皇冠明珠:Responses API 的实现,在服务端跑「模型↔工具」的 agentic 循环(create_openai_response 在 :619) |
DistributionRegistry | core/store/registry.py:22(盘上实现 DiskDistributionRegistry :65) | 跨 provider 记录所有已注册资源(模型、向量库、工具组、prompt…),持久化到 KVStore,重启不丢 |
2.3 主线走一遍:一条 chat completion 的一生(高层、不进代码)
用 ARCHITECTURE.md 的 "Detailed Flow Example"(ARCHITECTURE.md:49-57)为骨架,串起上面的名词:
- 进门。 客户端
POST /v1/chat/completions,带model: "ollama/llama3.2:3b-instruct-fp16"。 - 过中间件。 服务器先跑鉴权→租户→路由授权,解析出 user 和 tenant_id;通过后分发到 inference 路由。
- 问路。
InferenceRouter拿model_id去问路由表:routing_table.get_provider_impl(model_id)。 - 查表。
CommonRoutingTableImpl在DistributionRegistry里找这个模型,得知它属于 providerollama。 - 委派。 路由把调用转给
ollamaprovider 的openai_chat_completion()。 - 适配转发。
ollamaprovider 继承OpenAIMixin,内部建一个指向 Ollama 服务器的AsyncOpenAI客户端,把请求原样转发出去。 - 回流。 响应以 SSE 事件流的形式,沿原路穿过 Router 回到客户端。
一句话总 结这条主线:「同一个门面,查一次表,落到对的后端,再流回来。」 换成别的模型名, 第 4 步查表结果不同、第 5-6 步落到不同 provider,其余不变——这就是「换后端不改代码」的机制。
3. 两个包的边界:ogx_api vs ogx
在下钻各章之前,先记住一条最重要的物理边界:代码分成两个独立的 pip 包
(ARCHITECTURE.md:9-13、目录见 src/ogx_api/ 与 src/ogx/):
| 包 | 目录 | 里面是什么 | 谁依赖它 |
|---|---|---|---|
ogx-api | src/ogx_api/ | 只有契约:API 协议(Python Protocol 类)、Pydantic 数据类型、Provider 规格类型、KVStore/SqlStore 抽象接口。没有服务器代码、没有 provider 实现 | 第三方 provider 只依赖这个轻包 |
ogx | src/ogx/ | 服务器实现:provider 解析、路由、存储、CLI,以及所有内建 provider | 完整服务器 |
为什么这么切很关键:想给 OGX 写一个新后端的人,只需依赖那个轻量的契约包,不用把整个服务器 拖进依赖树。这条边界是「Provider 插件化」得以成立的物理前提——第 02 章会展开。
(还有第三个可选包 ogx-ui,src/ogx_ui/,是 Next.js 写的聊天/管理 Web UI,本系列不展开。)
4. 三大精华看点(为什么值得读下去)
OGX 有很多零件,但真正有设计含量、值得你带走的是这三处。每一处都点到即止,深挖见对应章节。
4.1 Provider 插件化 —— 同一套 API,任意后端
妙在哪: 「换模型/换后端不改应用代码」不是靠 if-else,而是靠一套注册表 + 解析器 + 自动路由
的装配机制。启动时 resolve_impls()(core/resolver.py:147)校验配置、按依赖拓扑排序、逐个实例化
provider,并为可路由的 API 自动配上一对 Router + RoutingTable(core/resolver.py:171,
specs_for_autorouted_apis)。远程 provider 大多共享 OpenAIMixin(providers/utils/inference/
openai_mixin.py:51),所以「接一个新的 OpenAI 兼容后端」往往只是填几行配置。
→ 下钻:02-providers-registry-resolver.md、 03-routing-and-openai-adapter.md
4.2 服务端 agentic 循环 —— 把 agent 的「大脑循环」搬进服务器
妙在哪: 传统上「调模型→模型要求调工具→执行工具→把结果再喂回模型」这个循环是客户端在跑。
OGX 的 Responses API 把它挪到了服务端:OpenAIResponsesImpl(providers/inline/responses/
builtin/responses/openai_responses.py:106)在一次 API 调用里完成多轮工具编排——包括内建 file
search(RAG)、MCP 服务器接入、后台响应。客户端只发一次请求,拿一次(可流式的)结果。
→ 下钻:04-responses-agentic-loop.md、 05-tools-rag-mcp-background.md
4.3 非旁路的租户隔离 —— 默认拒绝,过滤在数据层
妙在哪: 多租户隔离不是「业务代码记得加 WHERE」,而是下沉到存储层、不可绕过。
AuthorizedSqlStore(core/storage/sqlstore/authorized_sqlstore.py:128)在任何访问控制检查之前,
先套一层 WHERE tenant_id = ?;multi 模式下缺租户上下文会退化成 1=0——默认什么都看不到
(ARCHITECTURE.md:170-178)。租户模式在 Stack.initialize() 期间进程级设定
(_initialize_storage 调 set_default_tenancy_config,authorized_sqlstore.py:35),旧调用点无需改动。
→ 下钻:06-storage-registry-tenancy.md
5. 阅读地图(六章的顺序与各讲什么)
建议按编号顺序读——它就是「由浅入深、从一次请求到底层隔离」的路径。若你目标明确,也可按需跳读。
| 顺序 | 章节 | 讲什么 | 什么时候读 |
|---|---|---|---|
| 0 | 本章 index.md | OGX 是什么、全景图、两个包边界、阅读地图 | 先读,建立心智模型 |
| 1 | 01-request-lifecycle.md | 请求生命周期与服务器/进程骨架:StackApp 怎么起、中间件栈怎么排、路由怎么被自动发现登记 | 想懂「一个 HTTP 请求进来后到底发生了什么」 |
| 2 | 02-providers-registry-resolver.md | Provider 架构:注册表(get_provider_registry)、解析器(resolve_impls)、自动路由装配 | 想懂「换后端不改代码」在启动时是怎么装配出来的 |
| 3 | 03-routing-and-openai-adapter.md | 路由层(InferenceRouter + CommonRoutingTableImpl)与 OpenAI 兼容适配(OpenAIMixin):一次模型调用如何落到具体后端 | 想懂第 2 章图里「查表→委派→转发」的真实代码 |
| 4 | 04-responses-agentic-loop.md | 皇冠明珠:Responses API 的服务端 agentic 编排循环(OpenAIResponsesImpl) | 想懂 OGX 相对「纯代理」的核心增值 |
| 5 | 05-tools-rag-mcp-background.md | 工具执行、RAG / file search、MCP,以及后台响应与自动压缩 | 想懂 agentic 循环里「手脚」的实现细节 |
| 6 | 06-storage-registry-tenancy.md | 存储(KVStore / SqlStore)、分发注册表、以及非旁路的多租户 / ABAC 隔离 | 想懂持久化与「默认拒绝」的隔离底座 |
6. 边界与本章不覆盖的
- 本章只做导航与心智模型,刻意不进代码细节;每个机制的真实源码走读在对应编号章里。
- OGX 的价值前提是后端已经会说 OpenAI 那套协议(或有对应 provider 适配);它不替你训练、不替你 部署推理引擎,只做「统一 API + 路由 + 服务端编排」这一层。
- 名字变更:仓库里到处是
ogx前缀,但它就是原来的 Llama Stack(README.md:17-18);读旧资料时 把两者视为同一物。
7. 代码地 图(导航索引)
一张表让人/agent 直接跳进源码;优先用符号名 grep(比行号抗漂移)。所有条目 as-of
sourceCommit 4b88d6f。
| 主题 | 文件路径 | 符号名 |
|---|---|---|
| 复合 API 门面 | src/ogx/core/stack.py | OGX |
| 初始化 / 生命周期 | src/ogx/core/stack.py | Stack / Stack.initialize |
| FastAPI 应用包装 | src/ogx/core/server/server.py | StackApp / create_app |
| 中间件栈装配 | src/ogx/core/server/server.py | AuthenticationMiddleware / TenancyMiddleware / RouteAuthorizationMiddleware |
| 路由自动发现登记 | src/ogx/core/server/fastapi_router_registry.py | build_fastapi_router / _discover_router_factories |
| 启动装配引擎 | src/ogx/core/resolver.py | resolve_impls / sort_providers_by_deps / instantiate_provider |
| Provider 规格清单 | src/ogx/core/distribution.py | get_provider_registry |
| 自动路由 API 配对 | src/ogx/core/distribution.py | builtin_automatically_routed_apis / AutoRoutedApiInfo |
| 自动路由装配 | src/ogx/core/resolver.py | specs_for_autorouted_apis |
| 路由表基类 | src/ogx/core/routing_tables/common.py | CommonRoutingTableImpl / get_provider_impl |
| inference 分发器 | src/ogx/core/routers/inference.py | InferenceRouter / openai_chat_completion |
| OpenAI 兼容底座 | src/ogx/providers/utils/inference/openai_mixin.py | OpenAIMixin / client |
| Responses 编排循环 | src/ogx/providers/inline/responses/builtin/responses/openai_responses.py | OpenAIResponsesImpl / create_openai_response |
| 分发注册表 | src/ogx/core/store/registry.py | DistributionRegistry / DiskDistributionRegistry |
| 非旁路租户隔离 | src/ogx/core/storage/sqlstore/authorized_sqlstore.py | AuthorizedSqlStore / set_default_tenancy_config |
| API 契约包(轻) | src/ogx_api/ | 协议 / Pydantic 类型 / Provider 规格 |
| 顶层入口(README) | README.md | 最小使用示例 / ogx stack run starter |
| 架构总览 | ARCHITECTURE.md | Request Flow / Key Classes |