idea_world_labDEV JOURNAL
2026年6月25日星期四

Qwen PR Review Workflow 结构与改进记录

编写日期:2026年 6月 25日

目的

本文档记录了将基于 qwen-code 的 PR Review workflow 引入并定制以适配当前仓库的过程。

本次工作的核心不仅是让 workflow 成功结束,还要使 Qwen 生成的审查结果实际以 GitHub PR 评论的形式留下。

背景

本仓库同时使用 CodeRabbit、Sourcery、Qodo 等外部审查机器人。但我们仍单独引入 qwen-code workflow,通过 OpenRouter 路径运行,并尝试在每个 PR 中留下基于 Qwen 的审查。

最初因为费用问题暂停了 AI PR 审查 API 流程。随后在 OpenRouter 免费层可以使用 openai/gpt-oss-120b:free,因此在 README 中修改为重新尝试该路径的方向。

原始 workflow 结构

目标文件:

.github/workflows/qwen-code-pr-review.yml

原始工作流名称:

🧐 Qwen Pull Request Review

主要触发器:

on:
  pull_request_target:
    types: ['opened']
  pull_request_review_comment:
    types: ['created']
  pull_request_review:
    types: ['submitted']
  workflow_dispatch:
    inputs:
      pr_number:
        required: true
        type: 'number'

job 条件是设定在以下情况下执行。

  • workflow_dispatch 手动执行
  • pull_request_targetopened 事件且 PR 作者为 OWNERMEMBERCOLLABORATOR
  • PR review 评论中包含 @qwen /review
  • PR review 正文中包含 @qwen /review

workflow 的主要步骤如下。

  1. 检出 PR 代码
  2. 收集 PR 标题、正文、变更文件、diff 信息
  3. 执行 QwenLM/qwen-code-action
  4. 在 prompt 中让 Qwen 生成审查并指示使用 gh pr comment 添加评论

观察到的问题

在 PR #5 中实际观察到 workflow。

PR:

https://github.com/yyeongjin/idea_world/pull/5

PR 已正常创建,以下机器人作出了响应。

  • CodeRabbit
  • Sourcery
  • Qodo

Qwen 工作流也在 pull_request_target 事件中执行了。

观察到的运行:

workflow: 🧐 Qwen Pull Request Review
event: pull_request_target
conclusion: success

但是在实际的 PR 中没有留下 Qwen 的审查评论。

查看 workflow 日志可以看到,Qwen 在编写审查内容后并未执行实际的工具调用,而是以文本形式输出了如下 JSON 样式的指令。

{"tool":"write_file", ...}
{"tool":"run_shell_command", ...}

即 workflow 本身是 success,但用户期望的结果 “PR 评论撰写” 并未完成。

原因整理

问题在于将评论撰写的任务交给了 Qwen。

原始 prompt 指示 Qwen 直接执行以下操作。

1. write_file("review.md", "<your detailed review feedback here>")
2. gh pr comment $PR_NUMBER --body-file review.md --repo $REPOSITORY

但是在实际执行中,Qwen 并没有将此任务作为工具调用来执行,而是仅以文本形式输出了需要做的工作。

因此,如果模型没有正确调用工具,即使 workflow 成功,PR 也不会留下任何评论。

额外确认的结构问题

workflow 的 job 条件中包含了 issue_comment 事件。

(github.event_name == 'issue_comment' && ... contains(github.event.comment.body, '@qwen /review') ...)

但是 on: 触发器没有 issue_comment

即使在 PR 对话中留下 @qwen /review 评论,workflow 也根本不会启动。

此外,pull_request_target 触发器仅在 opened 时响应。

pull_request_target:
  types: ['opened']

所以在 PR 分支有新提交被 push 的 synchronize 事件中,并未自动重新执行。

改进方向

不再让模型负责 GitHub 评论的编写,而是让 GitHub Actions 步骤负责评论的编写。

改进后职责划分如下。

Qwen
  -> 只生成评论 Markdown 文本

GitHub Actions
  -> 将 Qwen 输出值保存到文件
  -> 使用 gh pr comment 在 PR 上发表评论

这样做的话,即使 Qwen 将工具调用输出为文本,也至少可以在 workflow 步骤中接收 qwen_result 并留下评论。

变更内容

1. trigger 加强

原始:

pull_request_target:
  types: ['opened']

更改:

pull_request_target:
  types: ['opened', 'reopened', 'synchronize']
issue_comment:
  types: ['created']

意图:

  • 当 PR 新建时执行
  • 当 PR 重新打开时执行
  • 当 PR 分支有新提交时执行
  • 当在 PR 对话中留下 @qwen /review 时执行

额外观察:

仅加强 on: 触发器并不足够。实际上,当向 PR 分支推送新提交时,pull_request_target 运行已生成,但作业条件仍仅允许 github.event.action == 'opened',导致运行以 skipped 结束。

因此,作业条件也需要像下面这样进行修改。

(github.event.action == 'opened' ||
 github.event.action == 'reopened' ||
 github.event.action == 'synchronize')

2. 为 Qwen 步骤分配 id

更改:

- name: 'Run Qwen PR Review'
  id: 'qwen_review'

意图:

为了在后续步骤中读取下一个输出。

steps.qwen_review.outputs.qwen_result

3. prompt 责任更改

原来的 prompt 直接指示 Qwen 编写文件和 PR 评论。

更改后,prompt 指示 Qwen 仅将审阅的 Markdown 文本作为最终回复返回。

Return the review markdown text as your final answer.
Do not call write_file.
Do not call gh pr comment.
Do not output JSON tool-call instructions.
A later GitHub Actions step will post your final answer as a PR comment.

意图:

  • 减少 Qwen 输出工具调用 JSON 的问题。
  • 将评论编写的责任从模型转移到工作流步骤。

4. 添加将 Qwen 输出值发布为 PR 评论的步骤

添加的步骤:

- name: 'Post Qwen PR Review'
  if: |-
    ${{ always() && steps.qwen_review.outputs.summary != '' }}
  env:
    GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
    PR_NUMBER: '${{ steps.get_pr.outputs.pr_number || steps.get_pr_comment.outputs.pr_number }}'
    REPOSITORY: '${{ github.repository }}'
    QWEN_RESULT: '${{ steps.qwen_review.outputs.summary }}'
  run: |-
    {
      echo "## Qwen PR Review"
      echo
      printf '%s\n' "$QWEN_RESULT"
    } > qwen-review.md
    gh pr comment "$PR_NUMBER" --body-file qwen-review.md --repo "$REPOSITORY"

意图:

  • 如果 Qwen 输出不为空,则一定以 PR 评论的形式留下。
  • 评论的撰写由使用 GITHUB_TOKENgh pr comment 的确定性步骤负责。

额外观察:

最初误读了输出名称为 steps.qwen_review.outputs.qwen_result。实际查看 QwenLM/qwen-code-actionaction.yml 后发现,复合步骤内部会生成 qwen_result,但向 action 外部公开的输出名称是 summary

outputs:
  summary:
    value: ${{ steps.qwen_run.outputs.qwen_result }}

所以后续的评论步骤需要读取 steps.qwen_review.outputs.summary。如果读取 qwen_result,即使 Qwen 正常生成了评论正文,post 步骤也会被跳过。

注意事项

pull_request_target 工作流不是基于 PR 分支的工作流文件,而是基于 base 分支的工作流文件执行。

因此,仅在 PR 分支上提交工作流修改并不会改变当前 PR 的 pull_request_target 行为。

要实际生效,需要以下任意一种方式:

  1. 首先将工作流修改合并到 main
  2. 然后在该 PR 中留下 @qwen /review,或推送新提交以运行已更改的工作流。

在本次任务中,先将工作流修改合并到 main,再在 PR #5 中重新触发 Qwen review,以确认是否真正生成评论。

安全规范

工作流文档中不要记录 API key、endpoint URL、provider base URL 等敏感信息。

在 GitHub Actions 日志中,以下值也必须进行 secret 掩码处理。

OPENAI_API_KEY
OPENAI_BASE_URL
OPENAI_MODEL
GITHUB_TOKEN

文档只保留模型更改事实和 workflow 结构,实际的 secret 值不记录。

当前结论

此次观察确认的内容如下。

  • PR 创建本身正常运行。
  • CodeRabbit、Sourcery、Qodo 正常响应 PR。
  • Qwen workflow 在 pull_request_target 中也以 success 结束。
  • 但在原有结构下,Qwen 可以不实际写评论,而是将工具调用指令以文本形式输出。
  • 因此需要将 “workflow 成功” 与 “PR 评论写入成功” 分开来看。
  • 将 Qwen 的输出改为让 GitHub Actions 后续步骤直接发布为评论会更安全。