एक SSE स्ट्रीम, सात LLM प्रोव्हायडर्स
मी एक Next.js ॲप बनवले आहे जे सात वेगवेगळ्या LLM प्रोव्हायडर्सना सपोर्ट करते.
OpenAI, Claude, Gemini, Ollama, Mistral, Groq, आणि Azure.
मी एक कडक नियम ठेवला: ब्राउझरने प्रत्येक प्रोव्हायडरसाठी अगदी तोच कोड पाथ (code path) वापरला पाहिजे.
हे कठीण आहे कारण हे APIs सारखे नाहीत. ते वेगवेगळ्या ट्रान्सपोर्ट पद्धती वापरतात. ते वेगवेगळ्या डेटा स्ट्रक्चर्समध्ये (data shapes) डेटा पाठवतात. काही SSE वापरतात तर काही NDJSON वापरतात.
जर तुम्ही हे फरक तुमच्या UI पर्यंत पोहोचू दिले, तर तुमचा कोड "if" स्टेटमेंट्सचा गोंधळ बनून जाईल. प्रत्येक वेळी तुम्ही नवीन प्रोव्हायडर जोडाल, तेव्हा तुमचे फ्रंटएंड अधिक गुंतागुंतीचे होत जाईल.
मी एक सिंगल कॉन्ट्रॅक्ट (contract) तयार करून हे सोडवले. प्रत्येक प्रोव्हायडरने ब्राउझरला हा फॉरमॅट पाठवणे आवश्यक आहे:
• data: {"delta":"
ब्राउझरला फक्त तीन गोष्टी समजून घेणे आवश्यक आहे: delta, error, आणि [DONE].
मी ते कसे बनवले ते खालीलप्रमाणे आहे:
Async Generators वापरा मी प्रत्येक प्रोव्हायडरला एक जनरेटर (generator) म्हणून मानतो जो प्लेन टेक्स्ट देतो. यामुळे API ची गुंतागुंत लपवली जाते.
द Wrapper Pattern मी
createSSEStreamनावाचे एक wrapper फंक्शन तयार केले. हे wrapper वायर फॉरमॅट (wire format) मॅनेज करते. तसेच स्ट्रीम नेहमी संपेल याचीही ते खात्री करते. जर एखादा प्रोव्हायडर अर्धवट प्रक्रियेत फेल झाला, तरीही wrapper एक error आणि [DONE] सिग्नल पाठवते. यामुळे क्लायंट हँग (hang) होत नाही.सारख्या APIs चे गट करणे OpenAI, Mistral, Groq, आणि Azure हे सर्व एकच डायलेक्ट (dialect) वापरतात. मी त्यांच्या सर्वांसाठी एकच इम्प्लिमेंटेशन लिहिले आहे. आता नवीन सुसंगत प्रोव्हायडर जोडण्यासाठी फक्त एक ओळ कोड लागतो.
अपवादांना हाताळणे (Handling Outliers) Anthropic आणि Ollama वेगळ्या पद्धतीने काम करतात. Anthropic विशिष्ट 'typed events' वापरते. Ollama NDJSON वापरते. मी त्यांच्यासाठी कस्टम पार्सर्स (custom parsers) लिहिले आहेत, परंतु ते दोन्ही मजकूर एकाच wrapper मध्ये पाठवतात. ब्राउझरला यातील फरक कधीच कळत नाही.
गोपनीयता आणि साधेपणा हे ॲप "Bring Your Own Key" मॉडेल वापरते.
• वापरकर्ते स्वतःची API की पेस्ट करतात. • की लोकल स्टोरेजमध्ये राहते. • सर्व्हर केवळ एक शुद्ध प्रॉक्सी (proxy) म्हणून काम करतो. • की कधीही डेटाबेसमध्ये साठवली जात नाही.
या पद्धतीमुळे जटिल ऑथेंटिकेशन (auth) किंवा सिक्रेट मॅनेजमेंटची गरज उरत नाही. यामुळे ॲप सेल्फ-होस्ट (self-host) करणे सोपे होते.
धडा साधा आहे: प्रत्येक इंटिग्रेशनला तुम्ही प्रत्यक्षात काय हवे आहे त्याचे जनरेटर म्हणून मॉडेल करा. त्याला एकदा wrap करा. बदलांना (variation) जनरेटर्समध्ये राहू द्या जेणेकरून तुमचा मुख्य लॉजिक स्वच्छ राहील.
पर्यायी लर्निंग कम्युनिटी: https://t.me/GyaanSetuAi