Beads 数据库瘦身实战:`bd compact` 压缩已关闭 issue 的完整指南
2026/9/13 11:41:01 网站建设 项目流程

Beads 数据库瘦身实战:bd compact压缩已关闭 issue 的完整指南

【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads

导读

Beads(一个为编码 Agent 提供"记忆升级"的开源项目)在长期运行中,issue 库会随着每条记录不断写入 Dolt 版本历史而持续膨胀,直接拖慢查询、占用磁盘。本文以 compact.md 为核心骨架,系统讲解bd admin compact命令的分层压缩(Tier)机制、三种执行模式、全部命令行参数与适用场景,并结合仓库源码深入剖析候选筛选、资格校验、AI 语义摘要、快照归档与回滚的完整实现链路。读完本文,你将掌握在不丢失关键技术决策的前提下,为长期项目安全地控制 issue 数据库体积的完整方案。


1. 为什么需要压缩:长期运行的记忆膨胀问题

Beads 使用 Dolt(带版本控制的 SQL 数据库)作为存储后端,bd admin compact正是为了控制这种膨胀而设计的。它的作用在命令帮助文本中定义得非常明确(见 cmd/bd/compact.go):

"Compaction reduces database size by summarizing closed issues that are no longer actively referenced. This is permanent graceful decay - original content is discarded."

即:通过语义摘要压缩那些已关闭、且不再被活跃引用的 issue,将原始正文丢弃,只保留浓缩后的技术要点。

bd admin compactadmin命令组下的一个子命令(注册位置见 cmd/bd/admin.go),其最简用法为:

bd admin compact --auto --all

1.1 为什么必须压缩:Dolt 的提交历史机制

理解压缩的必要性,需要先理解 Beads 的存储模型。从命令帮助文本可以看出一个关键事实(cmd/bd/compact.go):

"With auto-commit per mutation, Dolt commit history grows over time."

Beads 对每次数据变更(issue 创建、更新、关闭)都会产生一次 Dolt 提交。这意味着:

  • 每一次 issue 编辑都永久留在提交历史里;
  • 长期项目中,issue 数量与迭代次数同步增长,数据库体积线性膨胀;
  • 关闭的 issue 通常只承担"历史查询"价值,却占用与活跃 issue 相同的存储成本。

压缩机制的价值在于:把"长尾"的已关闭 issue 从"全文保留"降级为"结构化摘要保留",从而将存储成本集中到真正活跃的数据上。


2. 压缩分层(Compaction Tiers)机制

bd admin compact采用分层压缩策略,原文档定义了两种 Tier:

Tier触发条件压缩强度实现状态
Tier 1已关闭 30+ 天语义压缩,约 70% 体积缩减✅ 已实现
Tier 2已关闭 90+ 天(且已 Tier 1 压缩)超压缩(Ultra compression)⏳ 规划中,尚未实现

2.1 源码中的 Tier 1 判定细节

Tier 1 的完整资格判定逻辑位于 internal/storage/issueops/compaction.go,其校验条件严格且顺序明确:

  1. issue 必须存在,否则返回 "issue not found";
  2. 状态必须为 closedtypes.StatusClosed),未关闭的 issue 直接拒绝;
  3. 必须有closed_at时间戳,无时间戳无法计算关闭时长;
  4. 未被更高层级压缩过:Tier 1 要求compaction_level < 1,Tier 2 要求compaction_level < 2>= 1(即必须先完成 Tier 1);
  5. 关闭时长必须达标time.Since(closedAt) >= threshold,threshold 默认 Tier 1 为 30 天、Tier 2 为 90 天。

2.2 时间阈值可配置:compact_tier1_days/compact_tier2_days

阈值并非写死的常量。从 internal/storage/issueops/compaction.go 可以看到,阈值实际从 Beads 配置表的compact_tier1_dayscompact_tier2_days键读取:

  • 若键缺失、为空或解析失败(非正整数),回退到默认值(30 / 90);
  • 这意味你可以通过 Beads 配置(bd config set等途径)按项目实际情况调整压缩时延。

2.3 候选筛选的 SQL 依据

--all批量模式与--stats统计模式都依赖候选查询。Tier 1 候选的 SQL 定义在 internal/storage/issueops/compaction.go:

SELECT i.id, i.closed_at, CHAR_LENGTH(i.description) + CHAR_LENGTH(i.design) + CHAR_LENGTH(i.notes) + CHAR_LENGTH(i.acceptance_criteria) AS original_size, COALESCE((SELECT COUNT(*) FROM dependencies d WHERE d.depends_on_issue_id = i.id AND d.type = 'blocks'), 0) AS dependent_count FROM issues i WHERE i.status = 'closed' AND i.closed_at IS NOT NULL AND i.closed_at <= (now - 30 days) AND (i.compaction_level = 0 OR i.compaction_level IS NULL) ORDER BY i.closed_at ASC;

几个值得注意的实现细节:

  • original_size是四个文本字段的字符长度之和:Description、Design、Notes、AcceptanceCriteria,这正是压缩前后对比、计算节省字节数的基准;
  • 候选查询同时统计dependent_count(被多少个blocks类型依赖引用)——从源码结构看,这为将来"有依赖的 issue 优先跳过"提供了数据基础,但目前资格判定尚未使用该字段;
  • Tier 2 候选的查询(compaction.go)与 Tier 1 唯一的差异是要求compaction_level = 1(必须先经过 Tier 1 压缩)且关闭时长满足 90 天阈值。

3. 命令用法与参数全解

3.1 原文档的基础用法

场景命令
预览候选 issue(不执行)bd admin compact --dry-run
压缩所有符合条件的 issuebd admin compact --all
压缩指定 issuebd admin compact --id bd-42
强制压缩指定 issue(跳过资格校验)bd admin compact --id bd-42 --force
查看压缩统计bd admin compact --stats

注意:在 Beads 较新的 CLI 结构中,compact命令挂在admin命令组下,因此完整调用是bd admin compact ...。文档 frontmatter 中的argument-hint: "[--all] [--id issue-id] [--dry-run]"也印证了这一参数形态。

3.2 核心参数速查表

以下参数全部来自 cmd/bd/compact.go 的 flag 注册代码,语义与默认值以源码为准:

参数类型默认值说明
--tierint1压缩层级,仅 1 已实现,传 2 会直接报错拒绝
--workersint5并行 worker 数(batch 模式的并发上限)
--batch-sizeint10每批处理的 issue 数
--dry-runboolfalse只预览不实际压缩
--allboolfalse处理全部候选 issue
--idstring""指定单个 issue ID(如bd-42
--forceboolfalse强制压缩,绕过资格校验(必须配合--id
--statsboolfalse输出压缩统计信息
--jsonboolfalse以 JSON 格式输出结果
--analyzeboolfalse分析模式:导出候选供 Agent 审阅(无需 API Key)
--applyboolfalse应用模式:接受 Agent 提供的摘要(无需 API Key)
--autoboolfalse自动模式:AI 驱动压缩(需要 API Key)
--summarystring""摘要文件路径,-表示从 stdin 读取(配合--apply
--actorstring"agent"审计日志中的操作者名称
--limitint0候选数量上限,0 表示不限制(配合--analyze
--doltboolfalseDolt 模式:对.beads/dolt目录执行垃圾回收

3.3 参数组合的合法性约束

源码中对参数组合有严格的互斥与前置校验(cmd/bd/compact.go):

  • --analyze--apply--auto三种模式互斥,且必须且只能指定其一,否则报错;
  • --id--all不能同时使用;
  • --force必须配合--id使用;
  • --apply必须同时提供--id--summary
  • --auto模式下若不提供--id--all--dry-run三者之一,会因缺少目标而报错;
  • 指定--tier 2会被前置拦截:"Tier 2 compaction is not yet implemented; only --tier 1 is available"——这是刻意为之的"早失败"设计,避免在模式内部深层才暴露错误。

4. 三种工作模式详解

除了原文档描述的--auto(AI 自动模式),当前实现还提供了另外两种无需 API Key 的模式。三种模式统一由一个入口分发(cmd/bd/compact.go)。

4.1--analyze:导出候选供 Agent 审阅(无 API Key)

适用场景:你(或你的 Agent)希望人工/智能体审阅每个候选 issue 后再决定如何压缩,全程不调用外部 AI 服务。

# 导出全部候选(含完整正文),JSON 格式便于 Agent 处理 bd admin compact --analyze --json # 只看单个 issue 的完整内容 bd admin compact --analyze --id bd-42 --json # 限制候选数量 bd admin compact --analyze --limit 20 --json

从实现看(cmd/bd/compact.go),--analyze输出的每个候选包含:idtitledescriptiondesignnotesacceptance_criteria全文)、size_bytesage_daystiercompacted(是否已压缩)。它要求直接数据库访问(ensureDirectMode),不能走代理服务器模式。

4.2--apply:应用 Agent 提供的摘要(无 API Key)

这是与--analyze配套的落地步骤:Agent 审阅候选后自行撰写摘要,写入文件或通过 stdin 传入,--apply负责校验并写入数据库。

# 从文件读取摘要 bd admin compact --apply --id bd-42 --summary summary.txt # 从 stdin 读取摘要(管道/脚本友好) bd admin compact --apply --id bd-42 --summary - < summary.txt

--apply的关键校验逻辑(cmd/bd/compact.go):

  1. 资格校验:除非--force,否则复用与--auto相同的CheckEligibility逻辑;
  2. 尺寸校验(防膨胀保护):除非--force,否则摘要长度必须严格小于原文长度,否则报错并提示use --force to bypass size validation
  3. 写入:将摘要写入description,清空design/notes/acceptance_criteria,记录compaction_levelcompacted_atcompacted_at_commitoriginal_size等元数据;
  4. 审计:以--actor(默认agent)身份在 issue 上追加一条评论,记录压缩前后的字节数与节省比例。

4.3--auto:AI 驱动压缩(需要 API Key)

原文档的主推模式。适合完全无人值守地批量压缩:

# 预览(不消耗 API 调用,仅列出候选) bd admin compact --auto --dry-run # 压缩所有符合条件的历史 issue bd admin compact --auto --all # 压缩单个 issue bd admin compact --auto --id bd-42

--auto需要 AI API Key,解析优先级由 internal/config/config.go 定义:

  1. ANTHROPIC_API_KEY环境变量
  2. MINIMAX_API_KEY环境变量
  3. 配置项ai.api_key
  4. 显式传入的 key

若四种来源都为空,命令会直接报错提示配置缺失(--dry-run除外,因为它不需要真正的 AI 调用)。


5. 底层实现原理:AI 摘要如何工作

5.1 摘要引擎:Haiku 客户端

--auto模式的 AI 摘要由internal/compact包承担。核心组件是haikuClient(internal/compact/haiku.go),它封装 Anthropic 兼容 API 完成 issue 摘要。摘要模型的选择逻辑(internal/config/config.go):

  • 配置了ai.model时优先使用该模型;
  • 使用MINIMAX_API_KEY且未配置模型时,默认路由到 MiniMax 提供的 Anthropic 兼容模型(MiniMax-M2),可用MINIMAX_MODEL环境变量覆盖;
  • 使用ANTHROPIC_API_KEY时走 Anthropic 默认模型。

API Base URL 同样智能路由(internal/config/config.go):ai.base_urlBD_AI_BASE_URL优先,其次MINIMAX_BASE_URL,最后回落 MiniMax 默认端点(https://api.minimax.io/anthropic)。

5.2 Tier 1 摘要提示词:结构化三要素

摘要不是自由发挥,而是由固定的提示词模板(tier1PromptTemplate,见 internal/compact/haiku.go)驱动,要求模型输出严格的三段式结构

**Summary:** [2-3 句简明概括:做了什么、为什么] **Key Decisions:** [最重要的技术决策要点列表] **Resolution:** [一句话说明最终结果与持久影响]

提示词强制要求:"Your summary must be shorter than the original. Be concise and eliminate redundancy."——这从提示词层面保证了压缩率。

5.3 可靠性设计:重试、遥测与审计

从源码可以看到多层可靠性保障(internal/compact/haiku.go):

  • 指数退避重试:最多 3 次重试,初始退避 1 秒,仅对可重试错误(网络超时、429 限流、5xx)生效;
  • OTel 遥测:记录输入/输出 token 数与请求耗时(bd.ai.input_tokensbd.ai.output_tokensbd.ai.request.duration);
  • LLM 调用审计:若启用审计(AuditEnabled),每次 LLM 调用都会写入llm_call审计条目,且审计失败不会导致压缩失败(best-effort 设计)。

5.4 压缩主流程(CompactTier1

单个 issue 的 Tier 1 压缩在 internal/compact/compactor.go 中按以下顺序执行:

1. 资格预检(CheckEligibility,快速失败) 2. 读取 issue,计算原始大小(四字段字节之和) 3. 调用 AI 生成摘要 4. 尺寸保护:摘要 >= 原文则跳过并记录警告评论 5. SnapshotIssue:先把原文归档到 compaction_snapshots 表 6. UpdateIssue:用摘要覆盖 description,清空其余三字段 7. ApplyCompaction:写入压缩元数据(含 git commit hash) 8. AddComment:在 issue 上记录压缩事件

其中第 5 步是可回滚性的关键——先归档、后覆盖,顺序不可颠倒。若归档失败,整个压缩中止且原文保持原样。

5.5 批量压缩的并发模型

CompactTier1Batch(internal/compact/compactor.go)采用信号量限流的 goroutine 池:并发上限由--workers(默认 5)控制,逐个 issue 独立执行CompactTier1,结果按索引收集到BatchResult数组,最后统一汇总成功数、失败数与节省字节数。CLI 层会渲染一个基于文本的进度条(progressBar,见 cmd/bd/compact.go)。


6. 数据安全与回滚:bd restore

6.1 "优雅的永久衰减"意味着什么

原文档特别强调(compact.md):

"This ispermanent graceful decay- original content is discarded. Usebd restore <id>to view full history from git if needed."

翻译过来:压缩后 issue 的 description/design/notes/acceptance_criteria 原文不再以正文形式存在。但并非不可恢复——存在两条恢复路径。

6.2 快照归档机制(首选恢复路径)

当前实现比文档描述更进一步:压缩前会先执行SnapshotIssue(internal/storage/issueops/compaction.go),把完整原文 JSON 序列化后写入compaction_snapshots表。该快照按"压缩目标层级"打标签,是bd restore的权威恢复源。

bd restore <issue-id>命令(cmd/bd/restore.go)行为如下:

  • 默认只读:展示归档的原文内容,不修改数据库;
  • --apply写回:将快照内容恢复到 issue,并把compaction_level降回(完全恢复时清零,并清空compacted_atcompacted_at_commitoriginal_size等簿记字段,见 compaction.go);
  • 快照行保留:恢复后快照记录不删除,作为审计痕迹留存。

6.3 从 Dolt 历史恢复(兜底路径)

对于在快照归档机制引入之前就被压缩的旧 issue(没有快照),bd restore会退化为从 Dolt 版本历史尽力重建原文——但该路径只能展示,不能写回restore.go帮助文本明确:"can only be displayed, not applied")。

6.4 真实回滚场景

# 查看某 issue 压缩前的原文(只读) bd restore bd-42 # 将压缩前的原文写回 issue bd restore bd-42 --apply

7. Dolt 垃圾回收:bd compact --dolt

语义压缩解决的是"内容冗余",而--dolt模式解决的是"存储冗余"。

7.1 为什么需要 Dolt GC

如前所述,Beads 每次变更都会产生 Dolt 提交,历史提交不断累积。Dolt 的垃圾回收可以移除不可达的提交并压缩存储。bd compact --dolt即对.beads/dolt目录执行此操作。

# 预览 GC 效果(不真正执行) bd admin compact --dolt --dry-run # 执行 Dolt 垃圾回收 bd admin compact --dolt

7.2 实现要点

从 cmd/bd/compact.go 可以看到:

  • 命令先定位 Beads 目录(beads.FindBeadsDir()),检查.beads/dolt是否存在——该模式仅适用于 Dolt 后端仓库,非 Dolt 仓库会得到明确提示;
  • --dry-run会报告当前目录大小与可回收前提,但不执行;
  • 实际执行调用外部dolt gc --archive-level 0命令(--archive-level 0写入经典 Snappy 表文件而非 zstd 归档,与进程内 GC 路径保持一致);
  • 做了外部 Dolt 版本兼容处理:若外部dolt二进制不认识--archive-level参数(旧版本),会自动降级为普通dolt gc并给出提示,而不是直接失败——且仅在明确识别出"未知参数"类错误时才降级,真正的 GC 失败不会被吞掉;
  • 执行前后对比目录大小,输出释放的空间字节数(如1.2 GB → 850.0 MB (freed 374.0 MB));
  • 需要dolt命令存在于 PATH。

8. 统计与验证:bd admin compact --stats

执行大规模压缩前,先用统计模式评估收益:

bd admin compact --stats # JSON 输出,便于脚本解析 bd admin compact --stats --json

输出(cmd/bd/compact.go):

Compaction Statistics Tier 1 (30+ days closed): Candidates: 42 Total size: 153600 bytes Estimated savings: 107520 bytes (70%) Tier 2 (90+ days closed, Tier 1 compacted): not yet implemented Candidates: 0 Total size: 0 bytes

统计逻辑会查询 Tier 1 与 Tier 2 各自的候选集合,累加original_size(四字段长度之和),并按 70% 给出预估节省量。JSON 模式额外携带"implemented": false标记明确 Tier 2 未实现的状态。注意:这是基于EstimatedSize = OriginalSize * 3 / 10(compaction.go)的估算,实际节省以压缩后报告的字节数为准。


9. 运行前提与限制

综合原文档与源码,使用bd admin compact前需要了解以下前提:

  1. 模式互斥--analyze/--apply/--auto三选一,不能混用;
  2. API Key 依赖:只有--auto需要 AI Key(ANTHROPIC_API_KEYMINIMAX_API_KEY或配置ai.api_key);--analyze--apply全程离线;
  3. 服务模式要求:除--stats--analyze--dry-run等只读路径外,变更型操作要求以服务模式(server mode)运行,且--analyze--apply要求直接数据库访问(不能走代理服务器模式);
  4. 只读仓库防护:非只读路径会触发CheckReadonly("compact")防护;
  5. Tier 2 尚未实现:指定--tier 2会直接报错,请勿在生产中依赖该参数;
  6. 外部 Dolt--dolt模式需要 PATH 中存在dolt可执行文件;
  7. 恢复兜底:快照归档之前压缩的 issue 无法通过--apply写回原文(只能展示 Dolt 历史重建版本)。

10. 推荐工作流总结

针对不同场景,推荐以下组合:

场景 A:无人值守、全自动维护(适合长期 CI/定时任务)

# 1. 先看有多少可压缩的历史 bd admin compact --stats # 2. 预览候选 bd admin compact --auto --dry-run # 3. 全量压缩(需要 API Key) bd admin compact --auto --all

场景 B:Agent 人工审阅(适合重要 issue 或不确定的批量操作)

# 1. 导出候选全文供审阅 bd admin compact --analyze --json --limit 20 # 2. 为每个 issue 撰写摘要并应用 bd admin compact --apply --id bd-42 --summary - < summary.txt

场景 C:配套的存储回收

# 语义压缩完成后,回收 Dolt 提交历史占用的空间 bd admin compact --dolt

场景 D:误操作回滚

# 查看原文(只读) bd restore bd-42 # 确认后写回 bd restore bd-42 --apply

延伸阅读

  • 命令入口与参数定义:cmd/bd/compact.go
  • 压缩器核心逻辑:internal/compact/compactor.go
  • AI 摘要客户端与提示词:internal/compact/haiku.go
  • 存储层资格判定与快照/恢复 SQL:internal/storage/issueops/compaction.go
  • Dolt 后端存储适配:internal/storage/dolt/compact.go
  • 压缩功能测试:internal/storage/dolt/compact_test.go
  • 回滚命令实现:cmd/bd/restore.go
  • AI Key 与模型解析:internal/config/config.go

【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询