Research notes từ llm-as-a-verifier và TurboAgent. Bỏ qua mọi phân tích cost. Giả sử cost = 0. Câu hỏi duy nhất: nó giải quyết được vấn đề gì?
Vấn đề cốt lõi: LLM không biết khi nào nó sai
LLM có một đặc tính ít người nói thẳng: mỗi lần generate là một lần gamble.
Cùng một prompt “viết function reverse string”, gọi 5 lần liên tiếp, bạn có thể nhận:
def rev(s): return s[::-1] # đúng, idiomatic
def rev(s): return ''.join(reversed(s)) # đúng, chậm hơn
def rev(s): return s[::-1][:-1] # sai logic, mất ký tự cuối
def rev(s): return s.reverse() # bug: list.reverse() trả None
def rev(s): return s[::-1] # đúng
Bạn chỉ nhận được 1 trong 5. Nếu xui, bạn nhận lần 3 hoặc 4. Không có warning, không có confidence score, không có gì cả.
Đây không phải bug. Đây là bản chất của sampling từ một phân phối xác suất. Và nó áp dụng cho mọi task LLM làm, từ code generation đến planning đến long-form writing.
Câu hỏi tự nhiên: Nếu generate 5 candidates, có cách nào tự động biết candidate nào tốt nhất không?
Câu trả lời ngắn: Cho LLM chấm chính output của nó
llm-verifier (PyPI package từ repo llm-as-a-verifier/llm-as-a-verifier) làm đúng một việc: dùng LLM đánh giá output của LLM, theo cách có cơ sở toán học.
Trick: Score trên logprobs, không phải argmax
LLM-as-a-Judge truyền thống hoạt động thế này:
Prompt: "Rate this code from 1-10"
Model output: "8"
→ Score = 8
Vấn đề: model chọn “8” không có nghĩa model tin “8” hơn “7”. Có thể logprob của “7” là 0.49 và “8” là 0.51 — winner gần như coin flip.
llm-verifier làm khác:
Prompt: "Rate this code from A to T"
Model outputs distribution: P(A)=0.01, P(B)=0.02, ..., P(T)=0.73
→ Score = Σ P(token) × φ(token) # φ maps A→0.05, ..., T→1.0
Score là expectation trên toàn bộ phân phối, không phải argmax. Smooth hơn, robust hơn, và quan trọng nhất: continuous — dùng được làm training signal.
Đây là chìa khóa. Nó biến “LLM judgment” từ discrete label thành continuous reward function.
Hai sản phẩm, hai tầng
Tầng 1: llm-verifier (framework gốc)
Package Python, MIT license, ~2.6k stars. Import và dùng trong code:
import llm_verifier
candidates = [
"def rev(s): return s[::-1]",
"def rev(s): return s",
"def rev(s): return ''.join(sorted(s))",
]
result = llm_verifier.select(
problem="Write a function that reverses a string.",
candidates=candidates,
criteria={"Correctness": "Does the code actually reverse the string?"},
)
print(result.index) # 0
print(result.scores) # [0.73104, 0.38446, 0.38449]
3 API chính:
| API | Mục đích | Khi nào dùng |
|---|---|---|
select(problem, candidates, criteria) | Best-of-N: rank N candidates, return winner | Bạn đã có pool outputs, cần pick tốt nhất |
compare(problem, a, b, criteria) | Pairwise reward: reward_a, reward_b ∈ [0,1] | RLHF labeling, preference data, cần raw signal |
track(problem, steps, checkpoint_steps) / ProgressTracker.update(step) | Per-step progress score trong trajectory | Agent đang chạy dài, cần biết “đang đi đúng hướng không” |
Tầng 2: TurboAgent (chat client plugin)
Repo llm-as-a-verifier/TurboAgent, ~99 stars, Apache-2.0. Đây là LLM API proxy wrap llm-verifier cho chat clients (Claude Code, Codex, opencode).
pip install turbo-agent
turbo-agent # starts on port 8888
# Point Claude Code at the proxy
ANTHROPIC_BASE_URL=http://localhost:8888 claude
Mỗi request đi qua pipeline:
Client request
│
[Context Refinement] (optional) rewrite/augment system prompt
│
[Concurrent Inference] send N parallel candidates to backend
│
[Verification] pivot tournament over candidates, pick best
│
Best response → Client
User không thấy gì khác biệt ngoài việc response thường đúng hơn. Built-in DAG visualizer ở http://localhost:8888/visualizer để debug.
5 use case thực tế (cost = 0)
1. Self-improvement loop cho agents
Agent chạy task N lần → N trajectories khác nhau → verifier rank → winner làm training signal hoặc “correct answer”.
Đây là use case paper focus nhiều nhất. Trên Terminal-Bench 2.1:
| Config | Pass@1 | LLM-as-a-Verifier | Oracle |
|---|---|---|---|
| Best-of-3 | 79.4% | 86.5% ± 1.1% | 92.1% |
| Best-of-5 | 78.7% | 88.0% ± 0.6% | 96.6% |
Verifier là chính model đó (DeepSeek judge DeepSeek rollouts). Không cần model khác, không cần human. Model tự verify tốt hơn pick random 9 điểm %.
Insight: Self-verification work. Không phải vì model “biết khi nào đúng”, mà vì averaging over many noisy signals gives you a cleaner signal.
2. Test-time scaling cho benchmarks
Model A có Pass@1 = 70%. Nếu generate 5 attempts, xác suất ít nhất 1 đúng = 1 - (1-0.7)^5 = 99.8%. Vấn đề: bạn không biết attempt nào đúng.
Verifier giải quyết: generate 5, chọn winner. Bạn được ~85-90% (gần oracle 92%, tức pick đúng thủ công).
Numbers across benchmarks (Gemini 2.5 Flash verifier):
| Benchmark | Pass@1 | LLM-as-a-Verifier | Oracle |
|---|---|---|---|
| Terminal-Bench V2 | 83.1% | 86.5% | 92.1% |
| SWE-Bench Verified | 76.1% | 78.2% | 84.4% |
| MedAgentBench | 70.2% | 73.3% | 75.0% |
Insight: Đây là cách nâng performance mà không cần train lại model. Đổi inference cost lấy quality.
3. Replace human evaluation trong RLHF
Trong RLHF, bạn cần người thật chấm “response A tốt hơn response B”. Tốn tiền, chậm, không scale.
compare() của llm-verifier tự động hóa: cho 2 outputs, trả về continuous rewards ∈ [0,1]. Smooth hơn LLM-as-a-Judge (discrete labels), dùng được làm training loss trực tiếp.
Insight: Continuous reward > discrete label. Smooth gradients khi dùng cho RL.
4. Progress monitoring cho long-running agents
Agent chạy 30 steps trên task phức tạp. Bạn muốn biết “nó đang converge không, có nên abort sớm không?”
tracker = llm_verifier.ProgressTracker(problem, n_evaluations=4)
score = tracker.update('Read the problem statement') # 0.00002
score = tracker.update('Wrote def rev(s): return s') # 0.00013
score = tracker.update('Changed to def rev(s): return s[::-1]') # 0.73938
score = tracker.update('Tested: rev("abc") returned "cba"') # 0.98604
if score < 0.05:
abandon_rollout() # hopeless, don't waste compute
Trong paper, failed trajectory có score thấp xuyên suốt (0.001-0.03), successful trajectory có score tăng dần (0.001 → 0.99). Distinguishable rõ ràng từ sớm.
Insight: Early abort based on progress score. Tránh waste compute trên hopeless rollouts.
5. Training data generation ở scale
Cần generate dataset lớn cho fine-tuning. Quality matters.
Workflow:
- Generate 10 candidates per prompt
- Verifier pick best 1
- Save to training set
Đảm bảo quality mà không cần human review từng sample.
Insight: Quality filter tự động ở scale.
Tại sao dùng LLM verify thay vì rule-based check?
Câu hỏi tự nhiên: “Tại sao không chạy tests?”
Vì không phải task nào cũng có tests:
- “Refactor code cho clean hơn” — test nào check “clean”?
- “Viết email professional hơn” — test nào check “professional”?
- “Plan architecture cho hệ thống mới” — test nào check architecture quality?
Và tests không cover mọi case:
- Agent có thể pass tests nhưng sai logic edge case
- Tests check behavior, không check intent
Verifier = cách dùng LLM “hiểu” task để chấm output. Dùng được cho open-ended, multi-modal, subjective tasks mà rule-based không reach được.
Constraint quan trọng: Verifier phải trả logprobs
llm-verifier yêu cầu backend trả token logprobs. Đây là constraint cứng.
Work:
- DeepSeek (deepseek-v4-flash) — rẻ nhất, key đơn giản
- Gemini via Vertex AI — match paper numbers, setup phức tạp hơn
- Self-hosted vLLM/SGLang serving open model (e.g. Qwen3.5-9B) — max control
Không work:
- Anthropic Messages API — không trả logprobs. Claude có thể là candidate model (generate), nhưng không thể là verifier (judge).
Đây là lý do TurboAgent chặn Anthropic làm verifier ở config level: raise error sớm thay vì fail downstream.
Kết luận
llm-verifier không phải tool để dùng cho mọi task. Nó giải quyết một class bài toán cụ thể: khi bạn cần verifiable quality mà không có cách nào khác để measure.
5 use case trên không mutually exclusive. Một hệ thống có thể:
- Generate N candidates (use case #2)
- Track progress để abort sớm (use case #4)
- Pick winner (use case #1)
- Save winner to training set (use case #5)
- Dùng winner’s quality signal cho future RLHF (use case #3)
Đó là kiến trúc self-improving agent: generate, verify, learn, repeat. llm-verifier là missing piece để close loop mà không cần human trong vòng.
Links
- llm-as-a-verifier repo — framework gốc
- TurboAgent repo — Claude Code plugin
- Paper (arXiv) — methodology chi tiết
- llm-verifier trên PyPI —
pip install llm-verifier - TurboAgent trên PyPI —
pip install turbo-agent