OJ-6: Noen tanker boken Ekko - Et essay om algoritmer og begjær
I februar leste jeg boken Ekko - Et essay om algoritmer og begjær av Lena Lindgren. Boka kom ut i 2021, og er nok kjent for flere av dere da den mottok stor ros fra litteraturkritikere, og vant priser som Brageprisen for beste sakprosabok. Jeg hadde fått med meg at boka fantes, men det var ikke før i år at den havnet forran meg.
Boka, eller essayet, ble skrevet som et forsøk på å forstå samtiden, og hvordan Silicon Valley, medieteknologien og utviklingen av sosiale nettverk har bidratt til å påvirke den. Lindgren prøver å tolke fremveksten ekkokammer, hatprat, splitting og radikalisering, avhengighet, synlighet og oppmerksomhet, og effektene som har bidratt til disse fenomenene. Sentralt for fenomenene er oppmerksomhetsøkonomien, og algoritmene som er utformet for å maksimere inntjeningen. Og algoritmene har forstått at disse fenomenene er lønnsomme.
Essayet bruker den romerske myten om Ekko og Narcissus som en rød tråd, eller anologi for å beskrive disse fenomenene. Myten handler om Narcissus, som er forelsket i seg selv og sitt eget speilbilde, og nymfen Ekko, som forelsker seg i Narcissus. Ekko er blitt forbannet etter å ha bablet meningsløshet for å distrahere, og har nå kun mulighet til å gjenta det siste andre har sagt. Myten ender med at Narcissus dør, besatt av sitt eget speilbilde, mens Ekko blir revet i stykker, besatt av Narcissus, og lever videre kun som en stemme som gjentar andre. Det er ikke åpenbart å trekke parallene mellom denne cirka 2000 år gamle fortellingen, og hvordan vi som menneskers oppførsel er i den nye medieteknologien og sosiale nettverk. Jeg synes essayet fletter disse to sammen på en spenennde måte.
Men det var kanskje nok om selve boken. Den er ikke så lett å beskrive i korte trekk. Jeg tenker derfor å skrive kort om hvorfor jeg likte denne boka, og hva jeg fikk ut av den.
Jeg likte denne boken, først og fremst fordi den gav meg noe mer klarhet i en stadig mer forrvirende verden. De siste 10 årene, og kanskje særlig fra valget det amerikanske valget i 2016, hvor Trump for første gang ble stemt inn som president, har endringene skjedd fort. Folks oppførsel og handlinger oppleves mer og mer irrasjonelle, og det er vanskeligere og vanskeligere å forstå hvorfor folk gjør hva de gjør. Jeg opplever at vi lever i stadig mer forskjellige virkligheter. For min del har denne følelsen kun økt siden 2016. Og særlig denne siste måneden hvor Trump igjen har kommet til makten i USA, og verden har blitt veltet på hodet i forrykende tid.
Nettopp denne utviklingen synes jeg Ekko diskuterer på en god måte. Særlig synes jeg Lindgren gjør en god jobb i å belyse mekanismene som gjør at vi mennesker oppfører slik vi gjør, og hvordan algoritmene bidrar til dette. Det hjalp meg med å forstå hvorfor Trump gjør som han gjør nå, hvorfor teknologi-lederene i Silicon Valley stiller seg bak, og hvorfor mennesker gjør statig mer rare og uforståelige ting.
Jeg kommer ikke til å diskutere alt dette i denne mikrobloggen, da det fortsatt er vanskelig å sette alle tankene i ord, og. Jeg oppfordrer derimot til å lese Ekko - Et essay om algoritemer og begjær. Den er kort og bra skrevet, og veldig dagsaktuell. Også ønsker jeg gjerne å diskutere disse temaene videre.
Olav 📣

Unminifying av kode med LLM
Akkurat nå jobber jeg med å skrive om noe funksjonalitet i en gammel app. Spesifikt skal jeg bytte ut kartleverandør. I bunn er det Leaflet som brukes til å vise kartene, men Leaflet lå bak en wrapper fra den forrige kartleverandøren. Derfor var det ikke bare å erstatte det gamle kart-endepunktet med det nye. Jeg var derimot avhengig av å vite hva som skjedde bak kulissene, men wrapper-koden var minified. Da er ikke koden særlig lesbar.
For en stund tilbake kom jeg over denne artikkelen på HN, som i bunn og grunn er en bedre versjon av dette blogginnlegget jeg nå sitter og skriver. Poenget er at LLMer er overraskende gode på å unminifye kode, og det kan man bruke dersom man plutselig har behov for å forstå noe minified kode.
Jeg limte koden min inn i Claude, og ut fikk jeg en penere formatert kode, litt mer deskriptive variablenavn, og noen kommentarer. Kommentarene var ikke alltid riktig, men nå manglet jo modellen litt kontekst også. Uansett fikk jeg lesbar kode ut, som jeg kunne bruke til å forstå hva jeg trengte å ta med videre når jeg skulle skrive meg ut av denne wrapperen.
OJ-4: Hodeløse nettlesere i produksjon
Det finnes noen grunner til at du ønsker å kjøre en headless nettleser i produksjon. Det kan eksempelvis være å ta skjermbilder av en nettside, generere PDFer, skraping, automasjon, eller ende-til-ende tester. Altså om det er noe du må inn i nettleseren for å verifisere eller fikse. Bibliotek som Playwright, Puppeteer, Selenium og Cypress gjør det høvlig enkelt å skrive kode som interagerer med nettleseren. Og rett slik kan du automatisere hva nå enn du ønsker å gjøre i nettleseren. De vanligste headless nettleserene er Chromiums, Firefox, og Webkit, altså som de vanligste ikke-headless nettleserene, bare headless.
For ordens skyld: en headless nettleser er da en nettleser uten et grafisk brukergrensesnitt, og da ganske egnet for å kjøre i bakgrunnen på din maskin, eller, som jeg skal komme tilbake til, på en server.
Vi jobber med kode som blir vevd inn blant annen kode fra flere andre team, til et og samme produkt. Derfor opplever vi støtt og stadig at endringer utenfor vår kode brekker funksjonalitet vi har ansvar for. Og akkurat derfor fikk vi idéen om å lagen tester som alltid gikk automatisk i bakgrunnen, og sjekket disse tingene for oss. Dette har også medført en del fallgruver, så jeg tenker å vie resten av dette skriveriet til.
1. Ikke kjør en nettleser i produksjon om du absolutt ikke må
Stort sett ønsker man å kjøre slike programmer lokalt eller kanskje tester i CI. Et vanlig bruksområde er ende-til-ende tester som trykker seg rundt i applikasjonen din, sjekker at ting er der de skal være, men også at resten av systemet som skal tjene front-enden fungerer. I de aller fleste tilfeller er dette mest relevant å teste ved endringer. Har du ikke behov utover dette, eller som du tenker det går fint å kjøre fra din maskin er min anbefaling at du holder kjøringene der.
Men så finnes det jo alltid en eller annen grunn til at du kanskje føler du må dette alikevel. Eller en slik grunn greide i alle fall vi å pøske frem for oss selv. Det har jo også gitt litt hodebry.
2. Nettlesere krever mye minne og CPU
Appen din bruker nødvendigvis ikke så mye ressurser, men det gjør en
nettleser. Det er jo tross alt et ganske stort program man trekker inn.
Derfor må man sørge for at man har gitt tilstrekkelig med ressurser. Og
det nettleseren får, er den ofte gira på å ta. For oss har dette
innebært mye OOMKilled
og en del store CPU-spikes, eller
throttling om man har limits på slikt. Det krever rett og slett en del
skruing på knapper og måling av bruk for å lande på en ideel
ressursallokering og skalering. I min erfaring går det ofte fint med
litt CPU throttling for noen tester, men blir det for mye endte
vi i prakis opp med flaky tester fordi ting lastet for treigt.
Dette gjør også appen, og eventuelt podden veldig mye mer sårbar til å krasje. Ta hensyn for dette, evnt ved å splitte ut egen logikk for orkestrering, og tenke på retry-mekanismer. Mikroservice-helvette lusker visst overalt. Mitt beste tips her er å sørge for god tilgang til informasjon om ressursbruk i kjøremiljøet. For Kubernetes har jeg hatt veldig god nytte av k9s CLI og Grafana.
Og til slutt så er det jo noen som skal betale for skymorroa, og selv om man ikke alltid blir eksponert for sluttsummen selv.
3. Bruk grensesnittet ditt bibliotek gir til nettleseren riktig
Jeg tenker jo at dette skulle være åpenbart, helt til jeg skøyt meg
selv i foten ved å glemme browser.close()
. Dette er altså
Playwright-funksjonen for å lukke en nettleser, og ved å ikke lukke den
mellom hver test endte jeg opp med svært mange nettlesere, og til slutt
svært mange OOMKilled og drepte podder. Skriv denne koden med omhu.
Her er det også veldig mange måter å optimalisere, som ikke nødvendigvis er helt intuitiv. Eksemplevis kan dette være parallelisering, eller lage en kø for å kjøre ting sekvensielt. Dette er avhengig av hva du skal, hvilket bibliotek du bruker, og hvor mye ressurser du har tilgjengelig. Her er det relevant dokumentasjon for ditt bibliotek som gjelder, men for resten har jeg ikke funnet noen tydlig informasjon om hva som er best. Vi kjører ting sekvensielt med en kø.
Her er det også verdt å nevne at nettlesere kan ta inn massevis av argumenter på oppstart, hvor det finnes noen som er ekstra relevant for å kjøre en headless nettleser i containerised miljøer (eksempelvis Docker). Disse varierer fra nettleser til nettleser, og slik jeg tolker det er det viktigere for headless Chromium og headless Firefox, og mindre viktig for headless Webkit. Mange av disse argumentene kommer med avveininger. Eksempelvis ved å skru av sikkerhetsmekanismer som sandboxing for bedre ytelse, eller redusere ytelsen på kost av poteniselt mer flaky tester.
Her er en god oversikt over argumenter til Chromium.
Jeg har ikke funnet en tilsvarende god oversikt for Firefox config dessverre.
4. Nettlesere lager prosesser som ikke nødvendigvis blir ryddet opp skikkelig
Jeg har også fått inntrykk av at nettlesere har en tendens til å starte egne prosesser som ikke nødvendigvis blir avsluttet når man avslutter nettleseren. Dette kalles noe så kult som zombie processes! Skrekk og gru!
Særlig i containeriserte miljøer er det viktig å huske å drepe disse
før de spiser opp PIDer (prossess-IDer for aktive prosesser) og minne.
For å drepe zombier anbefales det å bruke et init-system i
containeren, som dumb-init eller tini. Disse konfigureres da
som en parent-prosess til det du tenker å kjøre i containeren, også har
innebygd logikk for å rydde opp i nettopp zombie prosesser. I nyere
versjoner er forresten tini bygd inn Docker og Podman, men må
da startes på run
med flagget --init
. Hvordan
jeg konfigererer opp args for docker run
i kubernetes har
jeg ikke blitt helt klok på, så jeg ruller med tini for nå.
Selv med dette virker det ikke alltid som nettleser-prosessser blir ryddet opp helt skikkelig, i alle fall mens nettleserne driver å kjører. Jeg har brukt programmer som htop til å aktivt monitorere prosessene som lever i min container for å prøve å få bedre bukt på dette. Om noen har noen tips akkurat her tar jeg gledelig i mot.
Avslutningsvis vil jeg gjerne gjenta at poeng 1. Prøv å unngå å prodsette disse beistene om du kan unngå det. Hodebryet er så mangt, og jeg er ikke i mål. Det finnes også selskaper som tilbyr headless nettlesere som en tjeneste. Det virker veldig digg, men jeg har ikke testet de. Jeg har derimot hentet en del tips og inspirasjon fra ett av de her.
Har du noen tips eller innspill?
-Olav
OJ-3: Kjøre språkmodeller på egen maskin
De siste par dagene har Ole Jacob og jeg utforsket hvordan vi kan kjøre språkmodeller (LLM-er) lokalt på vår maskin. Det vil si, vi fikk et par dager til å leke med denne teknologien for å se om det kunne bidra til å løse et reelt problem i et prosjekt.
Motivasjonen for å kjøre språkmodellene lokalt bunner ut i:
- Unngå avklaringsrunder og usikkerheter rundt om det er ok å laste opp data til en-eller-annen LLM-leverandør på nett.
- Slippe å styre med å lage bruker eller skaffe API-nøkkel til en eller flere tilbydere av LLM-tjenester.
I min erfaring er disse begrensningene ofte grunnen til at vi legger språkmodel-eksperiment på is allerede før vi har prøvd.
Her kommer derfor en liten oppsummering av hva vi har gjort med lokale LLMer og hva vi tenker om de.
Sette opp og kjøre språkmodeller på egen maskin:
Slik satt vi opp vårt språkmodell på vår maskin:
Kjøre selve språkmodellen
Vi lastet ned Ollama, som er et verktøy for å kjøre LLMer lokalt på maskinen. Man kan tenke litt på Ollama som en runtime for språkmodeller, som kan kjøre og interagere med modellene. Den kommer med et API, som gjør det enkelt for andre programmer å koble seg på.
Ollama kan startes enten ved å laste ned det offisielle
Docker-imaget, eller bare kjøre en enkel
brew install ollama
om man vil kjøre den rett på maskina.
Vi gjorde sistnevnte.
For å komme i gang lastet vi ned llama3-8b, som er Meta’s
open-source språkmodell. Med Ollama kan den lastes ned med en enkel
ollama run llama3
Med ollama serve
starter Ollama-serveren, som man
eksempelvis kan kalle slik:
curl -X POST http://localhost:11434/api/generate -d '{
"model": "llama3",
"prompt":"Hva er fordelen med å kjøre språkmodeller lokalt?"
}'
Denne spyr den tilbake en response fra din lokale llama3. Her finnes det også biblioteker for å enkelt jobbe med Ollama requester og responser i koden din.
Sette opp et UI for å interagere med språkmodellen
Det finnes også mange med UI-er man kan klone ned og kjøre lokalt for
å få grensesnitt til kjapt interagere med din lokale LLM. Vi valgte å
bruke Dify, som gjør
det enkelt å behandle filer og bygge workflows LLM-er. Denne kjørte vi
også opp lokalt, men her ved å klone ned repoet og kjøre en
docker compose
etter å ha fulgt Dify’s
dokumentasjon. Den starter en del greier, bla. en server, en
front-end, en database og en reverse proxy. Her var det litt
konfigurering for å sette riktig port i proxyen, og konfigurere den til
å kalle endepunktet til Ollama.
Dify har også ganske najs funksjonalitet for å importere data og gjøre det mulig å la en LLM å søke i det. Til dette koblet vi på en annen lokal språkmodel for å håndtere embedding. Videre kunne vi bruke denne dataen, og en språkmodell for å snakke med vår lokale språkmodell. Sånn ser det ut i Dify:
Så er det bare å kjøre denne, og chatte med språkmodellen som du ville med en annen GPT.
Knowledge retrieval fra egen maskin
De fleste språkmodeller er trent på utdatert informasjon, og har videre ikke informasjon spesifikk for din bedrift ol. I vårt tilfelle hadde vi en del filer, som vi ønsket at språkmodellen vår skulle kjenne til innholdet i. Til dette bruker vi teknikker som embedding, hvor man kan sende en rekke ulike filer og formater gjennom en annen embedding modell (vi brukte nomic-embed-text). Denne modellen brukte vi til å omgjøre filer til vektorer som kan sendes og tolkes som kontekst av språkmodellen vår. Når vi lagde kontekts kunne vi bla. gjøre mye rart, som å kjøre den på en måte hvor embedding-modellen vår lagde spørsmål-svar kombinasjoner til seg selv. Dette kverna litt på maskina, men tok heller ikke allverdens med tid.
Embedding av tekst er et fundament for å lage det vi ønsket å lage, nemlig en språkmodell som hadde konteksten av våre spesifikke forretningsbehov. Dette er hva som i dag ofte blir omtalt som å Retrieval Agmented Generation (RAG). Ideelt sett kan man da bruke også RAG til å søke i egene greier.
Sidenote om språkmodeller og programmer for å jobbe med disse.
I denne LLM-sfæren virker det som det dukker opp nye modeller og verktøy for å jobbe med de hver dag som går. Det her derfor ikke så mye verdi å bruke for mye tid på hvordan vi har jobbet med disse spesifikke verktøyene på vår maskin. Hensikten er i større grad å vise at de finnes, og hvordan de henger sammen, slik at vi har et bedre grunnlag til å kjapt komme i gang med testing når vi ønser å “gjøre noe med AI”.
Open WebUI er et annet alternativ til UI som jeg synes virker spennende.
Hva ble egentlig resulatet?
Tja. Hittil er det nok ikke superimponerende greier vi har konfigurert opp. Mestparten av tiden gikk med til å finne ut hvor vi skulle starte, og få det til å kjøre ok på vår maskin. Deretter var det å konfigurere data og prompts til å sjekke om denne teknologien faktisk kan løse problemet vårt. Hittil er kanskje ikke resultatene helt der, men det har nok noe med datagrunnlaget, promptingen og den litt mer lettkjørt språkmodellen vi brukte. Her tenker jeg en to be continued… er hensiktsmessig.
Jeg så også nå i ettertid at embedding-modellene vi brukte,
nomic-embed-text
stort sett er trent på engelsk tekst, som
kan ha bidratt til at den heller ikke leverte varene skikkelig.
Hva har vi lært?
Det viktigste er at det er ganske rett frem å sette opp en LLM på maskina. Med riktig UI-verktøy kan man også prototype workflowen man ønsker å bruke LLMen i. Vi tenker dette kan gi et godt utgangspunkt til å (1) tørre å eksperimentere med data du ikke føler deg helt komfortable med å sende til himmels, og (2) få oversikt over hvordan du vil koble opp data, LLM og prompts før du begynner å kode det.
Man trenger heller ikke sånn alvorlig mye datakraft for å kjøre de
litt enklere LLMene, så å deploye den til en server eller putte den på
noe shabby hardware kan fortsatt monne til en del oppgaver. Vår
favorittvideo denne uken er til inspirasjon, hvor en svenske har
fylt svak hardware til bremmen med en usensurert
llama3
-modell, og gjor den litt usikker.
Se opp for en demo fra oss, og ikke nøl med å spør om du er gira på å teste sjæl.
OJ JEG ER KONSULENT
“Allerede den første uken på studiet ble vi introdusert til konsulenthverdagen gjennom linjeforeningens hovedsamarbeidspartner, Bekk. Og jeg sitter igjen med inntrykket av at fra det tidspunktet var det nok få som så seg tilbake; jobbtilbud og sommerinternships hos konsulenthus sto øverst på listen over ønskede arbeidsgivere. Dette kan også sees i Abakus sin utmatrikuleringsundersøkelse for 2022, hvor fire av topp fem ideelle arbeidsgivere er konsulenthus, og den siste er Google. (Det er kult å merke seg at Iterate faktisk er på fjerdeplass her). Men gir egentlig det å lokke med gratis mat og alkohol det riktige inntrykket av hva en konsulenthverdag innebærer? Har studenter og nyutdannede egentlig tenkt over hva dette innebærer? Jeg vet i hvert fall med meg selv at jeg ikke har gjort det, og har tenkt flere ganger den første måneden:”Oj! Jeg er konsulent”.”
Første forespeilet oppdrag
Når en fra salg kom til oss (Olav og meg) første gang, skvatt jeg litt til. Han presenterte et potensielt oppdrag hos at av Iterate sine porteføljeselskapet, noe som fikk meg til å sukke litt. Ikke fordi prosjektet ikke var spennende – muligheten til å jobbe med mindre selskaper var en av de tingene jeg så på som en positiv side ved Iterate. Sukket var uavhengig av oppdraget, og heller relatert til det å være konsulent. For dette oppdraget innebar å sitte på kontorene til selskapet, noe som er et faktum for konsulenter, men som jeg ikke hadde ofret en tanke. Jeg hadde på dette tidspunktet brukt tre gode uker på å bli kjent med folk i Iterate og å komme godt i gang med lunsjslabberas. Men nå skulle jeg plutselig ikke møte disse menneskene på flere uker, mens jeg var ute på oppdrag. Det er en selvfølge man kanskje burde ha tenkt på, men det hadde jeg altså ikke gjort, og skvatt litt der og da.
Hoppe ut på dypet
Den andre ‘oj’-en kom da jeg plutselig snublet over et driftsoppdrag fra en kollega. Jeg har alltid tenkt at dette med å hoppe ut i det dype er måten jeg lærer best på, men denne gangen slo tanken meg: “Oj, jeg er konsulent.” Og her har jeg muligheten til å trå feil og faktisk gjøre ting verre for kunden. Jeg ble også stilt spørsmålet: “Hva vil du anbefale for vår kunde?” Tanken slo meg at som konsulent skal jeg faktisk kunne gi råd om hvordan noen skal utvikle sin bedrift, en kanskje litt skremmende oppgave, i hvert fall som nyutdannet.
Misforstå meg rett. Jeg elsker min nye tilværelse i Iterate, og ser mange positive sider ved å jobbe som konsulent. Men nå merker jeg at dette begynner å bli langt. Så det får jeg heller ta i en ny ‘oj’ om litt.
-Johan
OJ JEG ER NY
Det tok sin tid, men endelig kan jeg publisere det første innlegget på min (og Johans) egne mikroblogg: OJ. De siste ukene har vi jobbet med å lage funksjonalitet for å faktisk kunne gjøre nettopp dette, så dette innlegget blir litt om erfaringer fra denne jobben, og en test på at det vi har laget faktisk funker.
Prosessen gikk i grove trekk slik:
- Jeg har lyst til å lage en feature
- Innse at kodebase ikke støtter dette særlig bra
- Finne ut hva jeg må lage og hva jeg må endre
- Begynne å implementere (litt..) til noe annet må endres for å støtte den nye endringen
- Endre systemdesign..? Tenke.. diskutere.. tenke.. hvorfor er dette slik?.. diskutere.. OK (for nå).
- Implementer (litt til..)
- Gjente steg 3-5 en del ganger.
- Ting fungerer endelig (forhåpentligvis), men ser stort sett uendret ut.
Det var det, velkommen til OJ (om alt funker)! Som i de andre mikrobloggene gikk tematikken her brått inn på refaktorering.
Kommentarer, og gjerne tips til nyutdannet teknolog tas i mot med glede.
Olav