aliasunder/umm-actually
GitHub: aliasunder/umm-actually
一个通过 OpenRouter 调用 LLM 对 GitHub Pull Request 进行结构化代码审查的 GitHub Action,生成带行内评论的单一整合审查报告。
Stars: 0 | Forks: 0
# umm-actually
由 LLM 驱动的 pull request 审查 GitHub Action。每个 PR 生成一份整合的审查报告,并带有行内发现,支持 [OpenRouter](https://openrouter.ai) 上的任何模型。
## 它的功能
- 审查 PR diff 并**将更改的代码追踪到其调用方** —— 受影响代码中的回归和预存 bug 也是发现,而不是噪音
- 读取您仓库的规范文件(默认为 `AGENTS.md`)并据此进行审查
- 准确发布**一条** PR 审查,并带有锚定在 diff 行的行内评论 —— 没有重复评论,没有未经请求的审查者徽章
- 端到端的结构化输出:每项发现都包含类别、严重性、置信度和具体的失败场景
- 通过 OpenRouter 实现模型无关 —— 选择您的模型,查看您的每次调用成本
- 无法锚定到 diff(例如,未更改文件中的调用方)的发现将显示在审查正文中的“diff 之外的发现”下
- 对于超大 diff 的 PR,将优雅地跳过,并仅提供包含原因的正文审查
## 设置
umm-actually 作为基于 Docker 的 action 运行。它需要一个 GitHub token(用于获取 diff 和发布审查)和一个 OpenRouter API key。
为获得最佳体验,请使用 [GitHub App](https://docs.github.com/en/apps/creating-github-apps) 安装 token,以便将审查归属于机器人身份而非个人账户。
## 用法
```
name: Review
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
issue_comment:
types: [created]
permissions:
contents: read
concurrency:
group: review-${{ github.event.pull_request.number || github.event.issue.number }}
cancel-in-progress: true
jobs:
review:
runs-on: ubuntu-latest
if: >-
github.event_name == 'pull_request' ||
(
github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
contains(github.event.comment.body, '@umm review')
)
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ secrets.UMM_APP_ID }}
private-key: ${{ secrets.UMM_PRIVATE_KEY }}
- uses: aliasunder/umm-actually@v0
with:
github_token: ${{ steps.app-token.outputs.token }}
openrouter_api_key: ${{ secrets.OPENROUTER_KEY }}
```
`@umm review` 评论触发器允许您通过评论在任何 PR 上重新请求审查。`issue_comment` 事件会在 PR 评论时触发 —— `if` 条件会过滤出仅针对 PR 的事件。
## 输入项
| 输入项 | 默认值 | 描述 |
| ----------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `github_token` | _(必填)_ | 用于获取 diff 和发布审查的 Token。GitHub App 安装 token 可保持机器人身份。 |
| `openrouter_api_key` | _(必填)_ | OpenRouter API key |
| `model` | `anthropic/claude-sonnet-4-6` | openrouter.ai/models 上确切列出的 OpenRouter 模型 slug |
| `fallback_model` | `""` | 如果主模型在结构化输出过程中失败,用于重试的备用模型 |
| `max_findings` | `""` _(无限制)_ | 发布发现的数量上限,优先考虑最高严重性。为空 = 发布所有验证的发现。 |
| `severity_threshold` | `low` | 发布的最低严重性:`low` \| `medium` \| `high` \| `critical` |
| `conventions_file` | `AGENTS.md` | 包含在 prompt 中的规范文件的仓库相对路径 |
| `phases` | `combined` | 要运行的审查阶段。V1 支持:`combined` |
| `context_budget_tokens` | `80000` | prompt 上下文的大致 token 预算(文件内容 + diff —— 规范有单独的上限) |
| `trace_related_files` | `true` | 在 prompt 中包含引用了已更改文件的文件,以便模型可以将回归追踪到调用方 |
| `cost_summary` | `true` | 将每次运行的成本报告(模型、prompt/completion token、USD)写入 workflow 步骤摘要 |
| `pr_number` | `""` | PR 编号覆盖 —— 仅当触发事件未直接标识 PR 时才需要 |
## 输出项
| 输出项 | 描述 |
| ---------------- | ------------------------------------------------------------ |
| `findings_count` | 发布的发现数量(应用阈值和上限后) |
| `review_url` | 提交审查的 URL;未发布审查时为空 |
| `model_used` | 产生接受响应的模型 |
| `skipped_reason` | 当审查被跳过时非空(例如 diff 太大) |
## 工作原理
1. 从触发事件中解析 PR(支持 `pull_request`、`pull_request_target` 和 `issue_comment` 事件)
2. 通过 GitHub API 获取统一 diff —— 超过 API diff 大小限制的 PR 将被跳过
3. 读取规范文件和已更改的源文件(受 token 预算限制),然后追踪 import 以查找引用这些更改的相关文件
4. 构建带有随机分隔符 nonce(防范 prompt 注入)的结构化 prompt,并将其发送到 OpenRouter
5. 根据严格的 Zod schema 验证响应,如果主模型失败,则使用备用模型重试
6. 按严重性阈值过滤发现,对重叠的发现进行去重,并在配置时进行上限限制
7. 将发现映射到锚定在 diff 行的行内 PR 审查评论,并带有吸附到最近代码块的兜底机制
8. 发布一份整合的审查 —— 无法放在行内的发现将渲染在审查正文中
## 状态
umm-actually 目前处于早期开发阶段 —— 核心审查 pipeline 已经可以运行,但还有更多功能需要构建。以下是已发布和正在开发的内容:
**已发布 (V1)**
- 单次审查,带有锚定在 diff 行的行内发现
- 带有重试机制和备用模型的结构化输出
- Import 追踪:通过反向 import 扫描将更改的代码追踪到调用方
- 受 token 预算限制的上下文(更改的文件 + 相关文件 + 规范)
- Prompt 注入防御(随机分隔符 nonce)
- 带有发布原因的跳过路径处理(超大 diff、空 diff、API 限制)
- 成本透明(在 workflow 摘要中有包含模型/token/USD 的单次运行报告)
- 用于按需重新审查的 `@umm review` 评论触发器
**进行中**
- **重新运行时的审查去重** —— 目前每次 push 都会发布一次新的审查;正在努力跨运行去重发现,并更新单个摘要评论而不是创建新评论
- **文档过期检测** —— 将工作区扫描扩展到文档文件(`.md`, `.json`),以便描述已更改代码但未更改的文档能进入 prompt,从而使文档过期成为一种发现
- **品牌化检查运行** —— 使用 Checks API,以便 CI 检查显示 umm-actually 头像,而不是通用的 GitHub Actions 徽标
**已计划**
- V1.5:`read_file` 验证工具 —— 模型可以在最终确定发现之前读取其他文件
- V2:有界 agentic 探索 —— 在 `generateFindings` 接口后使用工具进行多步骤调查
## 许可证
[MIT](./LICENSE)
标签:C2, 自动化攻击, 请求拦截