प्रॉम्प्ट्स म्हणजे सूचना आहेत. हुक्स (Hooks) म्हणजे कडक निर्बंध आहेत.
कित्येक महिने, मी Claude Code कडे एका ज्युनियर डेव्हलपरप्रमाणे वागलो ज्याला फक्त स्पष्ट नियमांची गरज होती. माझे प्रोजेक्ट इन्स्ट्रक्शन्स स्पष्ट होते: कधीही force-push करू नका, कधीही branches डिलीट करू नका, कधीही destructive commands चालवू नका. बहुतेक संध्याकाळी, हे काम करत असे. एजंटने टेस्ट्स लिहिल्या, फंक्शन्स रिफॅक्टर केली आणि git history ला हातही लावला नाही. मग एक rebase चुकले.
कॉन्टेक्स्ट विंडो git एरर आउटपुटने भरून गेली. कॉन्फ्लिक्ट मार्कर्स, detached HEAD मेसेजेस आणि ब्रँच डायव्हर्जन्स वॉर्निंग्स टोकन-बाय-टोकन साचत गेल्या. त्या गोंधळात माझी 'force-push टाळा' अशी नम्र सूचना गाडली गेली होती. मॉडेलसाठी, थ्रेडमधील सर्वात अलीकडील आणि महत्त्वाचा मजकूर म्हणजे एरर स्ट्रीम होता. सांख्यिकीय लक्ष (Statistical attention) धोरणावर (policy) भारी पडले. एजंटने अशी कमांड चालवली ज्यामुळे दोन तासांचे अनकमिटेड लोकल बदल पुसले गेले. हे द्वेषपूर्ण नव्हते; ते केवळ विचलित झाल्यामुळे झाले होते. हा फरक महत्त्वाचा आहे. LLM द्वेषपोटी नियम मोडत नाही. ते नियम तेव्हा मोडते जेव्हा कॉन्टेक्स्ट विंडोमधील एखादा मोठा पॅटर्न तात्पुरत्या स्वरूपात आधीच्या सूचनेपेक्षा जास्त प्रभावी ठरतो.
त्या घटनेमुळे एजंट सेफ्टीबद्दलचा माझा विचार बदलला. ९९ टक्के वेळ काम करणारा गार्डरेल (guardrail) हा प्रत्यक्षात एक धोका आहे. जर त्या त्रुटीमुळे तुमचा वेळ, पैसा किंवा प्रोडक्शन डेटा गेला, तर तुम्ही ती सूचना फक्त प्रॉम्प्टमध्ये सोडू शकत नाही. तुम्हाला मॉडेलच्या रिझनिंग लूपच्या बाहेर अंमलबजावणी (enforcement) करण्याची गरज आहे.
Claude Code हुक्स नेमकी हीच समस्या सोडवतात. ते लहान स्क्रिप्ट्स आहेत जे तीन विशिष्ट क्षणी टूल कॉल्सना अडवतात: टूल चालण्यापूर्वी (PreToolUse), टूल पूर्ण झाल्यानंतर (PostToolUse), आणि जेव्हा एजंट ठरवतो की काम संपले आहे (Stop). ते बाह्य कोड म्हणून चालत असल्यामुळे, ते मॉडेलची मेमरी, मूड किंवा कॉन्टेक्स्ट प्रेशरवर अवलंबून नसतात. मॉडेल तुम्ही दिलेली प्रत्येक सूचना विसरू शकते; पण हुक तरीही 'नाही' म्हणेल.
तो वाया गेलेला संध्याकाळचा अनुभव घेतल्यानंतर मी तयार केलेले हार्नेस (harness) खालीलप्रमाणे आहे.
द गार्ड हुक: नुकसान होण्यापूर्वी अडवा
माझा PreToolUse हुक प्रत्येक Bash कमांड शेलला स्पर्श करण्यापूर्वी तपासतो. मी विनाशकारी (destructive) पॅटर्नची एक कडक denylist ठेवली आहे. जर कमांड स्ट्रिंग एखाद्या धोकादायक गोष्टीशी जुळली, तर हुक अंमलबजावणी थांबवतो आणि थेट एजंटला एरर परत करतो.
मी ब्लॉक केलेले पॅटर्न साधे आणि स्पष्ट आहेत:
git push --forceकिंवा कोणताही force-with-lease प्रकार ज्यावर मला अजून विश्वास नाहीgit reset --hardrm -rf
हे कोणतेही प्रगत सुरक्षा संशोधन नाही. हे फक्त एका सीटबेल्टसारखे आहे. पण महत्त्वाचा तपशील म्हणजे ब्लॉक केल्यानंतर काय होते.
मी कधीही फक्त "Blocked" असे उत्तर देत नाही. सरळ नकार दिल्याने एजंट गोंधळतो आणि तो त्याच विनाशकारी कमांडच्या विविध प्रकारांमध्ये अडकू शकतो. त्याऐवजी, एरर मेसेजमध्ये बाहेर पडण्याचा मार्ग (escape route) असतो. जेव्हा हुक 'hard reset' पकडतो, तेव्हा तो एजंटला सांगतो: “अनकमिटेड कामाचे संरक्षण करण्यासाठी ही कमांड ब्लॉक केली आहे. प्रथम एक चेकपॉइंट कमिट करा, मग पुन्हा विचार करा.” हे अतिरिक्त वाक्य एजंटचे वर्तन पूर्णपणे बदलते. तो नुकसान करण्याच्या प्रयत्नांऐवजी सुरक्षितता निर्माण करण्याकडे वळतो. हुक केवळ एक भिंत नाही; ते ट्रॅफिक कंट्रोल आहे.
मी शेल कमांड्ससाठी allowlist ऐवजी denylist निवडली. सुरुवातीला, मी फक्त सुरक्षित git सब-कमांड्सचा संच परवानगी देण्याचा विचार केला होता. पण ते लवकरच अपयशी ठरले. एजंट्स अतिशय शब्दशः (literal) काम करतात. ते स्थिती तपासण्यासाठी git stash push -m "wip" किंवा git branch --show-current सारख्या वैध पण अनपेक्षित कमांड्स चालवतात. जर मॉडेलने एखादी वैध पण लिस्टमध्ये नसलेली कमांड शोधली, तर allowlist सामान्य वर्कफ्लोमध्ये अडथळा आणते. खरोखरच विनाशकारी पॅटर्नची एक छोटी, निवडक denylist एजंटला काम करण्यासाठी मोकळीक देते आणि सीमांचे संरक्षणही करते.
द फॉरमॅटर हुक: कंटाळवाणी कामे स्वयंचलित करा
मी एजंटला "फाईल एडिट केल्यानंतर नेहमी फॉरमॅटर चालवा" असे सांगण्यात प्रॉम्प्ट टोकन्स वाया घालवत असे. तो अर्ध्या वेळा विसरून जायचा. उरलेल्या अर्ध्या वेळा, तो थांबायचा आणि फॉरमॅट करायचे की नाही हे विचारायचा, ज्यामुळे एकाच उत्तरासाठी टूल कॉल वाया जायचा.
आता मी ते PostToolUse हुकद्वारे हाताळतो. एजंटने फाईल एडिट केल्यानंतर, हुक फाईल एक्स्टेंशन तपासतो. जर ती Python असेल, तर तो Ruff चालवतो. जर ती JavaScript किंवा TypeScript असेल, तर तो Prettier चालवतो. जर ती Go असेल, तर तो gofmt चालवतो. एजंटला फॉरमॅटर अस्तित्वात आहे हे माहित नसते. त्याला त्याची गरजही नसते.
हे प्रॉम्प्टमधून बाहेर काढण्याचे दोन परिणाम झाले. पहिले म्हणजे, मॉडेलवर अतिरिक्त ताण न टाकता कोड सातत्याने स्वच्छ राहतो. दुसरे म्हणजे, माझे प्रोजेक्ट इन्स्ट्रक्शन्स लहान झाले. तुम्ही प्रॉम्प्टमधून प्रत्येक "नेहमी" (always) आणि "कधीही नाही" (never) काढता, तेव्हा मॉडेलला प्रत्यक्ष समस्या सोडवण्यासाठी एक टोकन मिळते. हुक नियमांची (invariant) जबाबदारी घेतो; प्रॉम्प्ट हेतूची (intent) जबाबदारी घेतो.
द क्वालिटी गेट: "पूर्ण झाले" याची नवीन व्याख्या
जेव्हा एजंटला वाटते की त्याने काम पूर्ण केले आहे आणि तो सेशन संपवण्याचा प्रयत्न करतो, तेव्हा 'Stop hook' कार्यान्वित होतो. मी त्याला तसे करू देत नाही. त्याऐवजी, हा hook संपूर्ण टेस्ट सूट (test suite) चालवतो. जर एखादी टेस्ट फेल झाली, तर हा hook 'stop command' रोखतो आणि एरर आउटपुट एजंटला परत पाठवतो.
यामुळे 'पूर्णता' (completion) ची व्याख्या बदलते. "पूर्ण झाले" (Done) ही आता मॉडेलची केवळ एक भावना उरत नाही, तर ती एक मोजता येण्याजोगी अट (measurable gate) बनते. जेव्हा harness हे कन्फर्म करते की कोड व्यवस्थित काम करत आहे, तेव्हाच एजंट काम पूर्ण करू शकतो. व्यवहारात, यामुळे एक घट्ट फीडबॅक लूप (feedback loop) तयार होतो. एजंट कोड लिहितो, त्याला वाटते की काम झाले आहे, तो 'stop' बटण दाबतो आणि लगेच त्याला pytest traceback दिसतो. त्यानंतर तो स्वतःहून सुधारणा करतो, import error किंवा broken assertion दुरुस्त करतो आणि पुन्हा थांबण्याचा प्रयत्न करतो. मी एजंट्सना मानवी हस्तक्षेपाशिवाय या लूपमध्ये तीन-चार वेळा सुधारणा करताना पाहिले आहे. Harness गुणवत्तेची अंमलबजावणी करते; मॉडेल सुधारणा (patches) पुरवते.
यातून एजंट इंजिनीअरिंगबद्दल काय शिकायला मिळते
विश्वसनीय स्वायत्त प्रणाली (autonomous systems) तयार करण्यासाठी विचारसरणीत बदल करणे आवश्यक आहे. तुम्ही लांब प्रॉम्प्ट्स (prompts) लिहिण्याऐवजी अधिक मजबूत harnesses तयार करण्याकडे वळता.
अंमलबजावणीसाठी (enforcement) hooks वापरा आणि धोरणांसाठी (policy) prompts वापरा. जर एखादा नियम शंभर टक्के पाळला जाणे आवश्यक असेल, तर तो कोडमध्ये असावा, नैसर्गिक भाषेत (natural language) नाही. प्रॉम्प्ट्स अस्पष्टता (ambiguity), चव (taste) आणि आर्किटेक्चरमध्ये उत्कृष्ट असतात, परंतु 'invariants' (न बदलणाऱ्या गोष्टी) बाबतीत ते अपयशी ठरतात. जर एखाद्या चुकीमुळे तुमचा बराच वेळ वाया जाणार असेल किंवा त्याहून वाईट, प्रोडक्शन अपटाइम (production uptime) बाधित झाला, तर एक hook लिहा.
लहान प्रॉम्प्ट्स अधिक चांगले परिणाम देतात. जेव्हा तुम्ही यांत्रिक नियम (mechanical rules) स्क्रिप्ट्समध्ये हलवता, तेव्हा मॉडेलला कमी गोष्टी लक्षात ठेवाव्या लागतात आणि विसंगती निर्माण होण्याची शक्यता कमी होते. एजंटची 'context window' ही एक मर्यादित संसाधने (scarce resource) आहे. ती फॉरमॅटिंगच्या सूचनांनी भरू नका.
शेवटी, तुमची भूमिका बदलत आहे हे स्वीकारा. जसा एजंट्सचा स्वायत्तता (autonomy) वाढते, तसे माणसाचे काम कंटेंट तयार करण्याकडून 'guardrails' डिझाइन करण्याकडे वळते. तुम्ही असे harness तयार करत आहात जे ठरवते की मॉडेल कशाला स्पर्श करू शकते, ते कधी काम पूर्ण करू शकते आणि जेव्हा गोष्टी चुकतात तेव्हा ते कसे वागावे. हे इंजिनीअरिंग आहे, केवळ प्रॉम्प्टिंग नाही.
या दृष्टिकोनासाठी प्रेरणा देणारा स्रोत आणि अधिक अंमलबजावणीचे तपशील येथे मिळू शकतात.
जर तुम्ही AI एजंट्ससह काम करत असाल आणि इतर व्यावसायिकांशी चर्चा करू इच्छित असाल, तर तुम्ही GyaanSetu लर्निंग कम्युनिटी येथे शोधू शकता.
