Models and your own key
ReviewGate runs on your model. The provider sits behind an abstraction: Anthropic's cloud, any OpenAI-compatible endpoint, a cheaper model, or a local one inside your own network.
Yandex AI Studio
One of the OpenAI-compatible providers, useful when your data must stay inside a particular jurisdiction. You need an API key of a service account (the ai.languageModels.user role) and a folder (folder_id). The default model is Qwen3-235B and the endpoint is filled in automatically.
LLM_PROVIDER=yandex
LLM_API_KEY=<the API key of a YC service account>
LLM_FOLDER_ID=b1g... # the Yandex Cloud folder
# the Qwen3-235B model and the llm.api.cloud.yandex.net endpoint are the defaultsx-data-logging-enabled: false, so the requests are not logged on Yandex's side. For a strict «the code never leaves our network», use a local model, below.Anthropic's cloud
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
ANTHROPIC_MODEL=claude-opus-4-8 # cheaper: claude-sonnet-4-6 / claude-haiku-4-5| model | when |
|---|---|
| claude-opus-4-8 | maximum quality (the default; code review is sensitive to how good the model is) |
| claude-sonnet-4-6 | a balance of price and quality |
| claude-haiku-4-5 | cheap and fast for large volumes. This model does not support the reasoning mode — ReviewGate repeats the request in a simplified form by itself and says so in the summary: there will be fewer findings and they will be shallower |
A bonus of the Anthropic path is prompt caching: the system block of the prompt is cached, and repeat reviews in the same repository read it from the cache for roughly a tenth of the input price; the judge reuses the same prefix.
A local model
In an air-gapped deployment nothing may leave at all. Ollama and vLLM expose an OpenAI-compatible API, and the bot talks to it directly, without a separate gateway. A quick start with Ollama: ollama pull qwen3-coder:30b-a3b-q8_0, then point the bot at the endpoint:
LLM_PROVIDER=ollama # an OpenAI-compatible provider
LLM_BASE_URL=http://localhost:11434/v1 # endpoint Ollama (или vLLM)
LLM_MODEL=qwen3-coder:30b-a3b-q8_0 # the model tag
# LLM_API_KEY= # Ollama needs none; OpenRouter/OpenAI require it
LLM_TIMEOUT_MS=900000 # a very slow local model (the default is 600000)
REVIEW_CONCURRENCY=1 # SET IT EXPLICITLY: the default is 3, but Ollama serves one at a time (vLLM more)REVIEW_CONCURRENCY (3 by default). With a local model this value must be lowered to what your inference actually sustains: Ollama serves requests one at a time out of the box, so set 1 for it (parallelism is enabled separately, see OLLAMA_NUM_PARALLEL); vLLM can carry several requests on one card (continuous batching), so go by its real throughput and your spare VRAM. A number above what the hardware can do will not speed reviews up — the queue simply moves from the bot to the GPU. On a cloud provider the guide is your RPM/TPM limits; the parameter itself tops out at 64. The cheat sheet for cloud providers is below.Reaching the provider through a proxy
If your network cannot reach the provider directly — a corporate egress policy, a regional block — give the bot an HTTP(S) CONNECT proxy: it will route only the model requests through it. The tunnel is blind: TLS to the provider stays end to end, and the proxy sees the host, never the code or the diff.
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-...
LLM_PROXY=http://user:pass@proxy.example.com:8888 # слепой CONNECT-туннельSeveral providers (multi-vendor)
An ensemble review (llm.generators / llm.judges / llm.arbiter) can spread the roles across different vendors: the main generator on Claude, the second on DeepSeek, the arbiter on Anthropic's strongest model. Different models see different problems, which raises the recall of the review, while the arbiter holds precision.
An extra vendor is declared as a named backend in the deployment environment: LLM_BACKEND_<NAME>_BASE_URL / _API_KEY / _MODEL / _PROVIDER / _PROXY / _JSON_MODE / _MAX_TOKENS / _TIMEOUT_MS / _BUDGET_TOKENS (NAME is latin letters and digits without underscores; the name default is reserved — it always addresses the deployment's main provider, configured with the flat LLM_* variables). In .reviewgate/config.yml a role references a backend by name: backend: deepseek — the keys and addresses stay with the operator and cannot be overridden from a repository; backend: default addresses the main provider explicitly.
# .env — a named backend (the keys stay with the operator)
LLM_BACKEND_DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
LLM_BACKEND_DEEPSEEK_API_KEY=sk-...
LLM_BACKEND_DEEPSEEK_MODEL=deepseek-v4-flash # or deepseek-v4-pro
LLM_BACKEND_DEEPSEEK_JSON_MODE=none # rejects json_schema; json_object returns empty content on long prompts
LLM_BACKEND_DEEPSEEK_MAX_TOKENS=64000 # the reasoning eats the same ceiling as the answer
# .reviewgate/config.yml — review roles across different vendors
llm:
generators:
- model: claude-sonnet-4-6 # pass 1 — the main vendor
- backend: deepseek # pass 2 — independent, another vendor
judges:
- model: claude-opus-4-8 # the judge: weighs the union and collapses duplicates_BUDGET_TOKENS is the token budget of a run for that backend (input + output + cache). A company policy limits the expensive cloud vendors; there is no point limiting local ones — no variable, no limit. The thresholds are fixed (80% a notice · 100% a loud notice, with the review still completing · 300% a stop that publishes what was collected) and cannot be overridden by users; the limits are unavailable from a repository config.yml — this is an operator knob. More in what to do when a run stops on budget.LLM_PROXY does not extend to named backends: if one of them needs a proxy, set the backend's own _PROXY. And remember that the diff goes to every vendor you choose — assess their data processing policy exactly as you did for the main one. If a provider does not accept a strict JSON schema (response_format: json_schema), set _JSON_MODE=none: the answer shape is then held by the prompt and the parser. DeepSeek is the live example — it rejects json_schema, and its json_object returns an empty answer on a real review run (a long prompt — the JSON lands in the reasoning). Reasoning models also spend the output ceiling on their thinking — give the backend its own _MAX_TOKENS (64000 for DeepSeek v4; the same number stays within the Sonnet 5 ceiling).Parallel reviews (REVIEW_CONCURRENCY)
Several requests opened at once are carried in parallel — up to three by default (REVIEW_CONCURRENCY=3, the allowed range is 1–64). A team of about ten developers or more should raise the value at installation time, otherwise requests wait for each other at peak hours. Within that range the ceiling is set not by the bot but by your model: a review is a token-heavy request (the input is often 50–150 thousand tokens, and an ensemble makes several calls per request), so with cloud providers you usually hit the tokens per minute limit rather than the request limit.
| cloud provider | what limits the parallelism | where to look |
|---|---|---|
| Anthropic | usage tiers (they grow with what you have paid so far): separate limits on requests (RPM) and on input/output tokens per minute (ITPM/OTPM). On the lower tiers the tokens may not even cover one large review without pauses — workable parallelism starts around tier 2–3. On current models cache reads do not count towards ITPM, and the bot caches the system prompt automatically, which noticeably raises the real throughput | Console → Limits |
| OpenAI | the same mechanics: tier RPM/TPM limits per model | Platform → Limits |
| DeepSeek | publishes no hard limits — under load it slows answers down dynamically: parallelism works, but the response time drifts | docs API |
| Yandex AI Studio | cloud quotas per folder (requests per second, concurrent generations); they are raised through a quota increase request | the YC console → Quotas |
| OpenRouter | the limits depend on the key and balance and on the provider the model is routed to | the OpenRouter dashboard |
Tuning
LLM_EFFORT=high # low | medium | high | xhigh | max
LLM_MAX_TOKENS=16000 # the cap on output tokens
LLM_DIFF_CHAR_BUDGET=400000 # the character budget for the diff in the prompt (~100K tokens)
LLM_CACHE_TTL=1h # the prompt cache TTL (Anthropic only): 1h | 5m | off