跳到主要内容

PG 运行时与 Seed

当前 Aidy 运行时统一来自 PostgreSQL。

PG runtime 资源

seed 主要覆盖这些资源:

  • providers
  • provider_pricings
  • tenants
  • routes
  • upstreams
  • consumers
  • consumer_api_keys

注意:

  • 上游 API key 直接写在 upstreams[].api_keys[]
  • Consumer API key 直接写在 consumers[].api_keys[] 里,tenant_id / consumer_id 会从所属 consumer 自动派生
  • upstream model 也直接写在 upstreams[] 里,不再单独定义顶层 upstream_models
  • providers[].headersupstreams[].headers 只接受扁平 string -> string 映射
  • providers[].proxy_url 可配置默认出站代理;upstreams[].proxy_url 可覆盖,值为 - 时表示显式直连

Seed 命令

go run ./cmd/aidy-gateway seed --profile dev
go run ./cmd/aidy-gateway -c ./examples/config/dev.static.toml seed --profile dev

常用封装:

just db-seed
just db-seed profile=demo
just db-seed demo
just db-seed -c ./examples/config/dev.static.toml
just db-seed --seed-file ./examples/config/custom.seed.yaml

seedmigrate 默认读取 --db-urlDATABASE_URL。传入 -c/--config 时,会从静态配置文件的 [dynamic-config].pg_rw 读取写库连接串:

go run ./cmd/aidy-gateway -c ./examples/config/dev.static.toml migrate
just db-migrate -c ./examples/config/dev.static.toml

执行顺序固定为:

  1. 删除当前 schema 中的所有表(包含 schema_migrations
  2. 重新执行内置 migration
  3. 再写入 seed profile

所以 seed 命令现在是“重建式初始化”,不是在现有数据上做增量 upsert。

示例

providers:
- id: gp_dev_openai
source_scope: global
source_ref_id: ""
name: openai-dev
protocol: chat-completions
base_url: http://127.0.0.1:18000/v1
proxy_url: socks5://127.0.0.1:1080

provider_pricings:
- id: ppr_dev_mock
provider_id: gp_dev_openai
model: mock
pricing:
basePricing:
textInput: 500
textOutput: 1500

tenants:
- id: tn_dev
name: Dev Tenant

routes:
- id: rt_dev
tenant_id: tn_dev
name: dev
path_prefix: /mock
upstreams:
- upstream_id: ups_dev_primary
priority: 0
lb_weight: 100

upstreams:
- id: ups_dev_primary
tenant_id: tn_dev
provider_id: gp_dev_openai
name: primary
proxy_url: "-"
labels:
tier: default
models:
- model: mock
labels:
family: chat
- model: mock-latest
alias_to: mock
labels:
family: chat
api_keys:
- id: uak_dev_primary
key: sk-upstream-dev

consumers:
- id: cs_dev_default
tenant_id: tn_dev
name: dev-default
disabled_at: null
unlimited_credit: true
remaining_credit: 0
used_credit: 0
api_keys:
- id: cak_dev_default
name: dev-default
key: sk-mock
disabled_at: null
expires_at: null
revoked_at: null
unlimited_credit: true
remaining_credit: 0
used_credit: 0

语义

Consumer API keys

在 seed 中,consumer key 直接写在 consumers[].api_keys[] 下。

consumers:
- id: cs_dev_default
tenant_id: tn_dev
name: dev-default
api_keys:
- id: cak_dev_default
name: dev-default
key: sk-mock

api_keys[] 内不需要写 tenant_idconsumer_id;运行时写表时会从所属 consumer 自动补齐。

consumers[] 支持这些状态与额度字段:

  • disabled_at:可选时间;非空时该 consumer 禁用
  • unlimited_credit:是否跳过额度限制
  • remaining_credit:当前剩余 Credit
  • used_credit:历史累计已用 Credit
  • route_selector:进一步收紧该 consumer 可访问的 route
  • upstream_selector / model_selector:进一步收紧上游与模型候选

consumers[].api_keys[] 支持这些状态与额度字段:

  • disabled_at:可选时间;非空时该 key 禁用
  • expires_at:可选时间;非空且早于当前时间时该 key 过期
  • revoked_at:可选时间;非空时该 key 吊销
  • unlimited_credit:是否跳过 key 级额度限制
  • remaining_credit:当前剩余 Credit
  • used_credit:历史累计已用 Credit
  • route_selector:进一步收紧该 key 可访问的 route
  • upstream_selector / model_selector:进一步收紧上游与模型候选

时间字段使用 YAML 可解析的 RFC3339 字符串,例如:

consumers:
- id: cs_disabled
tenant_id: tn_dev
name: disabled-consumer
disabled_at: 2026-04-27T00:00:00Z
api_keys:
- id: cak_disabled
name: disabled-key
key: sk-disabled
disabled_at: 2026-04-27T00:00:00Z
expires_at: 2026-05-01T00:00:00Z

Upstream API keys

在 seed 中,upstream key 直接写在 upstreams[].api_keys[] 下。

api_keys:
- id: uak_dev_primary
key: sk-upstream-dev

虽然这里的 id 并没有严格唯一的要求,但是建议尽量保持全局唯一,以便日志中可用精准追踪所使用的 key

Provider pricings

provider_pricings[].pricing 使用固定的 JSON 结构:

pricing:
basePricing:
textInput: 500
textOutput: 1500
adjustments:
- mode: ADJUSTMENT_MODE_MULTIPLIER
when:
serviceTier: priority
values:
textInput: 2
textOutput: 2

规则:

  • 不再写 unitunit_sizecurrencyinputoutput
  • 所有数字都表示“每 1,000,000 tokens 的 credit”
  • basePricing 只支持 textInputtextOutputtextInputCacheReadtextInputCacheWrite
  • adjustments 为可选数组,支持 modewhenunlessvalues

Upstream models

seed 中不再单独定义顶层 upstream_models

  • upstreams[].models[] 中的每个对象都会展开成一条模型映射
  • models[].alias_to 为空时是普通模型定义,非空时是 alias 映射
  • models[].labels 会写入对应 upstream_models.labels

示例:

upstreams:
- id: ups_dev_primary
tenant_id: tn_dev
provider_id: gp_dev_openai
name: primary
models:
- model: gpt-4o-mini
labels:
family: chat
- model: gpt-4o-mini-latest
alias_to: gpt-4o-mini
labels:
family: chat

Route upstreams 与 selectors

  • routes.labels 用于被 consumers.route_selector / consumer_api_keys.route_selector 匹配
  • routes.upstreams[] 决定该 route 允许使用的 upstream 集合
  • routes.upstream_selector / routes.model_selector 用于在绑定集合上继续收紧
  • consumers.*_selectorconsumer_api_keys.*_selector 会继续叠加;空 selector 表示不额外限制
  • 具体语义、保留前缀与内置系统 label,见 Label & Selector

示例:

routes:
- id: rt_dev
tenant_id: tn_dev
name: dev
path_prefix: /mock
upstreams:
- upstream_id: ups_dev_primary
priority: 0
lb_weight: 100
upstream_selector:
match_labels:
tier: default