{"id":6779,"date":"2024-12-17T18:30:00","date_gmt":"2024-12-17T17:30:00","guid":{"rendered":"https:\/\/haimagazine.com\/?p=6779"},"modified":"2025-06-26T10:14:18","modified_gmt":"2025-06-26T08:14:18","slug":"pohamuj-swoj-llm-sztuka-zmuszania-ai-do-konkretow","status":"publish","type":"post","link":"https:\/\/haimagazine.com\/pl\/hai-magazine\/pohamuj-swoj-llm-sztuka-zmuszania-ai-do-konkretow\/","title":{"rendered":"\ud83d\udd12 Pohamuj sw\u00f3j LLM. Sztuka zmuszania AI do konkret\u00f3w"},"content":{"rendered":"<p class=\"wp-block-paragraph\">Na przyk\u0142ad gdy chcemy, by modele udziela\u0142y sformalizowanych odpowiedzi, potrafi ponosi\u0107 je fantazja: dodaj\u0105 co\u015b od siebie, zapominaj\u0105 o znakach specjalnych, wplataj\u0105 elementy, kt\u00f3re psuj\u0105 kod, przechodz\u0105 mi\u0119dzy formatami, dodaj\u0105 komunikaty typu: \u201eOto wynik: (&#8230;)\u201d.<\/p><p class=\"wp-block-paragraph\">Oczywi\u015bcie czasem \u2013 zw\u0142aszcza gdy s\u0105 to pojedyncze odpowiedzi \u2013 mo\u017cna r\u0119cznie dostosowa\u0107 je do po\u017c\u0105danego formatu. S\u0105 jednak sytuacje, w kt\u00f3rych wsp\u00f3\u0142praca z modelem skutkuje tysi\u0105cami czy nawet milionami odpowiedzi. Do takich zada\u0144 nale\u017cy np. ekstrakcja danych z du\u017cej liczby dokument\u00f3w lub parsowanie, czyli przetwarzanie danych z jednego formatu na drugi. A w takich zastosowaniach na razie norm\u0105 jest niestety to, \u017ce LLM-y czasem si\u0119 myl\u0105 \u2013 i to na coraz bardziej r\u00f3\u017cnorodne sposoby. Za\u015b poprawa ka\u017cdego z tych uchybie\u0144 przypomina pr\u00f3b\u0119 \u0142atania pojawiaj\u0105cych si\u0119 ci\u0105gle nowych dziur w \u0142odzi. Na otwartym morzu. W trakcie sztormu.<\/p><p class=\"wp-block-paragraph\">I c\u00f3\u017c mamy zrobi\u0107? Pogodzi\u0107 si\u0119 z tym, \u017ce LLM-\u00f3w nie da si\u0119 okie\u0142zna\u0107, bo z za\u0142o\u017cenia s\u0105 one modelami niedeterministycznymi, kt\u00f3re bazuj\u0105 na prawach statystyki? Czy za pomoc\u0105 prompt\u00f3w eskalowa\u0107 w ich kierunku gro\u017aby, licz\u0105c na to, \u017ce w ko\u0144cu nas pos\u0142uchaj\u0105? Ot\u00f3\u017c z LLM-ami jest podobnie jak z dzie\u0107mi i ich wychowaniem \u2013 zamiast grozi\u0107, lepiej postawi\u0107 jasne granice!<\/p><p class=\"wp-block-paragraph\">Problemem tym zaj\u0119to si\u0119 ju\u017c w komercyjnych API, takich jak OpenAI czy Anthropic. Tam strukturyzacja odpowiedzi modeli wydaje si\u0119 prosta. Wystarczy zdefiniowa\u0107 w kodzie schemat, np. przez Pydantic, i u\u017cy\u0107 odpowiedniego trybu <code>response_format<\/code>.<\/p><figure class=\"wp-block-table\"><table class=\"has-very-light-gray-background-color has-background has-fixed-layout\"><tbody><tr><td><code>from pydantic import BaseModel<br>from openai import OpenAI<\/code><mark style=\"background-color:#B7B7B7\" class=\"has-inline-color\"><code><br><\/code><br><\/mark><code>class DocumentInfo(BaseModel):<br>    document_type: str<br>    issue_date: str<br>    amount: float<br>    contractor: str<\/code><mark style=\"background-color:#B7B7B7\" class=\"has-inline-color\"><code><br><\/code><br><\/mark><code>client = OpenAI()<br>completion = client.beta.chat.completions.parse(<br>    model=\"gpt-4o-2024-08-06\",<br>    messages=[<br>        {\"role\": \"system\", \"content\": \"Wydob\u0105d\u017a<br>    informacje z dokumentu.\"},<br>        {\"role\": \"user\", \"content\": \"\"\"Faktura VAT<br>    15\/2024 wystawiona przez firm\u0119 ABC Sp. z o.o.<br>        dnia 28.02.2024 na kwot\u0119 1250,00 PLN\"\"\"}<br>    ],<br>    response_format=DocumentInfo,<br>)<br><\/code><br><code>document = completion.choices[0].message.parsed<br><\/code><br><code>print(document.dict())<\/code><\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\">Co sprawi, \u017ce ka\u017cda odpowied\u017a, kt\u00f3r\u0105 otrzymamy, b\u0119dzie zgodna ze schematem:<\/p><figure class=\"wp-block-table\"><table class=\"has-very-light-gray-background-color has-background has-fixed-layout\"><tbody><tr><td><code>{<br>    'document_type': 'Faktura VAT',<br>    'issue_date': '28.02.2024',<br>    'amount': 1250.0,<br>    'contractor': 'ABC Sp. z o.o.'<br>}<\/code><\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\">Sytuacja przedstawia si\u0119 inaczej, gdy korzystamy z modeli j\u0119zykowych, jak np. Llama, Mistral czy Bielik, kt\u00f3re uruchamiamy lokalnie, na w\u0142asnym sprz\u0119cie. A bywa tak, \u017ce uruchamia\u0107 musimy je w\u0142a\u015bnie w taki spos\u00f3b, bo np. zale\u017cy nam na poufno\u015bci przetwarzanych danych.<\/p><p class=\"wp-block-paragraph\">Otwarty model \u2013 nawet gdy poinstruujemy go w prompcie, \u017ce ma zastosowa\u0107 wymagany format \u2013 cz\u0119sto dodaje w\u0142asne komentarze lub zb\u0119dne wyja\u015bnienia.<\/p><p class=\"wp-block-paragraph\">Sp\u00f3jrzmy na przyk\u0142adow\u0105 odpowied\u017a modelu Bielik-11B-v2.2-Instruct, kt\u00f3ry dosta\u0142 to samo zadanie:<\/p><figure class=\"wp-block-table\"><table class=\"has-very-light-gray-background-color has-background has-fixed-layout\"><tbody><tr><td><code>Wynik powinien by\u0107 w formacie JSON:<br> {<br>\"document_type\": \"Faktura VAT\",<br>\"issue_date\": \"28.02.2024\",<br>\"amount\": 1250.0,<br>\"contractor\": \"ABC Sp. z o.o.\"<br> }<br><\/code><br><code>Wyja\u015bnienie:<br>- document_type: Typ dokumentu (Faktura VAT)<br>- issue_date: Data wystawienia dokumentu (28.02.2024)<br>- amount: Kwota wskazana na dokumencie (1250,00 PLN zamienione na liczb\u0119 1250.0)<br>- contractor: Nazwa kontrahenta wystawiaj\u0105cego dokument (ABC Sp. z o.o.)<br><\/code><br><code>Wynik jest w poprawnym formacie JSON i zawiera wszystkie wymagane informacje z danego dokumentu.<\/code><\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\">Chocia\u017c model zwr\u00f3ci\u0142 poprawne dane, opatrzy\u0142 je zb\u0119dnymi obja\u015bnieniami, kt\u00f3re mog\u0105 utrudni\u0107 automatyczne przetwarzanie odpowiedzi.<\/p><p class=\"wp-block-paragraph\">Skupimy si\u0119 zatem na tym, co zrobi\u0107, by na modelach uruchamianych lokalnie uzyska\u0107 odpowied\u017a w dok\u0142adnie takim formacie, jakiego sobie za\u017cyczymy.<\/p><h4 class=\"wp-block-heading\"><strong>Maskowanie token\u00f3w<\/strong><\/h4><p class=\"wp-block-paragraph\">Warto najpierw przyjrze\u0107 si\u0119, co dzieje si\u0119 \u201epod mask\u0105\u201d LLM-u, gdy ten generuje kolejny token. <\/p><p class=\"wp-block-paragraph\">Dla przyk\u0142adowego polecenia:<\/p><figure class=\"wp-block-table\"><table class=\"has-very-light-gray-background-color has-background has-fixed-layout\"><tbody><tr><td><code>Podaj wynik r\u00f3wnania u\u017cywaj\u0105c tylko cyfry rzymskiej: 2+2=<\/code><\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\">Podczas generowania odpowiedzi model wykonuje nast\u0119puj\u0105ce kroki:<\/p><ol class=\"wp-block-list\"><li>Analizuje pe\u0142ny kontekst dost\u0119pny w oknie kontekstowym.<\/li>\n\n<li>Dla ka\u017cdego mo\u017cliwego tokena w s\u0142owniku (np. dla Bielika to 32 000 token\u00f3w) model wylicza warto\u015b\u0107 logitu \u2013 czyli surow\u0105, nieznormalizowan\u0105 warto\u015b\u0107 wyprodukowan\u0105 przez ostatni\u0105 warstw\u0119 sieci neuronowej.<\/li>\n\n<li>Stosowana jest funkcja softmax, kt\u00f3ra przelicza te logity na prawdopodobie\u0144stwa.<\/li><\/ol><p class=\"wp-block-paragraph\"> <img loading=\"lazy\" decoding=\"async\" width=\"400\" height=\"143\" class=\"wp-image-7139\" style=\"width: 400px;\" src=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/85_1.png\" alt=\"\" srcset=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/85_1.png 485w, https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/85_1-300x107.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/p><p class=\"wp-block-paragraph\">Na przyk\u0142ad:<\/p><p class=\"wp-block-paragraph\"> <img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"216\" class=\"wp-image-6850\" style=\"width: 500px;\" src=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/86_1.png\" alt=\"\" srcset=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/86_1.png 508w, https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/86_1-300x129.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p><p class=\"wp-block-paragraph\">A co, gdyby w danym momencie generowa\u0107 token tylko z puli tych, kt\u00f3re s\u0105 zgodne z danym wzorcem? Tu ca\u0142a na bia\u0142o wchodzi koncepcja maskowania token\u00f3w. Jest to proces, kt\u00f3ry:<\/p><ol class=\"wp-block-list\"><li>Odbywa si\u0119 przed transformacj\u0105 softmax.<\/li>\n\n<li>Polega na ustawieniu warto\u015bci logit\u00f3w na -in\u0192 dla niepo\u017c\u0105danych token\u00f3w.<\/li>\n\n<li>Jest wydajny obliczeniowo, poniewa\u017c nie wymaga modyfikacji architektury modelu.<\/li>\n\n<li>Skutkuje zerowymi prawdopodobie\u0144stwami dla zamaskowanych token\u00f3w, podczas gdy suma prawdopodobie\u0144stw dla pozosta\u0142ych nadal wynosi 1.<\/li><\/ol><p class=\"wp-block-paragraph\">Zobaczmy to na przyk\u0142adzie ograniczenia odpowiedzi modelu tylko do cyfr rzymskich. Po zastosowaniu maskowania prawdopodobie\u0144stwa wyboru poszczeg\u00f3lnych token\u00f3w zmieni\u0105 si\u0119 nast\u0119puj\u0105co:<\/p><p class=\"wp-block-paragraph\"> <img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"207\" class=\"wp-image-6852\" style=\"width: 500px;\" src=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/86_2.png\" alt=\"\" srcset=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/86_2.png 506w, https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/86_2-300x124.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p><p class=\"wp-block-paragraph\">Takie podej\u015bcie ma kilka istotnych zalet:<\/p><ul class=\"wp-block-list\"><li>jest bardziej niezawodne ni\u017c sama in\u017cynieria prompt\u00f3w;<\/li>\n\n<li>w zwi\u0105zku z tym, \u017ce model ma mniejsz\u0105 pul\u0119 token\u00f3w do wyboru, mo\u017ce przyspieszy\u0107 generowanie odpowiedzi;<\/li>\n\n<li>umo\u017cliwia tworzenie odpowiedzi w formatach, kt\u00f3re nie wyst\u0119powa\u0142y w danych treningowych modelu;<\/li>\n\n<li>nie wymaga dodatkowego treningu modelu.<\/li><\/ul><p class=\"wp-block-paragraph\">Powy\u017cszy przyk\u0142ad jest oczywi\u015bcie uproszczony. Na og\u00f3\u0142 zale\u017cy nam na du\u017co bardziej skomplikowanym formacie odpowiedzi, np. JSON.<\/p><p class=\"wp-block-paragraph\">Zmienianie warto\u015bci logit\u00f3w w trakcie dzia\u0142ania modelu mo\u017ce by\u0107 skomplikowane, szczeg\u00f3lnie gdy zale\u017cy nam na zachowaniu wysokiej wydajno\u015bci. Na szcz\u0119\u015bcie istniej\u0105 ju\u017c gotowe rozwi\u0105zania tego problemu: Instructor, Guidelines, Llama.cpp i formalne gramatyki GBNF, LMFE, Outlines.<\/p><p class=\"wp-block-paragraph\">Szczeg\u00f3lnie obiecuj\u0105cym narz\u0119dziem jest ta ostatnia \u2013 biblioteka Outlines, kt\u00f3ra wyr\u00f3\u017cnia si\u0119 dojrza\u0142o\u015bci\u0105 i dobr\u0105 integracj\u0105 z wydajnym frameworkiem vLLM. Przyjrzyjmy si\u0119 im bli\u017cej.<\/p><h4 class=\"wp-block-heading\">vLLM<\/h4><figure class=\"wp-block-table\"><table style=\"border-style:none;border-width:0px\"><tbody><tr><td>vLLM to framework optymalizuj\u0105cy dzia\u0142anie du\u017cych modeli j\u0119zykowych, kt\u00f3ry zapewnia wysok\u0105 wydajno\u015b\u0107 i niskie zu\u017cycie pami\u0119ci. Dzi\u0119ki dynamicznemu zarz\u0105dzaniu pami\u0119ci\u0105 i wsparciu dla r\u00f3\u017cnych GPU oferuje znacznie wy\u017csz\u0105 przepustowo\u015b\u0107 ni\u017c tradycyjne serwowanie modeli.<br><br><a href=\"https:\/\/github.com\/vllm-project\/vllm?fbclid=IwY2xjawHFgbBleHRuA2FlbQIxMAABHf1yw1JqDX4z0cub3d9nIxJdRqbJoz_Q1yJ8uihF7jUBkPI9odb9v06RHw_aem_KN0jM6fw5TNOy_2vLDSknQ\" target=\"_blank\" rel=\"noopener\"><mark style=\"background-color:#82D65E\" class=\"has-inline-color\">Github<\/mark><\/a><br><br><mark style=\"background-color:#82D65E\" class=\"has-inline-color\"><a href=\"https:\/\/github.com\/dottxt-ai\/outlines?fbclid=IwY2xjawHP59lleHRuA2FlbQIxMAABHST07Sj73to_Fp-fxS3fx-mC3WPSoWnOv66k2OD0ELGlA3Xh8326tNvYTQ_aem_TOoFXgOnloiIZgqFADsUrg\" data-type=\"link\" data-id=\"https:\/\/github.com\/dottxt-ai\/outlines?fbclid=IwY2xjawHP59lleHRuA2FlbQIxMAABHST07Sj73to_Fp-fxS3fx-mC3WPSoWnOv66k2OD0ELGlA3Xh8326tNvYTQ_aem_TOoFXgOnloiIZgqFADsUrg\" target=\"_blank\" rel=\"noopener\">Jak dzia\u0142a Outlines?<\/a><\/mark> Outlines wykorzystuje automaty do generowania tekstu na podstawie zdefiniowanych wzorc\u00f3w<br><br>Polega to na tym, \u017ce model j\u0119zykowy generuje tekst token po tokenie, ale tylko tokeny legalne (czyli zgodne z wzorcem) s\u0105 brane pod uwag\u0119 na ka\u017cdym kroku.<br><br>Podobnie jak w przyk\u0142adzie z cyframi rzymskimi, automaty przeprowadzaj\u0105 analiz\u0119 tego, jakie tokeny (odpowiadaj\u0105ce rzymskiej notacji typu IV, X, L itp.) s\u0105 dozwolone w danym momencie.<br><br>Outlines wykorzystuje technik\u0119 filtrowania mo\u017cliwych odpowiedzi modelu bezpo\u015brednio na poziomie mechanizmu przewidywania nast\u0119pnych token\u00f3w. W praktyce oznacza to, \u017ce Outlines maskuje tokeny, tzn. modyfikuje warto\u015bci logit\u00f3w dla token\u00f3w, a zarazem redukuje do zera prawdopodobie\u0144stwo ich wyst\u0105pienia na wyj\u015bciu funkcji softmax. Dzi\u0119ki temu eliminuje te niezgodne z wzorcem, co zapewnia precyzyjne i kontrolowalne generowanie tekstu przez model.<br><br>Wzorzec mo\u017cemy okre\u015bli\u0107 np. w bibliotece Pydantic i definiuj\u0105c go przez konstrukcj\u0119 odpowiednich klas.<\/td><td><img loading=\"lazy\" decoding=\"async\" width=\"1000\" height=\"2559\" class=\"wp-image-7798\" style=\"width: 1000px;\" src=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/wykres_Pohamuj.png\" alt=\"\" srcset=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/wykres_Pohamuj.png 635w, https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/wykres_Pohamuj-117x300.png 117w, https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/wykres_Pohamuj-400x1024.png 400w, https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/wykres_Pohamuj-600x1535.png 600w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/td><\/tr><\/tbody><\/table><\/figure><h4 class=\"wp-block-heading\">Przyk\u0142ad 1<\/h4><p class=\"wp-block-paragraph\">Zaczniemy od prostego przyk\u0142adu u\u017cycia Outlines: Za\u0142\u00f3\u017cmy, \u017ce chcemy, aby model odpowiada\u0142 tylko wygenerowanymi zagadkami filmowymi podawanymi przy pomocy emoji.<\/p><figure class=\"wp-block-table\"><table class=\"has-very-light-gray-background-color has-background has-fixed-layout\"><tbody><tr><td><code>Jeste\u015b mistrzem zagadek, specjalizuj\u0105cym si\u0119 w tworzeniu zagadek filmowych u\u017cywaj\u0105c tylko emoji. Twoim zadaniem jest tworzenie zagadek opartych na emoji (maks 10\u201312 emoji) dla podanych tytu\u0142\u00f3w film\u00f3w i najwa\u017cniejszych w nim wydarze\u0144.<\/code><\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\">Przyk\u0142adowa odpowied\u017a Bielika bez wymuszonej struktury odpowiedzi, dla zadanego filmu Kiler:<\/p><figure class=\"wp-block-table\"><table class=\"has-very-light-gray-background-color has-background has-fixed-layout\"><tbody><tr><td><code>Oto zagadka dla filmu \"Kiler\" (1997):<\/code><br><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"76\" class=\"wp-image-6854\" style=\"width: 300px;\" src=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/87_1.png\" alt=\"\" srcset=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/87_1.png 388w, https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/87_1-300x76.png 300w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><code><br>Wyja\u015bnienie:<br>\u2026<\/code><\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\">Jak widzimy, czasem zamiast tylko odpowiedzie\u0107, LLM dodaje co\u015b od siebie. Na przyk\u0142ad wyja\u015bnienie. Ale mo\u017cemy stworzy\u0107 wzorzec, kt\u00f3ry ograniczy u\u017cycie token\u00f3w wy\u0142\u0105cznie do tych, kt\u00f3re sami wybrali\u015bmy:<\/p><figure class=\"wp-block-table\"><table class=\"has-very-light-gray-background-color has-background has-fixed-layout\"><tbody><tr><td><code>import re<br>from outlines import models, generate<br><\/code><br><code># Select some emojis to use<br>emojis = [<\/code><br> <img loading=\"lazy\" decoding=\"async\" width=\"400\" height=\"155\" class=\"wp-image-6858\" style=\"width: 400px;\" src=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/87_3.png\" alt=\"\" srcset=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/87_3.png 457w, https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/87_3-300x116.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><br>       # <code>\u2026 and some more we'll hide here to save space<br>]<\/code><br># <code>Escape each emoji to safely include it in a regex pattern<br>escaped_emojis = [re.escape(e) for e in emojis]<\/code><br><code><br># Join them into a single pattern separated by '|'<br>regex_pattern = f\"({'|'.join(escaped_emojis)})+\"<br><\/code><br># <code>Initialize the language model<br>model = models.vllm(\"speakelash\/Bielik-11B-v2.2-Instruct\")<br><\/code><br># <code>Create the generator with the model and regex constraint<br>generator = generate.regex(model, regex_pattern)<br><\/code><br># <code>Generate the LLM response<br>response = generator(prompt)<br>print(response)<\/code><\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\">Teraz model odpowiada dok\u0142adnie w taki spos\u00f3b, jakiego oczekujemy, a co najwa\u017cniejsze \u2013 stosuje si\u0119 do wzorca za ka\u017cdym razem.<\/p><p class=\"wp-block-paragraph\">Przyk\u0142adowa odpowied\u017a modelu kontrolowana przez Outlines:<\/p><p class=\"wp-block-paragraph\"> <img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"59\" class=\"wp-image-6856\" style=\"width: 500px;\" src=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/87_2.png\" alt=\"\" srcset=\"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/87_2.png 1122w, https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/87_2-300x35.png 300w, https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/87_2-1024x120.png 1024w, https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/87_2-768x90.png 768w, https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/87_2-600x71.png 600w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/p><p class=\"wp-block-paragraph\">Jaki to polski film? Nie zdradz\u0119 tutaj tytu\u0142u \u2013 to w ko\u0144cu zagadka!<\/p><h4 class=\"wp-block-heading\">Przyk\u0142ad 2<\/h4><p class=\"wp-block-paragraph\">Teraz skorzystamy z vLLM i Outlines przy pomocy tego samego zapytania, kt\u00f3re skierowali\u015bmy do OpenAI na pocz\u0105tku artyku\u0142u. Zdefiniujemy struktur\u0119 odpowiedzi tak samo jak poprzednio, czyli przez Pydantic. Umo\u017cliwi nam to uruchomienie modelu LLM na w\u0142asnym serwerze z GPU:<\/p><figure class=\"wp-block-table\"><table class=\"has-very-light-gray-background-color has-background has-fixed-layout\"><tbody><tr><td><code>from outlines import generate, models<br>from pydantic import BaseModel<br>from transformers import AutoTokenizer<\/code><br><br># <code>Definicja schematu danych do walidacji odpowiedzi modelu<br>class DocumentInfo(BaseModel):<br>    document_type: str<br>    issue_date: str<br>    amount: float<br>    contractor: str<br># we will use Bielik tokenizer later to format prompt<br>tokenizer = AutoTokenizer.from_pretrained(\"speakleash\/Bielik-11B-v2.2-Instruct\")<\/code><br><br><code>chat = [<br>     {<br>         \"role\": \"system\",<br>         \"content\": f\"\"\"<br>Wydob\u0105d\u017a informacje z dokumentu.<br>Odpowiadaj tylko w poprawnym formacie JSON zgodnym z schematem:<br>{DocumentInfo.schema_json()}\"\"\",<br>   },<br>   {<br>         \"role\": \"user\",<br>         \"content\": \"\"\"<br># Dokument:<br>Faktura VAT 15\/2024 wystawiona przez firm\u0119<br>ABC Sp. z o.o.<br>dnia 28.02.2024 na kwot\u0119 1250,00 PLN\"\"\",<br>},<br>]<\/code><br><br><code># format the prompt for vlLM generator using tokenizer<br>prompt = f\"{tokenizer.apply_chat_template(chat, tokenize=False)}assistant\"<br><\/code><br># <code>Initialize the language model <\/code><br><code>model = models.vllm(\"speakleash\/Bielik-11B-v2. 2-Instruct\")<br><\/code><br># <code>Create the generator with the model and Pydantic class constraint<br>generator = generate.json(model, DocumentInfo)<\/code><br><code><br># Generate the LLM response response = generator(prompt, max_tokens=1024)<br>print(response.dict())<\/code><\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\">I tak samo jak w przyk\u0142adzie z OpenAI, gdzie korzystali\u015bmy z trybu JSON przez API, zawsze uzyskamy odpowied\u017a zgodn\u0105 ze schematem:<\/p><figure class=\"wp-block-table\"><table class=\"has-very-light-gray-background-color has-background has-fixed-layout\"><tbody><tr><td><code>{<br>    'document_type': 'Faktura VAT',<br>    'issue_date': '28.02.2024',<br>    'amount': 1250.0,<br>    'contractor': 'ABC Sp. z o.o.'<br>}<\/code><\/td><\/tr><\/tbody><\/table><\/figure><p class=\"wp-block-paragraph\"><mark style=\"background-color:#82D65E\" class=\"has-inline-color\"><a href=\"https:\/\/github.com\/speakleash\/Bielik-how-to-start\/blob\/main\/Bielik_2_(AWQ)_structured_output.ipynb?fbclid=IwY2xjawHFgOJleHRuA2FlbQIxMAABHWsNeGKPk3n4o9f4WOd-YAqDdzr_KIICuPA3xtDurpaLaqCLdExMjfozyw_aem_VCU5IkjZrdkDdlbdC4oZcA\" data-type=\"link\" data-id=\"https:\/\/github.com\/speakleash\/Bielik-how-to-start\/blob\/main\/Bielik_2_(AWQ)_structured_output.ipynb?fbclid=IwY2xjawHFgOJleHRuA2FlbQIxMAABHWsNeGKPk3n4o9f4WOd-YAqDdzr_KIICuPA3xtDurpaLaqCLdExMjfozyw_aem_VCU5IkjZrdkDdlbdC4oZcA\" target=\"_blank\" rel=\"noopener\">Zobacz m\u00f3j podobny przyk\u0142ad i pe\u0142ny kod na Githubie<\/a><\/mark>. Jest to dobry punkt startowy do implementacji tego typu rozwi\u0105za\u0144 we w\u0142asnych projektach.<\/p><h4 class=\"wp-block-heading\">Czy to ma negatywne konsekwencje?<\/h4><p class=\"wp-block-paragraph\">Czy taki spos\u00f3b samplowania nie wi\u0105\u017ce si\u0119 np. z ni\u017csz\u0105 jako\u015bci\u0105 odpowiedzi? Przeciwnie! Jako\u015b\u0107 odpowiedzi wr\u0119cz ro\u015bnie, podobnie zreszt\u0105 jak szybko\u015b\u0107 inferencji. Je\u017celi znamy schemat JSON, wed\u0142ug kt\u00f3rego ma odpowiedzie\u0107 model, mo\u017cemy go pomin\u0105\u0107 w trakcie generowania i tylko potencjalnie wype\u0142ni\u0107 danymi.<\/p><h4 class=\"wp-block-heading\">Podsumowanie<\/h4><p class=\"wp-block-paragraph\">Przy pomocy odpowiednich narz\u0119dzi strukturyzacja odpowiedzi w lokalnych modelach LLM jest naprawd\u0119 stosunkowo \u0142atwa do osi\u0105gni\u0119cia. Kluczowe wnioski s\u0105 nast\u0119puj\u0105ce:<\/p><ol class=\"wp-block-list\"><li><strong>Skuteczna kontrola<\/strong><br>\u2013 Mo\u017cemy \u0142atwo i precyzyjnie wymusi\u0107 okre\u015blon\u0105 struktur\u0119 odpowiedzi, nie trac\u0105c przy tym jako\u015bci.<br>\u2013 Nie wymaga to dodatkowego treningu ani skomplikowanej in\u017cynierii prompt\u00f3w.<\/li>\n\n<li><strong>Praktyczne korzy\u015bci<\/strong><br>\u2013 Przewidywalne odpowiedzi umo\u017cliwiaj\u0105ce automatyzacj\u0119 i skalowanie.<br>\u2013 \u0141atwiejsze debugowanie i testowanie aplikacji.<\/li>\n\n<li><strong>Dojrza\u0142e narz\u0119dzia<\/strong><br>\u2013 Dost\u0119pne i aktywnie rozwijane biblioteki jak vLLM + Outlines.<br>\u2013 Prosta implementacja i dobra dokumentacja.<\/li><\/ol><p class=\"wp-block-paragraph\">Kontrola struktury odpowiedzi to pierwszy krok w kierunku praktycznego wykorzystania lokalnych LLM-\u00f3w w \u015brodowisku produkcyjnym. \u0141\u0105czy elastyczno\u015b\u0107 modeli j\u0119zykowych z przewidywalno\u015bci\u0105 tradycyjnych system\u00f3w.<\/p><h4 class=\"wp-block-heading\">Przysz\u0142o\u015b\u0107<\/h4><p class=\"wp-block-paragraph\">Czy gdy modele stan\u0105 si\u0119 doskonalsze i b\u0119d\u0105 lepiej wykonywa\u0107 nasze polecenia, kontrolowanie samplingu b\u0119dzie nadal potrzebne? Wszystko wskazuje na to, \u017ce tak!<\/p><p class=\"wp-block-paragraph\">Po pierwsze, sampling pozwala wymusi\u0107 na modelu odpowiedzi w formatach, kt\u00f3rych nie ma w danych treningowych \u2013 i to bez konieczno\u015bci stosowania przyk\u0142ad\u00f3w (few shot learning). To z kolei oznacza mniejsze zu\u017cycie token\u00f3w na instrukcje.<\/p><p class=\"wp-block-paragraph\">Po drugie, badania nad modyfikacj\u0105 samplingu (jak np. Chain of Thoughts decoding czy analiza entropii) dopiero si\u0119 rozpoczynaj\u0105. To obiecuj\u0105ca dziedzina z ogromnym, niewykorzystanym jeszcze potencja\u0142e<\/p>","protected":false},"excerpt":{"rendered":"<p>Mimo pr\u00f3\u015bb i gr\u00f3\u017ab modele LLM trudno jest za pomoc\u0105 samych prompt\u00f3w sk\u0142oni\u0107 do konsekwentnego odpowiadania w konkretnym formacie.<\/p>\n","protected":false},"author":180,"featured_media":7128,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"rank_math_lock_modified_date":false,"footnotes":""},"categories":[402,763,754,405],"tags":[109,193],"popular":[],"difficulty-level":[37],"ppma_author":[442],"class_list":["post-6779","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-hai-magazine","category-ai_praktyka","category-hai_premium","category-hai-magazine-3","tag-genai","tag-llm-2","difficulty-level-hard"],"acf":[],"authors":[{"term_id":442,"user_id":180,"is_guest":0,"slug":"tomasz-gancarczyk","display_name":"Tomasz Gancarczyk","avatar_url":{"url":"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/tgancarczyk.jpeg","url2x":"https:\/\/haimagazine.com\/wp-content\/uploads\/2024\/12\/tgancarczyk.jpeg"},"first_name":"","last_name":"","user_url":"","job_title":"","description":"Niezale\u017cny konsultant automatyzacji i AI z ponad 10-letnim do\u015bwiadczeniem, wspiera organizacje w efektywnym wykorzystaniu nowoczesnych technologii"}],"_links":{"self":[{"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/posts\/6779","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/users\/180"}],"replies":[{"embeddable":true,"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/comments?post=6779"}],"version-history":[{"count":7,"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/posts\/6779\/revisions"}],"predecessor-version":[{"id":7803,"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/posts\/6779\/revisions\/7803"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/media\/7128"}],"wp:attachment":[{"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/media?parent=6779"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/categories?post=6779"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/tags?post=6779"},{"taxonomy":"popular","embeddable":true,"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/popular?post=6779"},{"taxonomy":"difficulty-level","embeddable":true,"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/difficulty-level?post=6779"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/haimagazine.com\/pl\/wp-json\/wp\/v2\/ppma_author?post=6779"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}