कोर्स
कल्पना कीजिए कि आप बिल्कुल वही बड़ा भाषा मॉडल (LLM) दो बार चलाते हैं, लेकिन हर बार उसे एकदम अलग हार्नेस देते हैं। एक रन जटिल रिफैक्टरिंग कार्य को साफ-सुथरे तरीके से पूरा कर देता है। दूसरा रन रुक जाता है और पूरी तरह विफल हो जाता है। मॉडल नहीं बदला, लेकिन मॉडल के चारों ओर की स्कैफोल्डिंग बदल गई।
संक्षेप में, एजेंट हार्नेस इंजीनियरिंग वह अभ्यास है जिसमें आप आसपास की लॉजिक, फाइल सिस्टम एक्सेस, मेमोरी, और नियम बनाते हैं ताकि LLM भरोसेमंद तरीके से क्रिया कर सके।
इस एजेंट हार्नेस इंजीनियरिंग ट्यूटोरियल में, मैं आपको Reason and Act (ReAct) लूप, टूल्स, और हुक्स के साथ एक न्यूनतम Python सेटअप बनाना सिखाऊंगा। आपको Python 3, आपकी मशीन पर pip इंस्टॉल, और LLM API कॉल्स करने की बुनियादी जानकारी चाहिए।
एजेंट हार्नेस इंजीनियरिंग क्या है?
एजेंट हार्नेस इंजीनियरिंग वह प्रैक्टिस है जिसमें बड़े भाषा मॉडल के चारों ओर इन्फ्रास्ट्रक्चर, कॉन्फ़िगरेशन, और एक्ज़ीक्यूशन लॉजिक बनाया जाता है, जो एक स्थिर LLM टेक्स्ट जनरेटर को एक स्वायत्त AI एजेंट में बदल देता है
एजेंट हार्नेस इंजीनियरिंग वह स्ट्रक्चरल कॉन्फ़िगरेशन है जो एक स्थिर टेक्स्ट जनरेटर को स्वायत्त वर्कर में बदलती है।
मुख्य समीकरण सरल है: एजेंट = मॉडल + हार्नेस। हार्नेस में सिस्टम प्रॉम्प्ट्स, टूल परिभाषाएँ, फाइल सिस्टम वर्कस्पेस, ऑर्केस्ट्रेशन लॉजिक, और ऑब्ज़र्वेबिलिटी हुक्स शामिल होते हैं।
एडी उस्मानी ने अप्रैल 2026 की अपनी O'Reilly रचना में AI वर्कफ़्लो पर इस अवधारणा को औपचारिक रूप दिया। उन्होंने हार्नेस को उस हर कोड, कॉन्फ़िगरेशन, और एक्ज़ीक्यूशन लॉजिक के रूप में परिभाषित किया जो स्वयं मॉडल नहीं है: एक डेवलपर के रूप में आपका सरफेस एरिया, जो प्रोवाइडर के API से अलग है।
जब मैंने पहली बार मशीन लर्निंग वर्कफ़्लो बनाने शुरू किए, तो हर बार जब एजेंट ने कोई Python डिपेंडेंसी गढ़ ली, मैंने मॉडल को दोष दिया। मुझे कठिन तरीके से सीखना पड़ा कि ज्यादातर विफलताएँ असल में कॉन्फ़िगरेशन समस्याएँ होती हैं।
उसी मॉडल का वही वर्ज़न, बेहतर हार्नेस के साथ, खराब हार्नेस की तुलना में खुद से मापनीय रूप से बेहतर प्रदर्शन करता है।

AI इंजीनियरिंग की सीढ़ी
हम AI विकास को नियंत्रण की अलग-अलग परतों में बाँट सकते हैं।
हार्नेस इंजीनियरिंग इस पदानुक्रम के ठीक मध्य में बैठती है।
|
लेयर |
यह क्या नियंत्रित करता है |
उदाहरण क्रिया |
|
प्रॉम्प्ट इंजीनियरिंग |
तत्काल टेक्स्ट |
निर्देशों में बदलाव |
|
कॉन्टेक्स्ट इंजीनियरिंग |
मॉडल को दिया गया डेटा |
RAG पाइपलाइन ट्यूनिंग |
|
हार्नेस इंजीनियरिंग |
एजेंट के भौतिक टूल |
एक Bash टूल जोड़ना |
|
लूप इंजीनियरिंग |
ऑर्केस्ट्रेशन स्टेप्स |
ReAct फ्लो बदलना |
|
ग्राफ इंजीनियरिंग |
मल्टी-एजेंट समन्वय |
रूटिंग नोड्स बनाना |
- प्रॉम्प्ट इंजीनियरिंग तत्काल टेक्स्ट निर्देशों को नियंत्रित करती है।
- कॉन्टेक्स्ट इंजीनियरिंग उस सटीक डेटाबेस रिकॉर्ड्स या API स्कीमा को मैनेज करती है जिन्हें आप प्रॉम्प्ट में फीड करते हैं।
- हार्नेस इंजीनियरिंग यह निर्धारित करती है कि एजेंट वास्तव में
pandasस्क्रिप्ट कैसे चलाता है या लोकल CSV कैसे पढ़ता है।
रैचेट: हर गलती एक नियम बनती है
एजेंट हार्नेस इंजीनियरिंग की परिभाषित मानसिकता रैचेट प्रभाव है।
जब एजेंट कोई गलती करता है, तो आप ऐसा समाधान इंजीनियर करते हैं कि वह गलती फिर न दोहराई जाए। एक अच्छा हार्नेस दरअसल ट्रायल-एंड-एरर का संक्षेप है।
एजेंट को गलतियाँ दोहराने देने के बजाय, आप अपने AGENTS.md में एक पंक्ति जोड़ते हैं, कोई नया हुक लिखते हैं, या किसी टूल विवरण को सख्त करते हैं।
आप सिर्फ सहज रूप से नया मॉडल नहीं चुनते; बल्कि, आप ऐसा कॉर्पस बनाते हैं जो विशिष्ट विफलताओं और उनके विरुद्ध आपकी सख्ती का ट्रेस रखने देता है।
AI एजेंट हार्नेस के कोर कंपोनेंट्स
AI एजेंट हार्नेस के कोर कंपोनेंट्स वह फाइल सिस्टम, टूल्स, मेमोरी, हुक्स, और कॉन्टेक्स्ट मैनेजमेंट सिस्टम हैं जो मॉडल को संचालित करने देते हैं।
ये हिस्से मिलकर अलग-थलग API कॉल्स को एक सतत फीडबैक लूप में बदलते हैं। कोड लिखने से पहले मैं आपको एक स्पष्ट नक्शा देना चाहता हूँ।
|
कंपोनेंट |
काम |
Python इम्प्लीमेंटेशन |
|
फाइल सिस्टम |
ड्यूरेबल स्टेट |
लोकल workspace/ डायरेक्टरी |
|
टूल्स |
पर्यावरण में क्रिया करना |
Bash के लिए Python फ़ंक्शंस |
|
मेमोरी |
प्रोजेक्ट कॉन्टेक्स्ट |
एक AGENTS.md फ़ाइल |
|
हुक्स |
प्रवर्तन |
प्री-कमिट वैलिडेशन स्क्रिप्ट्स |
|
कम्पैक्शन |
कॉन्टेक्स्ट मैनेजमेंट |
समरीकरण लॉजिक |
फाइल सिस्टम और Git: ड्यूरेबल स्टेट
मॉडल केवल अपनी सीमित कॉन्टेक्स्ट विंडो के अंदर की जानकारी प्रोसेस कर सकता है। एक फाइल सिस्टम स्थिर वर्कस्पेस देता है जहाँ डेटा पढ़ा जा सके, मध्यवर्ती परिणाम लिखे जा सकें, और सत्रों के बीच समन्वय हो सके।
Git वर्ज़न कंट्रोल जोड़ने से आवश्यक सेफ्टी नेट मिलता है। एजेंट प्रगति को ट्रैक कर सकता है, अलग-अलग हाइपरपैरामीटर्स के साथ प्रयोग के लिए ब्रांच बना सकता है, और टूटा हुआ कोड अपने आप रोलबैक कर सकता है।
टूल्स: एजेंट को हाथ देना
ReAct लूप तर्क करने, टूल कॉल के जरिए क्रिया करने, और परिणाम का निरीक्षण करने के चक्र में काम करता है। टूल विवरण मॉडल और पर्यावरण के बीच सीधा इंटरफ़ेस बनाते हैं। धुंधले विवरण धुंधला व्यवहार पैदा करते हैं।
Bash एक बेहतरीन जनरल-पर्पज़ टूल है। हर संभावित क्रिया के लिए अलग Python फ़ंक्शन पहले से बनाने के बजाय, Bash एजेंट को ज़रूरत के अनुसार तुरंत सटीक कमांड बनाने देता है। आपको इन कमांड्स को सावधानी से सैंडबॉक्स करना चाहिए ताकि सिस्टम को नुकसान न हो।
मेमोरी: AGENTS.md और नॉलेज इंजेक्शन
आपके एजेंट को स्थानीय परंपराएँ समझने के लिए प्रोजेक्ट-विशिष्ट मेमोरी चाहिए। AGENTS.md फ़ाइल रिपॉज़िटरी रूट पर एक सपाट मार्कडाउन दस्तावेज़ है जो हर टर्न में सिस्टम प्रॉम्प्ट में जाता है। यह आपकी टेक स्टैक, फॉर्मैटिंग नियम, और निषिद्ध कार्रवाइयाँ परिभाषित करता है।
इस फ़ाइल को 60 पंक्तियों से कम रखें। इसे व्यापक स्टाइल गाइड के बजाय पायलट की चेकलिस्ट की तरह मानें। अधिक उदाहरणों के लिए आप संपूर्ण AGENTS.md ट्यूटोरियल पढ़ सकते हैं। आपको पोस्ट-कटऑफ नॉलेज के लिए Model Context Protocol (MCP) टूल्स पर भी विचार करना चाहिए।
हुक्स: प्रवर्तन परत
हुक्स छोटे स्क्रिप्ट्स होते हैं जो विशिष्ट लाइफसाइकल बिंदुओं पर चलते हैं।
आप टूल कॉल से पहले, फाइल एडिट के बाद, या Git कमिट से पहले कोई हुक चला सकते हैं। उन्नत हुक पैटर्न के लिए इस गाइड को देखें: Claude Code Hooks।
हुक्स के लिए मुख्य डिजाइन सिद्धांत है कि सफलता मौन हो, लेकिन विफलताएँ विस्तृत हों। पास होती टाइपचेक कोई आउटपुट नहीं देती।
विफलता सटीक त्रुटि टेक्स्ट को एजेंट लूप में वापस इंजेक्ट करती है ताकि वह खुद-सुधार कर सके।
कॉन्टेक्स्ट कम्पैक्शन: कॉन्टेक्स्ट रॉट से लड़ना
कॉन्टेक्स्ट रॉट तब होता है जब लंबे वार्तालाप इतिहास से निर्देशों का पालन बिगड़ने लगता है क्योंकि कॉन्टेक्स्ट विंडो भर जाती है। एक मजबूत AI एजेंट स्कैफोल्डिंग को इसे सक्रिय रूप से मैनेज करना चाहिए। इन सीमाओं को समझने के लिए कॉन्टेक्स्ट विंडो पर अधिक पढ़ें।
आप पुराने संदेशों को समरी करके कॉन्टेक्स्ट घटा सकते हैं। बड़े टूल आउटपुट्स को डिस्क पर ऑफ़लोड कर सकते हैं और प्रॉम्प्ट में केवल छोटा संदर्भ रख सकते हैं।
अंततः, आप टोकन-भारी उप-कार्यों को उनके अपने नए कॉन्टेक्स्ट वाले सबएजेंट को अलग कर सकते हैं।
Python में एक न्यूनतम एजेंट हार्नेस बनाना
AI एजेंट हार्नेस बनाना वह Python ऑर्केस्ट्रेशन कोड लिखना है जो ReAct लूप, टूल्स, और हुक्स को जोड़ता है।
कोड लिखने से पहले इस संबंध को स्पष्ट रखें: harness.py ही एजेंट है, और आप इसे किसी भी अन्य स्क्रिप्ट की तरह python harness.py से स्वयं शुरू करते हैं।
मॉडल एक रिमोट API है जो कभी इस फ़ाइल को नहीं देखता; उसे केवल सिस्टम प्रॉम्प्ट, मैसेज हिस्ट्री, और वे टूल स्कीमा मिलते हैं जिन्हें आपकी स्क्रिप्ट भेजती है।
इस सेक्शन की हर स्निपेट एक ही फ़ाइल harness.py का हिस्सा है, और शुरुआती 4 सेक्शन इसे ऊपर से नीचे बनाते हैं। अंतिम 2 सेक्शन (हुक्स और कम्पैक्शन) इसे अपग्रेड करते हैं, और क्योंकि लूप Python के वहाँ पहुँचते ही चलने लगता है, उनकी फ़ंक्शन परिभाषाएँ लूप के ऊपर होनी चाहिए; हर सेक्शन बताता है कि उसका कोड कहाँ जाएगा।
अकाउंट सेटअप और प्रोजेक्ट संरचना
इसे बनाने के लिए, आपको अपने चुने हुए प्रोवाइडर के साथ एक डेवलपर अकाउंट चाहिए। मानक उपभोक्ता सब्सक्रिप्शन (जैसे ChatGPT Plus या Claude Pro) API एक्सेस नहीं देते।
- Anthropic/OpenAI सेटअप: प्रोवाइडर के डेवलपर कंसोल पर रजिस्टर करें और पे-एज़-यू-गो बिलिंग प्रोफाइल सेट करें। एक API की जनरेट करें और उसे अपने लोकल एनवायरनमेंट में
ANTHROPIC_API_KEY(याOPENAI_API_KEY) के रूप में एक्सपोर्ट करें। - लोकल विकल्प: यदि आप पूरी तरह से API लागत से बचना चाहते हैं, तो आप लोकली Ollama चला सकते हैं। Ollama एक लोकल एंडपॉइंट एक्सपोज़ करता है जिसे आप बिना किसी API की के क्वेरी कर सकते हैं।
इस उदाहरण के लिए, हम Anthropic का उपयोग करेंगे, इसलिए सुनिश्चित करें कि आप pip install anthropic का उपयोग करके Anthropic Python पैकेज इंस्टॉल करें।
अब प्रोजेक्ट स्केलेटन बनाएँ। हर फ़ाइल का नाम पहले से तय करना महत्वपूर्ण है: हमारा लूप स्टार्टअप पर AGENTS.md पढ़ेगा, इसलिए यह फ़ाइल लूप चलने से पहले मौजूद होनी चाहिए।
agent-harness/
├── AGENTS.md # Project memory (we write this first)
├── harness.py # The ReAct loop, tools, and hooks
└── workspace/ # The only directory the agent may touch
workspace/ डायरेक्टरी एजेंट का सैंडबॉक्स है। एजेंट जो कुछ भी पढ़ता, लिखता, या एक्ज़ीक्यूट करता है, वह इसी के अंदर होता है—कभी भी आपके प्रोजेक्ट रूट में नहीं।
AGENTS.md लिखना और उसे सिस्टम प्रॉम्प्ट में इंजेक्ट करना
हम लूप से पहले AGENTS.md लिखते हैं क्योंकि लूप उस पर निर्भर है।
फ़ाइल को अपने प्रोजेक्ट रूट में बनाएँ और अपनी विशिष्ट स्टैक जानकारी और आर्किटेक्चरल सीमाएँ शामिल करें:
# Project Context
Stack: Python 3.11, Pytest
Workspace: All commands run inside the workspace/ directory.
# Rules
1. Never use rm -rf. Use standard rm with specific file names.
2. Never write tests inside the main application file.
3. When you finish the task, reply with a plain-text summary and no tool call.
हमारा लूप "मॉडल ने बिना टूल माँगे जवाब दिया" को टास्क-पूर्ण का सिग्नल मानेगा, इसलिए हम मॉडल को स्पष्ट रूप से बताते हैं कि समापन कैसे संकेत करना है।
आपके अपने लूप मैकेनिक्स का संदर्भ देने वाले नियम हार्नेस इंजीनियरिंग की कुंजी हैं। मेमोरी फ़ाइल और ऑर्केस्ट्रेशन कोड साथ मिलकर डिज़ाइन किए जाते हैं।
अब harness.py शुरू करें—इस फ़ाइल को सिस्टम प्रॉम्प्ट के रूप में बनाकर और वर्कस्पेस तैयार करके:
import subprocess
from pathlib import Path
import anthropic
client = anthropic.Anthropic()
WORKSPACE = Path("workspace")
WORKSPACE.mkdir(exist_ok=True)
# Project memory: AGENTS.md lands in the system prompt on every turn
system_prompt = Path("AGENTS.md").read_text()
क्योंकि SDK हर API कॉल के साथ system_prompt भेजता है, AGENTS.md के नियम हर एक टर्न पर फिर से इंजेक्ट हो जाते हैं। मॉडल उन्हें "भूल" नहीं सकता जैसे वह बातचीत के बीच के निर्देश भूलता है।
टूल परिभाषित करना: लूप को हाथ देना
हम 2 टूल्स परिभाषित करते हैं: जनरल-पर्पज़ एक्ज़ीक्यूशन के लिए run_bash और फाइलें बनाने के लिए write_file।
दूसरा टूल भले ही अनावश्यक लगे क्योंकि Bash heredocs से फाइल लिख सकता है, लेकिन समर्पित write_file हमें एक साफ एडिट इवेंट देता है जिस पर हमारा पोस्ट-एडिट हुक बाद में पकड़ बना सकता है।
ऐसे हार्नेस डिजाइन निर्णय हमेशा इस बारे में होते हैं कि आप क्या देखना और लागू करना चाहते हैं।
टूल विवरण इंटरफ़ेस होते हैं, और उनकी गुणवत्ता सीधे एजेंट के व्यवहार को नियंत्रित करती है:
- धुंधला: "Bash चलाता है।" एजेंट इसे हर चीज़ के लिए उपयोग करेगा, जिसमें टूटे हुए एस्केपिंग के साथ नाज़ुक heredocs के ज़रिए मल्टीलाइन Python फाइलें लिखना भी शामिल है।
- विशिष्ट: "workspace/ डायरेक्टरी के अंदर एक bash कमांड चलाएँ और इसे stdout, stderr, और एग्ज़िट कोड सहित लौटाएँ। इसे फाइलें लिस्ट करने, स्क्रिप्ट चलाने, और टेस्ट चलाने के लिए उपयोग करें। Python फाइलें बनाने के लिए इसका उपयोग न करें; इसके लिए write_file का उपयोग करें।" एजेंट बिना अतिरिक्त प्रॉम्प्टिंग के काम को सही टूल की तरफ रूट करता है।
हमारी harness.py फ़ाइल में आगे बढ़ते हुए, अब हम अगली पंक्ति में टूल स्कीमा परिभाषित कर सकते हैं:
TOOLS = [
{
"name": "run_bash",
"description": (
"Run a bash command inside the workspace/ directory and return "
"its stdout, stderr, and exit code. Use it to list files, run "
"scripts, and run tests. Do not use it to create Python files; "
"use write_file instead."
),
"input_schema": {
"type": "object",
"properties": {
"command": {"type": "string", "description": "The bash command to run."}
},
"required": ["command"],
},
},
{
"name": "write_file",
"description": (
"Create or overwrite a file inside the workspace/ directory. "
"Provide a path relative to workspace/ and the full file content."
),
"input_schema": {
"type": "object",
"properties": {
"path": {"type": "string", "description": "Path relative to workspace/."},
"content": {"type": "string", "description": "Full file content."},
},
"required": ["path", "content"],
},
},
]
अगला ब्लॉक उन वास्तविक Python फ़ंक्शंस को परिभाषित करता है जो इन कमांड्स को चलाएँगे।
ध्यान दें कि इनमें बने हुए सुरक्षा फ़ीचर्स क्या हैं: एक सख़्त टाइमआउट ताकि कोई अटकी कमांड हार्नेस को लटका न दे, हर परिणाम में एग्ज़िट कोड शामिल ताकि एजेंट सफलता और विफलता में फर्क कर सके, और एक पाथ जाँच ताकि write_file() सैंडबॉक्स से बाहर न निकल सके।
def run_bash(command: str) -> str:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
cwd=WORKSPACE,
timeout=60,
)
output = (result.stdout + result.stderr).strip()
return f"exit code: {result.returncode}\n{output or '(no output)'}"
def write_file(path: str, content: str) -> str:
target = (WORKSPACE / path).resolve()
if WORKSPACE.resolve() not in target.parents:
return "Error: path escapes the workspace/ directory."
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(content)
return f"Wrote {len(content)} characters to {path}."
TOOL_EXECUTORS = {"run_bash": run_bash, "write_file": write_file}
or '(no output)' फ़ॉलबैक सौंदर्यात्मक नहीं है।
touch data.csv जैसी कमांड चुपचाप सफल हो जाती है, और खाली स्ट्रिंग लौटाने से मॉडल के पास निरीक्षण करने को कुछ नहीं रहता।
हमेशा एजेंट को स्पष्ट संकेत दें, भले ही चुप्पी ही क्यों न हो।
ReAct एजेंट लूप
हमारे हार्नेस का कोर एक मानक Python for लूप है जिसमें इटरेशन कैप है।
हर पास API कॉल करता है, जाँचता है कि मॉडल ने कोई टूल माँगा है या नहीं, हर माँगे गए टूल को चलाता है, और परिणामों को एक सिंगल संदेश के रूप में वापस फीड करता है।
यह ब्लॉक harness.py के सबसे नीचे बैठता है, क्योंकि Python के वहाँ पहुँचते ही यह चलना शुरू हो जाता है।
messages = [
{
"role": "user",
"content": "Create a fizzbuzz.py script in the workspace, "
"then run it to verify the output.",
}
]
MAX_STEPS = 15
for step in range(MAX_STEPS):
print(f"--- Iteration {step + 1} ---")
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=2000,
system=system_prompt,
messages=messages,
tools=TOOLS,
)
# Append the model's turn to the history
messages.append({"role": "assistant", "content": response.content})
# Stop condition: the model answered without requesting a tool
if response.stop_reason != "tool_use":
final_text = "".join(b.text for b in response.content if b.type == "text")
print(f"Task complete: {final_text}")
break
# Execute EVERY tool call in this turn, collecting the results
tool_results = []
for block in response.content:
if block.type != "tool_use":
continue
print(f"Agent calling {block.name}: {block.input}")
output = TOOL_EXECUTORS[block.name](**block.input)
tool_results.append(
{"type": "tool_result", "tool_use_id": block.id, "content": output}
)
# All tool results for one assistant turn go back in ONE user message
messages.append({"role": "user", "content": tool_results})
else:
print("Stopped: hit the maximum iteration cap without finishing.")
इस लूप में दो बातें वास्तविक क्रैश से बचाती हैं।
पहला, एक सिंगल मॉडल टर्न में कई टूल कॉल हो सकते हैं, और Anthropic API माँगता है कि उनके सभी परिणाम एक यूज़र संदेश में वापस आएँ।
दूसरा, for/else कंस्ट्रक्ट बताता है जब एजेंट इटरेशन कैप तक पहुँच जाता है, ताकि एक रुका हुआ रन चुपचाप खत्म होने के बजाय जोर से विफल हो।
यह स्पष्ट संरचना आपको ठीक-ठीक दिखाती है कि मॉडल कहाँ सोचना बंद करता है, Python कहाँ कमांड चलाने के लिए नियंत्रण लेता है, और आउटपुट लूप में वापस कैसे फीड होता है।
पोस्ट-एडिट हुक जोड़ना
हुक्स गलतियों को पकड़ लेते हैं इससे पहले कि वे बड़े स्ट्रक्चरल मुद्दों में बदलें।
हमारे हार्नेस में, हुक वह फ़ंक्शन है जो एक पूर्ण टूल कॉल का निरीक्षण करता है और टूल परिणाम में जोड़ने के लिए अतिरिक्त टेक्स्ट लौटाता है।
सफलता खाली स्ट्रिंग लौटाती है; विफलता विस्तृत रिपोर्ट लौटाती है।
इस फ़ंक्शन को ReAct लूप के ऊपर, टूल एग्ज़ीक्यूटर्स के पास harness.py में जोड़ें। लूप Python के वहाँ पहुँचते ही चल पड़ता है, इसलिए जो कुछ भी वह कॉल करता है, पहले से परिभाषित होना चाहिए।
def post_edit_hook(tool_name: str, tool_input: dict) -> str:
"""Run pytest after any edit to a Python file. Silent on success."""
edited_python = (
tool_name == "write_file" and tool_input.get("path", "").endswith(".py")
)
if not edited_python:
return ""
tests = subprocess.run(
["pytest", "--tb=short", "-q"],
capture_output=True,
text=True,
cwd=WORKSPACE,
timeout=120,
)
# Exit code 5 means "no tests collected", which is fine for our purposes
if tests.returncode in (0, 5):
return ""
return f"\n\n[HOOK] pytest failed after this edit:\n{tests.stdout}"
इसे लूप में वायर करना टूल एक्ज़ीक्यूशन ब्लॉक के अंदर एक-लाइन का बदलाव है:
output = TOOL_EXECUTORS[block.name](**block.input)
output += post_edit_hook(block.name, block.input) # hooks run after every tool call
हुक के बिना, एजेंट टूटी हुई फ़ाइल लिखता है, Wrote 412 characters to fizzbuzz.py देखता है, और आत्मविश्वास से आगे बढ़ जाता है।
हुक के साथ, वही टूल परिणाम सटीक pytest ट्रेसबैक लेकर आता है। अगली इटरेशन में, एजेंट त्रुटि पढ़ता है और बिना किसी अतिरिक्त प्रॉम्प्टिंग के खुद बग ठीक कर देता है।
बेसिक कॉन्टेक्स्ट कम्पैक्शन
कॉन्टेक्स्ट रॉट से लड़ने के लिए, अपनी messages सूची की लंबाई पर नज़र रखें और जब यह बहुत लंबी हो जाए तो पुराने टर्न्स को समरी कर दें।
एक जाल है: आप हिस्ट्री को किसी भी मनमाने बिंदु पर नहीं काट सकते, क्योंकि असिस्टेंट के tool_use ब्लॉक और उसके पेयर्ड tool_result संदेश को साथ रहना चाहिए। जोड़ी को विभाजित करना तत्काल API त्रुटि पैदा करता है।
हमारा कम्पैक्शन फ़ंक्शन कट प्वाइंट को आगे बढ़ाता है जब तक कि वह सुरक्षित सीमा पर न उतर जाए। इसे harness.py के ऊपर बनाएँ:
COMPACTION_THRESHOLD = 20
KEEP_RECENT = 6
def is_tool_result(message: dict) -> bool:
return (
message["role"] == "user"
and isinstance(message["content"], list)
and any(
isinstance(b, dict) and b.get("type") == "tool_result"
for b in message["content"]
)
)
def compact(messages: list) -> list:
if len(messages) <= COMPACTION_THRESHOLD:
return messages
# Never orphan a tool_result from its tool_use: slide the cut forward
cut = len(messages) - KEEP_RECENT
while cut < len(messages) and is_tool_result(messages[cut]):
cut += 1
old, recent = messages[1:cut], messages[cut:]
transcript = "\n".join(f"{m['role']}: {str(m['content'])[:500]}" for m in old)
summary = client.messages.create(
model="claude-haiku-4-5",
max_tokens=500,
messages=[{
"role": "user",
"content": "Summarize this agent transcript. Preserve the task, "
"decisions made, files created, and any unresolved "
f"errors:\n\n{transcript}",
}],
)
return [
messages[0], # always keep the original task verbatim
{
"role": "user",
"content": f"[Earlier progress, summarized by the harness]\n"
f"{summary.content[0].text}",
},
*recent,
]
ReAct लूप के शीर्ष पर, API कॉल से पहले एक पंक्ति जोड़ें:
messages = compact(messages)
हम समरी के लिए छोटा, सस्ता मॉडल उपयोग करते हैं क्योंकि कम्पैक्शन अक्सर चलता है और उसे गति चाहिए।
हम मूल टास्क संदेश को शब्दशः रखते हैं, समरी पर भरोसा करने के बजाय।
हार्नेस अब पूर्ण है।
आगे बढ़ने से पहले, जाँच लें कि आपका harness.py ऊपर से नीचे इस क्रम में पढ़ता है:
- इम्पोर्ट्स,
client,WORKSPACE, औरsystem_prompt TOOLSस्कीमा सूची- एग्ज़ीक्यूटर्स:
run_bash(),write_file(), औरTOOL_EXECUTORS - हुक:
post_edit_hook() - कम्पैक्शन कोड:
COMPACTION_THRESHOLD,KEEP_RECENT,is_tool_result(), औरcompact() - ReAct लूप, हमेशा सबसे अंत में
हुक और कम्पैक्शन सेक्शंस जोड़ने के बाद अंतिम API लूप कैसा दिखना चाहिए, इसका अंदाज़ा देने के लिए, यहाँ पूर्ण और अंतिम लूप है:
messages = [
{
"role": "user",
"content": "Create a fizzbuzz.py script in the workspace, "
"then run it to verify the output.",
}
]
MAX_STEPS = 15
for step in range(MAX_STEPS):
print(f"--- Iteration {step + 1} ---")
# Compaction: summarize old turns before they rot the context
messages = compact(messages)
# The API call: model, memory, history, and tools travel together
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=2000,
system=system_prompt, # AGENTS.md text, re-injected every turn
messages=messages, # the full (possibly compacted) history
tools=TOOLS, # the schemas from the tools section
)
# Append the model's turn to the history
messages.append({"role": "assistant", "content": response.content})
# Stop condition: the model answered without requesting a tool
if response.stop_reason != "tool_use":
final_text = "".join(b.text for b in response.content if b.type == "text")
print(f"Task complete: {final_text}")
break
# Execute EVERY tool call in this turn, collecting the results
tool_results = []
for block in response.content:
if block.type != "tool_use":
continue
print(f"Agent calling {block.name}: {block.input}")
output = TOOL_EXECUTORS[block.name](**block.input)
output += post_edit_hook(block.name, block.input) # hooks run after every tool call
tool_results.append(
{"type": "tool_result", "tool_use_id": block.id, "content": output}
)
# All tool results for one assistant turn go back in ONE user message
messages.append({"role": "user", "content": tool_results})
else:
print("Stopped: hit the maximum iteration cap without finishing.")
अब प्रोजेक्ट रूट से एजेंट चलाएँ python harness.py।
स्क्रिप्ट messages सूची से टास्क को API पर भेजती है।
हार्नेस काम करता है और आपको अपने टर्मिनल में हर इटरेशन प्रिंट होता दिखना चाहिए:
--- Iteration 1 ---
Agent calling write_file: {'path': 'fizzbuzz.py', 'content': 'def fizz(n):...'}
--- Iteration 2 ---
Agent calling run_bash: {'command': 'python fizzbuzz.py'}
--- Iteration 3 ---
Task complete: fizzbuzz.py is written and prints the correct sequence.
प्रोग्राम तब निकलता है जब मॉडल बिना टूल कॉल के जवाब देता है, या जब 15-इटरेशन कैप ट्रिप हो जाती है।
एजेंट को अलग टास्क देने के लिए, शुरुआती messages सूची में content स्ट्रिंग बदलें; प्रोडक्शन हार्नेस इसे input() या किसी कमांड-लाइन आर्ग्युमेंट से पढ़ेगा।
अपने एजेंट हार्नेस में सुधार: रैचेट इन एक्शन
रैचेट एजेंट विफलताओं का लगातार निदान करने और उन्हें रोकने के लिए अपने हार्नेस को अपडेट करने की प्रक्रिया है।
हार्नेस केवल वास्तविक दुनिया के एज केस देखने से ही सख्ती से बेहतर होता है।
आइए एक वास्तविक रूट ऑप्टिमाइज़ेशन प्रोजेक्ट पर आधारित पूर्ण विफलता और समाधान चक्र से गुजरते हैं।
मान लीजिए आपका एजेंट अपडेटेड वर्ज़न की बजाय legacy_route_math नामक एक डिप्रिकेटेड इंटरनल राउटिंग लाइब्रेरी इम्पोर्ट करता रहता है।
एजेंट स्क्रिप्ट लिखता है, टेस्ट फेल होते हैं, और वह लाइब्रेरी बदलने की बजाय सिंटैक्स ठीक करने की कोशिश में लूप में फँस जाता है।
यहाँ निदान सीधा है।
एजेंट बस यह नहीं जानता कि लाइब्रेरी डिप्रिकेटेड है। यह एक गुम नियम है, न कि अंतर्निहित न्यूरल नेटवर्क की विफलता।
फ़िक्स 1 मेमोरी लेयर अपडेट करता है, AGENTS.md में यह एक नियम जोड़ें:
# Rules
1. Never use rm -rf. Use standard rm with specific file names.
2. Never write tests inside the main application file.
3. When you finish the task, reply with a plain-text summary and no tool call.
4. Do not import legacy_route_math; it is deprecated. Use routes_v2 instead.
फ़िक्स 2 एक स्थायी प्रवर्तन हुक जोड़ता है।
नियम एजेंट के लिए सलाह हैं, हुक कमांड्स हैं। यह फ़िक्स कुछ पंक्तियाँ है और post_edit_hook() के पास जोड़ा जा सकता है, जब तक कि वह ReAct लूप से पहले हो।
def deprecated_import_hook(tool_name: str, tool_input: dict) -> str:
if tool_name != "write_file":
return ""
if "import legacy_route_math" in tool_input.get("content", ""):
return (
"\n\n[HOOK] Blocked pattern: legacy_route_math is deprecated. "
"Rewrite this file using routes_v2 instead."
)
return ""
इसे टूल एक्ज़ीक्यूशन ब्लॉक में pytest हुक के बगल में रजिस्टर करें:
output += post_edit_hook(block.name, block.input)
output += deprecated_import_hook(block.name, block.input)
दोनों फ़िक्स लागू होने के बाद ट्रांस्क्रिप्ट में सेल्फ-करेक्शन ऐसा दिखता है।
एजेंट फ़ाइल लिखता है, हुक फायर होता है, और अगला ही टर्न बिना मानव हस्तक्षेप के इम्पोर्ट ठीक कर देता है:
--- Iteration 3 ---
Agent calling write_file: {'path': 'optimizer.py', ...}
[HOOK] Blocked pattern: legacy_route_math is deprecated...
--- Iteration 4 ---
Agent calling write_file: {'path': 'optimizer.py', ...} # now imports routes_v2
--- Iteration 5 ---
Task complete: Rewrote optimizer.py using routes_v2 and verified the tests pass.
यह महत्वपूर्ण है क्योंकि यह कॉन्टेक्स्ट रॉट से जुड़ता है। बहुत लंबे सत्रों में बिगड़ा हुआ कॉन्टेक्स्ट अंततः मेमोरी नियमों को नज़रअंदाज़ कर देगा।
AGENTS.md का नियम ज्यादातर समय गलती को रोकता है, और हुक यह सुनिश्चित करता है कि जब नियम फिसले, तब भी गलती कोई नुकसान न करे।
हर विफलता जिसका आप निदान करते हैं, आपको दो सवाल पूछने चाहिए: कौन सा नियम गायब था, और कौन सी जाँच फिर भी उसे पकड़ सकती थी?
एजेंट हार्नेस इंजीनियरिंग के लिए सर्वोत्तम प्रथाएँ
एजेंट हार्नेस इंजीनियरिंग की सर्वोत्तम प्रथाएँ कॉन्फ़िगरेशन को हल्का रखने और भविष्य के मॉडल अपग्रेड के लिए डिजाइन करने पर केंद्रित हैं।
उद्देश्य ऐसा स्कैफोल्डिंग बनाना है जो मॉडल को सहारा दे, उसे अभिभूत नहीं करे।
मैंने विभिन्न एजेंट स्किल्स और आर्किटेक्चर्स बनाते हुए कुछ कड़े सबक सीखे हैं।
AGENTS.md को छोटा और अर्जित रखें
अपने कॉन्टेक्स्ट फ़ाइल के लिए अधिकतम 60 पंक्तियों का लक्ष्य रखें।
हर एक नियम का संबंध किसी वास्तविक, दस्तावेज़ीकृत विफलता से होना चाहिए जो आपने अनुभव की हो। यदि आप नियम के लिए घटना याद नहीं कर सकते, तो उसे हटाना उचित है।
यह अनुशासन इसलिए मायने रखता है क्योंकि AGENTS.md हर टर्न पर भुगतान किया जाता है।
300-पंक्ति का स्टाइल गाइड हर API कॉल पर आपके टोकन खर्च करता है और उन नियमों को पतला करता है जो मायने रखते हैं, क्योंकि मॉडल 10 तेज नियमों का 80 धुंधले नियमों की तुलना में कहीं बेहतर पालन करते हैं।
डेटस्टैम्प जोड़ना भी मेरी अगली सिफारिश में मदद कर सकता है।
ओब्सोलेसेंस के लिए डिजाइन करें
बेस मॉडल अपनी मूल क्षमताओं में सुधार करते हैं, इसलिए हार्नेस की लगातार री-आर्किटेक्चरिंग की जरूरत होती है।
अपने कंपोनेंट्स को ऐसे बनाएं कि आप उन्हें आसानी से हटा सकें।
इस ट्यूटोरियल में हुक पैटर्न इसी कारण जानबूझकर मॉड्यूलर है।
हर हुक अलग फ़ंक्शन है जिसे एक पंक्ति के रूप में जोड़ा जाता है। यदि आप हुक को डिप्रिकेट करते हैं, तो आप लूप में एक पंक्ति हटा देते हैं।
लूप में और कुछ नहीं बदलता।
इसे उस वैलिडेशन लॉजिक से तुलना करें जो सीधे आपके ReAct लूप में बुना गया है, जहाँ किसी बासी चेक को हटाने का मतलब पूरे ऑर्केस्ट्रेशन पाथ का फिर से परीक्षण करना है।
जो आज आवश्यक बैसाखी लगता है, अगली तिमाही में अनावश्यक ओवरहेड बन जाएगा।
जब नया मॉडल रिलीज़ हो, अपने पुराने विफलता मामलों को हर हुक को एक-एक कर अक्षम करके फिर चलाएं, और जिस हुक से अब कुछ नहीं पकड़ा जाता, उसे हटाने का उम्मीदवार मानें।
और अधिक आर्किटेक्चर टिप्स के लिए देखें Claude Code Best Practices।
सरल से शुरू करें और परतें जोड़ें
फाइल सिस्टम और एक Bash टूल के साथ एक साधारण ReAct लूप पहले से ही बहुत व्यावहारिक है।
भारी फ्रेमवर्क्स का उपयोग करके पहले से एक जटिल ग्राफ सिस्टम बनाने के प्रलोभन का विरोध करें। रैचेट केवल एक दिशा में काम करता है—देखी गई विफलता से लक्षित फ़िक्स तक। काल्पनिक फ़िक्स इसे उलट देते हैं।
कस्टम हुक्स केवल तब जोड़ें जब आपने वह सटीक विफलता देख ली हो जो उन्हें उचित ठहराती है। बेसिक सिस्टम स्ट्रक्चरिंग पर अधिक के लिए यह गाइड देखें LLM एजेंट्स।
एजेंट जो कुछ करता है उसे लॉग करें
आप उस चीज़ को रैचेट नहीं कर सकते जिसे आप देख नहीं सकते।
हमारा लूप पहले से हर टूल कॉल प्रिंट करता है, और यह न्यूनतम व्यावहार्य ऑब्ज़र्वेबिलिटी है: जब कोई रन विफल होता है, तो प्रिंटेड ट्रांसक्रिप्ट आपका निदान सामग्री है।
जैसे-जैसे आपका हार्नेस परिपक्व होता है, रन के अंत में हर सत्र का पूरा संदेश इतिहास एक टाइमस्टैम्प्ड JSON फ़ाइल में लिखें।
असफल ट्रांसक्रिप्ट्स आपका रिग्रेशन सूट बनते हैं; हर हार्नेस बदलाव के बाद पुराने असफल टास्क फिर चलाएँ और पुष्टि करें कि फ़िक्स अब भी कायम है।
यह हार्नेस इंजीनियर के टेस्ट सूट का समतुल्य है, और यह उस हार्नेस को अलग करता है जो बेहतर होता है उससे जो केवल बदलता है।
अंतिम विचार
एजेंट हार्नेस इंजीनियरिंग AI मॉडलों से उपयोगी काम करवाने की व्यावहारिक हकीकत है।
आज के मॉडल क्या सैद्धांतिक रूप से कर सकते हैं और आप उन्हें प्रोडक्शन में वास्तव में क्या करते देखते हैं—इनके बीच की खाई काफी हद तक हार्नेस की खाई है।
यह शास्त्र किसी विशेष फ्रेमवर्क सीखने के बारे में नहीं है।
आपके कोडबेस के लिए सही AI एजेंट हार्नेस पूरी तरह से आपकी अनोखी विफलता हिस्ट्री से आकार लेता है, रैचेट मेथड के जरिए क्रमिक रूप से बनाया जाता है।
क्या आप इन अवधारणाओं को अभ्यास में उतारने के लिए तैयार हैं?
DataCamp का AI Agent Fundamentals स्किल्स ट्रैक देखें ताकि प्रोडक्शन-रेडी सिस्टम बनाते रहें। आप Claude Agent SDK ट्यूटोरियल भी देख सकते हैं अधिक हैंड्स-ऑन कोड उदाहरणों के लिए।
आप AI for Software Engineering स्किल्स ट्रैक भी देखना चाहेंगे।
Agent harness इंजीनियरिंग FAQs
मॉडल और एजेंट हार्नेस में क्या अंतर है?
मॉडल प्रॉम्प्ट इनपुट्स के आधार पर टेक्स्ट जनरेट करता है। एजेंट हार्नेस वह आस-पास का इन्फ्रास्ट्रक्चर है जो मॉडल को टूल्स, मेमोरी, और नियम देता है ताकि वह किसी वातावरण में कार्य निष्पादित कर सके।
मुझे AGENTS.md फ़ाइल क्यों उपयोग करनी चाहिए?
AGENTS.md फ़ाइल सिस्टम प्रॉम्प्ट में प्रोजेक्ट-विशिष्ट नियम और कॉन्टेक्स्ट इंजेक्ट करती है। यह मॉडल को आपकी टेक स्टैक का अनुमान लगाने या आपकी आंतरिक कोडिंग परंपराओं का उल्लंघन करने से रोकती है।
ReAct लूप क्या है?
Reason and Act (ReAct) लूप एक फ्रेमवर्क है जिसमें एजेंट समस्या पर सोचता है, कोई टूल कॉल करके क्रिया करता है, और फिर दोबारा सोचने से पहले परिणाम का निरीक्षण करता है। यह तब तक लूप करता है जब तक टास्क पूरा न हो जाए।
हुक्स एजेंट विफलताओं को कैसे रोकते हैं?
हुक्स विशेष लाइफसाइकल क्षणों पर कस्टम स्क्रिप्ट्स चलाते हैं, जैसे किसी फ़ाइल एडिट के बाद टेस्ट सूट चलाना। यदि टेस्ट फेल होता है, तो हुक त्रुटि को तुरंत एजेंट तक लौटाता है ताकि वह खुद-सुधार कर सके।
AI एजेंट्स में कॉन्टेक्स्ट रॉट क्या है?
कॉन्टेक्स्ट रॉट तब होता है जब वार्तालाप इतिहास बहुत बड़ा हो जाता है और मॉडल निर्देशों को अनदेखा करने या लक्ष्य का ट्रैक खोने लगता है। आप पुराने संदेशों को समरी करके जगह खाली करके इसे ठीक करते हैं।
मैं एक डेटा साइंटिस्ट हूँ, जिसे स्पैटियल विश्लेषण, मशीन लर्निंग और डेटा पाइपलाइनों का अनुभव है। मैंने GCP, Hadoop, Hive, Snowflake, Airflow और अन्य डेटा साइंस/इंजीनियरिंग प्रक्रियाओं के साथ काम किया है।
