dimesum

Home / Blog / Techniek

Techniek

We hebben onze onkostenparser verwijderd

· 8 min leestijd ·

Onze regelparser hield het een week vol, waarna vier gewone zinnen geld op de verkeerde persoon zetten en één weigeringsregel de hele stapel bewakers verving.

We hebben een parser verwijderd die we net af hadden. Dimesums eerste poging tot het parsen van onkosten in natuurlijke taal was een engine op basis van regels, en vier gewone zinnen stuurden hem met pensioen: dinner 12-08 400 werd gelezen als €12, ravioli 600 zette een lid met de naam Ravindra in de verdeling, kirana 500 belastte een lid met de naam Kiran, en refund -483.50 werd een last van €483,50.

Een zin begrijpen is het werk van het model en van niets anders. Wat de engine op basis van regels verving is één trede genaamd amount_only: één enkel getal, alleen teruggegeven wanneer de tekst precies één ondubbelzinnige geldkandidaat bevat, en nooit een bewering over personen. Twee kandidaten betekent geen bedrag. Eén regel verving een groeiende stapel bewakers.

Vier zinnen beëindigden de regelparser

De verwijderde parser dekte de volledige set entiteiten die ons AI-ontwerpdocument voorschrijft: het matchen van leden en bijnamen, een uitsluitingslexicon, het afleiden van de betaler, een categorielexicon, en per veld afgestemde betrouwbaarheden. Elk van de vier storingen hieronder had een voor de hand liggende oplossing. Elke oplossing was een nieuwe bewaker met zijn eigen blinde vlek.

De vier storingen die Dimesums regelparser met pensioen stuurden, vastgelegd op 2026-08-20 in docs/tech/10-ai-design.md.
Wat de gebruiker typteWat de parser deedWaarom het gebeurde
dinner 12-08 400Las het bedrag als €12Een lezer ziet een datum en een totaal. Een regex ziet drie getallen en neemt de eerste.
ravioli 600Zette een lid met de naam Ravindra in de verdelingFuzzy matching van bijnamen scoorde een gerecht tegen een persoon.
kirana 500Belastte een lid met de naam KiranDezelfde matcher, dit keer met een winkelnaam.
refund -483.50Boekte een last van €483,50De cijfers overleefden en het teken niet, dus wees het geld de andere kant op.

Twee van de vier zijn één bug in andere kleren. Fuzzy matching kan een gerecht niet van een persoon onderscheiden, of een winkel van een persoon, want op tekenniveau lijken ravioli en Ravindra echt op elkaar. Eis een langere prefix-match en je breekt ravi, precies het geval waarvoor de matcher bestaat.

Elke bewaker die je toevoegt brengt twee nieuwe formuleringen naar boven

Een regelparser faalt in één specifieke vorm: hij antwoordt zelfverzekerd en fout. Een leeg veld kost een gebruiker één tik. Een verkeerde verdeling kost vertrouwen in het grootboek, en in een app die het delen van geld bijhoudt is het grootboek het product. De vier rijen hierboven zijn geen bijna-missers, het zijn geldbugs.

De tredmolen is het echte argument, niet één enkel defect. Voeg een datumbewaker toe en het geval van het bestelnummer arriveert. Voeg een bewaker voor bestelnummers toe en platte getallen arriveren, dan hoeveelheden, dan tafelnummers. De lijst met bewakers groeit en convergeert nooit, want natuurlijke taal heeft geen eindige set formuleringen om op te sommen.

Voor en na: een groeiende stapel bewakers, vervangen door één weigeringsregel VOOR: REGELPARSER (VERWIJDERD) dinner 12-08 400 bedrag-regex datumbewaker bestelnummerbewaker bijnaam-matcher uitsluitingslexicon leest €12, en boekt het Elke oplossing bracht twee nieuwe formuleringen naar boven. NA: amount_only dinner 12-08 400 precies één ondubbelzinnige geldkandidaat? nee, drie getallen bedrag blijft leeg ja, één bedrag teruggegeven in centen De trede zegt niets over personen, dus kan ze geen geld op de verkeerde persoon zetten.
De verwijderde parser beantwoordde elke zin. De trede die haar verving antwoordt met een getal of met niets.
De beslissing, gedateerd

Invoer in natuurlijke taal is een AI-functie, en niets in de Dimesum-repo matcht dat patroon. De beslissing viel op 2026-08-20, opgeschreven met de vier storingen, zodat niemand de bewakers per ongeluk opnieuw bouwt.

Wat live ging is één getal en een weigering

amount_only is de gedegradeerde trede uit ons AI-ontwerpdocument, letterlijk geïmplementeerd. Die trede luidt "het gewone formulier met client-side vooraf ingevulde bedrag-regex", dus de trede geeft een bedrag terug en niets anders: geen omschrijving, geen categorie, geen betalers, geen deelnemers, geen uitsluitingen. Het kost niets en belt niemand, en daarom draaien test en CI erop.

Ambiguïteit is een weigering, geen tiebreak

De hele regel leeft in één functie, extract_amount_minor. Een bedrag komt alleen terug wanneer de tekst er precies één kandidaat voor bevat, dus order 90210 dinner 400 en flat 402 rent 15000 geven leeg terug in plaats van een winnaar te kiezen. Een van een valutateken voorzien bedrag telt als ondubbelzinnig, zelfs naast kale getallen, en daarom leest split 3 ways ₹1,200 nog steeds ₹1,200.

Een bedrag met een minteken is helemaal geen bedrag in plaats van de absolute waarde ervan. -500, minus 200 en de (500) van de boekhouder komen allemaal leeg terug, want het veld is een last en de cijfers houden terwijl je het teken laat vallen wijst het geld de andere kant op dan de tekst. Haakjes tellen alleen wanneer ze op het bedrag zelf sluiten, dus (500 each) blijft een tussenzin.

Hoe amount_only kiest tussen één bedrag en geen antwoord verzamel elk bedrag dat geld zou kunnen zijn geen gevonden, of één van hen met een minteken? nee precies één met valutateken bedrag, zoals ₹1,200 of 500/-? nee helemaal geen tekens, en precies één kaal getal? ja amount_minor: gehele minor units, via de ISO 4217-exponent ja nee geen bedrag het veld toont leeg ja
Drie vragen, waarvan twee eindigen in een leeg veld. Kiezen tussen twee plausibele bedragen leverde het diner van €12 op.

De valuta bepaalt de rekenkunde

Minor units zijn de enige vorm die geld in Dimesum aanneemt, dus de trede converteert met een ISO 4217-exponententabel in plaats van een hardgecodeerde vermenigvuldiging met 100. De Japanse yen heeft helemaal geen subeenheid, en ×100 blaast een bon van ¥1,200 honderd keer op. Een bedrag fijner dan de kleinste eenheid van de valuta wordt geweigerd in plaats van afgerond, want het afronden van een bedrag dat iemand heeft getypt is er een verzinnen.

Indiase getalwoorden horen bij het schrijven van een bedrag, niet bij het begrijpen van een zin. 1.2k, 2 lakh en 500/- lossen allemaal op, net als 1,200. Alles boven het maximumbedrag van het grootboek komt leeg terug, dus een verkeerd getypt bedrag maakt één veld leeg in plaats van verderop een integer te laten overlopen.

Wat elke parse-trede mag beweren, per 29 augustus 2026.
VeldRegelparser (verwijderd)amount_only (live)Modeltrede (bedraad, zonder sleutel)
BedragGeraden uit meerdere getallenEén ondubbelzinnig bedrag, anders leegGelezen in context
Omschrijving, categorieLexiconmatchAltijd nullUit de zin gehaald
Deelnemers, uitsluitingenFuzzy naam-matchingAltijd leegHerleid tot echte lid-id's
BetalerAfgeleid uit de formuleringAltijd leegGenoemd, met een nulbaar bedrag
Algehele betrouwbaarheidPer veld afgestemdVast op 0.3Per parse
Gerapporteerde promptBestond nietNull, geen prompt gelezenPrompt-id en versie

De live trede haalt de 0.6-drempel voor bruikbaarheid nooit

Ons parse-contract laat een parse onder 0.6 algehele betrouwbaarheid vallen en stuurt de gebruiker naar het gewone formulier. amount_only rapporteert 0.3 op elk antwoord, en de constante is structureel in plaats van afgestemd. Een op zichzelf staand bedrag is geen parse, dus de trede zit op de helft van de drempel, wat ze ook vond. Eén constante voor elk antwoord houdt ze daar: een score per geval is een score die iemand uiteindelijk omhoog duwt.

De trede rapporteert ook helemaal geen prompt. Zowel prompt_id als prompt_version komen null terug, want de trede las geen prompt. Er een noemen zou elk evaluatieresultaat toeschrijven aan een promptversie die de trede nooit zag, en het evaluatieharnas is het enige instrument dat een trede mag promoveren tot suggestie met één tik, bij 95% precisie op bedrag en deelnemers samen.

Nog twee treden zijn gedeclareerd en geen van beide is live. De cheap-fast-trede heeft een Groq-adapter voor openai/gpt-oss-120b en geen sleutel; de midtrede heeft geen adapter. Een van beide selecteren faalt bij het opstarten in plaats van bij het eerste verzoek van een gebruiker, want een LLM rekent per aanroep en een factureerbare afhankelijkheid moet gesloten falen.

Niets boekt automatisch, dus een leeg veld kost één tik

Een leeg veld kost zo weinig alleen omdat geen enkele vastlegging in Dimesum geld kan wegschrijven. Een vastlegging maakt een suggestie, een persoon bevestigt die, en de bevestiging is wat de onkost aanmaakt. Briefbeslissing D5 stelt de regel, en .go-arch-lint.yml handhaaft die: de ingestiecontext krijgt geen enkele afhankelijkheid van expense of ledger, dus een vastlegging kan zelfs per ongeluk geen journaalpost boeken. CI laat de import falen, wat we controleerden door er één toe te voegen.

De vastlegging bewaart de ruwe tekst wat de parser ook doet, en noemt welke velden onopgelost zijn. De client markeert die lege velden in plaats van een verzonnen concept te tonen, en dat is het verschil tussen een parser die niets zegt en een die raadt. Bevestigen leidt zijn onkost-id af uit de suggestie-id, dus een dubbele tik speelt opnieuw af in plaats van twee keer te belasten.

De regel die het stelen waard is

Tel je bewakers, niet je bugs. Een lijst met bewakers die elke week groeit vertelt je dat het werk begrip is, en begrip hoort bij een model. Onze volgende stap is de gouden set in contracts/parse_expense/eval/ tegen een echte modeltrede draaien, want niets hier wordt een suggestie met één tik zonder dat oordeel.

Veelgestelde vragen

Waarom heeft Dimesum zijn onkostenparser op basis van regels verwijderd?

Dimesum verwijderde hem omdat vier gewone zinnen geldbugs opleverden en elke toegevoegde bewaker er twee nieuwe formuleringen bij bracht. dinner 12-08 400 werd gelezen als €12, ravioli 600 voegde een lid met de naam Ravindra toe, kirana 500 belastte een lid met de naam Kiran, en refund -483.50 werd een last van €483,50. Een zin begrijpen is het werk van het model.

Wat geeft de amount_only-trede eigenlijk terug?

De amount_only-trede geeft één getal terug en niets anders. Ze antwoordt alleen met een bedrag wanneer de tekst precies één ondubbelzinnige geldkandidaat bevat, en noemt nooit een deelnemer, een betaler, een omschrijving of een categorie. Twee kandidaten betekent helemaal geen bedrag. Al het overige in het parse-contract wacht op een modeltrede.

Waarom rapporteert amount_only 0.3 betrouwbaarheid in plaats van een echte score?

De 0.3 is structureel, niet afgestemd. Ons parse-contract laat een parse onder 0.6 vallen en stuurt de gebruiker naar het gewone formulier, en een los bedrag is geen parse, dus de trede zit op de helft van die drempel, wat ze ook vond. Eén vaste constante voor elk antwoord voorkomt dat een score per geval later omhoog wordt geduwd.

Kan een vastlegging in natuurlijke taal zonder mens naar het grootboek schrijven?

Nee. Een vastlegging maakt een suggestie en een persoon bevestigt die, volgens Briefbeslissing D5. De regel wordt gehandhaafd in .go-arch-lint.yml, die de ingestiecontext elke afhankelijkheid van expense of ledger ontzegt, dus CI laat de import falen als een vastlegging ooit naar een journaalpost grijpt. Bevestigen is wat de onkost aanmaakt.

Wat gebeurt er met het parsen van onkosten in natuurlijke taal als er geen modeltrede beschikbaar is?

Dimesum degradeert naar amount_only en toont lege velden. De cheap-fast-trede is bedraad naar Groq's openai/gpt-oss-120b en wordt geleverd zonder sleutel, en de midtrede heeft geen adapter, dus een van beide selecteren faalt bij het opstarten in plaats van bij het eerste verzoek van een gebruiker. De vastlegging bewaart de ruwe tekst hoe dan ook.