跳到主要内容

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 / Stackcore/stack.py:69 / core/stack.py:739OGX 是把所有 API 协议拼在一起的复合门面;Stack初始化、资源注册与生命周期(Stack.initializecore/stack.py:749)
StackAppcore/server/server.py:126FastAPI 应用的包装:构造时先把 Stack 初始化好,再据此登记路由
resolve_impls()core/resolver.py:147启动装配引擎:校验配置里的 provider → 按依赖排序 → 逐个实例化 → 为可路由 API 装上 Router+RoutingTable
get_provider_registry()core/distribution.py:101加载所有可用的 provider 规格(每个 API 一份清单),供上面的解析器挑选
CommonRoutingTableImplcore/routing_tables/common.py:88所有自动路由 API 的路由表基类:记「哪个资源(模型/向量库/工具组)归哪个 provider」,get_provider_impl 在 :130
InferenceRoutercore/routers/inference.py:73inference API 的门面/分发器:每次请求查路由表,把调用委派给正确的 provider
OpenAIMixinproviders/utils/inference/openai_mixin.py:51远程 provider 的共享底座:内部持一个 AsyncOpenAI 客户端,把请求转发给任何「说 OpenAI 话」的后端
OpenAIResponsesImplproviders/inline/responses/builtin/responses/openai_responses.py:106皇冠明珠:Responses API 的实现,在服务端跑「模型↔工具」的 agentic 循环(create_openai_response 在 :619)
DistributionRegistrycore/store/registry.py:22(盘上实现 DiskDistributionRegistry :65)跨 provider 记录所有已注册资源(模型、向量库、工具组、prompt…),持久化到 KVStore,重启不丢

2.3 主线走一遍:一条 chat completion 的一生(高层、不进代码)

用 ARCHITECTURE.md 的 "Detailed Flow Example"(ARCHITECTURE.md:49-57)为骨架,串起上面的名词:

  1. 进门。 客户端 POST /v1/chat/completions,带 model: "ollama/llama3.2:3b-instruct-fp16"
  2. 过中间件。 服务器先跑鉴权→租户→路由授权,解析出 user 和 tenant_id;通过后分发到 inference 路由。
  3. 问路。 InferenceRoutermodel_id 去问路由表:routing_table.get_provider_impl(model_id)
  4. 查表。 CommonRoutingTableImplDistributionRegistry 里找这个模型,得知它属于 provider ollama
  5. 委派。 路由把调用转给 ollama provider 的 openai_chat_completion()
  6. 适配转发。 ollama provider 继承 OpenAIMixin,内部建一个指向 Ollama 服务器的 AsyncOpenAI 客户端,把请求原样转发出去。
  7. 回流。 响应以 SSE 事件流的形式,沿原路穿过 Router 回到客户端。

一句话总结这条主线:「同一个门面,查一次表,落到对的后端,再流回来。」 换成别的模型名, 第 4 步查表结果不同、第 5-6 步落到不同 provider,其余不变——这就是「换后端不改代码」的机制。


3. 两个包的边界:ogx_api vs ogx

在下钻各章之前,先记住一条最重要的物理边界:代码分成两个独立的 pip 包 (ARCHITECTURE.md:9-13、目录见 src/ogx_api/src/ogx/):

目录里面是什么谁依赖它
ogx-apisrc/ogx_api/只有契约:API 协议(Python Protocol 类)、Pydantic 数据类型、Provider 规格类型、KVStore/SqlStore 抽象接口。没有服务器代码、没有 provider 实现第三方 provider 依赖这个轻包
ogxsrc/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.md03-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.md05-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_storageset_default_tenancy_config,authorized_sqlstore.py:35),旧调用点无需改动。

→ 下钻:06-storage-registry-tenancy.md


5. 阅读地图(六章的顺序与各讲什么)

建议按编号顺序读——它就是「由浅入深、从一次请求到底层隔离」的路径。若你目标明确,也可按需跳读。

顺序章节讲什么什么时候读
0本章 index.mdOGX 是什么、全景图、两个包边界、阅读地图先读,建立心智模型
101-request-lifecycle.md请求生命周期与服务器/进程骨架:StackApp 怎么起、中间件栈怎么排、路由怎么被自动发现登记想懂「一个 HTTP 请求进来后到底发生了什么」
202-providers-registry-resolver.mdProvider 架构:注册表(get_provider_registry)、解析器(resolve_impls)、自动路由装配想懂「换后端不改代码」在启动时是怎么装配出来的
303-routing-and-openai-adapter.md路由层(InferenceRouter + CommonRoutingTableImpl)与 OpenAI 兼容适配(OpenAIMixin):一次模型调用如何落到具体后端想懂第 2 章图里「查表→委派→转发」的真实代码
404-responses-agentic-loop.md皇冠明珠:Responses API 的服务端 agentic 编排循环(OpenAIResponsesImpl)想懂 OGX 相对「纯代理」的核心增值
505-tools-rag-mcp-background.md工具执行、RAG / file search、MCP,以及后台响应与自动压缩想懂 agentic 循环里「手脚」的实现细节
606-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.pyOGX
初始化 / 生命周期src/ogx/core/stack.pyStack / Stack.initialize
FastAPI 应用包装src/ogx/core/server/server.pyStackApp / create_app
中间件栈装配src/ogx/core/server/server.pyAuthenticationMiddleware / TenancyMiddleware / RouteAuthorizationMiddleware
路由自动发现登记src/ogx/core/server/fastapi_router_registry.pybuild_fastapi_router / _discover_router_factories
启动装配引擎src/ogx/core/resolver.pyresolve_impls / sort_providers_by_deps / instantiate_provider
Provider 规格清单src/ogx/core/distribution.pyget_provider_registry
自动路由 API 配对src/ogx/core/distribution.pybuiltin_automatically_routed_apis / AutoRoutedApiInfo
自动路由装配src/ogx/core/resolver.pyspecs_for_autorouted_apis
路由表基类src/ogx/core/routing_tables/common.pyCommonRoutingTableImpl / get_provider_impl
inference 分发器src/ogx/core/routers/inference.pyInferenceRouter / openai_chat_completion
OpenAI 兼容底座src/ogx/providers/utils/inference/openai_mixin.pyOpenAIMixin / client
Responses 编排循环src/ogx/providers/inline/responses/builtin/responses/openai_responses.pyOpenAIResponsesImpl / create_openai_response
分发注册表src/ogx/core/store/registry.pyDistributionRegistry / DiskDistributionRegistry
非旁路租户隔离src/ogx/core/storage/sqlstore/authorized_sqlstore.pyAuthorizedSqlStore / set_default_tenancy_config
API 契约包(轻)src/ogx_api/协议 / Pydantic 类型 / Provider 规格
顶层入口(README)README.md最小使用示例 / ogx stack run starter
架构总览ARCHITECTURE.mdRequest Flow / Key Classes