Hagnýt dæmi um sérsniðnar RAG-lausnir

Raunhæf dæmi sýna hvernig sérsniðin kerfi fyrir sóknarbætta svargerð leysa flókin þekkingarvandamál fyrirtækja.

Nú á dögum fær RAG stundum slæmt orð á sig, annaðhvort vegna þess að fólk telur það orðið sáraeinfalt (það er auðvelt að byrja en síður að stækka kerfið) eða vegna þess að það telur „gerandakerfi“ hafa leyst það af hólmi (en ef yfirborðið er aðeins kannað fara slík kerfi í mörgum tilvikum fljótt að líkjast RAG mjög mikið …)

Í þessari bloggfærslu förum við yfir nokkur raunhæf dæmi sem sýna hvernig við tökumst á við algengar áskoranir, nánar tiltekið:

  • Meðhöndlun blandaðra texta- og tölugagna og hvers vegna þau rugla einföld RAG-kerfi: lykilorð skarast og tölur hafa enga merkingarlega þýðingu.

  • Hvers vegna hjálpar að hanna ívafanir út frá samantekt: Búðu til stutta lýsandi samantekt fyrir hvern bút og ívafðu og leitaðu síðan út frá henni.

  • Hvernig búa má til samhengisbundnar samantektir: Láttu samhengi yfirskjalsins fylgja svo hægt sé að greina á milli tölfræðiupplýsinga sem líta svipað út.

  • Hvenær á að reiða sig á kóða og Pydantic-líkön: Þegar efnið þarf að vera orðrétt skaltu sameina sérsniðinn kóða og/eða Pydantic-líkan við köll í LLM til að tryggja áreiðanleika.

Sérsniðnar RAG-lausnir smíðaðar

Grunnatriðin

RAG-kerfi knýja allt frá þjónustuspjallmennum til innri þekkingaraðstoðarmanna.

Undir húddinu eru skrefin yfirleitt þessi:

  1. Skiptu frumskjölunum í búta

  2. Ívafðu hvern bút í vigurrými

  3. Sæktu K efstu bútana þegar fyrirspurn berst

  4. Búðu til svar sem byggist á þessum bútum

Vinsæl verkfærasöfn á borð við LangChain, LlamaIndex og Filestore frá OpenAI gera þessi skref nánast sáraeinföld. Í raunverulegum vinnslukeðjum rekstu þó á gögn sem eru ekki bara þéttur texti og einföld RAG-kerfi geta átt í erfiðleikum með þau. Í næstu köflum sýnum við raunhæf dæmi um gagnaáskoranir og byggjum lausnina smám saman upp eftir því sem flækjustigið eykst.

Þegar málin flækjast

  1. Þegar gögnin eru ekki bara texti (sem er raunar algengt)

Skoðum eftirfarandi gagnabút úr tölvuleik:

JSON

{ "Attack": { "Range": { "default": 5, "with_Draconic_Ascension": 5.5, }, "Speed": { "default": "2 seconds", "with_Draconic_Ascension": "2.2 seconds", }, "Damage": { "default": 10, "with_Draconic_Ascension": 12, } }} 

Ívafanir virka vegna lærðra tengsla milli orða sem byggjast á merkingu og málfræði. Í gögnunum hér að ofan blandast saman texti og tölur, en utan þessa tiltekna samhengis hafa tölurnar engin tengsl við orðin. Því má segja að þessi gagnabútur sé í raun samsettur úr nokkuð lýsandi orðum og svo tilviljanakenndum tölum.

Þetta væri í raun ekkert vandamál ef við hefðum aðeins þessa gerð gagna, því enn væri hægt að sækja þau út frá ívöfunum fyrir þau fáu lýsandi orð sem eru til staðar (eða einfaldlega nota text-to-SQL). En hvað ef þessi bútur er grafinn meðal fjölda textaþéttra búta þar sem sömu orð koma einnig fyrir? Til dæmis:

JSON

{"Draconic_Ascension": { "description": "Transform into dragon form. Attack range and speed are increased by 10%, damage is boosted by 20%.", "details": { "activation_conditions": "Can only be activated when HP is below 50%or Fury meter is full.", "visual_effects": "Wings unfurl, scales shimmer with embers, voice lines change to echoing growls.", "lore": "An ancient bloodline awakens. The bearer of the mark channels the soul of the last Flamewing Wyrm, becoming a living storm of fire and fury." } }}

Ímyndum okkur nú að við viljum sækja svarið við „What is the attack range with Draconic Ascension?“ Líklega tekst okkur ekki að sækja rétta bútinn, því hann týnist í hávaðanum frá öðrum bútum sem innihalda sömu lykilorð.

Rót vandans er sú að erfitt er að greina þessa gagnabúta í sundur, þótt þeir geymi ólíkar gerðir upplýsinga um sama efni. Gætum við auðgað eða bætt þetta á einhvern hátt? Auðvitað getum við það :smile:

  1. Auðgaðu gögnin með því að draga þau saman — já, þú last rétt

Í stað þess að ívafða bútinn sjálfan beint getum við fyrst búið til samantekt sem lýsir efni gagnanna og síðan ívafið og sótt út frá samantektinni. Við svargerð notum við þó áfram upprunalegu gögnin sem tengd eru samantektinni.

Fyrir bútana tvo hér að ofan myndum við því búa til samantektir á borð við:

  1. Tölfræði um drægni, hraða og skaða árása (sjálfgefið og með Draconic Ascension).

  2. Lýsing og ítarupplýsingar um Draconic Ascension, þar á meðal skilyrði virkjunar, sjónræn áhrif og baksaga.

Síðan auðgum við fyrirspurnina svo hún „samræmist“ samantektinni. Til dæmis myndum við breyta „What is the attack range with Draconic Ascension?“ í „What is the statistics of attack range with Draconic Ascension?“ Þetta er sérstaklega mikilvægt þegar leitarfyrirspurnin kemur frá notendum utan tæknigeirans sem spyrja á ~~„frjálsu máli“~~ venjulegu mannamáli. Þeir hvorki vita né þurfa að vita hvernig RAG hámarkar nákvæmni og endurheimt.

Skýringarmynd sem sýnir hvenær málin flækjast.

  1. Ekki slíta hluti úr samhengi (gildir almennt í lífinu)

Næsta dæmi snýst um að vinna með ógrynni gagnabúta sem líta allir eins út, líkt og hér að neðan:

Plain Text

# Chunk one{ "Attack": { "Range": { "default": 9, }, ... }}# Chunk two{ "Attack": { "Range": { "default": 6, }, ... }}# Chunk three{ "Attack": { "Range": { "default": 7, }, ... }}

Ef við höldum okkur við sömu aðferð skulum við ímynda okkur spurninguna „what is character X’s attack range?“ Þá yrði valið milli samantektanna sem við bjuggum til nánast eins og happdrætti, því þær væru líka mjög svipaðar. Hvernig gætum við þá greint þær í sundur?

Einfalda svarið er að veita samhengi. Við gætum einfaldlega sett tilvísun í yfirskjal bútsins inn í gagnabútinn, til dæmis {”character”: “X”} í þessu tilviki. Þá gætum við sótt réttu gögnin fyrir persónu X af nákvæmni, jafnvel þótt sömu gögn væru einnig til fyrir persónur Y og Z.

Betri og almennari aðferð væri þó að búa til samhengisbundna samantekt á bútnum. Í stað þess að draga aðeins gagnabútinn sjálfan saman gætum við sent bæði yfirskjalið og bútinn til að búa til almenna samhengisbundna samantekt. Þar lýsum við því hvernig búturinn fellur að yfirskjalinu, til dæmis:

  1. Þessi bútur veitir ítarlega tölfræði um … fyrir persónu X. Búturinn fellur að heildarskjalinu með því að sýna styrkleika X í árásarhraða …

  2. Þessi bútur veitir ítarlega tölfræði um … fyrir persónu Y. Búturinn fellur að heildarskjalinu með því að sýna bætta eiginleika Y þegar hún notar sérhæfileika sinn …

  3. Þessi bútur veitir ítarlega tölfræði um … fyrir persónu Z. Búturinn fellur að heildarskjalinu með því að sýna eiginleika Z sem henta vel fyrir varnarhlutverk í liðsleikjum …

Þessi aðferð (sem er að hluta innblásin af Anthropic) kann að virðast óþarflega umfangsmikil fyrir dæmið hér að ofan. Hún er þó mjög áhrifarík fyrir búta sem gætu verið rangtúlkaðir „utan samhengis“ og veitir jafnframt samræmda aðferð fyrir alla búta, svo vinnslukeðjan helst snyrtileg.

Skýringarmynd sem sýnir hvenær málin flækjast.

  1. Þegar þú þarft að vera ~~stjórnsamur~~ nákvæmur

Yfirleitt fáum við gögn í heilum einingum og skiptum þeim í búta fyrir RAG-kerfi. Í þessu dæmi sýnum við svolítið annað: gögn sem búið er að skipta í búta, en illa. Bútarnir eru tilviljanakenndir hlutar úr rökrænni heild sem þarf í raun að setja aftur saman. Rökrænn bútur er efnisbútur sem á eðli málsins samkvæmt að vera samhangandi, svo sem undirkafli skjals eða heildstæð málsgrein.

Skýringarmynd sem sýnir hvenær málin flækjast.

Fyrsta tilraunin okkar var að setja öll gögnin í LLM-kall, biðja það að flokka bútana saman eins og því þætti við hæfi og skila síðan flokkuðu efninu. LLM ætti að vera nokkuð gott í þessu, ekki satt? Bæði já og nei.

Við höfum einnig komist að því við ýmis önnur tækifæri að LLM eiga til að fara auðveldu leiðina og eru óáreiðanleg þegar krafist er alls efnisins orðrétts, sérstaklega þegar samhengið er langt. Sem er fullkomlega skiljanlegt. En það útilokaði þessa leið í þessu tiltekna tilviki, því við þurftum efnið nákvæmlega orð fyrir orð — engar samantektir og engum hluta upprunalega efnisins mátti sleppa. Engin smáatriði mega glatast.

„Já“-hlutinn var auðvitað sá að líkanið stóð sig frábærlega í að skilja merkingu og uppbyggingu brotnu bútanna. Svo lengi sem það neitar ekki að skila efninu nákvæmlega orðréttu. Fjandinn hafi það :/

Hvernig gætum við þá nýtt það sem LLM gerir vel en forðast það sem því er ekki treystandi fyrir? Við leituðum til gamals og góðs vinar: kóðans (þ.e. sérsniðinnar Python-falls). Og Pydantic-líkans sem gæti varla verið einfaldara. Lausnin er þessi:

  • Farðu í gegnum kaflana einn af öðrum og haltu utan um núverandi rökræna bút

  • Fyrir hvern kafla skaltu spyrja LLM: Tilheyrir þessi kafli núverandi rökræna bút? Svarið skal vera já eða nei (samkvæmt Pydantic-líkaninu).

  • Ef svarið er já skaltu bæta kaflanum við bútinn. Ef svarið er nei skaltu skila núverandi rökræna bút, enda er hann fullgerður, og hefja svo nýjan bút með kaflanum.

Skýringarmynd sem sýnir hvenær málin flækjast.

Við notum auðvitað aðeins fleiri tóka hér en ef allt efnið væri unnið í einni umferð. Í þessu tiltekna tilviki, þar sem mikilvægast var að varðveita efnið nákvæmlega, var sá litli aukakostnaður vel þess virði.

Þetta er mjög einföld lausn en fylgir mikilvægu grundvallaratriði: Þegar nákvæmni er nauðsynleg viljum við ekki treysta eingöngu á LLM, enda eru þau líkindafræðileg.

Með sérsniðnum kóða eða föllum og Pydantic-líkönum má ná fyrirsjáanlegri og áreiðanlegri niðurstöðu en jafnframt nýta getu LLM til fulls.

Að lokum

Að smíða lausn með skapandi gervigreind er jafnmikil verkfræðiáskorun og gervigreindaráskorun. Við vonum að þessi dæmi hafi veitt þér innblástur til að takast á við þínar eigin, einstöku áskoranir. Ef þú vilt lesa meira um verkfræðimiðaðar lausnir með skapandi gervigreind skaltu skoða bloggfærsluna okkar um hönnun gerandakerfa sem byggjast á beiningu.

Höfundur

Cynthia Yu