Files
reader/plans/keyword-cleanup-review-suggestions-layer-design.md
T

535 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# keyword-cleanup-review 建议产物补齐设计
## 1. 背景与目标
当前仓库已经具备 keyword cleanup review 的大部分基础设施:
- 已有 review bundle 构建脚本 `skills/keyword-cleanup-review/scripts/build_review_bundle.py`
- 已有 term stats 与 daily term index 数据源
- 已有治理输入:`configs/term_cleanup_policy.json`、`configs/term_watchlist.json`、`configs/term_change_log.json`
- 已有建议落地脚本 `scripts/apply_term_suggestions.py`
当前缺口是:
> 缺少一层“把 `keyword-cleanup-bundle.json` 转成正式建议产物”的实现层。
也就是说,仓库现在能生成 review bundle,也能消费 suggestions JSON,但中间缺少稳定、可复用、可落盘的 suggestions 生成器。
本轮目标是补齐最小闭环,让仓库能够从 review bundle 稳定生成两份正式建议产物:
- `outputs/term_index/review/term-cleanup-suggestions-YYYY-MM-DD.json`
- `outputs/term_index/review/term-cleanup-suggestions-YYYY-MM-DD.md`
并保证 JSON 与 `skills/keyword-cleanup-review/references/suggestion-schema.md` 对齐,且能直接衔接 `scripts/apply_term_suggestions.py`。
补充口径:本方案中的 JSON 是 review / apply 之间的唯一正式建议产物;bundle 与 Markdown 主要作为运行时工作文件和临时展示层,不建议与 facts/configs 一样长期沉淀。
---
## 2. 当前现状
### 2.1 已有输入层
`build_review_bundle.py` 已经把以下输入聚合成单个 bundle:
- `data/term_index/term_stats.json`
- `data/term_index/daily/*.json`
- `configs/term_aliases.json`
- `configs/term_stopwords.json`
- `configs/filter_context.personal.json`
- `configs/term_cleanup_policy.json`
- `configs/term_watchlist.json`
- `configs/term_change_log.json`
bundle 中已经包含:
- 当前配置快照
- 最近 N 天热点词
- uncovered terms
- interest review candidates
- watch review candidates
这些信息已经足够支撑“保守的、可审查的” suggestions 生成。
### 2.2 已有输出消费层
`scripts/apply_term_suggestions.py` 已经能消费 suggestions JSON,并将接受的建议写回:
- `configs/term_aliases.json`
- `configs/term_stopwords.json`
- `configs/filter_context.personal.json`
- `configs/term_watchlist.json`
- `configs/term_change_log.json`
这说明落地层已存在,缺的是中间的正式建议产物生成层。
---
## 3. 当前缺口
当前流程停在:
`build_review_bundle.py` -> `keyword-cleanup-bundle.json`
但缺少:
`keyword-cleanup-bundle.json` -> `term-cleanup-suggestions-YYYY-MM-DD.json/.md`
因此出现几个问题:
- README / 设计文档里已经引用 suggestions 产物,但仓库内没有稳定生成脚本
- 人工审阅与后续 apply 之间没有统一的正式交付格式
- 同一份 bundle 无法稳定、幂等地重放为同名 suggestions 产物
- alias / stopword / interest / watch 四类建议缺少统一出入口
---
## 4. 推荐最小闭环架构
推荐新增一层独立脚本:
- `scripts/generate_term_cleanup_suggestions.py`
职责:
- 输入:`outputs/term_index/review/keyword-cleanup-bundle.json`
- 输出:
- `outputs/term_index/review/term-cleanup-suggestions-YYYY-MM-DD.json`
- `outputs/term_index/review/term-cleanup-suggestions-YYYY-MM-DD.md`
推荐最小数据流:
1. `build_review_bundle.py` 生成 bundle
2. `generate_term_cleanup_suggestions.py` 读取 bundle
3. 脚本基于治理 hints 生成 suggestions JSON
4. 同时渲染人类可审阅的 Markdown
5. 审阅后可用 `apply_term_suggestions.py` 选择性写回配置
本轮不引入默认 LLM 路径:
- 默认实现采用确定性规则生成
- 如果未来需要 LLM 参与,应作为显式可选增强,而不是默认路径
---
## 5. 产物设计
### 5.1 JSON 产物
JSON 必须与 `suggestion-schema.md` 对齐,至少包含:
```json
{
"date": "2026-04-08",
"based_on_days": 7,
"alias_suggestions": [],
"stopword_suggestions": [],
"interest_keyword_suggestions": [
{
"term": "Claude Code",
"reason": "Meets the configured interest-keyword review threshold and is not yet covered."
}
],
"watch_terms": [
{
"term": "A2A",
"reason": "Falls into the configured watch-term review range and should be observed first."
}
]
}
```
在不破坏兼容性的前提下,可以补充少量元数据字段,建议仅限:
- `source_bundle`
- `policy_schema_version`
- `summary`
建议项字段口径:
- `alias_suggestions[]`
- `from`
- `to`
- `reason`
- `stopword_suggestions[]`
- `term`
- `reason`
- `interest_keyword_suggestions[]`
- `term`
- `reason`
- 可选:`total_count`、`days_seen`、`recent_count`
- `watch_terms[]`
- `term`
- `reason`
- 可选:`total_count`、`days_seen`、`recent_count`
兼容性要求:
- `apply_term_suggestions.py` 只依赖分类 bucket 与关键字段名
- 因此额外证据字段只能追加,不能替换现有字段名
### 5.2 Markdown 产物
Markdown 推荐结构:
1. 标题与日期
2. 输入 bundle 与策略摘要
3. 当前现状摘要
- top/global 观察
- uncovered terms 概览
- 当前 watchlist / interest 覆盖情况
4. 建议摘要
- interest 建议数量
- watch 建议数量
- alias 建议数量
- stopword 建议数量
5. `interest_keyword_suggestions`
6. `watch_terms`
7. `alias_suggestions`
8. `stopword_suggestions`
9. 应用方式
- 指向生成的 JSON
- 给出 `apply_term_suggestions.py` 的调用示例
这样可以保证:
- 人可以直接审阅
- 机器可以直接消费同名 JSON
- Markdown 与 JSON 始终一一对应
---
## 6. 建议生成策略
### 6.1 本轮主链路:interest / watch
本轮先实现最小可用主链路:
- `interest_keyword_suggestions`
- `watch_terms`
直接复用 bundle 中已有的:
- `governance_hints.interest_review_candidates`
- `governance_hints.watch_review_candidates`
原因:
- 这些候选已经与 policy 对齐
- 这些候选已经排除了大部分已覆盖项
- 能直接与现有 apply 脚本形成闭环
### 6.2 alias / stopword 保守处理
本轮边界明确如下:
- `alias_suggestions` 先保持保守,默认可为空
- `stopword_suggestions` 先保持保守,默认可为空
- 后续如果补充更强证据或人工审查规则,再逐步增强
这样可以避免在证据不足时误伤配置。
### 6.3 Phase 2 新方向:alias review 交给 LLM 整理
对于 alias,不再优先走程序规则匹配。
Phase 2 建议改为:
- 程序继续负责准备 review 输入(term stats / daily / current aliases / stopwords / interest / watchlist)
- LLM 负责整理 alias 候选
- 默认先输出人工审阅汇报,而不是直接 apply
- 人工确认后,再决定是否写入 `term_aliases.json`
这样做的原因:
- alias 更偏语义整理,而不是简单趋势筛选
- 与 watch / interest 相比,alias 一旦错误归并,代价更高
- 对当前低频治理场景来说,LLM + 人工确认更轻,也比在程序里持续堆复杂规则更合适
---
## 7. 错误处理
脚本应做显式校验,并在失败时给出明确错误:
### 7.1 输入错误
- bundle 文件不存在 -> 直接失败
- bundle 不是 JSON object -> 直接失败
- 缺少关键字段(如 `days`、`governance_hints`)-> 直接失败
- 候选 bucket 结构错误 -> 直接失败
### 7.2 输出错误
- 输出目录不存在时自动创建
- JSON / Markdown 写入失败时直接退出非 0
### 7.3 数据去重与冲突
- 同一 term 不能同时出现在 interest 与 watch 中
- 优先级:`interest_keyword_suggestions` > `watch_terms`
- 已在 bundle 当前配置中覆盖的 term 不重复输出
---
## 8. 幂等性
本轮要求具备基础幂等性:
- 同一份 bundle 多次运行,默认生成同名产物
- 同一份 bundle 多次运行,JSON 内容顺序稳定
- Markdown 内容顺序稳定
建议做法:
- 优先使用 bundle 的 `generated_at` 日期作为 suggestions 文件日期
- term 排序按证据强度与 term 名稳定排序
- 不在默认输出中写入“每次运行变化”的当前时间戳
这样可以让生成器作为可重放步骤存在于 review 流程中。
---
## 9. 与 apply_term_suggestions.py 的衔接
正式链路应变成:
1. `build_review_bundle.py`
2. `generate_term_cleanup_suggestions.py`
3. 人工审阅 Markdown
4. `apply_term_suggestions.py --suggestions ...`
衔接要求:
- JSON bucket 名必须与 `apply_term_suggestions.py` 读取逻辑一致
- `date` 与 `based_on_days` 字段保留,用于 change log 回写
- 建议项中的 `reason` 直接沿用到 apply 后的 change log
这保证建议生成层不会成为孤立产物,而是正式进入 repo 治理闭环。
---
## 10. Python 3.11 依赖处理
### 10.1 当前现状
`build_review_bundle.py` 当前使用 `from datetime import UTC`,这要求 Python 3.11。
仓库整体 `pyproject.toml` 当前也声明 `requires-python = ">=3.11"`,因此短期内使用 `/usr/bin/python3.11` 运行是符合仓库现状的。
### 10.2 短期建议
短期先在文档与验证命令中明确:
- bundle 构建使用 `/usr/bin/python3.11`
- suggestions 生成脚本也按仓库当前 3.11 基线运行
### 10.3 中期建议
如果后续希望把 keyword cleanup 工具链下探到 Python 3.10,可做兼容改造:
- 把 `datetime.UTC` 替换为 `datetime.timezone.utc`
- 重新检查相关脚本是否还有其他 3.11-only 语法或库依赖
本轮不做超范围兼容重构,只在文档中把此约束说清楚。
---
## 11. 边界与非目标
本轮明确边界:
- 先实现 interest/watch 主链路
- alias/stopword 先保持保守或留待后续增强
- 不做超范围重构
- 不把 LLM 作为默认生成路径
- 不直接改 `filter_rules.json`
- 不自动 apply 建议到配置
因此,本轮交付定义为:
- 补齐 bundle -> suggestions 的正式实现层
- 让 review 流程可运行、可落盘、可审阅、可应用
而不是一次性做完所有高级治理逻辑。
---
## 12. 实施建议
建议按以下小步落地:
### Phase 1(已完成)
1. 新增 `scripts/generate_term_cleanup_suggestions.py`
2. 读取 bundle 并做结构校验
3. 生成稳定排序的 interest/watch suggestions JSON
4. Markdown 改成按需生成
5. README / skill 文档补一条生成命令
6. 用 `/usr/bin/python3.11` 完整跑通 bundle -> suggestions
完成后,keyword cleanup review 的最小正式链路变为:
`review bundle` -> `suggestions json` -> `apply accepted suggestions`
其中 Markdown 只是按需生成的展示层。
### Phase 2(下一步)
1. 保持程序继续准备 review 输入
2. 引入 LLM 做 alias 候选整理
3. 默认先生成 alias review 汇报,而不是直接 apply
4. 由人工确认后再决定是否写入 `term_aliases.json`
这样 alias review 会成为一个低频治理动作,而不是主链路里的自动归一步骤。
### Phase 3(下一步)
1. 保持程序继续准备 review 输入
2. 引入 LLM 做 stopword 候选整理
3. 默认先生成 stopword review 汇报,而不是直接 apply
4. 由人工确认后再决定是否写入 `term_stopwords.json`
这样 stopword review 会成为一个低频减噪动作,而不是主链路里的自动过滤步骤。
#### Phase 3 输入建议
建议给 LLM 的输入包括:
- `data/term_index/term_stats.json` 中的高频词与 recent evidence
- 最近 N 天 `data/term_index/daily/*.json` 的热点词上下文
- 当前 `configs/term_stopwords.json`
- 当前 `configs/term_aliases.json`
- 当前 `configs/filter_context.personal.json` 中的 `interest_keywords`
- 当前 `configs/term_watchlist.json`
程序层只负责把这些输入整理成紧凑 review context,不负责直接做 stopword 决策。
#### Phase 3 输出建议
建议 LLM 默认输出一份人工审阅汇报,而不是直接写配置:
- `建议加入 stopword`
- 词
- 简短理由
- 证据(如 total_count / days_seen / recent_count)
- `暂不建议加入 stopword`
- 词
- 为什么虽然偏泛,但当前还不能杀
- `需要人工判断`
- 词
- 风险点:可能是噪声,也可能仍保留有价值信号
如需结构化输出,可额外补一份 `stopword_review_candidates.json`,但该文件只作为 review 输入,不直接作为自动 apply 指令。
#### Phase 3 审阅原则
- 宁可少删,不乱杀
- 优先处理过泛、低辨识度、持续污染统计的词
- 对可能仍承载有效技术语义的词保持保守
- 默认先汇报,确认后再执行
#### Phase 3 汇报模板建议
建议 stopword review 默认按以下结构汇报给用户:
1. `建议加入 stopword`
- 词
- 理由:为什么这个词对治理帮助低、噪声高
- 证据:`total_count` / `days_seen` / `recent_count` 或最近出现上下文
2. `暂不建议加入 stopword`
- 词
- 理由:为什么当前不建议删掉
3. `需要人工判断`
- 词
- 风险点:泛词与有效主题词之间边界不清等
推荐汇报风格:
- 简短、保守、可审阅
- 先给判断,再给证据
- 不输出机器式原始 dump
- 不默认承诺“已应用”,只汇报“建议”
#### Phase 2 输入建议
建议给 LLM 的输入包括:
- `data/term_index/term_stats.json` 中的高频词与 recent evidence
- 最近 N 天 `data/term_index/daily/*.json` 的热点词上下文
- 当前 `configs/term_aliases.json`
- 当前 `configs/term_stopwords.json`
- 当前 `configs/filter_context.personal.json` 中的 `interest_keywords`
- 当前 `configs/term_watchlist.json`
程序层只负责把这些输入整理成紧凑 review context,不负责直接做 alias 决策。
#### Phase 2 输出建议
建议 LLM 默认输出一份人工审阅汇报,而不是直接写配置:
- `建议合并`
- `from -> to`
- 简短理由
- 证据(如 total_count / days_seen / recent_count)
- `暂不建议合并`
- 为什么不建议并掉
- `需要人工判断`
- 语义相近但风险较高的项
如需结构化输出,可额外补一份 `alias_review_candidates.json`,但该文件只作为 review 输入,不直接作为自动 apply 指令。
#### Phase 2 审阅原则
- 宁可少提,不乱提
- 优先整理明显同义 / 同概念 / 词形差异
- 不把公司名、产品名、泛概念词强行混并
- 默认先汇报,确认后再执行
#### Phase 2 汇报模板建议
建议 alias review 默认按以下结构汇报给用户:
1. `建议合并`
- `from -> to`
- 理由:为什么判断为同一概念或更合适的标准词
- 证据:`total_count` / `days_seen` / `recent_count` 或最近出现上下文
2. `暂不建议合并`
- 候选对
- 理由:为什么虽然相近,但当前不建议并
3. `需要人工判断`
- 候选对
- 风险点:歧义、范围差异、产品名/公司名混淆等
推荐汇报风格:
- 简短、保守、可审阅
- 先给判断,再给证据
- 不输出机器式原始 dump
- 不默认承诺“已应用”,只汇报“建议”
#### Phase 2 示例输出
建议合并:
- `Claude code -> Claude Code`
- 理由:明显属于同一产品名,仅是大小写写法不一致。
- 证据:`Claude Code` 在最近多日持续出现,而小写写法只是在少量上下文中作为变体出现。
- `Sub-Agent -> SubAgent`
- 理由:更像词形差异,不构成新的独立概念。
- 证据:两者都围绕同一 agent 架构语境出现,且没有稳定区分语义。
暂不建议合并:
- `Skills ↔ Agent Skills`
- 理由:前者过泛,后者更具体,当前强行归并会损失粒度。
- `Anthropic ↔ Claude`
- 理由:公司名与产品名并不等价,不应直接视为一个关键词。
需要人工判断:
- `AI助手 ↔ AI Agent`
- 风险点:语义可能接近,但中文表述范围更宽,是否并入需要结合你的使用语境判断。