SSD Nodes Learn 🎉 VPS dari $5.50/bln
Panduan Matt ConnorOleh Matt Connor · Dikemas kini 2026-08-13

Cara Host Sendiri AI PR Review Agent di VPS

Kawal privasi kod anda dengan menjalankan ejen semakan PR di VPS sendiri. Panduan ini merangkumi konfigurasi runner, penapis diff, komen inline, dan kos sebenar setiap PR.

Fungsi ejen semakan PR yang dihoskan sendiri

Ejen semakan PR yang dihoskan sendiri ialah program kecil pada pelayan milik anda. Ia membaca diff bagi pull request (PR) dan hanya menghantar baris yang berubah kepada model. Hasil maklum balas yang diterima akan disiarkan sebagai komen semakan dalam talian. Ia tidak pernah melakukan checkout pada branch anda, dan ia tidak pernah membaca fail yang tidak disentuh oleh pull request tersebut. Satu-satunya kelayakan yang dipegang ialah satu kunci API (application programming interface) model dan satu token yang hanya boleh memberikan komen tanpa kebenaran lain.

Model boleh membaca diff. Bahagian itu sudah diselesaikan. Perkara yang penting ialah ke mana diff tersebut pergi dan siapa yang memegang kuncinya. Bot semakan yang dihoskan oleh pihak ketiga bermakna setiap diff daripada setiap repositori peribadi akan keluar dari rangkaian anda, disimpan dalam log pihak ketiga, dan tertakluk kepada polisi pengekalan data mereka. Pada VPS (virtual private server) milik anda, diff dihantar dari GitHub ke pelayan anda kemudian ke API model, dan anda boleh membaca empat puluh baris kod yang menentukan perkara yang dihantar.

Keperluan sebelum bermula

  • Sebuah VPS yang menjalankan Ubuntu 24.04 dengan GitHub Actions runner yang dihoskan sendiri yang telah didaftarkan pada repositori. Berikan label tambahan pr-review semasa anda mendaftarkannya, kerana aliran kerja di bawah akan memilih berdasarkan label tersebut.
  • Kunci API Anthropic daripada Claude Console.
  • Sebuah repositori di mana anda mengawal siapa yang boleh membuka pull request. Repositori peribadi adalah pilihan yang paling mudah. Bahagian fork di bawah merangkumi kes repositori awam, dan jawapan di sana kurang selesa.

Memasang reviewer pada VPS

Servis runner berjalan sebagai akaun tanpa keistimewaan yang anda cipta semasa menjalankan ./svc.sh install. Pasang reviewer di bawah akaun yang sama supaya tugasan boleh melaksanakannya tanpa sudo. Gantikan runner di bawah dengan nama akaun anda.

sudo apt update && sudo apt install -y gh python3-venv
sudo install -d -m 755 -o runner -g runner /opt/pr-review
sudo -u runner python3 -m venv /opt/pr-review/venv
sudo -u runner /opt/pr-review/venv/bin/pip install anthropic
gh --version

gh --version mencetak gh version 2.45.0 pada Ubuntu 24.04 setakat Ogos 2026. Sebarang keluaran daripada 2.20 dan seterusnya mempunyai flag --input yang digunakan di bawah. Mesej Command 'gh' not found bermaksud komponen universe tidak didayakan, jadi jalankan sudo add-apt-repository universe dan cuba lagi.

Lokasi kunci dan token

Dua rahsia, dua tempoh hayat yang berbeza. Tiada satu pun yang boleh dimasukkan ke dalam repositori.

ANTHROPIC_API_KEY ialah rahsia repositori, ditetapkan di bawah Settings, kemudian Secrets and variables, seterusnya Actions. GitHub menyulitkan rahsia ini dan menyuntiknya ke dalam persekitaran langkah (step) semasa masa jalan. Ia tidak pernah menjadi fail pada cakera dan tidak pernah wujud dalam sejarah git.

GITHUB_TOKEN berfungsi secara berbeza. Actions menjana token baharu bagi setiap tugasan dan memusnahkannya apabila tugasan tamat. Apa yang boleh dilakukan oleh token tersebut ditetapkan oleh blok permissions: dalam aliran kerja (workflow), jadi di sinilah prinsip keistimewaan paling rendah (least privilege) sebenarnya dilaksanakan:

permissions:
  contents: read
  pull-requests: write

Token tersebut boleh menghantar ulasan. Ia tidak boleh menolak (push) komit, menggabungkan (merge) cawangan, menyunting fail aliran kerja, atau menyentuh repositori lain. Ejen yang boleh memberi ulasan ialah penyemak (reviewer). Ejen yang boleh melakukan push ialah komiter (committer), dan tiada sesiapa pun yang bersetuju dengan perkara itu. Kendalikan kunci model dengan berhati-hati yang sama, kerana ia menggunakan wang dalam akaun anda. Terdapat lebih banyak maklumat mengenai bentuk masalah ini dalam menjauhkan rahsia daripada capaian ejen AI.

Actions menggantikan rentetan rahsia yang tepat dengan *** dalam log tugasan. Ia hanya memadankan rentetan yang tepat sahaja, jadi kunci yang anda kodkan dengan base64, dipecahkan kepada dua baris, atau dicetak satu aksara demi satu aksara akan kelihatan dalam bentuk teks jelas. Jangan tambah langkah nyahpepijat (debug) yang memaparkan kandungan persekitaran.

Mengapa pull request daripada fork tidak pernah melihat kunci API anda

Peraturan GitHub adalah ringkas: kecuali GITHUB_TOKEN, rahsia (secrets) tidak dihantar kepada runner apabila aliran kerja (workflow) dicetuskan daripada repositori yang di-fork. Oleh itu, pull_request yang dijalankan daripada fork memulakan skrip anda tanpa ANTHROPIC_API_KEY, dan panggilan API pertama akan gagal dengan invalid x-api-key.

Penyelesaian yang kelihatan mudah adalah dengan menukar pencetus kepada pull_request_target, yang berjalan dalam konteks repositori asas dan sememangnya menerima rahsia tersebut. Jangan lakukan perkara itu di sini. Panduan keselamatan GitHub sendiri menyatakan bahawa aliran kerja tersebut "adalah berkeistimewaan, yang bermaksud ia berkongsi cache cawangan utama yang sama dengan pencetus aliran kerja berkeistimewaan lain, serta mungkin mempunyai akses tulis repositori dan akses kepada rahsia yang dirujuk", dan hasilnya "boleh dieksploitasi untuk mengambil alih repositori".

Panduan yang sama menyatakan dengan jelas tentang runner: "Runner yang dihoskan sendiri (self-hosted runners) hampir tidak boleh digunakan untuk repositori awam di GitHub, kerana mana-mana pengguna boleh membuka pull request terhadap repositori tersebut dan menjejaskan persekitaran."

Perkara ini mendorong dua pilihan reka bentuk. Tugasan ini membawa pengawal supaya ia hanya berjalan pada cawangan yang ditolak (pushed) ke repositori anda sendiri. Dan aliran kerja tersebut tidak mempunyai langkah actions/checkout sama sekali. Ejen tidak pernah menyimpan cawangan tersebut pada cakera, jadi pull request yang berniat jahat hanyalah teks yang dihantar kepada model. Ia tidak boleh menjalankan skrip binaan pada VPS anda, kerana tiada apa-apa pada VPS anda yang pernah menjalankannya. Walau bagaimanapun, teks tidak bermakna ia tidak berbahaya: diff yang ditulis oleh orang asing adalah input yang tidak dipercayai yang sampai ke model, sempadan kepercayaan yang sama yang anda temui apabila anda memberikan ejen carian web, dan satu-satunya perkara yang mengekang perkara itu di sini ialah ejen ini tidak boleh melakukan apa-apa selain menyiarkan komen.

Dapatkan diff, bukan repositori

Satu permintaan akan mendapatkan keseluruhan diff sebagai teks biasa.

export GH_TOKEN=your_token   # in the workflow this comes from secrets.GITHUB_TOKEN
gh api /repos/OWNER/REPO/pulls/42 -H "Accept: application/vnd.github.diff"

Jenis media Accept: application/vnd.github.diff adalah perkara yang menukarkan respons daripada objek JSON yang menerangkan pull request kepada unified diff itu sendiri, dan gh api mencetak badan tersebut tanpa perubahan. Baris pertama yang anda lihat sepatutnya bermula dengan diff --git a/. gh: Not Found (HTTP 404) bermaksud token tidak dapat melihat repositori, yang pada fine-grained personal token hampir selalu bermaksud kebenaran Pull requests tidak diberikan.

Tapis sebelum anda menggunakan token

Bahagian ini menentukan perbezaan antara bot yang dibaca oleh pengguna dan bot yang disenyapkan. Setiap penapis di bawah dijalankan sebelum model melihat satu bait pun.

  • Penapis laluan (Path filters). Kunci fail, direktori vendor, bundle yang diminifikasi dan kod yang dijana. Komen model pada package-lock.json hanyalah gangguan, dan fail tersebut selalunya merangkumi kebanyakan bait dalam sesuatu diff.
  • Had saiz (Size cap). Jika melebihi had, langkau semakan dan keluar dengan status berjaya. Refactor sebanyak 4,000 baris akan mendapat satu baris jujur yang menyatakan ia terlalu besar untuk disemak secara automatik, bukannya enam puluh tekaan.
  • Ambang keterukan dan had komen. Laporkan penemuan tahap tinggi dan sederhana, sehingga sepuluh penemuan, dengan keutamaan diberikan kepada tahap keterukan tertinggi. Tiada siapa yang membaca komen kesebelas.

Skrip tersebut

Simpan ini sebagai /opt/pr-review/review.py. Ia membaca konfigurasinya daripada persekitaran, supaya aliran kerja boleh menukar model tanpa perlu mengubah kod.

#!/usr/bin/env python3
"""Review only the changed lines of one pull request."""
import json
import os
import subprocess
import sys

import anthropic

REPO = os.environ["GITHUB_REPOSITORY"]
PR = os.environ["PR_NUMBER"]
MODEL = os.environ.get("REVIEW_MODEL", "claude-haiku-4-5-20251001")
MAX_DIFF_BYTES = int(os.environ.get("MAX_DIFF_BYTES", "120000"))
MIN_SEVERITY = os.environ.get("MIN_SEVERITY", "medium")
MAX_COMMENTS = 10
RANK = {"low": 0, "medium": 1, "high": 2}
SKIP = ("package-lock.json", "poetry.lock", "/vendor/", "/node_modules/", ".min.js")

raw_diff = subprocess.run(
    ["gh", "api", f"/repos/{REPO}/pulls/{PR}",
     "-H", "Accept: application/vnd.github.diff"],
    check=True, capture_output=True, text=True,
).stdout

Memisahkan diff mengikut fail adalah perkara yang membolehkan penapisan laluan (path filtering). Menomborkan setiap baris adalah perkara yang membolehkan ulasan semakan diletakkan dengan tepat. GitHub hanya menerima ulasan sebaris pada baris yang merupakan sebahagian daripada diff, jadi model tersebut perlu memetik nombor baris yang sebenar. Memberikan nombor tersebut kepadanya bermakna ia boleh menyalin nombor yang sedia ada dan bukannya mencipta nombor baharu.

def per_file(diff_text):
    """Split a unified diff into one string per file."""
    sections, current = [], []
    for line in diff_text.splitlines():
        if line.startswith("diff --git ") and current:
            sections.append("\n".join(current))
            current = []
        current.append(line)
    if current:
        sections.append("\n".join(current))
    return sections


def annotate(section):
    """Prefix every line that exists in the new file with its line number."""
    out, n, in_hunk = [], 0, False
    for line in section.splitlines():
        if line.startswith("@@"):
            n = int(line.split("+")[1].split(",")[0].split(" ")[0])
            in_hunk = True
            out.append(line)
        elif not in_hunk or line.startswith(("-", "\\")):
            out.append(line)
        else:
            out.append(f"{n}\t{line}")
            n += 1
    return "\n".join(out)


kept = [s for s in per_file(raw_diff)
        if not any(p in s.split("\n", 1)[0] for p in SKIP)]
payload = "\n".join(annotate(s) for s in kept)

if not payload.strip():
    print("every changed file was filtered out")
    raise SystemExit(0)
if len(payload) > MAX_DIFF_BYTES:
    print(f"diff is {len(payload)} bytes, over the {MAX_DIFF_BYTES} cap")
    raise SystemExit(0)

Pengepala hunk membawa penomboran tersebut. @@ -12,7 +12,9 @@ menyatakan bahawa hunk fail baharu bermula pada baris 12, jadi pembilang bermula di situ dan bertambah pada baris yang ditambah dan tidak berubah sahaja. Baris yang dibuang tidak dinomborkan kerana ia tidak wujud dalam fail baharu. Pengawal pada baris yang bermula dengan garis miring terbalik (backslash) melangkau penanda no-newline yang ditulis oleh git pada penghujung fail, yang jika tidak, akan menyebabkan setiap nombor berikutnya beralih sebanyak satu.

Kedua-dua exit menggunakan status 0, bukan 1. Pull request yang ditapis atau bersaiz besar harus menunjukkan tanda semak hijau. Tanda semak merah yang tidak boleh diambil tindakan oleh manusia akan diabaikan, dan apabila satu semakan diabaikan, kesemuanya akan diabaikan.

SYSTEM = (
    "You review one pull request diff. Every line that exists in the new file is "
    "prefixed with its line number and a tab character. "
    "Report only defects you can see in the lines shown: a crash, a resource leak, "
    "a security mistake, a wrong boundary condition, a broken contract with code "
    "that is visible in this diff. Do not comment on style, naming or formatting. "
    "Do not guess about code you cannot see. Leave out anything you are not "
    "certain about. An empty findings list is a normal and common answer. "
    'Reply with JSON only, in this shape: {"findings": [{"path": "src/app.py", '
    '"line": 42, "severity": "high", "comment": "what is wrong, then why"}]} '
    "Every line number must be one you can see in the left column of that file."
)

client = anthropic.Anthropic()
message = client.messages.create(
    model=MODEL,
    max_tokens=2000,
    system=SYSTEM,
    messages=[{"role": "user", "content": payload}],
)
print(f"stop={message.stop_reason} in={message.usage.input_tokens} "
      f"out={message.usage.output_tokens}", file=sys.stderr)

text = message.content[0].text
findings = json.loads(text[text.find("{"):text.rfind("}") + 1])["findings"]
findings = [f for f in findings if RANK.get(f["severity"], 0) >= RANK[MIN_SEVERITY]]
findings.sort(key=lambda f: -RANK.get(f["severity"], 0))
del findings[MAX_COMMENTS:]

if not findings:
    print("nothing above the severity threshold; posting no comment")
    raise SystemExit(0)

review = {
    "event": "COMMENT",
    "body": f"Automated review of the changed lines. {len(findings)} finding(s).",
    "comments": [
        {"path": f["path"].removeprefix("b/"), "line": f["line"], "side": "RIGHT",
         "body": f"**{f['severity']}** {f['comment']}"}
        for f in findings
    ],
}
subprocess.run(
    ["gh", "api", "-X", "POST", f"/repos/{REPO}/pulls/{PR}/reviews", "--input", "-"],
    input=json.dumps(review), text=True, check=True,
)

Tiga perincian dalam blok tersebut adalah penting. JSON dipotong antara { yang pertama dan } yang terakhir kerana model kadangkala akan membalut jawapannya dalam code fence, dan json.loads akan gagal memproses fence tersebut. path dilucutkan daripada b/ di bahagian hadapan, memandangkan awalan tersebut datang daripada pengepala diff dan GitHub memerlukan laluan yang relatif kepada repositori. Dan --input - menghantar keseluruhan semakan sebagai satu panggilan API, supaya sepuluh penemuan sampai sebagai satu pemberitahuan dan bukannya sepuluh.

Apabila tiada apa-apa untuk dilaporkan, skrip tersebut tidak menghantar apa-apa. Bot yang menulis "tiada isu ditemui" pada setiap pull request mengajar orang ramai untuk melangkau mesej tersebut, dan akhirnya mereka akan melangkau mesej yang benar-benar penting.

Integrasikan ke dalam aliran kerja

Simpan ini sebagai .github/workflows/pr-review.yml:

name: pr-review

on:
  pull_request:
    types: [opened, synchronize, reopened]
    paths-ignore:
      - '**.md'
      - 'docs/**'

permissions:
  contents: read
  pull-requests: write

concurrency:
  group: pr-review-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  review:
    if: github.event.pull_request.head.repo.full_name == github.repository && !contains(github.event.pull_request.labels.*.name, 'no-ai-review')
    runs-on: [self-hosted, linux, pr-review]
    steps:
      - name: Review the changed lines
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
          REVIEW_MODEL: claude-haiku-4-5-20251001
          MIN_SEVERITY: medium
        run: /opt/pr-review/venv/bin/python /opt/pr-review/review.py

GITHUB_REPOSITORY tidak berada dalam blok env: tersebut kerana Actions telah menetapkannya untuk setiap tugasan secara automatik. Kumpulan concurrency penting untuk kos: tanpanya, menghantar tiga pembaikan pantas ke satu cawangan akan menjalankan tiga semakan penuh dan anda perlu membayar untuk kesemuanya, manakala dengannya hanya yang terakhir akan dikekalkan.

Baris if: melakukan dua tugas. Bahagian pertama melangkau pull request daripada fork, yang akan gagal walau bagaimanapun kerana ketiadaan kunci. Bahagian kedua memberikan pasukan anda suis pemati: tambahkan label no-ai-review pada pull request dan tugasan tersebut tidak akan dijalankan.

Buka pull request dan perhatikan apa yang berlaku:

gh run list --workflow=pr-review.yml --limit 3
gh run view --log
gh pr view 42 --comments

Larian yang selesai dalam beberapa saat dengan nothing above the severity threshold; posting no comment dalam log bermakna ia berfungsi dengan betul. Pada pull request yang kecil dan bersih, itulah hasil yang dijangkakan.

Berapakah kos semakan pull request automatik?

Diff merangkumi hampir keseluruhan input, jadi saiz diff menentukan harga. Di bawah adalah satu diff 500 baris yang diukur berserta system prompt, dikira menggunakan endpoint pengiraan token dan bukannya anggaran.

ChartTokens for one 500 line pull request diff, measured August 2026
The data behind this chart
[
  {
    "label": "Haiku 4.5",
    "input_tokens": "8,000",
    "output_tokens": "1,200"
  },
  {
    "label": "Sonnet 5",
    "input_tokens": "10,400",
    "output_tokens": "1,560"
  },
  {
    "label": "Opus 5",
    "input_tokens": "10,400",
    "output_tokens": "1,560"
  }
]

Diff tersebut menghasilkan 8,000 token input pada Haiku 4.5 dan 10,400 pada Sonnet 5. Teks yang sama, kiraan yang berbeza. Model Claude dari 4.7 ke atas menggunakan tokenizer baharu yang menghasilkan kira-kira 30% lebih banyak token untuk input yang sama, seperti yang didokumenkan oleh Anthropic pada halaman harga mereka. Ambil kira perkara ini apabila anda membandingkan model baharu dengan model lama berdasarkan harga per juta token sahaja.

Harga senarai setakat Ogos 2026: Haiku 4.5 ialah $1 per juta token input dan $5 per juta output. Sonnet 5 ialah $2 dan $10 di bawah harga pengenalan yang berlangsung sehingga 31 Ogos 2026, kemudian menjadi $3 dan $15. Opus 5 ialah $5 dan $25.

ChartCost of that one review at list prices, August 2026
The data behind this chart
[
  {
    "label": "Haiku 4.5",
    "cost_per_pr_cents": 1.4,
    "cost_200_prs_usd": "2.80"
  },
  {
    "label": "Sonnet 5",
    "cost_per_pr_cents": 3.64,
    "cost_200_prs_usd": "7.28"
  },
  {
    "label": "Opus 5",
    "cost_per_pr_cents": 9.1,
    "cost_200_prs_usd": "18.20"
  }
]

Ini adalah 1.4 sen bagi setiap pull request pada Haiku 4.5 dan 9.1 sen pada Opus 5. Pasukan yang menggabungkan 200 pull request sebulan membayar kira-kira $2.80 pada Haiku 4.5, $7.28 pada Sonnet 5, atau $18.20 pada Opus 5. Mulai 1 September 2026, darabkan baris Sonnet 5 dengan 1.5.

Dua perkara menyebabkan bil sebenar melebihi anggaran tersebut. synchronize mencetuskan semakan pada setiap push, jadi cawangan aktif dengan lapan push menelan kos lapan semakan, dan peraturan konkurensi hanya membantu apabila push berlaku dalam masa yang rapat. Angka-angka ini juga mengandaikan penapis laluan berfungsi: satu fail kunci yang tidak ditapis boleh menggandakan input dengan sendirinya.

Prompt caching tidak membantu di sini. Awalan yang dicache mestilah sama bait antara panggilan, dan diff adalah berbeza setiap kali. System prompt adalah satu-satunya bahagian yang stabil, dan ia berada jauh di bawah panjang minimum yang boleh dicache. Untuk peraturan umum, lihat bila prompt caching berbaloi, dan untuk memilih antara tiga model di atas, model Claude mana yang perlu digunakan untuk tugas yang mana.

Ukur diff anda sendiri sebelum mengaktifkannya

Tambah baris ini selepas payload dibina, kemudian jalankan skrip secara manual terhadap beberapa pull request bulan lepas:

print(client.messages.count_tokens(
    model=MODEL, system=SYSTEM, messages=[{"role": "user", "content": payload}]
).input_tokens)

Endpoint kiraan tidak menjalankan model, jadi ia tidak menggunakan token input atau output, dan ia menggunakan tokenizer yang dimiliki oleh model yang anda namakan. Jalankannya ke atas sepuluh pull request sebenar daripada repositori anda sendiri dan ambil median dan bukannya purata, supaya satu migrasi besar tidak memesongkan anggaran.

Mengapa bot semakan disenyapkan, dan cara untuk mengelakkannya

Dua kelakuan memusnahkan kepercayaan terhadap bot ini, dan kedua-duanya mempunyai penyelesaian dalam kod di atas.

Menyemak segala-galanya serentak. Bot yang meninggalkan empat puluh komen tidak akan dibaca langsung. Ambang keterukan dan had sepuluh komen bukanlah soal kesopanan, ia adalah perkara yang memastikan penemuan sebenar kekal kelihatan. Menyusun mengikut keterukan sebelum memotong bermakna had tersebut akan menggugurkan penemuan yang paling kurang penting dan bukannya sepuluh penemuan rawak.

Memberi komen dengan yakin tentang sesuatu yang tidak dapat diperiksa. Ini adalah perkara yang membuatkan jurutera mematikannya terus. Model yang ditunjukkan 200 baris daripada 40,000 baris kod asas masih akan menulis "ini merosakkan pembatalan cache dalam redis_client.py" tentang fail yang tidak pernah dilihatnya. Prompt sistem menolak perkara ini dalam bahasa yang jelas: laporkan hanya kecacatan yang kelihatan dalam baris yang ditunjukkan, dan abaikan apa-apa yang anda tidak pasti. Menamakan kegagalan secara langsung berfungsi lebih baik daripada meminta ketepatan secara umum, dan memberitahu model bahawa hasil kosong adalah perkara biasa adalah apa yang menghalangnya daripada mereka-reka sesuatu untuk diperkatakan tentang perubahan dua baris.

Hantar semakan sebagai COMMENT, jangan sekali-kali sebagai REQUEST_CHANGES. Pendapat model tidak sepatutnya boleh menyekat penggabungan (merge), dan sebaik sahaja ia boleh berbuat demikian, seseorang yang mempunyai tarikh akhir akan membuang keseluruhan aliran kerja tersebut daripada berhujah dengannya.

Mod kegagalan, berserta rentetan yang akan anda lihat

HTTP 422 semasa menghantar ulasan. gh mencetak gh: Unprocessable Entity (HTTP 422) dan badan respons menamakan medan tersebut: Pull request review thread line must be part of the diff. GitHub tidak dapat menambat komen tersebut. Punca biasa ialah nombor baris yang direka oleh model, path yang masih membawa awalan b/, atau komen pada baris yang telah dibuang, yang memerlukan side ditetapkan kepada LEFT dan bukannya RIGHT. Cetak JSON ulasan sebelum menghantar dan semak satu komen secara manual berbanding diff.

invalid x-api-key daripada API model. Langkah ini gagal pada panggilan messages.create yang pertama. Sama ada rahsia ANTHROPIC_API_KEY tidak ditetapkan pada repositori, atau permintaan tarik (pull request) datang daripada fork sehingga Actions tidak menghantar sebarang rahsia. Pengawal fork dalam baris if: sepatutnya melangkau perkara ini, jadi semak baris itu dahulu.

gh: Resource not accessible by integration (HTTP 403). Token kerja tidak boleh menulis pada permintaan tarik. Tambahkan pull-requests: write pada blok permissions:. Jika ia sudah ada di sana, lihat Settings, kemudian Actions, kemudian General, di mana polisi organisasi boleh mengehadkan perkara yang boleh diminta oleh mana-mana token aliran kerja.

json.decoder.JSONDecodeError. Model tidak mengembalikan JSON yang boleh dihuraikan. Punca biasa ialah respons yang mencapai had token dan berhenti di tengah-tengah objek. Baris log mencetak stop_reason untuk perkara ini: nilai max_tokens bermaksud naikkan max_tokens atau rendahkan MAX_COMMENTS.

Aliran kerja tidak pernah berjalan. gh run list tidak menunjukkan apa-apa untuk permintaan tarik tersebut. Semak bahawa paths-ignore tidak menapis setiap fail yang diubah, kemudian semak pengawal fork dan pengawal label, kemudian sama ada runner aktif dengan sudo systemctl status 'actions.runner.*' pada VPS. Runner yang luar talian akan membiarkan kerja dalam baris gilir tanpa sebarang mesej ralat di mana-mana dalam permintaan tarik.

Setiap ulasan kembali kosong. Tetapkan MIN_SEVERITY kepada low untuk satu larian. Jika penemuan muncul, ambang (threshold) berfungsi dengan betul. Jika tiada apa-apa yang muncul, cetak payload dan sahkan bahawa penapis tidak membuang keseluruhan diff.

Menjalankannya bersama ejen anda yang lain

Reviewer ini bersaiz kecil, jadi anda mungkin terdorong untuk meletakkannya pada pelayan yang sudah menjalankan segala-galanya. Asingkan ia jika repositori tersebut penting. Proses ini memegang token yang boleh memberi komen pada kod anda dan kunci yang membelanjakan wang anda, manakala runner yang dihoskan sendiri sememangnya direka sebagai tempat untuk kod aliran kerja dilaksanakan. Akaun tanpa keistimewaan khusus tanpa hak sudo, pada hos yang tidak menjalankan apa-apa lagi, adalah garis dasar. Jika anda juga menjalankan ejen interaktif yang melakukan check out kod, VM pakai buang bagi setiap ejen adalah corak yang disyorkan, dan menjalankan ejen pengekodan pada VPS merangkumi persediaan umum. Jika Anthropic API adalah perkara baharu bagi anda, aplikasi Claude API pertama pada VPS adalah tempat yang lebih kecil untuk bermula berbanding ini.

FAQ

Adakah ejen semakan PR AI memerlukan akses tulis ke repositori saya?

Tidak. Ia memerlukan pull-requests: write untuk menghantar semakan dan contents: read untuk mengambil diff. Itu sahaja senarai lengkapnya, dan anda menetapkannya dalam blok permissions: pada aliran kerja, yang mengehadkan perkara yang boleh dilakukan oleh GITHUB_TOKEN bagi setiap tugasan. Dengan dua baris tersebut, ejen boleh memberikan komen pada pull request tetapi tidak boleh menolak (push) commit atau menggabungkan (merge) cawangan. Hantar semakan dengan event: COMMENT dan bukannya REQUEST_CHANGES supaya ia juga tidak boleh menyekat penggabungan.

Mengapa komen semakan saya gagal dengan HTTP 422?

GitHub hanya menerima komen semakan dalam talian pada baris yang merupakan sebahagian daripada diff pull request, dan mengembalikan Pull request review thread line must be part of the diff apabila ia bukan sebahagian daripadanya. Pastikan path adalah relatif kepada repositori tanpa awalan b/ daripada pengepala diff, dan nombor baris tersebut muncul di dalam hunk fail berkenaan. side mestilah RIGHT untuk baris yang ditambah atau tidak berubah, dan LEFT untuk baris yang dibuang. Meletakkan awalan nombor baris fail baharu pada setiap baris diff sebelum menghantarnya kepada model adalah langkah yang menghalang model daripada mencipta nombor sendiri sejak awal lagi.

Bolehkah saya menjalankan ini pada repositori awam dengan pull request daripada fork?

Tidak dengan reka bentuk ini. GitHub tidak menghantar rahsia (secrets) kepada aliran kerja yang dicetuskan daripada fork, jadi kunci model tiada dan pelaksanaan akan gagal. GitHub juga menyatakan bahawa self-hosted runner "hampir tidak boleh digunakan untuk repositori awam", kerana sesiapa sahaja boleh membuka pull request yang menyebabkan kod dijalankan pada mesin anda. Untuk projek awam, sama ada hadkan penyemak kepada cawangan yang ditolak ke repositori itu sendiri, iaitu fungsi kawalan if:, atau pindahkan langkah semakan ke GitHub-hosted runner dan terima hakikat bahawa diff tersebut keluar daripada infrastruktur anda sendiri.

Model manakah yang patut saya gunakan untuk semakan pull request?

Mulakan dengan Haiku 4.5. Membaca diff yang terhad terhadap senarai tetap jenis kecacatan bukanlah masalah penaakulan yang sukar, dan model paling murah memastikan bil bulanan berada pada angka yang tidak dipertikaikan oleh sesiapa. Beralih kepada Sonnet 5 jika anda mendapati ia terlepas pepijat sebenar dalam bahasa atau rangka kerja anda, dan ukur perkara itu daripada membuat andaian. Opus 5 adalah yang paling mahal antara ketiga-tiganya dengan margin yang besar bagi setiap pull request, yang lebih mudah untuk dijustifikasikan pada cawangan keluaran (release branch) berbanding setiap push ke setiap cawangan ciri (feature branch).