Show HN: Outlines - LLM को valid JSON आदि structured output जनरेट करने की गारंटी देने वाला टूल
(github.com/normal-computing)- Outlines, LLM के लिए structured output टूल है, जो generation के दौरान इच्छित output type निर्दिष्ट करके यह सुनिश्चित करता है कि डेटा उसी structure से ठीक-ठीक मेल खाए
- parsing, regex, और fragile code के सहारे generation के बाद गलत output को ठीक करने के बजाय, यह generation चरण में ही valid structure को सीधे enforce करता है
- इसका उपयोग
model(prompt, output_type)के रूप में होता है, औरLiteral["Yes", "No"],int, Pydantic model जैसे Python type system के अनुरूप output निर्दिष्ट किया जा सकता है - supported output types में predefined choices, function signature-आधारित Function Calls, JSON/Pydantic schema, regex pattern, और grammar-based structure enforcement शामिल हैं
- model integration को server support वाले vLLM·Ollama, local model support वाले transformers·llama.cpp, और API support वाले OpenAI·Gemini·Dottxt में विभाजित किया गया है
- उदाहरण workflows में customer email को service ticket में बदलना, product description को category data में बदलना, अधूरे event description से structured information या
"I don't know"लौटाना, document को predefined categories में classify करना, और natural language meeting request को function parameters में बदलना शामिल है - prompt templates, Jinja-आधारित
outlines.Template.from_stringऔर file loading को support करते हैं, ताकि complex prompts को code से अलग करके दोबारा इस्तेमाल किया जा सके - installation
pip install outlinesसे उपलब्ध है, और.txt APIको फिलहाल early access स्थिति में दिखाया गया है
1 टिप्पणियां
Hacker News टिप्पणियाँ
यह लाइब्रेरी mechanism के तौर पर vocabulary space के एक हिस्से को mask करने और time steps के हिसाब से efficiently आगे बढ़ने वाले एक सरल idea का इस्तेमाल करती लगती है, और यह बढ़िया है
हालांकि base LLM पर output structure थोपने वाली libraries इस्तेमाल करने के अनुभव से, मुझे जिज्ञासा है कि Llama2 जैसे base models सच में कितने अच्छे से काम करते हैं
मेरे अनुभव में यह “बिलकुल नहीं” के करीब है, और इसे वास्तव में काम कराने के लिए किसी खास use case के हिसाब से काफ़ी instruction tuning की जरूरत पड़ी थी
ऊपर से, instruction-tuned model में generation के दौरान बाद में state space को mask करना आखिरकार generation distribution को बदलना ही है, इसलिए यह intuition के खिलाफ लगता है कि यह instruction tuning के लिए नुकसानदेह भी हो सकता है
दूसरे point पर, अगर लक्ष्य उदाहरण के लिए model से सिर्फ JSON generate कराना है, तो कौन-से output tokens इस्तेमाल हो सकते हैं और कौन-से नहीं, इसे restrict करके यह 100% संभव है
M2 Mac पर GPU इस्तेमाल कर सकता हूँ, इसलिए MLC version को https://github.com/simonw/llm-mlc plugin के रूप में इस्तेमाल कर रहा हूँ
paper “Guiding Language Models of Code with Global Context using Monitors”(https://arxiv.org/abs/2306.10763) में Monitor Guided Decoding प्रस्तावित किया गया था, जो LLM को static analysis से जोड़कर type-consistent code generate करने के लिए guide करता है
किसी भी fine-tuning के बिना, खास points पर static analysis से token-level generation को guide करने पर generated code की quality, compilability और सही answer से match—दोनों में काफी बेहतर हुई। बहुत छोटे models (1.1B) ने भी कहीं बड़े models (175B) की तुलना में अधिक compilable code बनाया और answer match भी improve किया
मुख्य फर्क सिर्फ इतना था कि generation function LLM नहीं बल्कि इंसान था। बीच के इंसान को हटाने की वजह नहीं दिखती
traditional code में edge cases literally छोटे special cases जैसे होते थे, लेकिन LLM में पता नहीं होता कि क्या चीज़ उसे गलत दिशा में उछाल देगी, और parsing code को उस chaos को संभालना पड़ता है
दूसरे शब्दों में, edge case के रूप में treat किए जाने वाले cases का अनुपात बहुत ज्यादा बढ़ गया महसूस होता है
GPT-4 को system message में examples ही डाल दें तो उससे valid JSON लौटवाया जा सकता है, और दस में नौ बार यह काम करता है
लेकिन यह अभी भी probabilistic है, और दस में नौ बार काफी नहीं है
कभी-कभी यह
{"key1": "value1", "key2": "value2" for i in range(n)}जैसे hallucinated responses भी बना देता हैparsing error message के साथ फिर से prompt करने पर आम तौर पर दूसरे प्रयास में solve हो जाता है
लेकिन double quotes और newline characters को escape करना कम stable है। कई examples देने पर भी लगभग आधे मामलों में ही सही escape करता है, और escape error पर दोबारा prompt करने पर भी success rate करीब 50% ही रहता है
वह prompt यहाँ है: https://github.com/microsoft/TypeChat/blob/c45460f4030938da3...
मुझे लगता है कि यहाँ दिख रही grammar-based approach या https://github.com/ggerganov/llama.cpp/pull/1773 जैसे तरीके कहीं ज्यादा elegant solution हैं
समझता हूँ कि लोग JSON चाहते हैं, लेकिन मेरे लिए यह बिल्ली को तैराने जैसा है। आखिर में आप सफल हो सकते हैं, पर यह उसकी natural tendency नहीं है
मुख्य गलती escape route न देना है। LLM सही answer खोजने की कोशिश करता है, इसलिए अगर आपने texts डालकर structured data लौटाने को कहा और किसी text में कुछ नहीं है, तो सही answer तय करना मुश्किल हो जाता है और hallucination होती है
solution यह है कि arguments में से एक के रूप में
textIsMissingजैसा boolean रखकर escape route बनाया जाए। इन failure modes का ध्यान रख लें तो यह flawless काम करता हैकई बार retry किया और follow-up fixes भी करवाए, लेकिन validation पास नहीं हुआ, और 100% valid JSON एक बार भी generate नहीं कर पाया, इसलिए आखिरकार छोड़ दिया
पहला, prompt में बहुत ज्यादा examples डालने की जरूरत नहीं होती, इसलिए tokens कम लगते हैं
दूसरा, forgetting problem का असर कम पड़ता है
एक छोटा फायदा यह है कि आप ठीक-ठीक control कर सकते हैं कि desired output कहाँ से शुरू होना चाहिए। हालांकि overall यह एक अच्छा add-on feature है, मुझे यह बहुत fundamental नहीं लगता
LLM की ताकत का एक बड़ा हिस्सा उसके जवाबों का calibrated probability distribution है, लेकिन यह तकनीक शायद उस क्षमता को छोड़ देती है। सवाल है कि यह स्तर पर्याप्त क्यों माना जाए
एक साधारण उदाहरण लें: मान लें LLM के संभावित output सिर्फ “hello world”, “food”, “hello”, “good day” हैं और prompt न होने पर सभी की probability समान है। मान लें grammar केवल यह constraint लगाती है कि output में कहीं न कहीं space होना चाहिए
अगर grammar पास होने तक LLM output sample करें, तो “hello world” और “good day” समान probability से मिलेंगे। लेकिन वेबसाइट की तकनीक लागू करने पर “hello world”, “good day” की तुलना में दोगुनी बार आएगा
मुख्य समस्या यह है कि किसी answer prefix के valid response तक पहुंचने की संभावना बेहद कम रही हो सकती है, फिर भी यह तकनीक, सफलता मानते हुए, उसी prefix से valid response बना देती है। अगर सही जगहों पर पर्याप्त independence हो तो ठीक हो सकता है, लेकिन autoregressive models में correlated errors तेजी से जमा हो जाते हैं
सिर्फ JSON तक सीमित करके पूछें तो: जब LLM ऐसा response बनाता है जो schema follow नहीं करता, तो क्या वह factual errors, hallucinations, कटी हुई strings, मुख्य characters की omission आदि ज्यादा बनाता है या कम? अगर factual error rate schema error rate से non-trivially related है, तो यह रास्ता दिखने से ज्यादा खतरनाक है। जिस तरह किसी खास शब्द या चिपके हुए phrase का LLM output पर बड़ा असर दिखता है, उससे लगता है कि schema compliance जैसी details भी output की दूसरी properties में फैल सकती हैं
मैंने ऐसा उदाहरण सोचने की कोशिश की जहाँ “answer prefix के valid response तक पहुंचने की संभावना बहुत कम थी, लेकिन technique किसी तरह valid response बना कर समस्या पैदा करती है”, पर अच्छा example दिमाग में नहीं आया। अगर कोई अच्छा example हो तो यह एक दिलचस्प research question हो सकता है
संबंधित रूप से LLama.cpp ने पिछले महीने grammar-based sampling implement किया था
https://news.ycombinator.com/item?id=36819906
https://github.com/ggerganov/llama.cpp/pull/1773
हमारा तरीका काफी ज्यादा efficient है। llama.cpp हर step पर mask बनाने के लिए पूरे vocabulary, लगभग 50k tokens, पर iterate करता है
हम initialization के समय index बनाते हैं, और हर step पर mask construct करते समय सिर्फ dictionary lookup करना होता है। यह speed को memory से trade off करता है, और sampling standard sampling जितनी तेज होती है
इससे जुड़े papers काफी थे, इसलिए शायद कई और जगहों पर भी ऐसा रहा होगा। यहां और मौजूदा काम का point बहुत low-cost guidance देना है; regex case में यह कुछ समय से implemented था और बाद में JSON तक extend किया गया
इसे बनाने के लिए धन्यवाद; इसका काम करने का तरीका इतना obvious idea लगता है कि हैरानी है कि first-party platforms ने इसे अभी तक नहीं किया
JSON के अलावा, structured input की जरूरत वाले दूसरे कामों में इसका कैसे इस्तेमाल हो सकता है, यह जानने की उत्सुकता है
यह limited developer resources का नतीजा भी हो सकता है। अगर 10 साल पुरानी technology में ऐसी basic feature missing होती तो हैरानी होती, लेकिन arms race वाली AI technology में अभी convenience features का missing होना समझ में आता है
मुझे ठीक से समझ नहीं आ रहा कि यह नीचे दिए गए projects से कैसे अलग है
https://github.com/1rgs/jsonformer
https://github.com/newhouseb/clownfish
https://github.com/mkuchnik/relm
https://github.com/ggerganov/llama.cpp/pull/1773
https://github.com/Shopify/torch-grammar
कुल मिलाकर ऐसे logit-based guidance systems बहुत हैं, और इन्हें ज्यादा traction न मिलने की वजह यह है कि best-performing models ऐसे REST APIs के पीछे हैं जो इतना fine-grained approach allow नहीं करते
वे models कहीं ज्यादा powerful हैं, इसलिए लोग आम तौर पर तब तक फिर से request करने से संतुष्ट रहते हैं जब तक सही format न आ जाए। GPT-4 में मेरे अनुभव के मुताबिक ऐसे failures काफी rare भी हैं
हम initialization के समय vocabulary पर एक बार iterate करके index बनाते हैं, और उसके बाद generation standard generation जितनी तेज होती है
दूसरे तरीके से कहें तो, क्या हर बार जब LLM एक token generate करता है, आप logits bias “mask” को update करते हैं ताकि अगला token सिर्फ़ valid JSON token ही हो? बहुत शानदार
मुझे यकीन नहीं कि यह तरीका सच में 100% guarantee कैसे दे सकता है
edit: paper में इस हिस्से को ज़्यादा सावधानी से समझाया गया है
क्या यह Brandon Willard वही Detroit वाला breakdancer Brandon Willard है?
edit: हाँ! https://brandonwillard.github.io/
remilouf, आपने अपनी background “probabilistic, relational, symbolic programming” बताई है, इसलिए लगता है कि आप समझते होंगे कि regular grammars या context-free grammars, बल्कि practically किसी भी level की grammar से text generate करना समस्या नहीं है
उदाहरण के लिए relational language Prolog में Definite Clause Grammars notation के साथ, अगर grammar दी हो तो यह बहुत आसानी से किया जा सकता है
मुझे लगता है इस approach में user को grammar provide करनी पड़ती है। तो फिर text generation के लिए LLM इस्तेमाल करने का फायदा क्या है, यह जानना चाहूँगा
सिर्फ़ grammar को generator की तरह run करके मनचाहा text क्यों न बनाया जाए? इससे शुरुआत में LLM train करने की बड़ी मेहनत और cost बच सकती है। अगर मकसद सिर्फ़ structured text generate करना है, तो natural-language model LLM की ज़रूरत क्यों है, यह भी सवाल है
सिर्फ़ structured text चाहिए तब भी LLM की ज़रूरत इसलिए है, ताकि इंसान द्वारा लिखे unstructured text को parse करके machine-usable structured data लौटाया जा सके
अगर request है “pi के पहले 10 digits क्या हैं?” और response को regex
"[0-9]+\.[0-9]+"तक सीमित किया गया है, तो मकसद सिर्फ़ pattern से match करने वाली “1.2346789” जैसी random string नहीं, बल्कि असली जवाब 3.1415926535 पाना हैदिलचस्प है, और हाल ही में हमने भी एक similar tool बनाया है[1] जो llama output को TypeScript interface से match करने तक सीमित करता है
मेरा दृढ़ विश्वास है कि output format guarantees आने वाले दशकों में, जब LLMs सचमुच non-toy use cases में इस्तेमाल होंगे, महत्वपूर्ण बनेंगे
[1] https://github.com/ggerganov/llama.cpp/discussions/2494