Hva slags vin passer til svineribbe, lutefisk eller pinnekjøtt?
Vinvenn har svaret – en løsning som hjelper deg å finne raske anbefalinger til mat og vin uten å måtte lete gjennom alle de tusenvis av vinene som finnes på et vinmonopol!
Hva er Vinvenn?
Vinvenn er en mobile-first webapplikasjon som i dag teller ca. 200 månedlig aktive brukere. Idéen oppstod da jeg selv opplevde et behov for å kunne hente ut anbefalinger fra noen mat- og vinbøker litt raskere enn å måtte fysisk slå opp i bøkene selv, og deretter overføre det jeg leste til konkrete produkter hos Vinmonopolet. Vinvenn bruker istedenfor store språkmodeller i kombinasjon med RAGs (Retrieval Augmented Generation) til å hente frem generelle mat- og vinanbefalinger fra eksperter. Ved bruk av såkalte RAGs kan disse anbefalingene hentes ut fra et datasett bestående av utvalgte vinbøker, -journaler, -artikler og smaksnotater, slik at du effektivt kan låne ekspertenes kompetanse når du skal finne frem til den beste mat- og vinkombinasjonen.
Den største forskjellen ved å bruke Vinvenn kontra tjenester som ChatGPT eller Perplexity er at Vinvenn tilbyr mer konkrete anbefalinger fra oppnevnte kilder, i tillegg til at Vinvenn gir anbefalinger fra et mer oppdatert inventar, så du er nærmest garantert at vinen du får anbefalt faktisk er tilgjengelig på ditt vinmonopol istedenfor at du anbefales en utgått/utilgjengelig vare.
Vinvenns forutsetninger
Det følger av dataens natur i Vinvenns datasett (masse tekstdata) at den ikke alltid forekommer på likt format, per definisjon ustrukturert data. Likevel finnes det en slags «struktur» i disse ustrukturerte dataene, og det er her de store språkmodellene virkelig får skinne. For hva betyr det egentlig at en vin omtales som «skarp» eller «tung»? Vel, de store språkmodellene vet heldigvis at dette er beskrivelser for henholdsvis syrlighet og fylde, så med Vinvenn slipper du altså å måtte kunne dette fancy språket selv når du skal tolke en anbefaling eller et smaksnotat. Ved å videre kombinere disse språkmodellene med en algoritme jeg har utviklet så fungerer Vinvenn som et slags anbefalingssystem.
En annen viktig forutsetning er at det meste av vin på Vinmonopolet bedømmes på en skala fra 1-12 langs dimensjonene: fylde, friskhet (les: syrlighet), og garvestoffer/sødme. Ved å ta i bruk store språkmodeller så kan vi altså la modellen gjøre de tekstlige tilnærmingene og dermed oversette de generelle anbefalingene til konkrete vinprofiler. En vinprofil er i denne sammenheng en beskrivelse av en type vin som passer til maten, og den inneholder eksempelvis informasjon om hvilke druer som kan inngå i vinen, området eller regionen vinen kommer fra, og da karakteristikkene for fylde, friskhet, og garvestoffer/sødme. Vinvenn bruker enda litt mer data for å avgjøre hvilke anbefalinger som er «best» (hva som er best er åpenbart subjektivt), men for å unngå at denne artikkelen blir altfor lang så skal vi ta en nærmere kikk på en liten del av algoritmen som foretar seg sistnevnte karakteristikker.
Vinvenns algoritme basert på fylde, friskhet og garvestoffer/sødme
Algoritmen handler altså i grove trekk om å oversette en vinprofil generert fra datasettet og språkmodellen til et konkret produkt som samsvarer med filteret brukeren har satt, det vil si matrett, et prisintervall og et utsalgssted (altså hvilket vinmonopol). La oss videre anta at brukeren har søkt på matretten svineribbe, med prisintervall 0-1500kr og Oslo Aker Brygge som utsalgssted.
For å regne ut hvor mye en vin ligner på gitt vinprofil bruker jeg noe som heter Gower’s distance: et mål på likhet mellom én rad og alle andre rader i en tabell.
I første steg må jeg altså konstruere en tabell, og første rad i denne tabellen er dermed en vinprofil med dets mål for fylde, friskhet og garvestoffer/sødme. Denne raden er med andre ord en beskrivelse av en vin som passer til svineribbe basert på hva Vinvenn fant i datasettet. De påfølgende radene er det totale inventaret av all vin mellom 0 til 1500kr som innehar verdier for fylde, friskhet og garvestoffer/sødme i sine produktbeskrivelser hos et utsalgssted, i vårt eksempel Oslo Aker Brygge. I tabell 1 har Vinvenn funnet en vinprofil av typen rødvin, og derfor benyttes kolonnene fylde, friskhet og garvestoffer. For andre typer som hvitvin ville Vinvenn regnet ut likhet basert på fylde, friskhet og sødme.
Fra ovennevnte tabell kan vi observere at vinprofilen har følgende verdier for fylde, friskhet, garvestoffer: fylde 9, friskhet 8, garvestoffer 7. Når jeg så bruker Gower’s distance til å måle hvor mye de andre vinene ligner på gitt vinprofil får alle produktene en score mellom 0 og 1. En score på 0 indikerer at radene er identiske, altså at produktet matcher 100% med vinprofilen. Det betyr at et produkt med score lik 0 er en god anbefaling basert på denne naïve utregningen. Tabell 2 viser hvordan tabellen ser ut etter første mellomregning med Gower's distance.
I neste steg sorterer jeg radene (det vil si produktene) i tabellen stigende basert på likhetsscoren. I den fullstendige algoritmen skjer det riktig nok litt mer under panseret for å finne de beste anbefalingene, men prinsippet med å rangere produktene etter en score er det samme.
Så kan man spørre seg: hva skjer i tilfellene der det er svært dårlige scores for en gitt vinprofil? Vel, for å ikke slippe gjennom dårlige anbefalinger har jeg satt en terskel t (threshold på engelsk) som filtrerer vekk rader som ikke oppfyller kravet. Det betyr at for enkelte kombinasjoner av matrett, prisintervall og utsalgssted så er det rett og slett ikke god nok match mellom hva språkmodellen sier at er en god anbefaling og de produktene som er tilgjengelig hos et gitt vinmonopol, og da vil man heller ikke få noen resultater i søket. Tabell 3 illustrerer den sorterte tabellen og uthenting av to produkter som oppfylte terskelnivået (t = 0.5), og dermed fikk passere som gode nok anbefalinger til akkurat svineribbe.
Generelt så forsøker jeg å hente ut de (maksimalt) 5 produktene som har best likhetsscore i tabellen. Per matrett ligger det inne 3 vinprofiler som jeg gjør utregninger på, så maksimalt kan man få anbefalt 15 viner per matrett (3 ganger 5). Målet med Vinvenn er som sagt å hjelpe forbruker med å innsnevre valgmulighetene så man kan bestemme seg raskere. Det er kjent fra psykologien at jo flere valg vi har, desto vanskeligere er det å ta et valg (kjent som paradox of choice). Ved bruk av Vinvenn går man altså fra tusenvis av valgmuligheter til maksimalt 15 (!).
Teknologier i Vinvenn
Vinvenn består av en backend-app skrevet i python-rammeverket Flask. Denne er hostet på Google Clouds App Engine. Backenden har en integrasjon mot OpenAI sine språkmodeller, i tillegg til OpenAI sin "RAG-as-a-service" kalt Assistants API. I tillegg bruker jeg en rekke biblioteker som blant annet scikit-learn, fuzzy og gower i algoritmen til å regne ut likhet på tvers av vinprofiler og faktiske produkter hos Vinmonopolet. Frontend-appen er skrevet i React/TypeScript som jeg hoster på Vercel.
Hva har jeg lært?
Selv om det var en konkret produktidé som lå til grunn da jeg begynte på dette prosjektet, så var det også for å ha en arena/lekeplass der jeg kunne teste ut forskjellige teknologier på mine egne premisser. For min egen motivasjon har det vært en stor fordel at det grunnleggende temaet (mat og vin) er noe jeg synes at er spennende – så mitt tips til deg som ønsker å teste ut nye teknologier i litt mer gøyale (les: motiverende) omgivelser så bør du bygge noe som har en forankring i noe du allerede synes at er interessant, istedenfor å lage din n-te «Todo»-app.
En annen ting jeg har fått erfare er at man ikke skal være redd for å vise frem produktet sitt selv i et uferdig stadium, for selv bak litt spydig kritikk så kan det ligge gode poenger ved nærmere inspeksjon. Jeg har delt Vinvenn i ulike kanaler som Reddit og «vin-grupper» på Facebook for å få tilbakemelding fra brukere, og der har jeg opplevd både positiv og negativ respons. Det er viktig å forberede seg på at det vil forekomme kritikk – noe mer rettferdig og forventet enn annet – men hvis du ikke mottar noe som helst kritikk så mener jeg at du faktisk har delt produktet ditt altfor sent! Poenget med tilbakemeldingene er jo nettopp for å hjelpe deg å prioritere og sette retning underveis, ellers risikerer du å lage et produkt som ingen vil bruke.
Så hva passer til svineribbe, lutefisk eller pinnekjøtt?
Jeg tenkte å trekke frem noen konkrete produkter som jeg har testet selv på anbefaling fra Vinvenn til å svare på dette spørsmålet!
Svineribbe:
Weinbach Riesling Réserve 2020
389,90kr
Lutefisk:
Allram Hasel Alte Reben Grüner Veltliner 2023
169,90kr
Pinnekjøtt:
Dom. de Bellene Saint-Romain Vieilles Vignes 2022
399,90kr
Ellers finner du åpenbart flere svar ved å ta i bruk Vinvenn 😉