- 窗口声明:models.json 组级 contextWindow + env LLM_CONTEXT_WINDOW(per-group materialize 播种,0 不写盘、负数报错)。 - 预算三态:CONTEXT_MAX_TOKENS 未设置 ⇒ 按窗口推导;>0 显式覆盖;0|负 关闭压缩(不变)。推导 budget = min(窗口×比例, 窗口−输出保留),比例默认 2/3(CONTEXT_BUDGET_RATIO,1M ⇒ 699050 tokens ≈ 683Ki);输出保留 = max(32768, 该组 maxTokens) 且封顶窗口/2(防配置矛盾时退化成 1 token);窗口未声明 ⇒ 回落 131072 + 恰好一条 WARN。接线在组合根 wire_context.go(唯一决策点)。 - usage/缓存可观测(此前**完全不可观测**):Response 增 CacheHit/CacheMiss/Reasoning tokens + CacheHitRate;解析 OpenAI 兼容(prompt_cache_hit_tokens/prompt_cache_miss_tokens/cached_tokens/reasoning_tokens)与 anthropic(cache_read_input_tokens/cache_creation_input_tokens)两种形状;记录点在适配器 record(换入口不丢成本日志),日志无凭据;单次输入 ≥预算 90% 记 WARN(不阻断)。 - 根治清单「续读」假承诺:抽取期不再按注入预算截断(sidecar 存全文,只受 MaxSidecarBytes=8 MiB 安全上限,ExtractorVersion v1→v2 旧 sidecar 失效重抽);注入预算改在装配期生效 ⇒ ref.Chars/Truncated 是注入侧事实、游标真是继续读的起点;document-read 的 limit 上限改为独立具名常量。 - 顺手修越界:config.go 505 行(超 500)拆出 llm.go。 - 主会话独立验收:隔离 worktree(HEAD + 本切片 39 文件,排除在途 gateway)build/vet 绿、全树 59 包 0 FAIL、linux+darwin 交叉编译绿;变异独立复现(比例改 0.25 ⇒ 推导用例红 262144 vs 699050)。
54 lines
3.1 KiB
Go
54 lines
3.1 KiB
Go
package config
|
||
|
||
// 本文件承载「上下文预算」的配置语义(design/04 §1.3 上下文溢出压缩 +
|
||
// 附录 A.3 的主人裁决)。推导本身在 context_budget.go。
|
||
//
|
||
// CONTEXT_MAX_TOKENS 是**三态**取值:
|
||
//
|
||
// - 未设置(默认) = 按模型窗口推导(DeriveContextBudget);
|
||
// - > 0 = 显式覆盖(原样使用);
|
||
// - 0 / 负数 = 关闭压缩(行为与引入推导之前逐字节一致)。
|
||
//
|
||
// 「未设置」不能用 0 表达:0 已经被「关闭压缩」占用。因此「有没有配过这个键」
|
||
// 必须单独记录(ContextConfig.MaxTokensSet,由 Load 在解码阶段填),
|
||
// 这正是 design/04 附录 A.3 第 2 条要求的「用 os.LookupEnv 判未设置,不要靠 0」。
|
||
//
|
||
// 旧口径(「默认模型 gpt-4o 窗口 128K ÷ 4 ⇒ 32K」)随本切片作废:默认模型的
|
||
// 真实窗口已达 1M token(DevDocs/reference/deepseek/facts-for-cyrene.md),
|
||
// 固定 32K 会既丢上下文、又因反复压缩作废 KV 缓存前缀而反复烧钱(附录 A.2)。
|
||
|
||
// ContextMaxTokensEnv 是上下文预算的配置键名。它必须与 ContextConfig.MaxTokens
|
||
// 的 env 标签**逐字一致**(Load 用它判定「未设置」),一致性由
|
||
// context_budget_test.go 的 TestContextMaxTokensEnvMatchesTag 钉住。
|
||
const ContextMaxTokensEnv = "CONTEXT_MAX_TOKENS"
|
||
|
||
// ContextConfig 承载运行时循环的上下文预算(design/04 §1.3)。
|
||
// 它与 MCP / Capacity 一样是运行时调优量,由组合根消费。
|
||
type ContextConfig struct {
|
||
// MaxTokens 是触发溢出压缩的上下文预算,单位是循环离线估算的 token 数
|
||
// (CONTEXT_MAX_TOKENS)。三态语义见本文件顶部说明。
|
||
//
|
||
// **它刻意没有 default 标签**:未配置时值为 0,而「0 且未配置」与
|
||
// 「显式 0」由 MaxTokensSet 区分 —— 前者按窗口推导,后者关闭压缩。
|
||
MaxTokens int `env:"CONTEXT_MAX_TOKENS"`
|
||
|
||
// MaxTokensSet 报告 CONTEXT_MAX_TOKENS 是否由进程环境或 .env 文件给出。
|
||
// 它由 Load 填写,不参与反射解码(没有 env 标签)。
|
||
//
|
||
// 判定规则(DeriveContextBudget 是唯一判据):MaxTokens > 0 一律按显式覆盖、
|
||
// < 0 一律按关闭;只有 MaxTokens == 0 需要本标志区分「显式 0 = 关闭」与
|
||
// 「未设置 = 推导」。因此手工构造 Config 的调用方给出非零值时不必同步本标志,
|
||
// 但**要表达「显式 0 = 关闭」就必须置真**。
|
||
MaxTokensSet bool
|
||
|
||
// DocumentMaxInjectChars 是**单份附件正文注入模型可见上下文**的字符上限
|
||
// (DOCUMENT_MAX_INJECT_CHARS)。0(默认)= 按推导出的上下文预算算
|
||
// (loop.DocumentInjectCharsFor);> 0 = 显式覆盖。
|
||
//
|
||
// 它与「sidecar 存多少」是两个数(design/24 §9.6 连带项、切片 T1 §7.2):
|
||
// sidecar 存抽取得到的全文,只受安全上限 documents.MaxSidecarBytes 约束;
|
||
// 本项只决定每回合往上下文里注入多少,截断因此发生在**装配期**,
|
||
// 于是清单行的续读游标才真是「继续读的起点」。
|
||
DocumentMaxInjectChars int `env:"DOCUMENT_MAX_INJECT_CHARS"`
|
||
}
|