mirror of
https://github.com/iflytek/skillhub.git
synced 2026-09-24 00:55:35 +00:00
* add issue triage automation mvp * Document issue automation design in Chinese * Fix legacy compat slug tests
323 lines
10 KiB
Markdown
323 lines
10 KiB
Markdown
# Issue 自动分诊 MVP 设计
|
||
|
||
## 目标
|
||
|
||
通过自动将 GitHub issue 分诊到三个队列中,降低维护者负担:
|
||
|
||
- `triage/deferred`:低优先级 issue,会随着时间推移逐步上浮
|
||
- `triage/core`:高优先级或高风险 issue,需要 core maintainer 接手
|
||
- `triage/agent-ready`:高优先级、低风险 issue,适合作为后续 agent 执行候选
|
||
|
||
本 MVP 版本还不会自动修复 issue。它聚焦在评分、路由、打标签,以及让
|
||
backlog 持续流动。
|
||
|
||
当前版本支持两种执行模式:
|
||
|
||
- 仅规则分诊
|
||
- 规则 + 兼容 OpenAI 的 LLM 辅助
|
||
|
||
## 为什么这样拆分
|
||
|
||
最初的方案把优先级和执行难度混在同一个决策里。实践上,如果把它们拆开,
|
||
系统会更容易调参:
|
||
|
||
- `Priority`:这个 issue 现在是否值得投入时间?
|
||
- `Route`:一旦值得处理,应该由谁来接手?
|
||
|
||
这样一来,高价值但高难度的 issue 仍然可以保持高优先级,同时继续路由到
|
||
`triage/core`。
|
||
|
||
## 输入
|
||
|
||
自动化会读取 issue 的实时标题、正文、标签、评论和时间戳。
|
||
|
||
结构化的 issue 表单字段来自:
|
||
|
||
- [bug_report.yml](../.github/ISSUE_TEMPLATE/bug_report.yml)
|
||
- [feature_request.yml](../.github/ISSUE_TEMPLATE/feature_request.yml)
|
||
- [reward-task.yml](../.github/ISSUE_TEMPLATE/reward-task.yml)
|
||
|
||
## 评分模型
|
||
|
||
每个 issue 会沿四个维度评分:
|
||
|
||
- `impact`(1-5):对用户和工作流的影响
|
||
- `urgency`(1-5):发布时间压力、功能损坏情况或重复讨论程度
|
||
- `effort`(1-5):预估改动规模和协作成本
|
||
- `confidence`(1-5):issue 描述的完整性和可执行程度
|
||
|
||
优先级计算公式如下:
|
||
|
||
```text
|
||
priority = impact * 0.45 + urgency * 0.35 + age_boost + engagement_boost
|
||
```
|
||
|
||
其中:
|
||
|
||
- `age_boost`:基于 SLA 的升级机制
|
||
- 第 7-9 天:预热阶段,最低提升到 `priority/p2`
|
||
- 第 10-13 天:强制移出 `triage/deferred`,最低提升到 `priority/p1`
|
||
- 第 14 天及以后:在下一次 triage/rescore 时,将该 issue 视为已违反 SLA,
|
||
并至少提升到 `priority/p0`
|
||
- `engagement_boost`:由评论压力和奖励金额共同决定,上限为 +1.0
|
||
|
||
在 MVP 中,`effort` 不会直接降低优先级,它只影响路由。
|
||
|
||
## LLM 辅助分诊
|
||
|
||
配置后,工作流可以调用兼容 OpenAI 的 chat completions API。
|
||
|
||
LLM 不会替代规则引擎。它只用于辅助:
|
||
|
||
- 生成 issue 摘要
|
||
- 对软性分数做微调
|
||
- 生成 `needs-info` 的追问问题
|
||
- 为维护者提供更好的判断依据
|
||
- 为 `triage/core` 生成 maintainer 交接摘要
|
||
|
||
硬性门槛仍然由规则控制:
|
||
|
||
- 缺失必填信息
|
||
- auth、schema、migration、SDK 或公共契约变更等高风险区域
|
||
- 最终是否可以提升到 `triage/agent-ready`
|
||
|
||
issue 正文和评论都视为不可信输入。工作流会:
|
||
|
||
- 在发送给模型前截断过长的正文和评论
|
||
- 明确告诉模型,issue 文本是数据而不是指令
|
||
- 使用严格的 JSON 协议校验模型输出
|
||
- 如果 provider 调用失败或 JSON 校验失败,则回退到仅规则模式
|
||
|
||
### 模式
|
||
|
||
- `off`:仅规则
|
||
- `shadow`:调用 LLM 并展示其建议,但最终仍沿用仅规则的路由和标签
|
||
- `assist`:允许 LLM 对软性分数做最多 `+/-1` 的微调,然后重新应用硬性门槛
|
||
|
||
### 何时使用 LLM
|
||
|
||
工作流只会在 issue 看起来存在歧义或价值较高时调用 LLM,例如:
|
||
|
||
- `triage/needs-info`
|
||
- `triage/core`
|
||
- 靠近路由阈值的 issue
|
||
- 低置信度案例
|
||
- 正文很长或讨论很多的 issue
|
||
- 需要更多判断的 feature 或 reward issue
|
||
|
||
## 路由规则
|
||
|
||
1. `triage/needs-info`
|
||
当缺少必填字段或 `confidence <= 2` 时触发。
|
||
|
||
2. `triage/deferred`
|
||
当 `priority < 3.6`、issue 不受信息缺失阻塞、且 issue 年龄仍低于 SLA
|
||
升级底线时触发。
|
||
|
||
3. `triage/core`
|
||
当 `priority >= 3.6` 且满足以下任一条件时触发:
|
||
- issue 阻塞了 OpenClaw/ClawHub 核心工作流,例如 install、publish、
|
||
update、sync 或基于 namespace 的发布
|
||
- `effort >= 4`
|
||
- `confidence <= 3`
|
||
- 存在高风险关键词或会影响契约的字段
|
||
|
||
4. `triage/agent-ready`
|
||
当 `priority >= 3.6`、`effort <= 3`、`confidence >= 4`,且不存在高风险
|
||
信号时触发。
|
||
|
||
在 `assist` 模式下,LLM 建议可以对 `impact`、`urgency`、`effort` 和
|
||
`confidence` 各自最多调整 1 分。规则引擎随后会重新计算优先级和路由。
|
||
|
||
涉及 OpenClaw/ClawHub 核心工作流的 issue 是进入 `triage/core` 的硬性门槛;
|
||
LLM 辅助不会放宽这一规则。
|
||
|
||
## 受管标签
|
||
|
||
自动化负责管理以下标签前缀:
|
||
|
||
- `triage/`
|
||
- `priority/`
|
||
- `effort/`
|
||
- `risk/`
|
||
|
||
当前使用的具体标签有:
|
||
|
||
- `triage/needs-info`
|
||
- `triage/deferred`
|
||
- `triage/core`
|
||
- `triage/agent-ready`
|
||
- `priority/p0`
|
||
- `priority/p1`
|
||
- `priority/p2`
|
||
- `priority/p3`
|
||
- `effort/s`
|
||
- `effort/m`
|
||
- `effort/l`
|
||
- `risk/high`
|
||
|
||
其余所有标签都保持不变。
|
||
|
||
另外,自动化还识别一个不由其管理的人工操作标签:
|
||
|
||
- `triage-manual`:冻结该 issue 的自动分诊更新
|
||
|
||
## 工作流
|
||
|
||
### 1. Issue 分诊
|
||
|
||
文件:[issue-triage.yml](../.github/workflows/issue-triage.yml)
|
||
|
||
触发条件:
|
||
|
||
- `issues.opened`
|
||
- `issues.edited`
|
||
- `issues.reopened`
|
||
- 当评论包含 `/retriage` 时触发 `issue_comment.created`
|
||
- `workflow_dispatch`
|
||
|
||
执行动作:
|
||
|
||
- 拉取 issue 和评论
|
||
- 计算分数和路由
|
||
- 更新或创建受管标签
|
||
- 更新或创建一条分诊评论,其中同时包含人类可读的判断理由和隐藏的机器状态
|
||
- 可选调用兼容 OpenAI 的 provider,并合并结果
|
||
|
||
### 2. Deferred Backlog 重新评分
|
||
|
||
文件:
|
||
[issue-backlog-rescore.yml](../.github/workflows/issue-backlog-rescore.yml)
|
||
|
||
触发条件:
|
||
|
||
- 每 6 小时一次
|
||
- `workflow_dispatch`
|
||
|
||
执行动作:
|
||
|
||
- 列出所有带有 `triage/deferred` 标签的 open issue
|
||
- 结合年龄和参与度加成重新计算优先级
|
||
- 决定将每个 issue 升级还是保留
|
||
- 原地更新分诊评论
|
||
- 当 issue 内容未变化时复用缓存的 LLM 结果
|
||
|
||
试运行说明:
|
||
|
||
- 当前定时 rescore 只扫描 `triage/deferred` 队列中的 issue
|
||
- 这可以保证低优先级 backlog 不会在 `deferred` 中闲置超过第 10 天
|
||
- 一旦某个 issue 已经从 `deferred` 中升级出去,之后第 14 天的进一步升级
|
||
依赖新的 triage 事件或手动 `/retriage`
|
||
- 在试运行阶段,14 天规则应被视为运营层面的 SLA 目标,而不是仓库范围内的
|
||
硬性计时器
|
||
|
||
## 脚本
|
||
|
||
新的 GitHub 自动化脚本位于
|
||
[`.github/scripts`](/Users/wowo/workspace/skillhub/.github/scripts):
|
||
|
||
- [github.ts](/Users/wowo/workspace/skillhub/.github/scripts/github.ts):精简版
|
||
GitHub REST 客户端
|
||
- [issue-triage-config.ts](/Users/wowo/workspace/skillhub/.github/scripts/issue-triage-config.ts):
|
||
标签、阈值和关键词规则
|
||
- [issue-llm-config.ts](/Users/wowo/workspace/skillhub/.github/scripts/issue-llm-config.ts):
|
||
LLM 模式、环境变量和调用启发式
|
||
- [issue-llm-provider.ts](/Users/wowo/workspace/skillhub/.github/scripts/issue-llm-provider.ts):
|
||
兼容 OpenAI 的 chat completions 客户端
|
||
- [issue-llm-evaluator.ts](/Users/wowo/workspace/skillhub/.github/scripts/issue-llm-evaluator.ts):
|
||
prompt 构造、JSON 校验和缓存 key 生成
|
||
- [issue-triage-lib.ts](/Users/wowo/workspace/skillhub/.github/scripts/issue-triage-lib.ts):
|
||
解析、评分、路由和评论渲染
|
||
- [issue-triage-merge.ts](/Users/wowo/workspace/skillhub/.github/scripts/issue-triage-merge.ts):
|
||
有界合并和硬性门槛重应用
|
||
- [issue-triage.ts](/Users/wowo/workspace/skillhub/.github/scripts/issue-triage.ts):
|
||
单 issue 入口
|
||
- [issue-backlog-rescore.ts](/Users/wowo/workspace/skillhub/.github/scripts/issue-backlog-rescore.ts):
|
||
deferred 队列重新评分入口
|
||
|
||
## 配置
|
||
|
||
设置以下 GitHub 仓库变量和 secret,即可启用 LLM 辅助分诊:
|
||
|
||
仓库变量:
|
||
|
||
- `ISSUE_TRIAGE_LLM_MODE`
|
||
- `ISSUE_TRIAGE_LLM_BASE_URL`
|
||
- `ISSUE_TRIAGE_LLM_MODEL`
|
||
- `ISSUE_TRIAGE_LLM_TIMEOUT_MS` 可选
|
||
- `ISSUE_TRIAGE_LLM_TEMPERATURE` 可选
|
||
- `ISSUE_TRIAGE_LLM_MAX_COMMENTS` 可选
|
||
- `ISSUE_TRIAGE_LLM_MAX_COMMENT_CHARS` 可选
|
||
- `ISSUE_TRIAGE_LLM_MAX_BODY_CHARS` 可选
|
||
|
||
仓库 secret:
|
||
|
||
- `ISSUE_TRIAGE_LLM_API_KEY`
|
||
|
||
建议的第一轮上线方式:
|
||
|
||
- `ISSUE_TRIAGE_LLM_MODE=shadow`
|
||
- 先观察几天分诊评论
|
||
- 等 LLM 建议看起来稳定后,再切换到 `assist`
|
||
|
||
兼容 OpenAI 的变量示例:
|
||
|
||
```text
|
||
ISSUE_TRIAGE_LLM_MODE=shadow
|
||
ISSUE_TRIAGE_LLM_BASE_URL=https://your-provider.example.com/v1
|
||
ISSUE_TRIAGE_LLM_MODEL=gpt-4.1-mini
|
||
```
|
||
|
||
## 推出计划
|
||
|
||
### Phase 1:当前阶段
|
||
|
||
- 启用 triage 和 backlog rescore
|
||
- 观察几周的 issue 流量后微调阈值
|
||
- 允许维护者通过 `triage-manual` 冻结特定 issue 的自动化处理
|
||
- 如果使用 LLM,从 `shadow` 模式开始
|
||
|
||
### Phase 2:Maintainer 交接
|
||
|
||
为 `triage/core` issue 增加 issue-brief 生成器,输出内容包括:
|
||
|
||
- 复现提示
|
||
- 可能涉及的模块
|
||
- 风险备注
|
||
- 验证清单
|
||
|
||
这些输出可以直接用于本地编程 agent 会话,以及现有的并行 worktree 流程。
|
||
|
||
当前 MVP 已经会在 `triage/core` issue 的分诊评论中直接嵌入一个
|
||
`Maintainer Brief` 区块。该摘要包括:
|
||
|
||
- 简洁的 issue 摘要
|
||
- issue 为什么被升级到 core
|
||
- 复现路径或操作路径备注
|
||
- 疑似相关模块或工作流负责人
|
||
- 风险提示
|
||
- 验证清单
|
||
|
||
### Phase 3:自托管 Issue Agent
|
||
|
||
增加一个自托管 runner,监听 `triage/agent-ready`,并执行:
|
||
|
||
- 创建隔离的分支和 worktree
|
||
- 运行解决 issue 的 agent
|
||
- 执行最小相关测试集
|
||
- 打开一个 draft PR
|
||
|
||
在这个阶段,以下场景仍应保留硬性阻断:
|
||
|
||
- auth 和权限变更
|
||
- 安全敏感变更
|
||
- schema 或 migration 相关工作
|
||
- 公共 API、SDK 或 CLI 契约变更
|
||
|
||
## 待调优问题
|
||
|
||
- 参与度加成是否只看评论数就够了,还是也应该拉取 reactions
|
||
- reward issue 是否应比当前 MVP 获得更强的价值加成
|
||
- `agent-ready` 是否应要求 `effort <= 2`,而不是 `<= 3`
|
||
- 某些区域(如 `scanner`)是否应默认视为高风险
|
||
- 某些团队是否应长期保持 `shadow` 模式,只把 `assist` 用在更窄的仓库子集上
|