Documentation
¶
Overview ¶
Package compact 会话压缩策略面:auto-compact 判定(阈值/熔断/token 双轨)+ microcompact(旧工具结果占位清除)。对标 ZCode compact/policy.ts + microcompact.ts。
两层分工:
- ShouldCompact 回答「该压缩了吗」——阈值 = (contextWindow − output 预留) − buffer(provider 的 context window 是输入输出共享窗口,阈值分母必须先扣 output 侧);token 口径双轨:优先 provider 真实用量(含 cache 读写,本地 估算漏计缓存),无则本地估算;连续失败 3 次熔断(压缩本身失败反复重试 只会原地打转)。
- MaybeMicrocompact 回答「不动模型就能省一点吗」——轻量先手:把旧工具结果 替换为占位符(保留最近 N 组与出错结果),无需摘要请求。阈值 = auto 阈值 的 min(90%, 阈值−2000)(先于 auto 触发才有意义);idle 超时也触发 (长会话挂起后旧结果大概率已无引用价值)。
本包只做确定性判定与转写变换;摘要生成(真压缩)归调用方——模型请求、 prompt 组装与 provider 交互不在工具箱原语层。
用法:
d := compact.ShouldCompact(msgs, compact.Config{ContextWindow: 128_000}, failures, usage)
if d.ShouldCompact { …调用方做摘要压缩… }
mr := compact.MaybeMicrocompact(msgs, compact.MicroConfig{
ThresholdTokens: compact.BuildDefaultThreshold(d.Threshold),
}, lastDone, time.Now())
msgs = mr.Messages
溢出自适应与熔断(compact 二期,对标 ZCode compact-selection.ts + turn-loop-state.ts):压缩请求本身 prompt-too-long 时按 provider 报的 token gap 逐次上移保留组数;压缩后 <N 个工具轮次又满连续 M 次判 rapid-refill 熔断 (某个文件/工具输出过大,继续压缩只是原地打转)。
会话恢复的中断补洞(对标 ZCode session-history-hydrator 的关键修复): 持久化转写里 assistant 带 toolCalls 但缺对应 tool 结果(进程中断/崩溃时 结果未落盘)时,直接回放会被 provider 4xx 拒绝——必须在恢复期插入占位 结果补齐调用-结果配对。
摘要 prompt 模板与产物格式化(compact 二期,对标 ZCode compact/prompt.ts)。 模板是生产验证过的形态:9 段结构 + 安全约束逐字保留 + 前后 no-tools 围栏 (摘要请求带工具表时模型可能发起工具调用——那是摘要请求的失败形态)。
Index ¶
- Constants
- func BuildDefaultThreshold(autoCompactThreshold int) int
- func EstimateTokens(msgs []Message) int
- func FormatSummary(modelOutput string) string
- func GroupRounds(msgs []Message) [][]Message
- func HasEnoughToCompact(msgs []Message) bool
- func SummaryMessage(summary string, opts SummaryOptions) string
- func SummaryPrompt(customInstructions string) string
- func TokenGap(cause error) (int, bool)
- type Config
- type Decision
- type ErrRapidRefill
- type Message
- type MicroConfig
- type MicroReason
- type MicroResult
- type MicroTrigger
- type RapidRefillDecision
- type Reason
- type Selection
- type SummaryOptions
- type TokenOverride
- type TokenSource
- type ToolCall
Constants ¶
const ( // DefaultContextWindow 缺省上下文窗口。 DefaultContextWindow = 200_000 // DefaultOutputReserve 缺省 output 预留(正常请求输出已收敛 32K 目标)。 DefaultOutputReserve = 32_000 // ReserveCap output 预留上限(preflight 口径:完整预留既过早压缩又浪费窗口)。 ReserveCap = 21_000 // DefaultBuffer 阈值下方缓冲(压缩动作本身要花 token,贴线触发会反复穿越)。 DefaultBuffer = 13_000 // MaxConsecutiveFailures 连续压缩失败熔断阈值。 MaxConsecutiveFailures = 3 )
策略常量(对标 ZCode policy.ts;每个值都是生产调过的,别拍脑袋改)。
const ( RoleUser = "user" RoleAssistant = "assistant" RoleTool = "tool" )
Role 消息角色词表(Message.Role 的合法值——此前魔法字符串散落两文件, 拼错即静默改变分组行为;收口轮常量化,值不变零迁移)。
const ( // ClearedPlaceholder 被清除工具结果的占位文本(LLM 可感知的诚实形态: // 明示内容已清除而非静默吞)。 ClearedPlaceholder = "[Old tool result content cleared]" // DefaultKeepRecent 保留最近 N 组工具结果。 DefaultKeepRecent = 5 // DefaultIdle 空闲触发阈值(长会话挂起后旧结果大概率已无引用价值)。 DefaultIdle = 60 * time.Minute // DefaultMinTokenSavings 最小节省门槛(省不了几个 token 就不动转写—— // 避免为微小收益让会话形态抖动)。 DefaultMinTokenSavings = 256 )
microcompact 常量(对标 ZCode microcompact.ts)。
const InterruptedToolResult = "[Tool execution was interrupted before resume]"
InterruptedToolResult 中断占位结果(LLM 可感知的诚实形态:明示被中断, 模型可自行决定是否重发调用)。
const MaxConsecutiveRapidRefills = 3
MaxConsecutiveRapidRefills 连续 rapid-refill 熔断阈值。
const MaxOverflowRetries = 3
MaxOverflowRetries 压缩请求本身溢出的自适应重试上限(对标 MAX_COMPACT_PROMPT_TOO_LONG_RETRIES)。
const RapidRefillToolTurnThreshold = 3
RapidRefillToolTurnThreshold 判 rapid-refill 的工具轮次阈值:压缩后少于 该轮次又满,计入连续 rapid-refill。
Variables ¶
This section is empty.
Functions ¶
func BuildDefaultThreshold ¶
BuildDefaultThreshold 由 auto-compact 阈值推导 microcompact 阈值: min(阈值×0.9, 阈值−2000),下限 0(先于 auto 触发才有意义)。
func EstimateTokens ¶
EstimateTokens 本地 token 估算:Σ ceil(字符数/3),字符数含正文与工具调用 入参(name + args JSON)。
func FormatSummary ¶
FormatSummary 摘要模型输出 → 可注入的正文:剥 <analysis> 思考段、 <summary> 展开为标题 + 正文、压连续空行。空输出返回空串(调用方按失败处理)。
func GroupRounds ¶
GroupRounds 按 assistant 轮次分组:每个 assistant 消息开启新组,组前消息 (用户输入/上一轮工具结果)归入本组;首组之前的头部消息自成一组的开头。 分组是压缩/保留的最小单位——半组保留会让工具调用与结果断链。
func HasEnoughToCompact ¶
HasEnoughToCompact 消息量是否值得压缩(<2 个 assistant 轮次压缩无意义—— 摘要请求的开销可能超过省下的窗口)。
func SummaryMessage ¶
func SummaryMessage(summary string, opts SummaryOptions) string
SummaryMessage 压缩后的续接引导消息(置于保留消息之前)。
func SummaryPrompt ¶
SummaryPrompt 组装摘要请求 prompt(customInstructions 为领域附加指令, 如「重点保留测试输出」;空 = 无附加段)。
Types ¶
type Config ¶
type Config struct {
// ContextWindow ≤0 → DefaultContextWindow。
ContextWindow int
// MaxOutputTokens ≤0 → DefaultOutputReserve;实际预留 = min(值, ReserveCap)。
MaxOutputTokens int
// BufferTokens ≤0 → DefaultBuffer。
BufferTokens int
// MaxConsecutiveFailures ≤0 → MaxConsecutiveFailures。
MaxConsecutiveFailures int
// Enabled nil = 启用;false = 整体关闭(决策面仍返回计量供观测)。
Enabled *bool
}
Config auto-compact 策略配置。零值可用(全部落缺省)。
func (Config) EffectiveWindow ¶
EffectiveWindow 输入侧可用窗口 = window − min(预留, window),下限 0。
type Decision ¶
type Decision struct {
ShouldCompact bool
Reason Reason
TokenCount int
TokenSource TokenSource
EstimatedTokens int
Threshold int
ContextWindow int
EffectiveWindow int
OutputReserve int
}
Decision 压缩判定(含全量计量供观测与审计)。
func ShouldCompact ¶
func ShouldCompact(msgs []Message, cfg Config, consecutiveFailures int, ov *TokenOverride) Decision
ShouldCompact auto-compact 判定。consecutiveFailures 为此前连续压缩失败次数 (成功后调用方清零);ov 非 nil 时 token 口径取 provider 真实用量。
type ErrRapidRefill ¶
ErrRapidRefill rapid-refill 熔断错误(不可继续压缩——指引排查大输出源)。
func (*ErrRapidRefill) Error ¶
func (e *ErrRapidRefill) Error() string
type Message ¶
type Message struct {
Role string // RoleUser | RoleAssistant | RoleTool(词表常量见下)
Text string
// ToolCalls assistant 发起的工具调用(token 估算必须计入——大型入参若只计
// 正文,auto-compact 与预算口径都会低估,ZCode 踩过的漏计面)。
ToolCalls []ToolCall
// ToolCallID / ToolName role=tool 时标识对应调用与工具名。
ToolCallID string
ToolName string
// IsError 工具结果失败(microcompact 默认保留——出错结果是排障证据)。
IsError bool
}
Message 转写消息(对话 + 工具调用形态的最小通用模型)。
func RepairInterrupted ¶
RepairInterrupted 扫描转写,为每个「有调用、无结果」的 ToolCall 插入占位 tool 结果(按调用原序补在下一个非 tool 消息之前)。返回修复后的新切片, 原切片不变;无洞时返回原切片。
type MicroConfig ¶
type MicroConfig struct {
// ThresholdTokens ≤0 = 不按 token 触发(仍可 idle 触发)。
ThresholdTokens int
// Idle 空闲触发阈值:0 → DefaultIdle;负值禁用 idle 触发。
Idle time.Duration
// KeepRecent 保留最近 N 组工具结果(≤0 → DefaultKeepRecent,下限 1)。
KeepRecent int
// CompactableTools 可清除的工具名集合:nil = 不限(全部工具结果可清除)。
// agentkit 无 ZCode 的内置工具名缺省表,生产装配应传实际名单收紧面。
CompactableTools []string
// ClearErrorResults 是否清除出错结果(缺省 false——出错结果是排障证据)。
ClearErrorResults bool
// MinTokenSavings ≤0 → DefaultMinTokenSavings。
MinTokenSavings int
// Enabled nil = 启用。
Enabled *bool
}
MicroConfig microcompact 配置。零值字段落缺省。
type MicroReason ¶
type MicroReason string
MicroReason microcompact 决策原因。
const ( MicroDisabled MicroReason = "disabled" // 关闭 MicroNotTriggered MicroReason = "not_triggered" // 无触发(未到阈值且不空闲) MicroNoCandidates MicroReason = "no_candidates" // 无可清除工具结果 MicroNothingToClear MicroReason = "nothing_to_clear" // 组数 ≤ 保留数 MicroBelowSavings MicroReason = "below_min_savings" // 节省不足门槛 MicroApplied MicroReason = "applied" // 已清除 )
type MicroResult ¶
type MicroResult struct {
Reason MicroReason
Trigger MicroTrigger
Messages []Message
TokensBefore int
TokensAfter int
TokensSaved int
ClearedIDs []string
ThresholdTokens int
}
MicroResult microcompact 结果:Messages 恒为完整转写(未触发时原样返回), 计量与清除明细供观测。
func MaybeMicrocompact ¶
func MaybeMicrocompact(msgs []Message, cfg MicroConfig, lastAssistantDone, now time.Time) MicroResult
MaybeMicrocompact 轻量压缩:把旧工具结果替换为占位符。lastAssistantDone 为最近一次 assistant 完成时刻(零值 = 不评估 idle 触发)。
func MaybeMicrocompactWithUsage ¶
func MaybeMicrocompactWithUsage(msgs []Message, cfg MicroConfig, lastAssistantDone, now time.Time, usageTokens int) MicroResult
MaybeMicrocompactWithUsage TokenOverride 形态:provider 真实用量(>0)优先 于本地估算——此前触发只认本地估算,中文场景估算低估约半,micro 到点时 真实 token 已近两倍超窗,轻量先手永远晚于 auto-compact(马后炮)。
type MicroTrigger ¶
type MicroTrigger string
MicroTrigger 触发来源。
const ( TriggerIdle MicroTrigger = "idle" // 空闲超时 TriggerTokens MicroTrigger = "token_threshold" // token 压力 )
type RapidRefillDecision ¶
type RapidRefillDecision struct {
ConsecutiveRapidRefills int
ShouldBlock bool
ToolTurnsSinceCompact int
}
RapidRefillDecision rapid-refill 评估结果。
func EvaluateRapidRefill ¶
func EvaluateRapidRefill(toolTurnsSinceCompact, consecutiveRapidRefills int) RapidRefillDecision
EvaluateRapidRefill 在每次「又触发压缩」时评估:距上次压缩不足 RapidRefillToolTurnThreshold 个工具轮次 → 连续计数 +1;否则清零。 tracking 传上次记录(nil = 无历史)。
type Selection ¶
type Selection struct {
ForSummary []Message
Preserved []Message
// GroupsPreserved 保留的组数(0 = 全量摘要)。
GroupsPreserved int
TotalGroups int
}
Selection 压缩切分产物:ForSummary 交摘要(更早),Preserved 原样保留(最近)。
func Select ¶
Select 切分:保留最近 preserveGroups 组原文(下限 0、上限 len(groups)−1—— 至少一组进摘要,否则无物可压)。preserveGroups≤0 = 全量摘要。
func SelectAfterOverflow ¶
SelectAfterOverflow 压缩请求本身 prompt-too-long 后的自适应重选:按 token gap 估算还要多保留几组(保留得越多、进摘要的越少、摘要请求越小),逐次上移。 currentPreserved 为本次失败选择已保留的组数。无法再收紧(已到上限/组数不足/ 摘要侧不足 2 组)返回 nil——调用方走 TruncateForRetry 或放弃。
type SummaryOptions ¶
type SummaryOptions struct {
// RecentPreserved 保留近期消息时声明(模型不必向用户复述摘要)。
RecentPreserved bool
// SuppressFollowup 直接续跑(不确认摘要、不复述、不打招呼)。
SuppressFollowup bool
// TranscriptPath 全量转写落盘路径(需要精确原文时按需读)。
TranscriptPath string
}
SummaryOptions 续接消息的可选声明段。
type TokenOverride ¶
type TokenOverride struct {
TokenCount int // 必填:provider 报告的输入侧总量
CacheRead int // 可观测用
CacheWrite int
Output int
}
TokenOverride provider 真实用量(ShouldCompact 优先于本地估算——provider 口径 覆盖 cache 读写与嵌入内容,本地估算必然低估)。
type TokenSource ¶
type TokenSource string
TokenSource token 口径来源。
const ( SourceEstimate TokenSource = "estimate" // 本地估算 SourceProviderUsage TokenSource = "provider_usage" // provider 真实用量 )