Qwen PR Review Workflow структура и запись улучшений
Дата создания: 25 июня 2026 г.
Цель
Этот документ описывает процесс взятия workflow обзора PR на основе qwen-code и его настройки под текущий репозиторий.
Суть этой задачи не просто в том, чтобы workflow завершился успешно, а в том, чтобы результаты обзора, созданные Qwen, оставались в виде реального комментария к GitHub PR.
Предыстория
Этот репозиторий также использует внешние боты для обзора, такие как CodeRabbit, Sourcery, Qodo. Однако отдельно берётся workflow qwen-code, который запускается через путь OpenRouter, и экспериментируется процесс, при котором для каждого PR оставляется обзор на основе Qwen.
Сначала из‑за проблем с затратами поток AI PR Review 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ручной запуск- событие
openedуpull_request_target, и автор PR являетсяOWNER,MEMBERилиCOLLABORATOR - в комментарии обзора PR содержится
@qwen /review - в тексте обзора PR содержится
@qwen /review
Основные шаги workflow были следующими.
- checkout кода PR
- сбор заголовка PR, описания, изменённых файлов, информации diff
- запуск
QwenLM/qwen-code-action - внутри prompt заставить Qwen создать обзор и указать
gh pr commentдля публикации комментария
Наблюдаемая проблема
Наблюдал workflow в реальном времени на PR #5.
PR:
https://github.com/yyeongjin/idea_world/pull/5PR успешно создан, и следующие боты отреагировали.
- 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 завершился успешно, но ожидаемый пользователем результат — «создание комментария к PR» — не был выполнен.
Сводка причин
Проблема заключалась в том, что структура делегировала написание комментариев Qwen.
Исходный запрос инструктировал 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 был включён событие issue_comment.
(github.event_name == 'issue_comment' && ... contains(github.event.comment.body, '@qwen /review') ...)Однако в триггере on: не было issue_comment.
То есть, даже если оставить комментарий @qwen /review в обсуждении PR, workflow вообще не запускался.
Кроме того, триггер pull_request_target реагировал только на opened.
pull_request_target:
types: ['opened']Поэтому событие synchronize, когда в ветку PR пушится новый коммит, не запускалось автоматически.
Улучшения
Не поручать модели написание комментариев в GitHub, а сделать так, чтобы шаг GitHub Actions отвечал за написание комментариев.
После улучшения разделение ответственности выглядит следующим образом.
Qwen
-> создать только текст Markdown‑обзора
GitHub Actions
-> сохранить вывод Qwen в файл
-> оставить комментарий к PR с помощью gh pr commentТаким образом, даже если 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. Назначение id шагу Qwen
Изменения:
- name: 'Run Qwen PR Review'
id: 'qwen_review'Цель:
Для того, чтобы в последующем шаге прочитать следующий вывод.
steps.qwen_review.outputs.qwen_result3. изменение ответственности prompt
Исходный запрос напрямую указывал Qwen создавать файлы и писать комментарии к PR.
После изменения запрос инструктирует 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_TOKENиgh pr comment.
Дополнительные наблюдения:
Сначала я неправильно считал имя вывода как steps.qwen_review.outputs.qwen_result. На самом деле, проверив action.yml в QwenLM/qwen-code-action, обнаружилось, что внутри composite‑шаг создаёт qwen_result, но имя вывода, публикуемое наружу из действия, — summary.
outputs:
summary:
value: ${{ steps.qwen_run.outputs.qwen_result }}Так что последующий шаг комментария должен читать steps.qwen_review.outputs.summary. Если читать qwen_result, то даже если Qwen корректно создал тело обзора, шаг post будет пропущен.
Важные замечания
Рабочий процесс pull_request_target запускается не на основе файла workflow из ветки PR, а на основе файла workflow из базовой ветки.
Поэтому просто внесение изменений в workflow в ветке PR не изменит поведение pull_request_target текущего PR.
Чтобы действительно применить изменения, необходимо одно из следующего.
- Сначала применить изменение workflow в
main. - Затем в следующем PR оставить
@qwen /reviewили выполнить новый commit и push, чтобы запустить изменённый workflow.
В этой задаче изменение workflow сначала будет применено в main, а затем в PR #5 будет повторно запущен Qwen review, чтобы проверить, будет ли действительно создан комментарий.
Требования к безопасности
В документации workflow не следует записывать такие чувствительные данные, как API‑ключ, URL конечной точки, базовый URL провайдера.
В журналах GitHub Actions следующие значения также должны быть замаскированы как секреты.
OPENAI_API_KEY
OPENAI_BASE_URL
OPENAI_MODEL
GITHUB_TOKENВ документе оставляются только факт изменения модели и структура workflow, а реальные значения secret не записываются.
Текущее заключение
Следующее было подтверждено в этом наблюдении.
- Создание PR работало нормально.
- CodeRabbit, Sourcery и Qodo корректно реагировали на PR.
- Qwen workflow также завершился успешно в
pull_request_target. - Однако в прежней структуре Qwen мог выводить указания вызова инструмента в виде текста, не оставляя реального комментария.
- Поэтому «успех workflow» и «успех написания комментария к PR» следует рассматривать отдельно.
- Безопаснее изменить процесс так, чтобы последующий шаг GitHub Actions публиковал вывод Qwen непосредственно в виде комментария.