AI कोडिंग एजेंट के लिए GitHub PR जैसी कोड रिव्यू
Potato में GitHub PR जैसी कोड रिव्यू एनोटेशन सेट करें, जिसमें इनलाइन diff टिप्पणियाँ, फ़ाइल-स्तरीय गुणवत्ता रेटिंग, और कोडिंग एजेंट के आउटपुट पर approve या reject का फ़ैसला शामिल है।
कोड रिव्यू एनोटेशन क्यों मायने रखता है
ज़्यादातर कोडिंग एजेंट बेंचमार्क मूल्यांकन को एक बाइनरी सवाल तक सीमित कर देते हैं: टेस्ट पास हुए या नहीं? SWE-bench हल किए गए इशू का प्रतिशत बताता है। HumanEval pass@k बताता है। लीडरबोर्ड के लिए ये आँकड़े काम के हैं, पर कोड की गुणवत्ता समझने के लिए बेकार हैं।
कोई एजेंट हर टेस्ट पास कर सकता है और फिर भी ऐसा कोड लिख सकता है जिसे कोई मेंटेन नहीं करना चाहेगा -- सुरक्षा में छेद वाला कोड, धीमा रास्ता, या ऐसी शैली जो बाक़ी कोडबेस से टकराती हो। कोई मानव रिव्यूअर उस PR पर बदलाव माँगेगा, भले ही टेस्ट हरे हों। अगर आप ऐसे एजेंट चाहते हैं जिनका कोड लोग सचमुच मर्ज करें, तो सिर्फ़ टेस्ट चलाना काफ़ी नहीं, कोड पढ़ना पड़ेगा।
Potato की code_review एनोटेशन योजना GitHub PR रिव्यू का अनुभव एक एनोटेशन टूल के भीतर ले आती है। एनोटेटर सिंटैक्स हाइलाइटिंग सहित unified diff देखते हैं, diff की किसी पंक्ति पर क्लिक करके इनलाइन टिप्पणी जोड़ते हैं, हर फ़ाइल को कुछ गुणवत्ता आयामों पर रेट करते हैं, और approve, request-changes या comment का फ़ैसला देते हैं -- ठीक वैसे ही जैसे किसी असली pull request की समीक्षा करते समय। योजना के पूरे संदर्भ के लिए कोडिंग एजेंट एनोटेशन दस्तावेज़ और एजेंट मूल्यांकन गाइड देखें।
Potato का कोड रिव्यू इंटरफ़ेस, जिसमें इनलाइन diff टिप्पणियाँ और फ़ाइल-स्तरीय रेटिंग दिख रही हैं:
इनलाइन diff टिप्पणियों और फ़ाइल-स्तरीय गुणवत्ता रेटिंग के साथ Potato का कोड रिव्यू इंटरफ़ेस
कोड रिव्यू योजना का सार
code_review योजना की तीन परतें हैं:
- इनलाइन diff टिप्पणियाँ: एनोटेटर diff की किसी भी पंक्ति पर क्लिक करके श्रेणीबद्ध टिप्पणी जोड़ते हैं (bug, style, performance, security, logic, suggestion, question)
- फ़ाइल-स्तरीय रेटिंग: बदली गई हर फ़ाइल को शुद्धता (1-5) और कोड गुणवत्ता (1-5) के लिए अलग-अलग रेटिंग मिलती है
- कुल फ़ैसला: एनोटेटर आख़िरी फ़ैसला देता है: approve, request changes, या सिर्फ़ comment
यह असली कोड रिव्यू की नक़ल है, इसलिए डेवलपरों को स्वाभाविक लगता है, और इससे बनने वाला संरचित आउटपुट सीधे कोड रिव्यू मॉडल के प्रशिक्षण में बैठ जाता है।
CodingTraceDisplay: diff कैसे रेंडर होते हैं
CodingTraceDisplay कंपोनेंट कोडिंग एजेंट ट्रेस को टूल कॉल और उनके आउटपुट के क्रम के रूप में रेंडर करता है, और फ़ाइल संपादनों को ख़ास तरीक़े से दिखाता है। जब एजेंट कोई फ़ाइल बदलता है, तो डिस्प्ले एक unified diff दिखाता है जिसमें:
- लाल पंक्तियाँ: हटाई गई पंक्तियाँ (
-से शुरू) - हरी पंक्तियाँ: जोड़ी गई पंक्तियाँ (
+से शुरू) - धूसर पंक्तियाँ: संदर्भ पंक्तियाँ (अपरिवर्तित)
- पंक्ति संख्याएँ: गटर में पुरानी और नई, दोनों पंक्ति संख्याएँ
- सिंटैक्स हाइलाइटिंग: फ़ाइल एक्सटेंशन के आधार पर भाषा-अनुरूप हाइलाइटिंग
- क्लिक-टू-कमेंट: किसी भी पंक्ति पर क्लिक करने से उस पंक्ति से जुड़ा टिप्पणी फ़ॉर्म खुल जाता है
diff एजेंट के संपादन ऑपरेशन से अपने आप निकाला जाता है। अगर एजेंट ने search-and-replace टूल इस्तेमाल किया हो, तो Potato पहले और बाद की स्थिति दोबारा बनाकर unified diff तैयार कर देता है।
जो एजेंट एक ही ट्रेस में कई फ़ाइलें बदलते हैं (असली बग फ़िक्स में यह आम है), उनके लिए हर फ़ाइल को अपना समेटा जा सकने वाला diff सेक्शन मिलता है, GitHub PR के "Files changed" टैब जैसा।
CodingTraceDisplay कोड बदलावों को सही सिंटैक्स हाइलाइटिंग के साथ रेंडर करता है:
सिंटैक्स हाइलाइटिंग और फ़ाइल ट्री साइडबार के साथ unified diff रेंडर करता CodingTraceDisplay
टिप्पणी श्रेणियाँ
जब एनोटेटर diff की किसी पंक्ति पर क्लिक करके टिप्पणी जोड़ता है, तो वह एक श्रेणी चुनता है:
| श्रेणी | रंग | विवरण | उदाहरण |
|---|---|---|---|
bug | लाल | कोड में कामकाजी ग़लती है | "अगर user None हुआ तो यह NullPointerException फेंकेगा" |
style | नीला | कोड शैली या परिपाटी की समस्या | "परियोजना फ़ंक्शन के लिए snake_case इस्तेमाल करती है, camelCase नहीं" |
performance | नारंगी | अकुशल कोड | "यह लूप के भीतर डेटाबेस क्वेरी करता है; बैच क्वेरी इस्तेमाल करें" |
security | बैंगनी | सुरक्षा भेद्यता | "उपयोगकर्ता का इनपुट बिना सैनिटाइज़ किए सीधे SQL क्वेरी में जा रहा है" |
logic | पीला | तर्क की समस्या, जिससे तुरंत विफलता न भी हो | "यह शर्त > नहीं, >= होनी चाहिए; सीमा पर ऑफ़-बाय-वन है" |
suggestion | हरा | सुधार का सुझाव, ग़लती नहीं | "यहाँ संसाधन प्रबंधन साफ़ रखने के लिए context manager इस्तेमाल करने पर विचार करें" |
question | धूसर | स्पष्टीकरण चाहिए | "यह import क्यों जोड़ा गया? यह कहीं इस्तेमाल होता नहीं दिखता" |
हर टिप्पणी में एक मुक्त-पाठ बॉडी भी होती है जहाँ एनोटेटर समस्या को विस्तार से समझाता है, ठीक वैसे ही जैसे असली PR टिप्पणी लिखते समय।
फ़ाइल-स्तरीय रेटिंग
हर फ़ाइल का diff देखने के बाद एनोटेटर उसे दो आयामों पर रेट करता है:
शुद्धता (1-5):
- 1: काम नहीं करता, नए बग लाता है
- 2: आंशिक रूप से काम करता है, बड़ी समस्याएँ हैं
- 3: सामान्य रास्ते पर काम करता है पर किनारे के मामले छूट जाते हैं
- 4: छोटी-मोटी समस्याओं के साथ सही काम करता है
- 5: पूरी तरह सही, किनारे के मामले भी ठीक से सँभालता है
कोड गुणवत्ता (1-5):
- 1: मेंटेन न किया जा सकने वाला, कोई ढाँचा नहीं
- 2: घटिया गुणवत्ता, शैली/डिज़ाइन की बड़ी समस्याएँ
- 3: चलने लायक, बुनियादी परिपाटियों का पालन करता है
- 4: अच्छी गुणवत्ता, साफ़ और पढ़ने योग्य
- 5: बढ़िया, मुहावरेदार, अच्छे से दस्तावेज़ीकृत
फ़ैसले के विकल्प
सारी फ़ाइलें देख लेने के बाद एनोटेटर तीन में से एक फ़ैसला चुनता है:
- Approve: कोड जैसा है वैसा ही, या मामूली बदलाव के साथ मर्ज होने लायक है
- Request Changes: मर्ज करने से पहले कोड में बड़े सुधार चाहिए
- Comment Only: मर्ज का फ़ैसला दिए बिना प्रतिक्रिया देना
यह सीधे GitHub की तीन PR रिव्यू स्थितियों से मेल खाता है।
चरण-दर-चरण सेटअप
चरण 1: कोडिंग एजेंट ट्रेस बदलें
कोडिंग एजेंट ट्रेस कई फ़ॉर्मैट में आते हैं। यहाँ तीन लोकप्रिय एजेंट के उदाहरण हैं।
Claude Code से (JSON निर्यात):
python -m potato.trace_converter \
--input claude_code_sessions/ \
--output data/code_traces.jsonl \
--input-format claude_codeAider से (चैट इतिहास):
python -m potato.trace_converter \
--input aider_logs/ \
--output data/code_traces.jsonl \
--input-format aiderSWE-Agent से (trajectories डायरेक्टरी):
python -m potato.trace_converter \
--input swe_agent_trajectories/ \
--output data/code_traces.jsonl \
--input-format swe_agent_trajectoryकन्वर्टर एक मानकीकृत JSONL फ़ॉर्मैट बनाता है। हर पंक्ति में एक ट्रेस होता है, जिसमें टास्क, एजेंट के चरण, और फ़ाइल diff शामिल होते हैं:
{
"trace_id": "swe_bench_123",
"task": "Fix the TypeError in django/db/models/query.py when calling .values() on an empty QuerySet",
"repo": "django/django",
"base_commit": "a1b2c3d",
"steps": [
{
"type": "thought",
"content": "Let me look at the QuerySet.values() method to understand the TypeError."
},
{
"type": "action",
"tool": "search",
"input": "def values",
"file": "django/db/models/query.py"
},
{
"type": "observation",
"content": "Found at line 234: def values(self, *fields):\n ..."
},
{
"type": "action",
"tool": "edit",
"file": "django/db/models/query.py",
"old_content": " def values(self, *fields):\n clone = self._clone()\n clone.query.set_values(fields)",
"new_content": " def values(self, *fields):\n clone = self._clone()\n if not fields and not self.query.values_select:\n return clone\n clone.query.set_values(fields)"
},
{
"type": "action",
"tool": "edit",
"file": "tests/queries/test_values.py",
"old_content": "class ValuesTests(TestCase):",
"new_content": "class ValuesTests(TestCase):\n def test_empty_queryset_values(self):\n \"\"\"Calling .values() on empty QuerySet should not raise TypeError.\"\"\"\n qs = Author.objects.none()\n result = list(qs.values())\n self.assertEqual(result, [])"
}
],
"files_changed": [
{
"path": "django/db/models/query.py",
"diff": "--- a/django/db/models/query.py\n+++ b/django/db/models/query.py\n@@ -234,6 +234,8 @@\n def values(self, *fields):\n clone = self._clone()\n+ if not fields and not self.query.values_select:\n+ return clone\n clone.query.set_values(fields)"
},
{
"path": "tests/queries/test_values.py",
"diff": "--- a/tests/queries/test_values.py\n+++ b/tests/queries/test_values.py\n@@ -1,4 +1,10 @@\n class ValuesTests(TestCase):\n+ def test_empty_queryset_values(self):\n+ \"\"\"Calling .values() on empty QuerySet should not raise TypeError.\"\"\"\n+ qs = Author.objects.none()\n+ result = list(qs.values())\n+ self.assertEqual(result, [])"
}
]
}चरण 2: कोड रिव्यू योजना कॉन्फ़िगर करें
अपनी config.yaml बनाएँ:
annotation_task_name: "Coding Agent Code Review"
data_files:
- "data/code_traces.jsonl"
item_properties:
id_key: "trace_id"
text_key: "task"
# Display coding agent traces with diff rendering
display:
type: "coding_trace"
trace_key: "steps"
diff_key: "files_changed"
syntax_highlighting: true
show_line_numbers: true
collapse_large_diffs: true
max_uncollapsed_lines: 200
annotation_schemes:
- annotation_type: "code_review"
# Inline comment categories
# File-level ratings
# Overall verdict
# Annotator settings
annotator_config:
allow_back_navigation: true
# Output settings
output:
path: "output/"
format: "jsonl"चरण 3: एनोटेशन सर्वर चालू करें
potato start config.yaml -p 8000http://localhost:8000 पर जाएँ। आपको पहला कोडिंग एजेंट ट्रेस दिखेगा, जिसमें टास्क का विवरण, एजेंट के तर्क-चरण, और सिंटैक्स हाइलाइटिंग सहित रेंडर किए गए फ़ाइल diff होंगे।
चरण 4: एनोटेटर का कार्यप्रवाह
आम तौर पर रिव्यू इस तरह चलता है:
- टास्क पढ़ें: समझें कि एजेंट से क्या करने को कहा गया था (जैसे, "django/db/models/query.py में TypeError ठीक करें")
- ट्रेस देखें: एजेंट के तर्क-चरणों से गुज़रकर उसका तरीक़ा समझें
- हर फ़ाइल का diff देखें:
- सिंटैक्स हाइलाइटिंग सहित diff पढ़ें
- किसी भी पंक्ति पर क्लिक करके इनलाइन टिप्पणी जोड़ें
- टिप्पणी की श्रेणी चुनें (bug, style, performance वगैरह)
- समस्या समझाते हुए टिप्पणी की बॉडी लिखें
- फ़ाइल को शुद्धता (1-5) और कोड गुणवत्ता (1-5) पर रेट करें
- फ़ैसला दें: approve, request changes, या सिर्फ़ comment चुनें
- जमा करें: "Submit" पर क्लिक करें या Ctrl+Enter दबाएँ
कीबोर्ड शॉर्टकट काम की रफ़्तार बढ़ा देते हैं:
| शॉर्टकट | क्रिया |
|---|---|
j / k | फ़ाइलों के बीच आवाजाही |
c | चुनी हुई पंक्ति पर टिप्पणी खोलें |
1-5 | मौजूदा आयाम की रेटिंग तय करें |
a | फ़ैसला approve पर सेट करें |
r | फ़ैसला request changes पर सेट करें |
Ctrl+Enter | रिव्यू जमा करें |
निर्यात फ़ॉर्मैट
जमा की गई हर रिव्यू एक संरचित JSON ऑब्जेक्ट बनाती है:
{
"trace_id": "swe_bench_123",
"annotator": "reviewer_01",
"timestamp": "2026-03-22T14:32:11Z",
"review": {
"inline_comments": [
{
"file": "django/db/models/query.py",
"line": 236,
"side": "right",
"category": "logic",
"body": "This early return skips set_values entirely, but if fields are provided later via .values('name'), the previous empty .values() call will have returned a clone that never went through set_values. Consider checking if this clone is still valid downstream."
},
{
"file": "tests/queries/test_values.py",
"line": 5,
"side": "right",
"category": "suggestion",
"body": "Consider adding a test case for .values() followed by .values('name') to verify the chaining behavior after your fix."
}
],
"file_ratings": [
{
"file": "django/db/models/query.py",
"correctness": 3,
"code_quality": 4
},
{
"file": "tests/queries/test_values.py",
"correctness": 4,
"code_quality": 4
}
],
"verdict": "request_changes"
}
}यह संरचित फ़ॉर्मैट कोड रिव्यू मॉडल के प्रशिक्षण और समग्र विश्लेषण, दोनों में सीधे इस्तेमाल हो सकता है।
विश्लेषण: रिव्यू डेटा के साथ काम करना
रिव्यू लोड करना
import json
import pandas as pd
from pathlib import Path
reviews = []
for f in Path("output/").glob("*.jsonl"):
with open(f) as fh:
for line in fh:
reviews.append(json.loads(line))
print(f"Loaded {len(reviews)} code reviews")टिप्पणी श्रेणियों का वितरण
from collections import Counter
all_comments = []
for rev in reviews:
for comment in rev["review"]["inline_comments"]:
all_comments.append(comment)
category_counts = Counter(c["category"] for c in all_comments)
print("Comment categories:")
for cat, count in category_counts.most_common():
print(f" {cat}: {count}")औसत फ़ाइल रेटिंग
ratings = []
for rev in reviews:
for fr in rev["review"]["file_ratings"]:
ratings.append(fr)
ratings_df = pd.DataFrame(ratings)
print("Average ratings by file:")
print(
ratings_df.groupby("file")[["correctness", "code_quality"]]
.mean()
.round(2)
.to_string()
)फ़ैसलों का वितरण
verdict_counts = Counter(rev["review"]["verdict"] for rev in reviews)
total = sum(verdict_counts.values())
print("Verdict distribution:")
for verdict, count in verdict_counts.most_common():
print(f" {verdict}: {count} ({count/total*100:.1f}%)")एजेंट के हिसाब से बग दर
अगर आपके ट्रेस में agent फ़ील्ड है, तो आप एजेंटों की बग दर की तुलना कर सकते हैं:
agent_bugs = {}
for rev in reviews:
agent = rev.get("agent", "unknown")
bug_count = sum(
1 for c in rev["review"]["inline_comments"]
if c["category"] == "bug"
)
if agent not in agent_bugs:
agent_bugs[agent] = []
agent_bugs[agent].append(bug_count)
print("Average bugs per review by agent:")
for agent, bugs in sorted(agent_bugs.items()):
print(f" {agent}: {sum(bugs)/len(bugs):.2f} (n={len(bugs)})")इस्तेमाल के मामले
कोड रिव्यू मॉडल का प्रशिक्षण
Potato की कोड रिव्यू एनोटेशन से मिलने वाली संरचित इनलाइन टिप्पणियाँ, फ़ाइल रेटिंग और फ़ैसले स्वचालित कोड रिव्यू मॉडल के लिए अच्छा प्रशिक्षण डेटा हैं। हर रिव्यू देती है:
- diff की ख़ास पंक्तियों से जुड़ी स्थानीय प्रतिक्रिया
- श्रेणीबद्ध समस्याएँ (bug बनाम style बनाम performance)
- कई स्तरों पर गुणवत्ता संकेत (पंक्ति, फ़ाइल, कुल)
यह वही डेटा फ़ॉर्मैट है जो CodeRabbit और Graphite के AI रिव्यूअर जैसे टूल इस्तेमाल करते हैं, फ़र्क़ बस इतना कि यह किसी LLM से डिस्टिल करने के बजाय मानव विशेषज्ञों से आता है।
SWE-bench पर कोडिंग एजेंट का मूल्यांकन
SWE-bench बताता है कि एजेंट ने इशू हल किया या नहीं (टेस्ट पास हुए), पर यह नहीं कि कोड मर्ज करने लायक है या नहीं। SWE-bench के समाधानों पर कोड रिव्यू एनोटेशन चलाकर आप पहचान सकते हैं कि कौन-से एजेंट साफ़ कोड से इशू हल करते हैं और कौन-से जुगाड़ से। इससे बनने वाला लीडरबोर्ड ज़्यादा बारीक होता है और असल डेवलपर अनुभव से मेल खाता है।
कोड गुणवत्ता डेटासेट बनाना
कई ट्रेस की कोड रिव्यू डेटा जोड़कर आप AI-जनित कोड में आने वाली आम गुणवत्ता समस्याओं का डेटासेट बना सकते हैं। ऐसे डेटासेट इनमें काम आते हैं:
- कोड जनरेशन मॉडल को फ़ाइन-ट्यून करना ताकि वे आम ग़लतियाँ न दोहराएँ
- AI-जनित कोड के पैटर्न के लिए ख़ास लिंटर बनाना
- ऐसे क्लासिफ़ायर प्रशिक्षित करना जो मानव समीक्षा से पहले ही एजेंट के आउटपुट में संभावित समस्याएँ पकड़ लें
सारांश
Potato की code_review योजना GitHub PR रिव्यू के कार्यप्रवाह को एजेंट मूल्यांकन के भीतर ले आती है। जो इनलाइन टिप्पणियाँ, फ़ाइल रेटिंग और फ़ैसले आप जुटाते हैं, उनसे संरचित कोड गुणवत्ता डेटा मिलता है, जो पास/फ़ेल टेस्ट नतीजे से कहीं ज़्यादा बताता है। कोड रिव्यू मॉडल प्रशिक्षित करना हो, साफ़ SWE-bench समाधानों को जुगाड़ू समाधानों से अलग करना हो, या बस अपने एजेंट के लिए गुणवत्ता का एक आधार तय करना हो, ज़रूरत उसी डेटा की पड़ती है।