Перейти к содержимому
USE CASE

Бот ревью PR на Claude в 2026: пишем сами

Автоматический PR-ревью бот на Claude Sonnet 4.5 — парсинг диффа, теги серьёзности, постинг комментов, интеграция с CI. С кодом и настройкой Claudexia.

Ревью пул-реквестов — узкое место современной разработки. Сеньоры тратят часы, листая диффы, где 90% — бойлерплейт, пропускают те самые 10%, которые имеют значение, и всё равно мерджат тонкие баги. В 2026 году нет повода продолжать делать это руками. Claude Sonnet 4.5 — сильнейшая публично доступная модель для кода, и в паре с GitHub API она даёт вам собственного ревьюера, который работает на каждом PR, стоит копейки и не устаёт.

В этом гайде мы соберём такого бота — не игрушку, а реальный продакшн. Будем использовать Claude Sonnet 4.5 через Claudexia (https://api.claudexia.tech/v1): тот же API Anthropic, но дешевле и без проблем с лимитами.

Почему именно Claude для код-ревью

Три причины, по убыванию важности:

  1. Способность к коду. Sonnet 4.5 на вершине SWE-bench Verified и читает диффы как сеньор — отслеживает типы между файлами, замечает пропущенную обработку ошибок, ловит off-by-one, которые линтер не видит. GPT-5 и Gemini 3 близко, но именно для ревью (где ценится консервативность и обоснование) Claude выигрывает по соотношению сигнал/шум.
  2. Надёжный структурированный вывод. Claude следует JSON-схемам в tool_use практически со 100% соблюдением. Это критично: вывод бота должен парситься чисто каждый раз — один кривой JSON на тысячу запусков, и вас будят ночью.
  3. Длинный контекст + кэширование промптов. 200K токенов позволяют засунуть в системный промпт весь стайл-гайд репо, архитектурные заметки и недавние коммиты. Кэширование делает это практически бесплатным после первого вызова. См. наш разбор цен Claude API с экономикой кэша.

Сравнение с хостед-сервисами вроде CodeRabbit и Greptile: они нормальные, но вы отдаёте им свой исходный код, платите $30–$100 на разработчика в месяц и принимаете тот промпт, который они написали. Свой бот стоит $0.05–$0.30 за PR, работает на ваших промптах, и код не покидает ваш CI.

Архитектура

Полный пайплайн — четыре блока:

PR открыт/обновлён в GitHub
   ↓
Срабатывает GitHub Action
   ↓
Тянем дифф через GitHub API
   ↓
Шлём в Claude Sonnet 4.5 (через Claudexia)
   ↓
Парсим JSON-ответ
   ↓
Постим комменты ревью через GitHub API

Всё. Никакой векторной БД, эмбеддингов, агентного цикла. Дифф маленький (обычно <50K токенов), Claude читает его один раз и выдаёт структурированные комменты. Что-то сложнее — оверинжиниринг, пока у вас нет данных, говорящих обратное.

Промпт

Промпт — 80% работы. Вот шаблон, который у нас отработал на Go, TypeScript и Python:

Ты — senior staff engineer, ревьюишь pull request. Твоя задача — ловить
баги, проблемы безопасности и ошибки дизайна, а НЕ следить за стилем
(для этого есть линтеры) и НЕ хвалить хороший код.

SCOPE:
- Комментируй только строки, изменённые в этом диффе.
- Не комментируй неизменённые контекстные строки.
- Не требуй изменений, которые не можешь обосновать конкретным сценарием
  отказа.

СЕРЬЁЗНОСТЬ:
- blocker: приведёт к продакшн-инциденту, потере данных, бреши в
  безопасности или очевидному багу корректности. Чинить до мерджа.
- warning: реальная проблема, но не блокер. Гонки под маловероятной
  нагрузкой, отсутствующие error-пути, плохое именование, которое
  выстрелит позже.
- nit: мелкая придирка. Используй экономно — максимум 2 на PR.

ВЫВОД:
Вызови инструмент `post_review` со списком комментариев в JSON. Каждый
комментарий должен содержать:
- file: путь относительно корня репо
- line: номер строки в новом файле (после изменения)
- severity: "blocker" | "warning" | "nit"
- comment: 1–3 предложения. Сначала проблема, затем как чинить.
- justification: почему это важно. Если не можешь это сформулировать —
  выкини коммент.

Если PR выглядит нормально — верни пустой список. Не выдумывай проблемы.

КОНТЕКСТ РЕПО:
{кэшированный системный блок: стайл-гайд, заметки по архитектуре,
недавние решения}

ДИФФ:
{собственно дифф}

Две неочевидные вещи делают это рабочим:

Поле justification — это форсинг-функция против ложных срабатываний. Claude (и любая другая модель) будет галлюцинировать проблемы, если ей позволить. Требование письменного обоснования режет шум на ~60% в нашем внутреннем эвале — модель сама отсекает слабые комменты до того, как их выдать.

tool_use вместо «ответь JSON-ом». Описав post_review как инструмент со строгой схемой ввода, вы заставляете API само отбраковывать кривой вывод. Никаких функций починки JSON писать не надо.

Описание инструмента

const postReviewTool = {
  name: "post_review",
  description: "Опубликовать комменты ревью на PR. Передай пустой массив, если проблем нет.",
  input_schema: {
    type: "object",
    properties: {
      comments: {
        type: "array",
        items: {
          type: "object",
          properties: {
            file: { type: "string" },
            line: { type: "integer" },
            severity: {
              type: "string",
              enum: ["blocker", "warning", "nit"]
            },
            comment: { type: "string" },
            justification: { type: "string" }
          },
          required: ["file", "line", "severity", "comment", "justification"]
        }
      }
    },
    required: ["comments"]
  }
};

Установите tool_choice: { type: "tool", name: "post_review" }, чтобы заставить модель вызвать его. Никакого текстового ответа, никаких утечек.

Бот (TypeScript)

import Anthropic from "@anthropic-ai/sdk";
import { Octokit } from "@octokit/rest";

const claude = new Anthropic({
  apiKey: process.env.CLAUDEXIA_API_KEY,
  baseURL: "https://api.claudexia.tech/v1",
});

const gh = new Octokit({ auth: process.env.GITHUB_TOKEN });

async function reviewPR(owner: string, repo: string, pull_number: number) {
  // 1. Тянем дифф
  const { data: files } = await gh.pulls.listFiles({
    owner, repo, pull_number, per_page: 100,
  });

  // 2. Бьём по файлам — параллелим для больших PR
  const reviews = await Promise.all(
    files
      .filter(f => f.patch && f.status !== "removed")
      .map(file => reviewFile(file))
  );

  // 3. Сплющиваем + дедуп по (file, line, severity)
  const all = reviews.flat();
  const seen = new Set<string>();
  const unique = all.filter(c => {
    const k = `${c.file}:${c.line}:${c.severity}`;
    if (seen.has(k)) return false;
    seen.add(k);
    return true;
  });

  // 4. Постим одним ревью
  await gh.pulls.createReview({
    owner, repo, pull_number,
    event: unique.some(c => c.severity === "blocker")
      ? "REQUEST_CHANGES"
      : "COMMENT",
    comments: unique.map(c => ({
      path: c.file,
      line: c.line,
      body: `**[${c.severity}]** ${c.comment}\n\n_${c.justification}_`,
    })),
  });
}

async function reviewFile(file: any) {
  const response = await claude.messages.create({
    model: "claude-sonnet-4.5",
    max_tokens: 4096,
    system: [
      {
        type: "text",
        text: REPO_CONTEXT,           // стайл-гайд, архитектура
        cache_control: { type: "ephemeral" },
      },
      {
        type: "text",
        text: REVIEW_INSTRUCTIONS,    // промпт выше
      },
    ],
    tools: [postReviewTool],
    tool_choice: { type: "tool", name: "post_review" },
    messages: [
      {
        role: "user",
        content: `Файл: ${file.filename}\n\nДифф:\n\`\`\`diff\n${file.patch}\n\`\`\``,
      },
    ],
  });

  const toolUse = response.content.find(b => b.type === "tool_use");
  return toolUse ? (toolUse.input as any).comments : [];
}

Обратите внимание на cache_control на блоке контекста репо. Это и есть кэширование промптов — первый PR платит за эти токены полную цену, каждый следующий в течение 5 минут платит 10%. На активном репо это режет стоимость на 70%+.

Большие диффы

PR на 5000 строк взорвёт ваш бюджет токенов, если слать одним куском. Стратегия чанкования выше (один вызов Claude на файл) решает это естественным образом:

  • Вызовы по файлам идут параллельно — wall time остаётся ~3–5 секунд даже для PR из 30 файлов.
  • Каждый вызов получает сфокусированный контекст — Claude ревьюит auth.ts без package-lock.json под боком.
  • Дедуп между вызовами — иногда Claude помечает один и тот же паттерн в двух файлах; ключ (file, line, severity) убирает дубли.

Для реально огромных PR (>100 файлов) добавьте префильтр, который выкидывает лок-файлы, сгенерированный код и vendor/. Большинство «огромных PR» сжимаются до 10 ревьюабельных файлов после этого.

Настройка GitHub Actions

name: Claude Review
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  review:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write
      contents: read
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "20"
      - run: npm ci
      - run: npx tsx scripts/review.ts
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          CLAUDEXIA_API_KEY: ${{ secrets.CLAUDEXIA_API_KEY }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
          REPO_OWNER: ${{ github.repository_owner }}
          REPO_NAME: ${{ github.event.repository.name }}

Кладёте ключ Claudexia в секреты репо, коммитите YAML — и оно работает.

Стоимость на PR

Реальные цифры с нашего деплоя по 200 PR:

Размер PRТокены входТокены выходСтоимость (с кэшем)
Маленький (<10 файлов)~8K~500$0.04
Средний (10–30)~25K~1.5K$0.12
Большой (30–80)~70K~3K$0.28

Это с ценами Claude Sonnet 4.5 на Claudexia и активным кэшированием. Команда из 50 разработчиков на 100 PR в день — примерно $300 в месяц. Меньше одной лицензии CodeRabbit Pro.

Свой бот vs SaaS-ревьюеры

ПараметрВаш бот (Claude + Claudexia)CodeRabbit / Greptile
Стоимость$0.05–$0.30 за PR$30–$100 на разраба/мес
Контроль промптаПолныйНикакого
Где живут данныеВаш CIИх сервера
КастомизацияЧто напромптитеИх фичи
Время на запускОдин деньОдин час
ПоддержкаВашаИх

Размен реальный: SaaS быстрее ставится и вы его не поддерживаете. Своё даёт контроль, дешевле в пересчёте на PR на масштабе и возможность закодировать реальный вкус вашей команды.

Итог

Это можно зашипить за день. Все компоненты — Claude Sonnet 4.5 через Claudexia, GitHub Actions, Octokit SDK — стабильны, хорошо задокументированы и дешёвы. Единственная сложная часть — промпт, и шаблон выше покрывает 90% того, что нужно.

Начните с простого: один промпт, по файлу за раз, blocker/warning/nit. Прогоните по 20 последним замердженным PR и почитайте вывод. Итерация промпта пройдёт два раза, и к концу недели у вас будет нечто лучшее, чем большинство сервисов по $50 в месяц.