Настройка AI-ревьюера для GitHub PR. Бесплатно, локально, без отправки кода в облако.
Архитектура проста: GitHub Webhook ловит событие pull_request, скрипт получает diff через GitHub API, разбивает на чанки, прогоняет через локальную LLM (Ollama + llama3), и публикует результаты как комментарий к PR.
# Архитектура AI код-ревью # # GitHub PR ──webhook──▶ GitHub Actions # │ # ┌─────────▼──────────┐ # │ fetch diff (gh) │ # │ split → chunks │ # │ Ollama llama3 │ # │ post review │ # └────────────────────┘ # # Преимущества: приватность (код не уходит в облако), # бесплатно (локальная LLM), кастомизируемые правила.
Workflow запускается на каждый pull_request. checkout кода, установка gh CLI и Ollama, запуск скрипта ревью и публикация комментария.
# .github/workflows/ai-review.yml name: AI Code Review on: pull_request: types: [opened, synchronize] jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Install gh CLI run: | type -p curl >/dev/null || sudo apt install curl -y curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli.gpg sudo apt install gh -y - name: Run AI Review env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} run: python3 scripts/ai_review.py
Скрипт получает diff PR через gh CLI, разбивает на чанки по 200 строк, отправляет каждый в Ollama с llama3 и собирает результаты.
import subprocess, os, requests, json def get_pr_diff(pr_number: str) -> str: """Получает diff pull request через gh CLI""" result = subprocess.run( ["gh", "pr", "diff", pr_number], capture_output=True, text=True ) return result.stdout def chunk_diff(diff: str, size: int = 200) -> list: """Разбивает diff на чанки по ~200 строк""" lines = diff.split('\n') return ['\n'.join(lines[i:i+size]) for i in range(0, len(lines), size)] def review_chunk(chunk: str) -> str: """Отправляет чанк в Ollama llama3 для ревью""" resp = requests.post("http://localhost:11434/api/generate", json={ "model": "llama3", "prompt": f"Review this diff for bugs, security issues, style:\n{chunk}", "stream": False }) return resp.json()["response"] def post_review(pr_number: str, body: str): """Публикует комментарий к PR""" subprocess.run( ["gh", "pr", "comment", pr_number, "--body", body] ) if __name__ == "__main__": pr = os.environ["PR_NUMBER"] diff = get_pr_diff(pr) reviews = [review_chunk(c) for c in chunk_diff(diff)] post_review(pr, "## 🤖 AI Review\n" + "\n---\n".join(reviews))
Настройте категории проверок в промпте. AI-ревьюер ищет SQL-инъекции, XSS, утечки секретов, нарушения код-стиля и логические ошибки.
# Системный промпт для AI-ревьюера SYSTEM_PROMPT = """ Ты — senior разработчик на код-ревью. Проверяй diff по категориям: 🔒 БЕЗОПАСНОСТЬ: - SQL-инъекции (конкатенация строк в запросах) - XSS (неэкранированный пользовательский ввод) - Секреты в коде (ключи API, пароли, токены) - Path traversal (../../etc/passwd) 📐 СТИЛЬ: - Имена переменных (должны быть осмысленными) - Длина функций (> 50 строк — предлагай разбить) - Комментарии к сложной логике ⚡ ПРОИЗВОДИТЕЛЬНОСТЬ: - N+1 запросы в циклах - Неоптимальные структуры данных - Отсутствие кэширования 🧠 ЛОГИКА: - Неинициализированные переменные - Off-by-one ошибки - Неправильная обработка граничных случаев Формат ответа: ### 🔒 Security - проблема → решение ### 📐 Style - проблема → решение """
Альтернативный подход — ревью прямо в редакторе. Cursor Rules + pre-commit hook позволяют проверять код до коммита, не дожидаясь CI.
# .cursor/rules/review.md — Cursor Rules для авто-ревью Ты делаешь код-ревью каждого изменения. Проверяй: 1. Безопасность: нет секретов, инъекций, path traversal 2. Стиль: PEP8, осмысленные имена, функции < 50 строк 3. Тесты: новый код должен быть покрыт тестами 4. Документация: публичные функции с docstring # .git/hooks/pre-commit — AI pre-commit hook #!/bin/bash # Запускает AI-ревью на staged изменения FILES=$(git diff --cached --name-only) if [ -n "$FILES" ]; then git diff --cached | python3 scripts/quick_review.py fi
Агент не только находит проблемы, но и генерирует patch-файлы с исправлениями. GitHub Actions может автоматически применить их и создать коммит.
def generate_fix(issue: str, code: str) -> str: """Генерирует исправление через LLM и возвращает unified diff""" resp = requests.post("http://localhost:11434/api/generate", json={ "model": "llama3", "prompt": f"""Fix this issue:\n{issue}\n\nCode:\n{code}\n\nReturn ONLY a unified diff patch.""", "stream": False }) return resp.json()["response"] # GitHub Actions: авто-исправление + коммит # patch_file=$(python3 scripts/generate_fix.py) # git apply patch_file # git commit -am "🤖 Auto-fix by AI Reviewer" # git push # Важно: авто-исправления только для категорий Style и Performance, # Security issues требуют ручного ревью разработчика.