Қазір RAG туралы кейде теріс пікір айтылады: біреулер оны тым қарапайым деп санайды (бастау оңай, ал ауқымын кеңейту олай емес), енді біреулер оның орнын «агенттік жүйелер» басты дейді (бірақ көбінің бетін сәл қырнасаңыз, RAG-қа қатты ұқсайтыны тез байқалады...)
Бұл блогта жиі кездесетін мына қиындықтарды қалай шешетініміз бір-екі нақты мысал арқылы көрсетіледі:
Мәтін мен сандық деректерді бірге өңдеу және олардың қарапайым RAG жұмысын неліктен бұзатыны: кілт сөздер қабаттасады, ал сандардың семантикалық мағынасы жоқ.
Алдымен түйіндеме жасап, содан кейін ендіру неге тиімді: әр бөлікке қысқа сипаттамалық түйіндеме жасап, ендіру мен іздеуді соның негізінде орындаңыз.
Мәтінмәндік түйіндемелерді жасау жолы: пішіні ұқсас статистикаларды ажырату үшін негізгі құжаттың мәнмәтінін қосыңыз.
Код пен Pydantic модельдеріне қашан сүйену керек: мазмұнды сөзбе-сөз сақтау қажет болса, сенімділік үшін арнайы кодты және/немесе Pydantic моделін LLM (үлкен тілдік модель) шақыруларымен біріктіріңіз.
Негіздері
RAG жүйелері қолдау боттарынан бастап ішкі білім көмекшілеріне дейінгі көптеген құралдың негізінде жұмыс істейді.
Әдетте жүйе ішінде мына әрекеттер орындалады:
Бастапқы құжаттарды бөліктерге бөлу
Әр бөлікті векторлық кеңістікке ендіру
Сұрау кезінде ең үздік K бөлікті іздеп алу
Сол бөліктерге сүйеніп жауап жасау
LangChain, LlamaIndex және OpenAI Filestore секілді танымал құралдар бұл қадамдарды барынша жеңілдетеді. Алайда нақты конвейерлерде тек тұтас мәтіннен тұрмайтын деректер кездеседі, ал қарапайым RAG оларды өңдеуде қиналуы мүмкін. Келесі бөлімдерде деректерге қатысты қиындықтардың нақты мысалдарын көрсетіп, күрделілік артқан сайын шешімді біртіндеп жетілдіреміз.
Деректеріңіз тек мәтіннен тұрмаса (бұл жиі кездеседі)
Ойынға қатысты мына деректер бөлігін қарастырайық:
JSON
Ендірулер сөздер арасындағы семантикалық және грамматикалық байланыстарды меңгерудің арқасында жұмыс істейді. Жоғарыдағы деректер мәтін мен сандардан тұрады, ал осы нақты мәнмәтіннен тыс жерде сандардың сөздермен еш байланысы жоқ. Демек, бұл деректер бөлігі аздап сипаттайтын сөздер мен олардың артынан келетін кездейсоқ сандардың қосындысы деуге болады.
Егер қолымызда тек осындай деректер болса, бұл мәселе туғызбас еді: сипаттаушы бірнеше сөздің ендірулері арқылы қажеттісін таба алар едік (немесе text-to-sql қолданар едік). Ал бұл бөлік сол сөздер кездесетін, мәтіні мол көптеген бөліктің арасында көміліп қалса ше? Мысалы:
JSON
Енді “What is the attack range with Draconic Ascension?” деген сұрауға қатысты деректі іздегіміз келді делік. Қажетті бөлікті таба алмауымыз әбден мүмкін, өйткені ол дәл сондай кілт сөздері бар басқа бөліктердің шуына көміліп қалады.
Түпкі мәселе — бір тақырып туралы әртүрлі ақпарат қамтылғанымен, бұл деректер бөліктерін бір-бірінен дұрыс ажырата алмаймыз. Оларды қандай да бір жолмен байытып, жақсартуға бола ма? Әрине, болады:smile:
Деректерді түйіндеу арқылы байытыңыз — иә, дұрыс оқыдыңыз
Бөліктің өзін тікелей ендірудің орнына, алдымен деректің не туралы екенін сипаттайтын түйіндеме жасап, содан кейін соны ендіріп, соның негізінде іздей аламыз. Жауап жасау кезеңінде түйіндемемен байланыстырылған бастапқы деректерді әлі де қолданамыз.
Сонда жоғарыда көрсетілген екі бөлікке мынадай түйіндемелер жасар едік:
Шабуыл қашықтығы, жылдамдығы мен залалының статистикасы (әдепкі және Draconic Ascension қолданылған кездегі).
Draconic Ascension сипаттамасы мен егжей-тегжейі, соның ішінде іске қосылу шарттары, визуалдық әсерлері және тарихы.
Содан кейін сұрауды да түйіндемеге «сәйкестендіре» толықтырамыз. Мысалы, “What is the attack range with Draconic Ascension?” сұрауын “What is the statistics of attack range with Draconic Ascension?” деп өзгертер едік. Бұл әсіресе іздеу сұрауын техникалық салада істемейтін пайдаланушылар ~~«еркін стильде»~~ кәдімгі адам тілінде қойған кезде маңызды. Өйткені дәлдік пен толық қамтуды барынша арттыру үшін RAG қалай жұмыс істейтінін білу олардың міндеті де, мақсаты да емес.


Ештеңені мәнмәтіннен жұлып алмаңыз (өмірде де пайдалы қағида)
Енді төмендегідей бір-біріне ұқсайтын өте көп деректер бөлігін өңдеу керек болатын жағдайды қарастырайық:
Plain Text
Осы тәсілді жалғастырып, “what is character X’s attack range?” деп сұрағанымызды елестетіңіз. Жаңа ғана жасаған түйіндемелеріміз бір-біріне өте ұқсас болғандықтан, дұрыс жауапты табу сәттілікке тәуелді жорамал ойынына айналар еді. Оларды қалай ажыратуға болады?
Қарапайым жауап: мәнмәтін қосу керек. Деректер бөлігіне оның негізгі құжатына сілтеме қоса аламыз, мысалы, бұл жағдайда {”character”: “X”}. Сонда Y және Z кейіпкерлері туралы дәл сондай деректер болса да, X кейіпкеріне қатысты дұрыс деректі дәл таба аламыз.
Алайда бұдан да тиімді әрі жалпылауға қолайлы тәсіл — бөліктің мәнмәтіндік түйіндемесін жасау. Яғни деректер бөлігінің өзін ғана түйіндеудің орнына, оның негізгі құжаты мен бөліктің өзін бірге беріп, жалпы мәнмәтіндік түйіндеме жасай аламыз. Онда бұл бөліктің негізгі құжаттағы орны да түсіндіріледі, мысалы:
Бұл бөлік X кейіпкеріне арналған ... туралы толық статистиканы ұсынады. Бұл бөлік X кейіпкерінің шабуыл жылдамдығындағы мықты тұсын көрсету арқылы толық құжатты толықтырады...
Бұл бөлік Y кейіпкеріне арналған ... туралы толық статистиканы ұсынады. Бұл бөлік Y кейіпкерінің арнайы қабілеті қолданылғанда күшейетін сипаттамаларын көрсету арқылы толық құжатты толықтырады...
Бұл бөлік Z кейіпкеріне арналған ... туралы толық статистиканы ұсынады. Бұл бөлік Z кейіпкерінің командалық матчтарда танк рөліне жақсы сәйкес келетін сипаттамаларын көрсету арқылы толық құжатты толықтырады...
Бұл әдіс (ішінара Anthropic идеясынан алынған) жоғарыдағы мысал үшін артық көрінуі мүмкін. Алайда ол «мәнмәтіннен тыс» қате түсіндірілуі ықтимал бөліктерге өте тиімді әрі барлық бөлікке жарайтын бірыңғай тәсіл ұсынып, инженерлік конвейерді жинақы сақтайды.


~~Бәрін бақылауда ұстау~~ аса мұқият болу қажет кезде
Әдетте деректер бізге тұтас күйінде келіп, оларды RAG жүйесі үшін бөліктерге бөлеміз. Бұл мысалда сәл өзгеше жағдайды көрсетеміз: деректер бөліктерге бөлінген, бірақ дұрыс емес. Олар бір логикалық бөліктің кездейсоқ үзінділері болғандықтан, қайта біріктірілуі керек. Логикалық бөлік — құжаттың ішкі бөлімі немесе мағынасы тұтас абзац секілді табиғи түрде бірге орналасуы тиіс мазмұн үзіндісі.


Алғашқы талпынысымызда барлық деректі LLM (үлкен тілдік модель) шақыруына беріп, оларды орынды деп тапқан тәсілмен топтастырып, біріктірілген мазмұнды қайтаруды сұрадық. LLM (үлкен тілдік модель) мұны жақсы орындауы керек қой, солай емес пе? Иә деуге де, жоқ деуге де болады.
Бұған дейінгі бірнеше жағдайда да байқағанымыздай, толық әрі дәл мазмұн қажет болғанда, әсіресе мәнмәтін ұзақ болса, LLM (үлкен тілдік модель) жүйелері жұмысты жеңілдетуге бейім әрі сенімсіз болады. Бұл түсінікті де. Алайда бұл нақты қолдану жағдайында оған жол беруге болмайды, өйткені бізге мазмұн сөзбе-сөз дәл керек: ешқандай түйіндеме жасалмауы және бастапқы мазмұнның ешбір бөлігі түсіп қалмауы тиіс. Ешбір егжей-тегжей назардан тыс қалмауы керек.
Әрине, «иә» деуіміздің себебі — ол бөлшектенген бөліктердің семантикасы мен құрылымын тамаша түсінді. Тек нақты мазмұнды сөзбе-сөз қайтарудан бас тартпаса болғаны. Қап:/
Онда LLM (үлкен тілдік модель) жақсы орындайтын мүмкіндіктерді пайдаланып, сенімсіз тұстарын қалай айналып өтуге болады? Сенімді ескі досымыз — кодқа жүгіндік (мұны арнайы Python функциясы деп түсініңіз). Оған қоса, «бұдан оңай болуы мүмкін емес» Pydantic моделін қолдандық. Шешімі мынадай:
Ағымдағы логикалық бөлікті сақтай отырып, бөлімдерді бір-бірлеп қарап шығу
Әр бөлімде LLM (үлкен тілдік модель) жүйесінен: «Бұл бөлім ағымдағы логикалық бөлікке жата ма?» — деп сұрап, Pydantic моделіне сай «иә» немесе «жоқ» деген жауап алу.
Жауап «иә» болса, бөлімді бөлікке қосу; «жоқ» болса, аяқталған ағымдағы логикалық бөлікті шығарып, осы бөлімнен жаңа бөлік бастау.


Әрине, мұнда бүкіл мазмұнды бір рет өңдегеннен сәл көбірек токен жұмсаймыз. Бірақ нақты мазмұнды толық сақтау басты басымдық болғандықтан, бұл шағын қосымша шығын өзін толық ақтады.
Бұл — өте қарапайым шешім, бірақ ол маңызды қағиданы ұстанады: аса мұқияттық қажет болса, ықтималдыққа негізделетін LLM (үлкен тілдік модель) жүйелеріне ғана сенуге болмайды.
Арнайы кодты немесе функцияларды және Pydantic модельдерін қолдану арқылы LLM (үлкен тілдік модель) мүмкіндіктерін толық пайдаланып, болжамды әрі сенімді нәтижеге қол жеткізуге болады.
Генеративті ЖИ шешімін әзірлеу — ЖИ саласындағы ғана емес, инженерлік міндет те. Бұл мысалдар сізді өзіңізге тән бірегей қиындықтарды шешуге шабыттандырды деп үміттенеміз. Инженерлік тәсілге басымдық беретін генеративті ЖИ шешімдері туралы көбірек білу үшін маршрутизаторға негізделген агенттік жүйені жобалау туралы блог жазбамызды оқыңыз.