Help us shape the future of Go! Take the 2026 Go Developer Survey

compact

package
v0.6.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2026 License: MIT Imports: 7 Imported by: 0

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

View Source
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;每个值都是生产调过的,别拍脑袋改)。

View Source
const (
	RoleUser      = "user"
	RoleAssistant = "assistant"
	RoleTool      = "tool"
)

Role 消息角色词表(Message.Role 的合法值——此前魔法字符串散落两文件, 拼错即静默改变分组行为;收口轮常量化,值不变零迁移)。

View Source
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)。

View Source
const InterruptedToolResult = "[Tool execution was interrupted before resume]"

InterruptedToolResult 中断占位结果(LLM 可感知的诚实形态:明示被中断, 模型可自行决定是否重发调用)。

View Source
const MaxConsecutiveRapidRefills = 3

MaxConsecutiveRapidRefills 连续 rapid-refill 熔断阈值。

View Source
const MaxOverflowRetries = 3

MaxOverflowRetries 压缩请求本身溢出的自适应重试上限(对标 MAX_COMPACT_PROMPT_TOO_LONG_RETRIES)。

View Source
const RapidRefillToolTurnThreshold = 3

RapidRefillToolTurnThreshold 判 rapid-refill 的工具轮次阈值:压缩后少于 该轮次又满,计入连续 rapid-refill。

Variables

This section is empty.

Functions

func BuildDefaultThreshold

func BuildDefaultThreshold(autoCompactThreshold int) int

BuildDefaultThreshold 由 auto-compact 阈值推导 microcompact 阈值: min(阈值×0.9, 阈值−2000),下限 0(先于 auto 触发才有意义)。

func EstimateTokens

func EstimateTokens(msgs []Message) int

EstimateTokens 本地 token 估算:Σ ceil(字符数/3),字符数含正文与工具调用 入参(name + args JSON)。

func FormatSummary

func FormatSummary(modelOutput string) string

FormatSummary 摘要模型输出 → 可注入的正文:剥 <analysis> 思考段、 <summary> 展开为标题 + 正文、压连续空行。空输出返回空串(调用方按失败处理)。

func GroupRounds

func GroupRounds(msgs []Message) [][]Message

GroupRounds 按 assistant 轮次分组:每个 assistant 消息开启新组,组前消息 (用户输入/上一轮工具结果)归入本组;首组之前的头部消息自成一组的开头。 分组是压缩/保留的最小单位——半组保留会让工具调用与结果断链。

func HasEnoughToCompact

func HasEnoughToCompact(msgs []Message) bool

HasEnoughToCompact 消息量是否值得压缩(<2 个 assistant 轮次压缩无意义—— 摘要请求的开销可能超过省下的窗口)。

func SummaryMessage

func SummaryMessage(summary string, opts SummaryOptions) string

SummaryMessage 压缩后的续接引导消息(置于保留消息之前)。

func SummaryPrompt

func SummaryPrompt(customInstructions string) string

SummaryPrompt 组装摘要请求 prompt(customInstructions 为领域附加指令, 如「重点保留测试输出」;空 = 无附加段)。

func TokenGap

func TokenGap(cause error) (int, bool)

TokenGap 从 provider 的 prompt-too-long 错误报文提取超差 token 数 (requested − maximum 或 本身 − 上限)。未识别形态返回 false——调用方 走保守降级(按比例丢弃)而非瞎猜。

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

func (c Config) EffectiveWindow() int

EffectiveWindow 输入侧可用窗口 = window − min(预留, window),下限 0。

func (Config) Threshold

func (c Config) Threshold() int

Threshold 压缩触发阈值 = max(0, 有效窗口 − buffer)。

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

type ErrRapidRefill struct {
	ConsecutiveRapidRefills int
	ToolTurnsSinceCompact   int
}

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

func RepairInterrupted(msgs []Message) []Message

RepairInterrupted 扫描转写,为每个「有调用、无结果」的 ToolCall 插入占位 tool 结果(按调用原序补在下一个非 tool 消息之前)。返回修复后的新切片, 原切片不变;无洞时返回原切片。

func TruncateForRetry

func TruncateForRetry(entries []Message, cause error, attempt int) []Message

TruncateForRetry 摘要素材的直接丢弃重试(SelectAfterOverflow 也到头时): 从摘要素材头部按 gap 覆盖丢最旧组(无 gap 按 20% 丢),保底留 1 组。 attempt 从 1 起,超过 MaxOverflowRetries 返回 nil(放弃)。

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 Reason

type Reason string

Reason 决策原因(可观测;语义对标 ZCode AutoCompactDecision.reason)。

const (
	ReasonDisabled       Reason = "disabled"        // 策略关闭
	ReasonNotEnough      Reason = "not_enough"      // 消息量不足
	ReasonCircuitBreaker Reason = "circuit_breaker" // 连续失败熔断
	ReasonBelowThreshold Reason = "below_threshold" // 未到阈值
	ReasonAboveThreshold Reason = "above_threshold" // 触发压缩
)

type Selection

type Selection struct {
	ForSummary []Message
	Preserved  []Message
	// GroupsPreserved 保留的组数(0 = 全量摘要)。
	GroupsPreserved int
	TotalGroups     int
}

Selection 压缩切分产物:ForSummary 交摘要(更早),Preserved 原样保留(最近)。

func Select

func Select(msgs []Message, preserveGroups int) Selection

Select 切分:保留最近 preserveGroups 组原文(下限 0、上限 len(groups)−1—— 至少一组进摘要,否则无物可压)。preserveGroups≤0 = 全量摘要。

func SelectAfterOverflow

func SelectAfterOverflow(msgs []Message, cause error, currentPreserved int) *Selection

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 真实用量
)

type ToolCall

type ToolCall struct {
	ID       string
	Name     string
	ArgsJSON string
}

ToolCall 工具调用记录(ArgsJSON 为参数原文,仅用于 token 估算与展示)。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL