compact

package
v0.0.0-...-1991b76 Latest Latest
Warning

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

Go to latest
Published: May 16, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package compact 提供 eino 框架通用的上下文压缩插件. 实现基于 Claude Code 的 4 层递进压缩体系:

Layer 1: MicroCompact  - 规则清理旧工具输出 (<1ms)
Layer 2: AutoCompact   - 阈值触发 + 断路器
Layer 3: FullCompact   - LLM 摘要生成 (5-30s)
Layer 4: SessionMemory - 复用已有摘要 (<10ms)

集成方式见 examples/eino_demo/ 目录下的完整示例.

Package compact 提供 eino 框架通用的上下文压缩插件. 实现基于 Claude Code 的 4 层递进压缩体系:

Layer 1: MicroCompact  - 规则清理旧工具输出 (<1ms)
Layer 2: AutoCompact   - 阈值触发 + 断路器
Layer 3: FullCompact   - LLM 摘要生成 (5-30s)
Layer 4: SessionMemory - 复用已有摘要 (<10ms)

Index

Constants

View Source
const BaseCompactPrompt = noToolsPreamble + `
你正在总结一个 AI Agent 与用户之间的对话。
你的任务是生成一份详细、结构化的摘要,使对话能够从断点处继续,且不丢失上下文。

首先,输出一个 <分析> 块,按时间顺序逐步梳理对话:
1. 逐条查看每条消息
2. 识别用户意图、技术决策和代码模式
3. 特别关注用户反馈 —— 当用户让你做不同的事情时
4. 仔细检查技术准确性和完整性

然后,输出一个 <摘要> 块,包含以下章节:

1. 主要请求和意图:
   [详细描述所有用户请求和意图]

2. 关键技术概念:
   - [概念 1]
   - [概念 2]

3. 文件和代码段:
   - [文件名]
     - 该文件为什么重要
     - 关键代码片段或所做的修改
   - [文件名]
     - 代码片段

4. 错误与修复:
   - [错误描述]:
     - 修复方式
     - 用户对修复的反馈

5. 问题解决:
   [描述已解决的问题和推理过程]

6. 所有用户消息:
   - [列出每条非工具结果的用户消息]

7. 待办任务:
   - [任务 1]
   - [任务 2]

8. 当前工作:
   [精确描述当前正在进行的工作,包含文件名和代码片段]

9. 下一步(可选):
   [接下来应该做什么,引用最近对话中的原话]

` + noToolsTrailer

BaseCompactPrompt 完整压缩提示词模板.

View Source
const CompactBoundaryMarker = "[CompactBoundary]"

CompactBoundaryMarker 压缩边界标记常量。

既出现在生成的边界消息中,也用于 isCompactBoundary 反向识别, 二者必须保持一致 —— 早期版本曾经写入中文 "[压缩边界]" 而识别函数只查找 "[CompactBoundary]",导致 session memory 路径无法找到边界。

View Source
const PartialCompactPrompt = noToolsPreamble + `
你正在总结一段较长对话的最近部分。
仅关注最新的消息 —— 对话的早期部分已被单独保留。

输出一个 <分析> 块,后跟一个 <摘要> 块。
<摘要> 必须涵盖完整压缩格式中的第 1-9 节,
但仅限于最近的消息。

不要总结整个对话 —— 仅总结最近的部分。
` + noToolsTrailer

PartialCompactPrompt 部分压缩提示词(from 模式). 只摘要最近的消息,旧消息保留.

View Source
const PartialCompactUpToPrompt = noToolsPreamble + `
你正在总结一段对话的早期部分。
摘要点之后的最近消息将被逐字保留。

你的摘要将放在最近消息之前,因此请包含:

除了标准格式中的第 1-9 节外,再添加:

10. 继续工作的上下文:
    [提供有助于理解后续最近消息的上下文。
     解释发生了什么、做了哪些决策、以及摘要部分结束时工作处于什么状态。
     这段上下文对于理解接下来的逐字消息至关重要。]

输出一个 <分析> 块,后跟一个 <摘要> 块。
` + noToolsTrailer

PartialCompactUpToPrompt 部分压缩提示词(up_to 模式). 摘要旧消息,保留新消息。摘要放在开头作为后续消息的前导.

Variables

View Source
var CompactableTools = map[string]bool{
	"Read":      true,
	"Bash":      true,
	"Grep":      true,
	"Glob":      true,
	"WebSearch": true,
	"WebFetch":  true,
	"Edit":      true,
	"Write":     true,
}

CompactableTools 保留向后兼容的可被微压缩工具集合. 若需要自定义白名单,请使用 CompactionConfig.MicroCompactWhitelist.

View Source
var DefaultFileReadToolNames = []string{
	"Read",
	"read_file",
	"ReadFile",
	"file_read",
	"cat",
	"view",
	"show",
}

DefaultFileReadToolNames 是默认的"文件读取"工具名列表。 附件重注入器会识别这些工具的 tool_result,将其内容在压缩后重新注入上下文。

View Source
var ErrPromptTooLong = errors.New("prompt is too long")

ErrPromptTooLong 通用的 prompt-too-long 哨兵错误。

用户实现 LLMClient 时,若能从 SDK 错误中识别出 PTL 类型, 推荐用 fmt.Errorf("...: %w", ErrPromptTooLong) 包裹, 这样 IsPromptTooLongError 会用 errors.Is 准确识别, 避免字符串匹配的误判。

Functions

func DefaultPinnedMessageFilter

func DefaultPinnedMessageFilter(index, total int, msg Message) bool

DefaultPinnedMessageFilter 默认 pinned 判定规则:

  1. 首条 user 消息(通常承载原始任务指令)始终保留
  2. Extra["pinned"] == "true" 的任何消息保留
  3. Extra["role"] == "system_prompt" 的消息保留(兼容部分接入方约定)

func DefaultPromptTooLongDetector

func DefaultPromptTooLongDetector(err error) bool

DefaultPromptTooLongDetector 默认 PTL 判定。

比旧实现更严格:

  1. 先用 errors.Is 检查 ErrPromptTooLong 哨兵
  2. 再按完整短语匹配(避免 "400" + "token" 这类宽松匹配)
  3. 全部检查均在小写化后进行

func EstimateCompactionCost

func EstimateCompactionCost(inputTokens int) (inputEstimate int, outputEstimate int)

EstimateCompactionCost 估算一次压缩的 token 消耗.

func EstimateMessageTokens

func EstimateMessageTokens(messages []Message) int

EstimateMessageTokens 估算消息列表的 token 总数(含保守填充).

func EstimateMessageTokensPrecise

func EstimateMessageTokensPrecise(messages []Message) int

EstimateMessageTokensPrecise 优先使用 API 返回的精确 token 数,不可用时回退到估算.

func EstimateMessageTokensWithCache

func EstimateMessageTokensWithCache(messages []Message, cache *TokenCache) int

EstimateMessageTokensWithCache 与 EstimateMessageTokens 行为一致, 但对长文本块使用 cache 加速.

cache 为 nil 时直接退化为 EstimateMessageTokens(零开销)。

func FormatCompactSummary

func FormatCompactSummary(summary string) string

FormatCompactSummary 后处理压缩摘要.

操作:

  1. 删除 <analysis>/<分析> 块(思考草稿,不再有价值)
  2. 提取 <summary>/<摘要> 内容,替换为可读格式
  3. 清理多余空行

同时支持中英文标签(向后兼容).

func FormatCompactionCost

func FormatCompactionCost(modelName string, inputTokens, outputTokens int) string

FormatCompactionCost 格式化成本信息.

func GetAutoCompactThreshold

func GetAutoCompactThreshold(model string, bufferTokens int, maxOutputForSummary int) int

GetAutoCompactThreshold 自动压缩触发阈值.

func GetContextWindow

func GetContextWindow(model string) int

GetContextWindow 根据模型名获取上下文窗口大小. 委托给 PresetForModel 以统一模型预设数据源.

func GetEffectiveContextWindow

func GetEffectiveContextWindow(model string, maxOutputForSummary int) int

GetEffectiveContextWindow 有效上下文窗口 = 总窗口 - 摘要输出预留.

func GetNextStepHint

func GetNextStepHint(lastAssistantMsg string) string

GetNextStepHint 生成下一步提示(用于压缩后的引导).

func IsUnknownPreset

func IsUnknownPreset(p ModelPreset) bool

IsUnknownPreset 判断给定预设是否为未识别模型的兜底值.

func LightModelFor

func LightModelFor(mainModel string) string

LightModelFor 根据主模型推荐轻量压缩模型.

func RoughTokenEstimate

func RoughTokenEstimate(text string) int

RoughTokenEstimate 粗略 token 估算(字符数/4).

func SnipTokensCalculation

func SnipTokensCalculation(microResult *MicroCompactResult, messages []Message) int

SnipTokensCalculation 计算微压缩释放的 token 数.

Types

type AttachmentInjector

type AttachmentInjector struct {
	// 最近读取的文件附件(由调用方提供,或从消息历史中自动提取)
	RecentFiles []FileAttachment
	// Plan 文件内容(可选)
	PlanContent string
}

AttachmentInjector 附件重注入器.

func NewAttachmentInjector

func NewAttachmentInjector() *AttachmentInjector

NewAttachmentInjector 创建附件注入器.

func (*AttachmentInjector) InjectAttachments

func (a *AttachmentInjector) InjectAttachments(
	messages []Message,
	config CompactionConfig,
) []Message

InjectAttachments 将附件注入压缩后的消息列表.

注入顺序(Claude Code 兼容):

  1. Plan 文件(如果有)
  2. 最近读取的文件
  3. 其他附件

func (*AttachmentInjector) WithPlanContent

func (a *AttachmentInjector) WithPlanContent(content string) *AttachmentInjector

WithPlanContent 设置 Plan 文件内容.

func (*AttachmentInjector) WithRecentFiles

func (a *AttachmentInjector) WithRecentFiles(files []FileAttachment) *AttachmentInjector

WithRecentFiles 设置最近读取的文件.

type AutoCompactor

type AutoCompactor struct {
	// contains filtered or unexported fields
}

AutoCompactor 第2层压缩:自动压缩(阈值判断 + 断路器).

核心职责:

  • shouldAutoCompact 决策树:判断是否应该触发压缩
  • autoCompactIfNeeded 执行流程:SM 优先,回退到传统压缩
  • 断路器:连续失败 N 次后停止尝试

断路器状态完全由内部 circuitBreaker 持有,不在外层再维护重复计数器, 避免多 goroutine 下的状态不一致。

func NewAutoCompactor

func NewAutoCompactor(
	fullCompactor *FullCompactor,
	sessionCompactor *SessionMemoryCompactor,
	config CompactionConfig,
) *AutoCompactor

NewAutoCompactor 创建自动压缩器.

func (*AutoCompactor) AutoCompactIfNeeded

func (a *AutoCompactor) AutoCompactIfNeeded(
	ctx context.Context,
	messages []Message,
	modelMaxTokens int,
	querySource QuerySource,
) (*CompactionResult, error)

AutoCompactIfNeeded 自动压缩执行流程.

流程:

  1. 断路器检查
  2. ShouldAutoCompact 判断
  3. 优先尝试 Session Memory 压缩
  4. 回退到传统压缩
  5. 记录失败,触发断路器

func (*AutoCompactor) ConsecutiveFailures

func (a *AutoCompactor) ConsecutiveFailures() int

ConsecutiveFailures 返回当前连续失败次数(用于可观测性与测试).

func (*AutoCompactor) GetWarningThreshold

func (a *AutoCompactor) GetWarningThreshold(modelMaxTokens int) int

GetWarningThreshold 获取警告阈值(token 超过此值发出警告).

func (*AutoCompactor) IsCircuitOpen

func (a *AutoCompactor) IsCircuitOpen() bool

IsCircuitOpen 返回断路器是否已打开(外部只读访问).

func (*AutoCompactor) IsNearLimit

func (a *AutoCompactor) IsNearLimit(messages []Message, modelMaxTokens int) bool

IsNearLimit 判断是否接近上下文限制.

func (*AutoCompactor) Reset

func (a *AutoCompactor) Reset()

Reset 重置自动压缩器状态.

func (*AutoCompactor) ShouldAutoCompact

func (a *AutoCompactor) ShouldAutoCompact(
	messages []Message,
	modelMaxTokens int,
	querySource QuerySource,
) bool

ShouldAutoCompact 决策树:判断是否应该触发自动压缩.

决策树:

  1. querySource 是 compact 或 session_memory?→ false(防止递归死锁)
  2. 自动压缩未启用?→ false
  3. 断路器打开?→ false
  4. token 数超过阈值?→ true

type CompactionConfig

type CompactionConfig struct {
	// 自动压缩阈值相关
	AutoCompactEnabled        bool `json:"auto_compact_enabled"`
	AutoCompactBufferTokens   int  `json:"auto_compact_buffer_tokens"`    // 默认 13K
	MaxOutputTokensForSummary int  `json:"max_output_tokens_for_summary"` // 默认 20K
	WarningThresholdBuffer    int  `json:"warning_threshold_buffer"`      // 默认 20K

	// 断路器
	MaxConsecutiveFailures int `json:"max_consecutive_failures"` // 默认 3

	// Full Compact 重试与降级
	FullCompactMaxRetries   int     `json:"full_compact_max_retries"`   // 默认 3
	FallbackTruncateRatio   float64 `json:"fallback_truncate_ratio"`    // 默认 0.3
	FallbackTruncateMinKeep int     `json:"fallback_truncate_min_keep"` // 默认 4

	// Session Memory 配置
	SMMinTokens            int `json:"sm_min_tokens"`          // 默认 10K
	SMMaxTokens            int `json:"sm_max_tokens"`          // 默认 40K
	SMMinTextBlockMessages int `json:"sm_min_text_block_msgs"` // 默认 5

	// 微压缩
	MicroCompactEnabled bool `json:"micro_compact_enabled"`
	RecentToolsKeep     int  `json:"recent_tools_keep"` // 保留最近 N 个工具结果

	// MicroCompactWhitelist 微压缩白名单。
	// nil 或空 map 表示所有工具结果均可压缩(默认行为)。
	// 传入非空 map 时,仅压缩白名单内的工具。
	MicroCompactWhitelist map[string]bool `json:"-"`

	// MicroCompactCaseInsensitive 白名单是否忽略大小写(默认 true)。
	// 设为 true 时,"Read" 可匹配 "read"/"READ"/"Read"。
	MicroCompactCaseInsensitive bool `json:"micro_compact_case_insensitive"`

	// 模型
	ModelName string `json:"model_name"` // 模型名(用于上下文窗口检测)

	// 文件重注入
	RecentFilesMax      int `json:"recent_files_max"`       // 默认 5
	RecentFileMaxTokens int `json:"recent_file_max_tokens"` // 默认 5000
	FileReinjectBudget  int `json:"file_reinject_budget"`   // 默认 50000

	// FileReadToolNames 视为"文件读取"的工具名列表。
	FileReadToolNames []string `json:"file_read_tool_names"`

	// 回调
	OnCompactionStart func(info CompactionInfo)     `json:"-"`
	OnCompactionEnd   func(result CompactionResult) `json:"-"`

	// PreCompact 在压缩开始前回调,允许用户改写消息列表。
	// 典型用途:敏感信息脱敏、特定消息打标、Pinned 标记的注入。
	// 返回的消息列表会替代原列表参与后续压缩。返回 error 时压缩中止。
	// nil 表示不处理。
	PreCompact func(ctx context.Context, messages []Message) ([]Message, error) `json:"-"`

	// PostCompact 在压缩完成后回调,允许用户改写压缩结果。
	// 典型用途:附加自定义元数据、二次过滤、上报。
	// 返回的结果会替代原结果。返回 error 时整次压缩视为失败。
	// nil 表示不处理。
	PostCompact func(ctx context.Context, result *CompactionResult) (*CompactionResult, error) `json:"-"`

	// PromptTooLongDetector 用户自定义的 PTL 错误判定函数。
	// nil 时使用 DefaultPromptTooLongDetector。
	// 详见 errors.go。
	PromptTooLongDetector PromptTooLongDetector `json:"-"`

	// Logger 用户传入的日志实现。
	// nil 时使用基于 stdlib log 的默认实现(NewStdLogger)。
	// 适配 slog/zap/logrus 时,实现 Logger 接口即可。
	Logger Logger `json:"-"`

	// LogLevel 日志级别。
	// 零值(LogLevelUnset)等同于 LogLevelInfo。
	// 仅在 Logger 为 nil 时生效(用户传入的 Logger 自己管理 level)。
	LogLevel LogLevel `json:"-"`

	// PinnedMessageFilter 判断一条消息是否"必须保留"。
	// 在降级截断(fallbackTruncate)等会丢弃消息的路径中,
	// 标记为 pinned 的消息会被强制保留在结果中。
	// 默认实现:保留首条 user 消息 + 任何 Extra["pinned"]=="true" 的消息。
	// nil 时使用 DefaultPinnedMessageFilter。
	PinnedMessageFilter PinnedMessageFilter `json:"-"`
}

CompactionConfig 压缩全局配置.

func DefaultCompactionConfig

func DefaultCompactionConfig() CompactionConfig

DefaultCompactionConfig 返回默认配置.

参数值来源于 Claude Code 源码逆向分析(见项目根目录 Claude_Code上下文压缩算法深度分析.md)。 AutoCompact 触发阈值在运行时动态计算:

threshold = modelMaxTokens - MaxOutputTokensForSummary(20K) - AutoCompactBufferTokens(13K)

举例:256K 上下文 → 阈值 = 256K - 20K - 13K = 223K

如需覆盖默认参数,用 Builder 方法链式调整:

config := compact.DefaultCompactionConfig().
    WithAutoCompactBufferTokens(10_000).
    WithRecentToolsKeep(2)

func PresetForScenario

func PresetForScenario(s Scenario) CompactionConfig

PresetForScenario 根据场景返回调优过的默认配置.

用户可在返回值上继续链式调整:

cfg := compact.PresetForScenario(compact.ScenarioCodingAgent).
    WithRecentToolsKeep(5)

未识别场景时返回 DefaultCompactionConfig().

func (CompactionConfig) AppendFileReadToolNames

func (c CompactionConfig) AppendFileReadToolNames(names ...string) CompactionConfig

AppendFileReadToolNames 追加文件读取工具名.

func (CompactionConfig) ResetFileReadToolNames

func (c CompactionConfig) ResetFileReadToolNames() CompactionConfig

ResetFileReadToolNames 恢复为默认文件读取工具名列表.

func (CompactionConfig) WithAutoCompactBufferTokens

func (c CompactionConfig) WithAutoCompactBufferTokens(n int) CompactionConfig

WithAutoCompactBufferTokens 设置自动压缩缓冲 tokens.

func (CompactionConfig) WithFallbackTruncateMinKeep

func (c CompactionConfig) WithFallbackTruncateMinKeep(n int) CompactionConfig

WithFallbackTruncateMinKeep 设置降级截断最少保留消息数.

func (CompactionConfig) WithFallbackTruncateRatio

func (c CompactionConfig) WithFallbackTruncateRatio(ratio float64) CompactionConfig

WithFallbackTruncateRatio 设置降级截断保留比例(0~1).

func (CompactionConfig) WithFileReadToolNames

func (c CompactionConfig) WithFileReadToolNames(names ...string) CompactionConfig

WithFileReadToolNames 直接替换文件读取工具名列表.

func (CompactionConfig) WithFileReinjectBudget

func (c CompactionConfig) WithFileReinjectBudget(n int) CompactionConfig

WithFileReinjectBudget 设置附件重注入总预算 tokens.

func (CompactionConfig) WithFullCompactMaxRetries

func (c CompactionConfig) WithFullCompactMaxRetries(n int) CompactionConfig

WithFullCompactMaxRetries 设置 Full Compact 最大重试次数.

func (CompactionConfig) WithLogLevel

func (c CompactionConfig) WithLogLevel(level LogLevel) CompactionConfig

WithLogLevel 设置默认 logger 的日志级别(仅当未提供自定义 Logger 时生效).

func (CompactionConfig) WithLogger

func (c CompactionConfig) WithLogger(logger Logger) CompactionConfig

WithLogger 设置自定义 Logger。

用户可适配 slog/zap/logrus —— 实现 Logger 接口即可。 nil 时回退到内置默认 logger(受 LogLevel 控制)。

func (CompactionConfig) WithMaxOutputTokensForSummary

func (c CompactionConfig) WithMaxOutputTokensForSummary(n int) CompactionConfig

WithMaxOutputTokensForSummary 设置摘要最大输出 tokens.

func (CompactionConfig) WithMicroCompactCaseInsensitive

func (c CompactionConfig) WithMicroCompactCaseInsensitive(v bool) CompactionConfig

WithMicroCompactCaseInsensitive 设置白名单是否忽略大小写(默认 true)。

func (CompactionConfig) WithMicroCompactWhitelist

func (c CompactionConfig) WithMicroCompactWhitelist(whitelist map[string]bool) CompactionConfig

WithMicroCompactWhitelist 设置微压缩白名单. nil 或空 map 表示所有工具结果均可压缩。

func (CompactionConfig) WithPinnedMessageFilter

func (c CompactionConfig) WithPinnedMessageFilter(f PinnedMessageFilter) CompactionConfig

WithPinnedMessageFilter 设置 pinned 消息判定函数(用于降级截断保留关键消息).

func (CompactionConfig) WithPostCompact

func (c CompactionConfig) WithPostCompact(
	fn func(ctx context.Context, result *CompactionResult) (*CompactionResult, error),
) CompactionConfig

WithPostCompact 注册压缩后回调。

钩子返回的结果会替代原结果。 返回 error 时本次压缩视为失败(会影响断路器计数)。

func (CompactionConfig) WithPreCompact

func (c CompactionConfig) WithPreCompact(
	fn func(ctx context.Context, messages []Message) ([]Message, error),
) CompactionConfig

WithPreCompact 注册压缩前回调。

钩子返回的消息列表会替代原列表参与后续压缩。 返回 error 时整次压缩中止(不会触发 PostCompact)。

func (CompactionConfig) WithPromptTooLongDetector

func (c CompactionConfig) WithPromptTooLongDetector(d PromptTooLongDetector) CompactionConfig

WithPromptTooLongDetector 设置用户自定义的 PTL 错误判定函数.

func (CompactionConfig) WithRecentFileMaxTokens

func (c CompactionConfig) WithRecentFileMaxTokens(n int) CompactionConfig

WithRecentFileMaxTokens 设置单个文件最大 tokens.

func (CompactionConfig) WithRecentFilesMax

func (c CompactionConfig) WithRecentFilesMax(n int) CompactionConfig

WithRecentFilesMax 设置最大跟踪文件数.

func (CompactionConfig) WithRecentToolsKeep

func (c CompactionConfig) WithRecentToolsKeep(n int) CompactionConfig

WithRecentToolsKeep 设置保留最近工具结果的数量.

func (CompactionConfig) WithSMMaxTokens

func (c CompactionConfig) WithSMMaxTokens(n int) CompactionConfig

WithSMMaxTokens 设置 Session Memory 最大存储 tokens.

func (CompactionConfig) WithSMMinTokens

func (c CompactionConfig) WithSMMinTokens(n int) CompactionConfig

WithSMMinTokens 设置 Session Memory 最小触发 tokens.

type CompactionHook

type CompactionHook struct {
	// Compactor 压缩器实例 (必填).
	Compactor *DefaultCompactor

	// ModelMaxTokens 模型上下文窗口大小 (默认 200_000).
	ModelMaxTokens int

	// MicroCompactOnly 仅执行微压缩,不触发自动压缩 (默认 false).
	// 设为 true 时,Hook 仅做每轮工具结果清理,不做 LLM 摘要.
	MicroCompactOnly bool

	// Silent 静默模式,关闭日志 (默认 false).
	//
	// Deprecated: 使用 Logger / LogLevel 进行更细粒度控制。
	// 当 Logger 为 nil 时,Silent=true 等价于 LogLevel=LogLevelSilent。
	Silent bool

	// Logger 自定义日志实现。
	// nil 时使用 Compactor.Config().Logger,再 fallback 到默认 logger。
	Logger Logger

	// LogLevel 当未提供 Logger 时控制默认 logger 的级别。
	LogLevel LogLevel

	// OnCompacted 压缩完成回调 (可选).
	// 可用于记录指标、审计日志.
	OnCompacted func(result *CompactionResult)
}

CompactionHook 压缩钩子配置.

零值可用 (字段均为可选):

hook := &CompactionHook{Compactor: compactor, ModelMaxTokens: 200_000}

func NewCompactionHook

func NewCompactionHook(compactor *DefaultCompactor, modelMaxTokens int) *CompactionHook

NewCompactionHook 创建压缩钩子.

func NewMicroCompactHook

func NewMicroCompactHook(compactor *DefaultCompactor) *CompactionHook

NewMicroCompactHook 创建仅微压缩的钩子(最轻量,无 LLM 调用).

func (*CompactionHook) PostProcess

func (h *CompactionHook) PostProcess(ctx context.Context, messages []Message, state interface{}) ([]Message, error)

PostProcess 在 ChatModel 调用后执行(可用于记录 token 使用).

func (*CompactionHook) PreProcess

func (h *CompactionHook) PreProcess(ctx context.Context, messages []Message, state interface{}) ([]Message, error)

PreProcess 在 ChatModel 调用前执行压缩.

此方法签名兼容 eino 的 StatePreHandler. 实际集成时签名需匹配 eino 的 func(ctx, []*schema.Message, state) ([]*schema.Message, error).

func (*CompactionHook) WithCallback

func (h *CompactionHook) WithCallback(fn func(result *CompactionResult)) *CompactionHook

WithCallback 设置压缩完成回调.

func (*CompactionHook) WithLogLevel

func (h *CompactionHook) WithLogLevel(level LogLevel) *CompactionHook

WithLogLevel 设置默认 logger 的级别.

func (*CompactionHook) WithLogger

func (h *CompactionHook) WithLogger(logger Logger) *CompactionHook

WithLogger 设置自定义 Logger.

func (*CompactionHook) WithSilent deprecated

func (h *CompactionHook) WithSilent(silent bool) *CompactionHook

WithSilent 设置静默模式.

Deprecated: 使用 WithLogger(compact.NewNopLogger()) 或 WithLogLevel(compact.LogLevelSilent) 替代。

type CompactionInfo

type CompactionInfo struct {
	Trigger      string `json:"trigger"`
	TokensBefore int    `json:"tokens_before"`
	Threshold    int    `json:"threshold"`
	Layer        int    `json:"layer"`
}

CompactionInfo 压缩事件信息.

type CompactionModelConfig

type CompactionModelConfig struct {
	Strategy    CompactionModelStrategy // 策略
	MainModel   string                  // 主 agent 模型名
	CustomModel string                  // 自定义模型名(仅 StrategyCustomModel 时生效)
}

CompactionModelConfig 压缩模型配置.

func (*CompactionModelConfig) ResolveModel

func (c *CompactionModelConfig) ResolveModel() string

ResolveModel 根据策略解析实际使用的压缩模型.

type CompactionModelStrategy

type CompactionModelStrategy string

CompactionModelStrategy 压缩模型选择策略.

const (
	// StrategySameModel 复用主 agent 模型 —— 摘要质量最高,cache 可共享.
	StrategySameModel CompactionModelStrategy = "same_model"

	// StrategyLightModel 使用轻量模型 —— 成本低速度快,推荐用于日常.
	StrategyLightModel CompactionModelStrategy = "light_model"

	// StrategyCustomModel 自定义模型 —— 完全由调用方指定.
	StrategyCustomModel CompactionModelStrategy = "custom"
)

type CompactionResult

type CompactionResult struct {
	WasCompacted   bool      `json:"was_compacted"`
	Messages       []Message `json:"messages"`
	TokensBefore   int       `json:"tokens_before"`
	TokensAfter    int       `json:"tokens_after"`
	Trigger        string    `json:"trigger"`
	Summary        string    `json:"summary,omitempty"`
	BoundaryMarker bool      `json:"boundary_marker,omitempty"`
}

CompactionResult 压缩结果.

func PartialCompact

func PartialCompact(
	ctx context.Context,
	fullCompactor *FullCompactor,
	messages []Message,
	splitIndex int,
	direction string,
) (*CompactionResult, error)

PartialCompact 部分压缩:只压缩一部分消息.

direction:

  • "from": 保留旧消息,只摘要最近消息(默认)
  • "up_to": 摘要旧消息,保留新消息

type Compactor

type Compactor interface {
	Compact(ctx context.Context, messages []Message, modelMaxTokens int) (*CompactionResult, error)
	ShouldCompact(messages []Message, modelMaxTokens int) bool
	Reset()
}

Compactor 上下文压缩器接口.

type ContentBlock

type ContentBlock struct {
	Type       ContentType `json:"type"`
	Text       string      `json:"text,omitempty"`
	ToolName   string      `json:"tool_name,omitempty"`
	ToolInput  string      `json:"tool_input,omitempty"`
	ToolUseID  string      `json:"tool_use_id,omitempty"`
	ToolOutput string      `json:"tool_output,omitempty"`
	Thinking   string      `json:"thinking,omitempty"`
}

ContentBlock 消息内容块.

type ContentType

type ContentType string

ContentType 内容块类型.

const (
	ContentTypeText       ContentType = "text"
	ContentTypeToolUse    ContentType = "tool_use"
	ContentTypeToolResult ContentType = "tool_result"
	ContentTypeImage      ContentType = "image"
	ContentTypeThinking   ContentType = "thinking"
)

type DefaultCompactor

type DefaultCompactor struct {
	// contains filtered or unexported fields
}

DefaultCompactor 默认压缩器——编排 4 层压缩体系.

每轮查询前执行:

用户消息 → [Layer 1: MicroCompact] → [Layer 2: AutoCompact] → API 调用
              ↓                          ↓
         细粒度清理旧工具输出        阈值触发时:
         (不丢语义, <1ms)          → Layer 4: Session Memory (<10ms)
                                   → Layer 3: Full Compact (5-30s)

实现 Compactor 接口,可作为 eino 组件使用.

func NewDefaultCompactor

func NewDefaultCompactor(
	config CompactionConfig,
	summarizer Summarizer,
	memoryStore SessionMemoryStore,
) *DefaultCompactor

NewDefaultCompactor 创建默认压缩器.

参数:

  • config: 压缩配置
  • summarizer: LLM 摘要生成器(用于 FullCompact,可为 nil 禁用第3层)
  • memoryStore: Session Memory 存储(用于第4层,可为 nil 禁用)

func (*DefaultCompactor) Compact

func (c *DefaultCompactor) Compact(
	ctx context.Context,
	messages []Message,
	modelMaxTokens int,
) (*CompactionResult, error)

Compact 对消息列表执行完整的压缩管线.

管线:

  1. PreCompact 钩子(用户可改写消息列表)
  2. MicroCompact: 清理旧的工具输出
  3. AutoCompact: 如果超过阈值,触发 SM 或 Full Compact
  4. PostCompact 钩子(用户可改写压缩结果)

func (*DefaultCompactor) CompactOnly

func (c *DefaultCompactor) CompactOnly(messages []Message) []Message

CompactOnly 仅执行 MicroCompact(不触发 AutoCompact).

func (*DefaultCompactor) CompactWithDirection

func (c *DefaultCompactor) CompactWithDirection(
	ctx context.Context,
	messages []Message,
	modelMaxTokens int,
	direction string,
	splitIndex int,
) (*CompactionResult, error)

CompactWithDirection 支持部分压缩方向的完整压缩.

func (*DefaultCompactor) Config

func (c *DefaultCompactor) Config() CompactionConfig

Config 获取压缩配置.

func (*DefaultCompactor) GetAutoCompactor

func (c *DefaultCompactor) GetAutoCompactor() *AutoCompactor

GetAutoCompactor 获取内部 AutoCompactor(用于高级定制).

func (*DefaultCompactor) GetFullCompactor

func (c *DefaultCompactor) GetFullCompactor() *FullCompactor

GetFullCompactor 获取内部 FullCompactor(用于高级定制).

func (*DefaultCompactor) GetSessionMemoryCompactor

func (c *DefaultCompactor) GetSessionMemoryCompactor() *SessionMemoryCompactor

GetSessionMemoryCompactor 获取内部 SessionMemoryCompactor(用于高级定制).

func (*DefaultCompactor) ManualCompact

func (c *DefaultCompactor) ManualCompact(
	ctx context.Context,
	messages []Message,
	modelMaxTokens int,
) (*CompactionResult, error)

ManualCompact 手动触发压缩(绕过阈值检查).

func (*DefaultCompactor) ReactiveCompact

func (c *DefaultCompactor) ReactiveCompact(
	ctx context.Context,
	messages []Message,
	modelMaxTokens int,
) (*CompactionResult, error)

ReactiveCompact 响应式压缩 —— API 调用失败后调用.

场景:API 返回 prompt-too-long 错误,需要紧急截断消息以继续对话。 与主动压缩不同,响应式压缩:

  • 不调用 LLM 生成摘要(避免再次触发 PTL)
  • 直接执行降级截断,保留最近消息
  • 使用更激进的保留比例(默认 20%)

这是 Claude Code 5 层错误恢复中的第 2 层。

func (*DefaultCompactor) Reset

func (c *DefaultCompactor) Reset()

Reset 重置内部状态.

func (*DefaultCompactor) ShouldCompact

func (c *DefaultCompactor) ShouldCompact(messages []Message, modelMaxTokens int) bool

ShouldCompact 判断是否应该触发压缩.

type FileAttachment

type FileAttachment struct {
	Path    string `json:"path"`
	Content string `json:"content"`
}

FileAttachment 文件附件信息.

func ExtractRecentFilesFromMessages

func ExtractRecentFilesFromMessages(messages []Message, config CompactionConfig) []FileAttachment

ExtractRecentFilesFromMessages 从消息历史中自动提取最近读取的文件.

扫描配置中指定的"文件读取"工具(FileReadToolNames)的 tool_result, 按出现顺序收集文件内容。

路径来源优先级:

  1. tool_use 的 ToolInput 中解析 file_path(如 {"file_path":"main.go"})
  2. tool_result 内容开头的文件路径标记(如 "// file: main.go")
  3. tool_use_id 作为回退标识

type FullCompactor

type FullCompactor struct {
	// contains filtered or unexported fields
}

FullCompactor 第3层压缩:LLM 摘要生成(传统压缩).

使用 Fork Agent 模式:传入全部消息,生成结构化摘要。 核心机制:

  • 预处理管线: stripImages → stripReinjected → normalize
  • 结构化输出: <analysis> 思考草稿 + <summary> 9 章节摘要
  • 重试: 当 LLM 调用失败时最多重试 N 次
  • PTL 重试: 当压缩请求自身超限时裁剪最旧消息重试
  • 降级截断: 重试全部失败后,直接截断旧消息并保留最近消息

func NewFullCompactor

func NewFullCompactor(summarizer Summarizer, config CompactionConfig) *FullCompactor

NewFullCompactor 创建传统压缩器.

func (*FullCompactor) Compact

func (f *FullCompactor) Compact(
	ctx context.Context,
	messages []Message,
	promptTemplate string,
	partialDirection string,
) (*CompactionResult, error)

Compact 执行传统压缩.

执行流程:

  1. 预处理消息(替换图片等)
  2. 调用 LLM 生成摘要(带重试 + PTL 重试)
  3. 重试全部失败 → 执行降级截断(fallback truncate)

type InMemorySessionMemoryStore

type InMemorySessionMemoryStore struct {
	// contains filtered or unexported fields
}

InMemorySessionMemoryStore 是 SessionMemoryStore 的开箱即用内存实现.

适用场景:

  • 单进程 / 单会话的开发与示例代码
  • 评测脚本、测试用例
  • 接入真正的持久层(Redis/SQL/向量库)之前的快速原型

不适用场景:

  • 多副本 / 多用户的生产环境(应自行实现持久化 + 隔离的 Store)

线程安全:所有访问通过 RWMutex 保护,读多写少的并发负载下性能良好.

func NewInMemorySessionMemoryStore

func NewInMemorySessionMemoryStore() *InMemorySessionMemoryStore

NewInMemorySessionMemoryStore 创建空的内存 Session Memory.

func (*InMemorySessionMemoryStore) AppendMemory

func (s *InMemorySessionMemoryStore) AppendMemory(snippet string)

AppendMemory 追加一段 memory 内容,原子操作.

用于"增量更新"模式:每轮对话后追加一段新摘要片段,避免覆盖之前的累积. 自动在原 memory 与新内容之间插入空行分隔.

func (*InMemorySessionMemoryStore) Clear

func (s *InMemorySessionMemoryStore) Clear()

Clear 重置 memory 与 lastSummarizedMessageID.

func (*InMemorySessionMemoryStore) GetLastSummarizedMessageID

func (s *InMemorySessionMemoryStore) GetLastSummarizedMessageID(_ context.Context) string

GetLastSummarizedMessageID 返回上次被纳入摘要的消息 ID.

func (*InMemorySessionMemoryStore) GetMemory

GetMemory 返回当前累积的 Session Memory 文本.

func (*InMemorySessionMemoryStore) IsEmpty

IsEmpty 当 memory 为空白时返回 true.

func (*InMemorySessionMemoryStore) SetLastSummarizedMessageID

func (s *InMemorySessionMemoryStore) SetLastSummarizedMessageID(id string)

SetLastSummarizedMessageID 记录最近一次被纳入摘要的消息 ID.

SessionMemoryCompactor 据此判断哪些消息已被摘要、哪些应原样保留.

func (*InMemorySessionMemoryStore) SetMemory

func (s *InMemorySessionMemoryStore) SetMemory(memory string)

SetMemory 覆盖当前 memory(典型用法:后台记忆提取协程定期写入).

type LLMClient

type LLMClient interface {
	// Chat 发送消息并获取回复文本.
	Chat(ctx context.Context, prompt string, messages []Message) (string, error)
}

LLMClient 通用 LLM 客户端接口(兼容 eino ChatModel 和直接 API 调用).

type LLMSummarizer

type LLMSummarizer struct {
	// contains filtered or unexported fields
}

LLMSummarizer 基于通用 LLM 客户端的摘要生成器.

func NewLLMSummarizer

func NewLLMSummarizer(client LLMClient, modelName string) *LLMSummarizer

NewLLMSummarizer 创建 LLM 摘要生成器.

func NewSummarizer

func NewSummarizer(cfg CompactionModelConfig, client LLMClient) *LLMSummarizer

NewSummarizer 根据策略创建摘要生成器.

func NewSummarizerWithClient

func NewSummarizerWithClient(client LLMClient, modelName string) *LLMSummarizer

NewSummarizerWithClient 用用户传入的 LLMClient 创建摘要器.

func (*LLMSummarizer) GenerateSummary

func (s *LLMSummarizer) GenerateSummary(ctx context.Context, messages []Message) (string, error)

GenerateSummary 实现 Summarizer 接口.

func (*LLMSummarizer) ModelName

func (s *LLMSummarizer) ModelName() string

ModelName 返回使用的模型名.

func (*LLMSummarizer) WithPrompt

func (s *LLMSummarizer) WithPrompt(prompt string) *LLMSummarizer

WithPrompt 自定义压缩提示词.

type LogLevel

type LogLevel int

LogLevel 日志级别.

零值(LogLevelUnset)会被 getLogger 解释为 LogLevelInfo —— 这样用户在 CompactionConfig 中不显式设置 LogLevel 时仍能拿到合理默认行为, 同时不破坏 LogLevelDebug 的可达性。

const (
	// LogLevelUnset 零值,等同于 LogLevelInfo.
	LogLevelUnset LogLevel = iota
	// LogLevelDebug 详细诊断信息,仅用于排查问题.
	LogLevelDebug
	// LogLevelInfo 常规事件,如压缩触发、阈值穿越.
	LogLevelInfo
	// LogLevelWarn 异常但可恢复的情况,如断路器即将触发.
	LogLevelWarn
	// LogLevelError 操作失败,需要外部关注.
	LogLevelError
	// LogLevelSilent 静默,关闭所有输出.
	LogLevelSilent
)

func ParseLogLevel

func ParseLogLevel(s string) LogLevel

ParseLogLevel 从字符串解析日志级别(大小写不敏感). 未识别时返回 LogLevelInfo.

func (LogLevel) String

func (l LogLevel) String() string

String 返回 LogLevel 的可读名称.

type Logger

type Logger interface {
	Debug(msg string, args ...any)
	Info(msg string, args ...any)
	Warn(msg string, args ...any)
	Error(msg string, args ...any)
}

Logger 结构化日志接口。

设计目标:

  • 不绑定到具体日志库(slog/zap/logrus 均可适配)
  • args 采用 (key, value, key, value, ...) 形式,与 slog 兼容
  • 用户传入自定义实现即可对接生产日志系统

实现示例(slog 适配):

type SlogAdapter struct{ Logger *slog.Logger }
func (s SlogAdapter) Debug(msg string, args ...any) { s.Logger.Debug(msg, args...) }
func (s SlogAdapter) Info(msg string, args ...any)  { s.Logger.Info(msg, args...) }
func (s SlogAdapter) Warn(msg string, args ...any)  { s.Logger.Warn(msg, args...) }
func (s SlogAdapter) Error(msg string, args ...any) { s.Logger.Error(msg, args...) }

func GetLogger

func GetLogger(config CompactionConfig) Logger

GetLogger 是 getLogger 的导出版本,供 eino 适配器等子包使用.

不保证线程安全 —— 与底层 stdLogger 一致,每次调用产生新实例。 如需复用同一实例,请在 CompactionConfig.Logger 中显式注入。

func NewDefaultLogger

func NewDefaultLogger() Logger

NewDefaultLogger 返回默认 logger(INFO 级别,stderr 输出).

func NewNopLogger

func NewNopLogger() Logger

NewNopLogger 返回静默 logger(不输出任何信息).

func NewStdLogger

func NewStdLogger(level LogLevel, w io.Writer) Logger

NewStdLogger 创建基于标准库 log 包的 Logger。 w 为 nil 时使用 os.Stderr.

type Message

type Message struct {
	Role    Role           `json:"role"`
	Content []ContentBlock `json:"content"`
	// Meta 元数据字段
	MessageID string            `json:"message_id,omitempty"`
	Usage     *TokenUsage       `json:"usage,omitempty"`
	Extra     map[string]string `json:"extra,omitempty"`
}

Message 通用消息类型,兼容 eino schema.Message.

func CreateCompactBoundary

func CreateCompactBoundary(tokensBefore, tokensAfter int, trigger string) Message

CreateCompactBoundary 创建压缩边界标记消息.

标记同时包含英文 [CompactBoundary] 与中文 [压缩边界],以便:

  1. 程序检测:依赖固定英文标记,避免本地化文案漂移
  2. 人工阅读:中文标签让对话调试时更易识别

func GetCompactUserSummaryMessage

func GetCompactUserSummaryMessage(summary string, suppressFollowUp bool, recentPreserved bool) Message

GetCompactUserSummaryMessage 生成压缩后的摘要用户消息.

func TopologicalSortMessages

func TopologicalSortMessages(messages []Message) []Message

TopologicalSortMessages 按拓扑顺序排列消息(确保 tool_use 在 tool_result 之前).

type MicroCompactResult

type MicroCompactResult struct {
	WasCompacted bool
	TokensFreed  int
	ToolsCleared int
	Messages     []Message
}

MicroCompactResult 微压缩结果.

func MicroCompact

func MicroCompact(messages []Message, keepRecent int, caseInsensitive bool, whitelist ...map[string]bool) *MicroCompactResult

MicroCompact 第1层压缩:纯规则操作,清理旧的工具输出结果.

不调用 LLM,不丢语义信息。遍历消息列表,将旧的可压缩工具结果替换为 "[Old tool result content cleared]",同时保留最近的 N 个工具结果.

特点:

  • <1ms 延迟
  • 不修改 tool_use 块(保持配对完整性)
  • 保留最近 N 个工具结果
  • 不传入 whitelist 时,默认**所有**工具结果均可压缩
  • caseInsensitive 控制白名单是否忽略大小写

func MicroCompactTimeBased

func MicroCompactTimeBased(messages []Message, keepRecent int) *MicroCompactResult

MicroCompactTimeBased 时间触发的微压缩(子路径 A).

当缓存已过期时使用此路径。与 MicroCompact 逻辑相同,但额外清理 时间戳标记,以便后续处理知道哪些结果已被清除.

func MicroCompactWithConfig

func MicroCompactWithConfig(messages []Message, config CompactionConfig) *MicroCompactResult

MicroCompactWithConfig 使用 CompactionConfig 进行微压缩(推荐)。

type ModelPreset

type ModelPreset struct {
	Name               string // 模型显示名
	ContextWindow      int    // 总上下文窗口 (tokens)
	MaxOutputTokens    int    // 模型最大输出 (tokens)
	ReservedForSummary int    // 留给摘要输出的预算 (默认 20K)
	BufferTokens       int    // 自动压缩缓冲 (默认 13K)
}

ModelPreset 模型预设 —— 预定义的窗口大小和推荐配置.

使用方式:

preset := PresetClaudeOpus4()        // 推荐:按模型选择
preset := PresetForModel("sonnet")   // 自动匹配

func CustomPreset

func CustomPreset(contextWindow, reservedForSummary int) ModelPreset

CustomPreset 创建自定义预设.

只需填关键参数,其他使用默认值:

preset := compact.CustomPreset(100_000, 8_000)  // 100K 窗口, 8K 输入

func PresetClaudeHaiku4_5

func PresetClaudeHaiku4_5() ModelPreset

func PresetClaudeOpus4

func PresetClaudeOpus4() ModelPreset

Anthropic Claude 系列

func PresetClaudeSonnet4

func PresetClaudeSonnet4() ModelPreset

func PresetClaudeSonnet4_5

func PresetClaudeSonnet4_5() ModelPreset

func PresetDeepSeekV3

func PresetDeepSeekV3() ModelPreset

DeepSeek 系列

func PresetForModel

func PresetForModel(modelName string) ModelPreset

PresetForModel 根据模型名自动选择预设. 匹配规则:模型名转小写后按关键词匹配. 未匹配到任何已知模型时返回 UnknownPreset,调用方应通过 IsUnknownPreset 检测并提示用户显式传入 WithModelMaxTokens()。

func PresetGPT4Turbo

func PresetGPT4Turbo() ModelPreset

func PresetGPT4o

func PresetGPT4o() ModelPreset

OpenAI 系列

func PresetGPT4oMini

func PresetGPT4oMini() ModelPreset

func PresetQwenMax

func PresetQwenMax() ModelPreset

Qwen 系列

func UnknownPreset

func UnknownPreset() ModelPreset

UnknownPreset 表示未知模型的兜底预设。 Name 以 "Unknown" 开头,便于 IsUnknownPreset 识别。

注意:兜底窗口仍设为 128K 以便程序能继续运行,但调用方必须意识到 这只是一个保守猜测。理想情况下,用户应通过 WithModelMaxTokens() 显式覆盖,否则真实窗口超出此值时阈值不会触发, 真实窗口小于此值时则会被 API 直接拒绝。

func (ModelPreset) AutoCompactThreshold

func (p ModelPreset) AutoCompactThreshold() int

AutoCompactThreshold 该预设下的自动压缩触发阈值.

阈值 = ContextWindow - max(ReservedForSummary, MaxOutputTokens) - BufferTokens

func (ModelPreset) EffectiveWindow

func (p ModelPreset) EffectiveWindow() int

EffectiveWindow 该预设下的有效上下文窗口.

func (ModelPreset) WithBuffer

func (p ModelPreset) WithBuffer(tokens int) ModelPreset

WithBuffer 自定义缓冲大小.

func (ModelPreset) WithName

func (p ModelPreset) WithName(name string) ModelPreset

WithName 设置显示名.

type PinnedMessageFilter

type PinnedMessageFilter func(index, total int, msg Message) bool

PinnedMessageFilter 判断一条消息是否在降级截断中必须保留。

参数:

  • index: 该消息在原始列表中的位置
  • total: 原始列表的总长度
  • msg: 被判断的消息本体

返回 true 表示"必须保留"。Pinned 消息会被附加到截断后保留消息的前面(按原始顺序)。

type PromptTooLongDetector

type PromptTooLongDetector func(err error) bool

PromptTooLongDetector 用户自定义的 PTL 错误判断函数。

不同 LLM SDK 返回的错误结构不同(Anthropic 用 *anthropic.Error, OpenAI 用 *openai.APIError,eino 透传原始错误等)。 通过此钩子,用户可以传入针对自家 SDK 的精确判定逻辑。

nil 表示使用默认实现(DefaultPromptTooLongDetector)。

type QuerySource

type QuerySource string

QuerySource 查询来源类型.

const (
	QuerySourceNormal        QuerySource = "normal"
	QuerySourceCompact       QuerySource = "compact"
	QuerySourceSessionMemory QuerySource = "session_memory"
)

type ReinjectBudget

type ReinjectBudget struct {
	// contains filtered or unexported fields
}

ReinjectBudget 文件重注入预算管理.

压缩后重新注入最近读取的文件,以保持上下文连续性。 预算控制:

  • 最近 N 个文件(默认 5)
  • 每个文件 ≤ maxTokens(默认 5K)
  • 总预算 ≤ budget(默认 50K tokens)

func DefaultReinjectBudget

func DefaultReinjectBudget() *ReinjectBudget

DefaultReinjectBudget 默认重注入预算.

func NewReinjectBudget

func NewReinjectBudget(maxFiles, maxTokens, budget int) *ReinjectBudget

NewReinjectBudget 创建文件重注入预算管理器.

func (*ReinjectBudget) SelectFiles

func (r *ReinjectBudget) SelectFiles(files []FileAttachment) []FileAttachment

SelectFiles 从文件列表中选择可重注入的文件.

策略:

  1. 按最近使用排序(调用方保证顺序)
  2. 逐个检查 token 预算
  3. 在总预算内尽可能多地包含文件

type Role

type Role string

Role 消息角色.

const (
	RoleUser      Role = "user"
	RoleAssistant Role = "assistant"
	RoleTool      Role = "tool"
	RoleSystem    Role = "system"
)

type Scenario

type Scenario string

Scenario 压缩场景类型 —— 不同应用场景对压缩策略的偏好不同.

通过 PresetForScenario 一键拿到针对该场景调优过的 CompactionConfig, 避免每个用户都重新摸索"缓冲该设多大、文件该重注入多少"等参数。

const (
	// ScenarioCodingAgent 编码代理:长对话、大量 tool_result、文件读取频繁.
	//
	// 特点:
	//   - RecentToolsKeep 较大(保留更多最近工具结果,便于 LLM 引用)
	//   - FileReinjectBudget 充裕(鼓励重注入文件给后续轮次使用)
	//   - 自动压缩缓冲略大(避免一次压缩后立即又超阈值)
	ScenarioCodingAgent Scenario = "coding_agent"

	// ScenarioCustomerSupport 客服 / 长会话问答:以纯文本对话为主、少工具调用.
	//
	// 特点:
	//   - 微压缩白名单缩窄(少量工具,无需激进压缩)
	//   - SMMinTokens / SMMaxTokens 较小(早摘要、早释放)
	//   - 文件重注入预算很小(很少读文件)
	ScenarioCustomerSupport Scenario = "customer_support"

	// ScenarioResearchAnalysis 研究分析:多检索 / 多 RAG 调用、上下文跨多份文档.
	//
	// 特点:
	//   - RecentToolsKeep 较大(保留最近检索结果链)
	//   - SMMaxTokens 较大(允许 session memory 容纳更多源信息)
	//   - 摘要预算较大(让 LLM 生成更详尽摘要)
	ScenarioResearchAnalysis Scenario = "research_analysis"

	// ScenarioLightweight 轻量 / 嵌入式:尽可能少触发 LLM 压缩,省 token.
	//
	// 特点:
	//   - 关闭 Session Memory(SMMinTokens 设大到等同于禁用)
	//   - 降级截断更激进(保留 25% 即可)
	//   - 微压缩开启但 RecentToolsKeep 调小
	ScenarioLightweight Scenario = "lightweight"
)

type SessionMemoryCompactor

type SessionMemoryCompactor struct {
	// contains filtered or unexported fields
}

SessionMemoryCompactor 第4层压缩:复用已有 Session Memory 作为摘要.

不调用 LLM,直接使用后台记忆提取积累的 Session Memory。 优势:

  • <10ms 延迟
  • 质量可预测(渐进更新,非一次性压缩)
  • 保留近期消息

func NewSessionMemoryCompactor

func NewSessionMemoryCompactor(store SessionMemoryStore, config CompactionConfig) *SessionMemoryCompactor

NewSessionMemoryCompactor 创建 Session Memory 压缩器.

func (*SessionMemoryCompactor) TryCompact

func (s *SessionMemoryCompactor) TryCompact(
	ctx context.Context,
	messages []Message,
	autoCompactThreshold int,
) (*CompactionResult, error)

TryCompact 尝试使用 Session Memory 进行压缩. 返回 nil 表示不适用或失败,需要回退到传统压缩.

type SessionMemoryStore

type SessionMemoryStore interface {
	GetMemory(ctx context.Context) (string, error)
	GetLastSummarizedMessageID(ctx context.Context) string
	IsEmpty(ctx context.Context) bool
}

SessionMemoryStore Session Memory 存储接口.

type Summarizer

type Summarizer interface {
	GenerateSummary(ctx context.Context, messages []Message) (string, error)
}

Summarizer LLM 摘要生成接口,用于 FullCompact.

type TokenCache

type TokenCache struct {
	// contains filtered or unexported fields
}

TokenCache 是一个并发安全的 LRU,用于缓存"内容串 → token 数"映射.

设计目标:

  • 默认 *不启用*:调用方按需创建并通过 EstimateMessageTokensWithCache 显式传入
  • 只缓存大块内容(短串本来就 O(len/4),缓存反而更慢)
  • 用 FNV-1a 而非加密哈希,键空间冲突可以接受 —— 估算误差最多偏 1 个 block

适用场景:

  • Agent 主循环里同一批消息会被 ShouldCompact + Compact 反复扫描
  • 单元测试 / benchmark 场景反复构造相似消息

不适用场景:

  • 消息内容每次都变化(命中率低,反而是负优化)

func NewTokenCache

func NewTokenCache(capacity int) *TokenCache

NewTokenCache 创建容量为 capacity 的 LRU。

capacity <= 0 时强制使用 1024 —— 太小的缓存价值不大,太大又容易吃内存。
minBlockLen 控制只缓存 len(content) >= 阈值的块(默认 512 字符)。

func (*TokenCache) Clear

func (c *TokenCache) Clear()

Clear 清空缓存.

func (*TokenCache) EstimateBlock

func (c *TokenCache) EstimateBlock(content string) int

EstimateBlock 估算单个内容串 token 数,命中缓存时直接返回。

content 较短(< minBlockLen)时跳过缓存 —— hash 比 len/4 更慢。

func (*TokenCache) Size

func (c *TokenCache) Size() int

Size 返回当前缓存条目数,仅用于测试与可观测性.

func (*TokenCache) WithMinBlockLen

func (c *TokenCache) WithMinBlockLen(n int) *TokenCache

WithMinBlockLen 调整最小缓存阈值;返回自身以便链式调用.

type TokenUsage

type TokenUsage struct {
	InputTokens  int `json:"input_tokens"`
	OutputTokens int `json:"output_tokens"`
}

TokenUsage API 返回的精确 token 统计.

Jump to

Keyboard shortcuts

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