Documentation
¶
Overview ¶
Package config 定义 core 的配置文件模型、加载与校验。
配置只描述事实,不承载行为:它不知道渠道客户端与插件宿主的存在,装配由 server 层完成。凭据一律只写环境变量名,配置文件里不出现密钥。
Index ¶
- Constants
- func ForbiddenPassHeaders() []string
- func Match(pattern, name string) bool
- type Account
- type Affinity
- type Auth
- type Backoff
- type Behavior
- type Channel
- type Config
- func (c *Config) AffinityMinPrefixBytes() int
- func (c *Config) AffinityTTL() time.Duration
- func (c *Config) AffinityTableSize() int
- func (c *Config) ChannelByName(name string) (Channel, bool)
- func (c *Config) DefaultMaxTokens() int
- func (c *Config) Defaults()
- func (c *Config) EnabledPlugins() []Plugin
- func (c *Config) Expand() *Config
- func (c *Config) FailoverStatusesFor(channel Channel) ([]int, error)
- func (c *Config) MaxBodyBytes() int64
- func (c *Config) PluginConfig(key string) map[string]any
- func (c *Config) Resolve(model string) []Route
- func (c *Config) RetryStatuses() ([]int, error)
- func (c *Config) Validate() error
- type Duration
- type Key
- type Log
- type Matcher
- type Model
- type Plugin
- type Plugins
- type Retry
- type Route
Constants ¶
const ( DefaultListen = "127.0.0.1:8787" DefaultLogFormat = "json" DefaultLogLevel = "info" DefaultTimeout = 120 * time.Second DefaultPluginDir = "plugins" DefaultMaxBodyBytes = 32 << 20 // DefaultMaxTokens 是源请求未带 max_tokens 时给 Claude 补的值。它与 // relay.DefaultClaudeMaxTokens 是同一个数:分层红线不允许 config 导入 relay, // 只能各写一份,改一处要同时改另一处。 DefaultMaxTokens = 4096 // MaxRetries 是渠道重试次数的上限,与 channel.MaxRetries 保持一致。 MaxRetries = 10 // 渠道亲和的参数默认值。 DefaultAffinityTableSize = 8192 DefaultAffinityTTL = 10 * time.Minute // DefaultAffinityMinPrefixBytes 是前缀的字节下限。按中英文混排估算,4096 字节 // 大致是一千出头到两千 tokens,落在上游最小可缓存长度(按模型 512 到 4096 // tokens)的下半段。它是个启发式,估不准时应当按实际模型调高。 DefaultAffinityMinPrefixBytes = 4096 // DefaultInChannelStatuses 与 DefaultFailoverStatuses 是两组重试判据的默认 // 取值。它们与 channel 包里内置的集合是同一组值:分层红线不允许 config 导入 // channel,只能各写一份,改一处要同时改另一处。 DefaultInChannelStatuses = "408,429,500,502,503,504" DefaultFailoverStatuses = "408,401,403,429,500-599" )
默认值。只在这里写一次,Load 与文档都以它为准。
Variables ¶
This section is empty.
Functions ¶
func ForbiddenPassHeaders ¶ added in v0.7.1
func ForbiddenPassHeaders() []string
ForbiddenPassHeaders 返回 pass_headers 里永不放行的头名,已按 http.CanonicalHeaderKey 归一。返回值是副本,调用方改动它不影响校验。
Types ¶
type Account ¶ added in v0.7.0
type Account struct {
Name string `yaml:"name"`
KeyEnv string `yaml:"key_env"`
Headers map[string]string `yaml:"headers"`
}
Account 是一个上游账号。账号不是渠道,渠道在 auth.accounts 里按名字引用它, 加载时展开成多条渠道。单列一层是因为同一把凭据常要配给多种方言或同一上游的多个 入口,写成渠道就得把基址、路径、超时逐条抄一遍。
Headers 是账号级的附加请求头,用于上游按 workspace 或 organization 隔离的场景。
type Affinity ¶ added in v0.2.0
type Affinity struct {
// TableSize 是前缀链记忆的条数上限。不大于零时没有会话标识的客户端不参与
// 亲和。
TableSize *int `yaml:"table_size"`
// TTL 是前缀链记忆的寿命,按上游缓存的寿命设。
TTL Duration `yaml:"ttl"`
// MinPrefixBytes 是前缀的字节下限,短于它时不做亲和。
MinPrefixBytes *int `yaml:"min_prefix_bytes"`
}
Affinity 是渠道亲和的参数。哪些渠道参与亲和由 Model.Affinity 的组名决定, 这里只放参数。
三个字段都是可选的,不写就用本文件里的默认常量。用指针是为了把「没写」与 「显式写成 0」区分开:最小前缀长度写成 0 表示不做这个判断。
type Auth ¶
type Auth struct {
// Style 取 bearer、x-api-key、query、custom 或 none。
Style string `yaml:"style"`
// KeyEnv 是凭据所在的环境变量名。
KeyEnv string `yaml:"key_env"`
// Accounts 是引用的顶层账号名,与 KeyEnv 互斥。它也是加载期字段:Expand
// 把账号的 KeyEnv 填进展开出的每条渠道,这里随之清空,平铺形态因而与手写
// 的等价配置完全一致。
Accounts []string `yaml:"accounts"`
// Header 是 Style 为 custom 时的请求头名。
Header string `yaml:"header"`
// Query 是 Style 为 query 时的查询参数名。
Query string `yaml:"query"`
}
Auth 是渠道的鉴权方式。凭据值只从 KeyEnv 指定的环境变量读取,或由 Accounts 引用的顶层账号给出。
type Backoff ¶ added in v0.7.0
type Backoff struct {
// Base 是第一次重试前的等待时长,第 n 次重试等待 base × 2^(n-1)。
Base Duration `yaml:"base"`
// Max 是指数退避的上限。
Max Duration `yaml:"max"`
// MaxRetryAfter 是上游 Retry-After 的上限,超过就不再重试,直接换候选。
MaxRetryAfter Duration `yaml:"max_retry_after"`
}
Backoff 是渠道内重试的退避参数。三个字段都可以不写,不写就用内置常量。
上限与 Retry-After 都放在渠道级而不引入全局默认值来源:退避是「这条上游 多久能再收一个请求」的属性,不同上游不一样,与账号、方言无关。
type Behavior ¶ added in v0.7.0
type Behavior struct {
// MaxBodyBytes 是客户端请求体的字节上限。
MaxBodyBytes *int `yaml:"max_body_bytes"`
// DefaultMaxTokens 是源请求未带 max_tokens 时给 Claude 补的值。
DefaultMaxTokens *int `yaml:"default_max_tokens"`
}
Behavior 是进程级的行为默认值,YAML 里写成 defaults 段。
两个数都是「装配时读一次、运行期不再变」的进程级参数,因此不塞进渠道或模型 这些既有段:请求体上限属于整个进程,补 max_tokens 是内核的部署级行为。用指针 是为了把「没写」与「显式写成 0」区分开,0 不是合法值,校验会拦下。
内核还有 tool_loss_policy、model_suffix、thinking_adapter 三个行为开关, 这里没有对应的键:前两个会改变「哪个模型名参与匹配」,打开之后 models[].upstream 与 ${model} 的语义跟着变,要另写一节语义说明;tool_loss_policy 等「要不要允许 reject」的口径定了再上。在它们落地之前,宿主仍可在 Go 侧构造 relay.Options 注入内核。
type Channel ¶
type Channel struct {
Name string `yaml:"name"`
Dialect string `yaml:"dialect"`
BaseURL string `yaml:"base_url"`
Path string `yaml:"path"`
Auth Auth `yaml:"auth"`
Timeout Duration `yaml:"timeout"`
MaxRetries *int `yaml:"max_retries"`
Headers map[string]string `yaml:"headers"`
// PassHeaders 是从客户端转发的请求头白名单,只放行列在这里的名字,其余
// 一律不带去上游。放行的信任边界是「这条上游渠道可以收到哪些客户端头」,
// 因此放在渠道级而不是方言级:按方言放行会把 Claude 客户端的特性开关带给
// 一个它没打算对话的 OpenAI 上游。
//
// 名单是白名单,不能写成黑名单。禁止放行的头见 ForbiddenPassHeaders,写进
// 来会在校验期报错。留着这个口子是因为 anthropic-beta、X-Codex-* 这类头按
// 请求变化,静态的 headers 表达不了。
PassHeaders []string `yaml:"pass_headers"`
Backoff Backoff `yaml:"backoff"`
// FailoverStatuses 覆盖全局的 retry.failover,空串表示沿用全局。
FailoverStatuses string `yaml:"failover_statuses"`
}
Channel 是一个上游渠道。BaseURL 是渠道基址,Path 为空时按方言取默认路径。
type Config ¶
type Config struct {
// Path 是配置文件的绝对路径,由 Load 填入。Parse 不填。
Path string `yaml:"-"`
Listen string `yaml:"listen"`
Log Log `yaml:"log"`
// Behavior 是 defaults 段,放进程级的行为默认值。
//
// 字段名不叫 Defaults:Config.Defaults() 已经是公开方法,同名字段与它冲突。
// YAML 键固定写作 defaults,那是配置文件里的名字,不随 Go 侧命名走。
Behavior Behavior `yaml:"defaults"`
// Accounts 是加载期的顶层账号清单,Expand 之后为空。
Accounts []Account `yaml:"accounts"`
Channels []Channel `yaml:"channels"`
Models []Model `yaml:"models"`
Plugins Plugins `yaml:"plugins"`
Affinity Affinity `yaml:"affinity"`
// Retry 是重试判据的两组状态码集合。
Retry Retry `yaml:"retry"`
}
Config 是一份完整的服务配置。
func Load ¶
Load 读取并校验配置文件。
解码开启 KnownFields:拼错的字段在加载时报错,而不是被静默忽略。相对路径一律 以配置文件所在目录为基准,因此工作目录变化不会改变行为。
func Parse ¶
Parse 从阅读器解析配置并校验。相对路径保留原样,调用方需要时自行归一。
顶层账号是加载期形态,Parse 会自己调一次 Expand,因此返回值里只剩下展开后的 渠道名,没有账号引用。校验跑两次:第一次看原始写法,账号引用关系(账号是否 存在、有没有人引用)只有在展开之前才看得清;第二次看平铺形态,用来抓展开名 与手写渠道名撞车这类展开之后才出现的重名。见 Config.Expand 的注释。
func (*Config) AffinityMinPrefixBytes ¶ added in v0.2.0
AffinityMinPrefixBytes 返回前缀的字节下限。返回零表示不做这个判断。
func (*Config) AffinityTTL ¶ added in v0.2.0
AffinityTTL 返回前缀链记忆的寿命。
func (*Config) AffinityTableSize ¶ added in v0.2.0
AffinityTableSize 返回前缀链记忆的条数上限。
func (*Config) ChannelByName ¶
ChannelByName 按名字取渠道配置。
func (*Config) DefaultMaxTokens ¶ added in v0.7.0
DefaultMaxTokens 返回源请求未带 max_tokens 时给 Claude 补的值。没写 defaults.default_max_tokens 时返回 DefaultMaxTokens。
func (*Config) EnabledPlugins ¶
EnabledPlugins 返回启用中的插件,按 order 升序排列;order 相同时保持配置顺序。
func (*Config) Expand ¶ added in v0.7.0
Expand 返回展开顶层账号之后的副本,原对象不改。
顶层账号是加载期形态,因此这个方法是那条约定的唯一入口:Load 与 Parse 解析 完自己会调一次,从它们拿到的 Config 已经是平铺的。程序化构造带账号的 Config 之后要自己再调一次,否则展开出的渠道没被建出来,渠道的 Auth.KeyEnv 是空的。
展开按内容判断是否还有账号数据:顶层 accounts 为空且没有渠道写 auth.accounts 时直接返回副本。判断基于字段内容而不是调用历史,所以平铺形态再展开不会让 候选数按账号数相乘,同一个对象重复调用结果也一致。
展开会清掉账号层的痕迹:顶层 accounts 与每条渠道的 auth.accounts 都不保留, 所以返回的 Config 能直接序列化后重新加载。
func (*Config) FailoverStatusesFor ¶ added in v0.7.0
FailoverStatusesFor 返回该渠道生效的换候选状态码集合,升序。渠道写了 failover_statuses 就用它,否则用全局的 retry.failover,都没写时用内置默认集合。
func (*Config) MaxBodyBytes ¶ added in v0.7.0
MaxBodyBytes 返回请求体的字节上限。没写 defaults.max_body_bytes 时返回 DefaultMaxBodyBytes,因此不配置时的行为与逐字段写死默认值的版本一致。
func (*Config) PluginConfig ¶
PluginConfig 返回指定插件的配置对象,未配置时返回空 map。
func (*Config) RetryStatuses ¶ added in v0.7.0
RetryStatuses 返回生效的渠道内重试状态码集合,升序。没写 retry.in_channel 时返回内置默认集合。装配层把它填进每个渠道的 Spec。
type Duration ¶
Duration 是配置里可读的时长,写法与 time.ParseDuration 一致,例如 120s、1m30s。 为兼容只写数字的配置,纯数字按秒解释。
func (Duration) MarshalYAML ¶
MarshalYAML 按 time.Duration 的字符串形式写出。
func (*Duration) UnmarshalJSON ¶
UnmarshalJSON 让 Duration 在 JSON 里也能工作,便于 CLI 输出配置快照。
type Key ¶ added in v0.7.0
type Key struct {
// Path 是配置路径。
//
// 嵌套用点号连接,列表在字段名后加 [] 再写元素字段,例如 channels[].timeout。
// 不写成 channels.timeout:后者读起来像 channels 自己有个 timeout 字段,而实际
// 字段在列表元素上;[] 把这一层明写出来。元素本身是标量的列表(如
// channels[].auth.accounts)路径就到字段名为止,类型名里的 [] 已经说明了它是列表。
Path string
// Type 是类型名,如 string、int、duration、map[string]string。
Type string
// Default 是默认值的可读形式。没有默认值的字段写「必填」或「空」。
Default string
}
Key 是配置键表里的一条。CLI 的帮助、新配置模板与 `config path` 输出都从这份 表生成,同一份字段信息不再抄三份。
type Matcher ¶
type Matcher struct {
// contains filtered or unexported fields
}
Matcher 是一个已校验的模型名匹配器。
func CompileMatch ¶
CompileMatch 校验匹配式并返回匹配器。
支持两个通配符:* 匹配任意长度的一段(含 / 与 :),? 匹配一个字符。 其余字符按字面比较。模型名按 UTF-8 字符逐个比较。
type Model ¶
type Model struct {
Match string `yaml:"match"`
Channel string `yaml:"channel"`
Upstream string `yaml:"upstream"`
Dialect string `yaml:"dialect"`
Affinity string `yaml:"affinity"`
}
Model 是一条模型路由规则。Match 支持 * 通配,同一个模型可以有多条规则, 按配置顺序依次尝试。
Upstream 是发往上游的模型名,可以写 ${model} 占位符,替换成客户端请求里 经插件改写后真正参与匹配的那个模型名。写法与校验规则见 Validate 与 docs/config.md。
Affinity 是渠道亲和的组名。命中该模型的规则里,组名相同的候选组成一个池, 池里的渠道被当作可互换的;同一段会话的连续请求会在池内粘住一条,池外的候选 按配置顺序排在池后面兜底。留空表示不参与。
type Plugin ¶
type Plugin struct {
Key string `yaml:"key"`
Enabled bool `yaml:"enabled"`
Order int `yaml:"order"`
Config map[string]any `yaml:"config"`
}
Plugin 是一个插件的启用状态与顺序。
type Plugins ¶
type Plugins struct {
// Dir 是插件目录,相对路径以配置文件所在目录为基准。
Dir string `yaml:"dir"`
List []Plugin `yaml:"list"`
}
Plugins 是插件目录与插件清单。
type Retry ¶ added in v0.7.0
type Retry struct {
// InChannel 是渠道内原地重试的状态码集合。
InChannel string `yaml:"in_channel"`
// Failover 是换下一条候选的状态码集合,渠道级 failover_statuses 可以覆盖它。
Failover string `yaml:"failover"`
}
Retry 是重试判据的两组状态码集合,都写成逗号分隔的字符串。
in_channel 是渠道内原地重试的集合,failover 是换下一条候选的集合。 failover 必须包含 in_channel:凡是在渠道内重试过的失败,重试耗尽后还要能降级, 否则会出现「重试了却不换候选」的死角。401 与 403 只在 failover 一侧:它们说明 凭据或权限有问题,同一条渠道原地重试不会变好。
写成字符串而不是 YAML 数组:区间写法(500-599)与混类型数组难写也难校验。 范围是 100 到 599,每项要么是整数,要么是 a-b 且 a <= b。