第 2 课
Issue 分诊工作流:触发器、safe outputs 与 staged 预览
按官方图库示例写一个新开 Issue 就自动运行的分诊工作流,用 add-labels 白名单和 add-comment 次数限定 AI 的写操作,故意改成 issues: write 看严格模式如何拒绝,从 lock 文件里确认代理拿到的工具,再用 staged: true 只预览不落地。
课程目录第 2 / 3 课
学习位置仅保存在当前浏览器,有效期 180 天。
图文教材
本课对照的官方页面:AI Issue Triage、Safe Outputs、Triggers、Staged Mode、Threat Detection。命令与输出在 Linux(gh-aw v1.0.1)上实测,输出为节选。
上一课的周报按日程运行。这一课写一个由事件触发的工作流:每当有人新开或重开 Issue,AI 读一遍内容,从允许的标签里挑 1~2 个加上,再留一条说明评论。示例按官方图库里的 Issue 分诊工作流精简而来,重点是看清 gh-aw 怎么限制代理「能写什么」。
第 1 步:写触发器、权限与允许的输出
在上一课的仓库里新建 .github/workflows/issue-triage.md,先写 frontmatter:
---
on:
issues:
types: [opened, reopened]
reaction: eyes
permissions:
contents: read
issues: read
safe-outputs:
add-labels:
allowed: [bug, feature, question, needs-info]
max: 2
add-comment:
max: 1
timeout-minutes: 10
---
on.issues.types和普通 GitHub Actions 的写法一样。reaction: eyes是 gh-aw 的扩展:工作流一启动,就在这个 Issue 上点一个 👀,让提问的人知道已经在处理。add-labels.allowed是标签白名单,代理只能从这 4 个里选。max: 2限制最多调用 2 次。add-comment.max: 1表示最多评论 1 条。- 官方文档提醒:仓库里还不存在的标签会被拒绝并报错。可以先在仓库里建好,或者在
add-labels下加create-if-missing: true。
建标签可以用 gh 自带的命令,bug、question 等一般已经是默认标签:
gh label create needs-info --color FBCA04
gh label create feature --color A2EEEF
第 2 步:写给代理的指令
frontmatter 下面接着写正文:
# Issue 分诊助手
分析 Issue #${{ github.event.issue.number }}。
1. 读标题和正文,判断它属于 bug、feature 还是 question。
2. 信息不足以复现时,加 needs-info 标签。
3. 用 add-labels 加 1~2 个标签,只能从允许列表里选。
4. 用 add-comment 留一条简短中文评论:说明分类理由;
如果缺信息,列出需要补充的内容。
${{ github.event.issue.number }} 是 GitHub Actions 的上下文表达式,运行时会替换成当前 Issue 的编号。代理会通过内置的 GitHub MCP 工具自己去读这个 Issue 的标题和正文,所以不用把正文塞进提示词里。
第 3 步:编译,并故意写错一次
先正常编译:
gh aw compile issue-triage
对照结果(省略 info 提示):
✓ .github/workflows/issue-triage.md (140.5 KB)
✓ Compiled 1 workflow: 1 succeeded, 0 warnings
再试一个常见的错误想法:既然要加标签,那就把 issues: read 改成 issues: write,再编译一次:
✗ Compiled 1 workflow: 0 succeeded, 1 failed, 1 error, 0 warnings
✗ issue-triage.md (1 error(s)):
• 1. .github/workflows/issue-triage.md:1:1: error: strict mode:
write permission 'issues: write' is not allowed for security
reasons. Use 'safe-outputs.create-issue',
'safe-outputs.create-pull-request', 'safe-outputs.add-comment',
or 'safe-outputs.update-issue' to perform write operations
safely.
✗ compilation failed
(为了不横向溢出,长行做了折行,原文是一整行。)编译器默认启用严格模式,直接拒绝给代理写权限,并指向 safe-outputs。改回 issues: read 后重新编译即可。
第 4 步:看清代理拿到了哪些工具
lock 文件第二行的 gh-aw-manifest 注释记录了这个工作流用到的 secrets、action、容器和 MCP 工具。把 safe outputs 工具单独取出来:
grep '^# gh-aw-manifest' .github/workflows/issue-triage.lock.yml \
| grep -o '"name":"safeoutputs","tools":\[[^]]*\]'
grep -nE '^ [a-z_]+:$' .github/workflows/issue-triage.lock.yml
对照结果:
"name":"safeoutputs","tools":["add_comment","add_labels","noop",
"report_incomplete","report_missing_data","report_missing_tool"]
76: activation:
446: agent:
1285: conclusion:
1637: detection:
1988: pre_activation:
2027: safe_outputs:
(第一行同样做了折行。)可以看到:
- 代理能调用的写类工具只有
add_comment和add_labels,正好对应 frontmatter 里的声明。noop、report_*是内置的「没事可做 / 报告缺失」工具。 - 和周报相比多了一个
pre_activation作业。Issue 事件谁都能触发,这个作业先检查触发者在仓库里的角色(默认只放行 admin、maintainer、write),不符合就不启动代理。👀 反应则由activation作业里的「Add eyes reaction for immediate feedback」步骤点上。 - 代理运行完之后,
detection作业先扫描它想写出的内容,检查提示词注入、密钥泄露和恶意代码改动,通过后safe_outputs作业才用自己的令牌真正加标签、发评论。
第 5 步:用 staged 模式先预览、不落地
第一次在真实仓库上跑,可以先开 staged 模式:代理照常分析,但不真正加标签、发评论,只在 Actions 运行摘要里列出「本来会做什么」。在 safe-outputs: 下加一行:
safe-outputs:
staged: true
add-labels:
allowed: [bug, feature, question, needs-info]
max: 2
add-comment:
max: 1
重新编译并确认开关已经写进 lock 文件:
gh aw compile issue-triage
grep -n 'GH_AW_SAFE_OUTPUTS_STAGED' \
.github/workflows/issue-triage.lock.yml
对照结果:
✓ Compiled 1 workflow: 1 succeeded, 0 warnings
1033: GH_AW_SAFE_OUTPUTS_STAGED: true
2051: GH_AW_SAFE_OUTPUTS_STAGED: "true"
2127: GH_AW_SAFE_OUTPUTS_STAGED: "true"
也可以只给某一种输出单独设 staged: true,比如只预览评论、标签照常加。看过几次预览、确认结果靠谱后,删掉 staged: true 再编译,就会真正写入。官方提醒:staged 只管内置的 safe outputs,自定义脚本、外部 MCP 服务等不在它的控制范围内。
小结
- 事件触发写在
on:里,reaction可以立刻给提问者反馈。 - 代理权限只能是只读,严格模式会拒绝
issues: write这类写法。 add-labels.allowed、max等字段把代理的写操作限定在白名单和次数以内,代理之外还有威胁检测作业把关。- 不确定效果时先开
staged: true预览。 - 下一课把这两个工作流推到 GitHub,配置 AI 认证,真正跑起来,并设好成本上限。
