VisibleBase
Understand VisibleBase

架构总览

一次请求如何从产品 client 进入 Base,再被路由到真实 provider。

理解架构时,最重要的不是记住模块名,而是先确认这个系统服务的是多个 client,而不是单个项目里的单次调用。

在这个前提下,再记住下面这条调用链:

  1. 产品侧拿到 product_id + user_token
  2. UserClient 调某个 service
  3. Base 校验 token、读取模型目录、合并 query fallback
  4. Base 通过 match() 决定真实 handler
  5. handler 再调用真实 provider 或内部 AI Gateway

整体结构

产品 client浏览器、插件、App、桌面端或产品后端代用户发起调用。UserClient
VisibleBase Runtime校验 user_token,读取 products/models,执行 service、hooks 和 HTTP 路由。
业务系统登录、订阅、余额、订单和业务数据继续放在你自己的后端,不被 Base 接管。
上游调用层OpenAI、Claude、Gemini、私有模型,或你自己的 AI Gateway / 中转服务。

一次请求在 Base 里会发生什么

1. 先确认产品上下文

HTTP 请求进入 Base 后,Runtime 会先读取:

  • Authorization: Bearer <user_token>
  • 请求体里的 product_id
  • 当前调用的 service

如果 token 无效、过期或 product_id 不匹配,Base 会直接返回 401 或 403,而不是把这类问题伪装成普通 500。

2. 再拼出最终 query

service 的 handler 不直接吃“原始 client 输入”,而是吃最终的 ctx.query

这个 ctx.query 来自两部分:

  • client 显式传入的 query
  • service.default() 返回的 fallback query

default() 不定义模型注册逻辑,它只是补齐默认 query。典型写法是:

base.text().default({
  model: "gpt-5.4",
  temperature: 0.2,
});

3. 根据 ctx.query.model 解析模型

当 fallback 合并完成后,Runtime 才会从 ctx.query.model 解析真实模型。

模型来自数据库里的全局目录,而不是运行时代码注册:

  • client 传什么 model
  • default() 是否补了 model
  • 数据库里是否存在这个 active model

这三件事共同决定本次调用最终用哪个模型。

4. 通过 match() 选择 handler

service 里的不同 provider 或不同调用风格,交给 match() 分流:

base.text()
  .default({ model: "gpt-5.4" })
  .match((ctx) => ctx.model.provider === "openai", openaiHandler)
  .match((ctx) => ctx.model.provider === "anthropic", anthropicHandler);

也就是说,产品侧只需要知道自己在调用 text() 和哪个 model;真正怎么接 OpenAI、Claude 或内部网关,是 Base 内部决定的。

5. hooks 收口业务扩展

当 handler 命中后,Base 会按顺序执行:

  • before hooks
  • service handler
  • after hooks
  • onError hooks(失败时)

这让 usage、限额、扣费、日志和风控逻辑可以统一挂在 Base 上,而不是散在每个产品 repo 里。

Base 和 AI Gateway 的区别

AI Gateway 面向的是“上游调用统一入口”。
VisibleBase 面向的是“产品如何稳定使用 AI”。

所以它更关心这些东西:

  • product_id
  • user_token
  • service 边界
  • hooks 和 usage
  • 多产品复用

如果你已经有 AI Gateway,VisibleBase 也可以把它当成自己的上游调用层来用。

On this page