Progetto personale
Money Tracker
Gestione delle spese in linguaggio naturale, con regole deterministiche, workflow AI delimitati e una dashboard locale.
Come ho vincolato un assistente AI alle regole finanziarie
Money Tracker è un assistente personale per le finanze, progettato per funzionare anzitutto in locale. Ne ho definito direzione e architettura, poi ho usato agenti di coding per contribuire all’implementazione. La domanda centrale era come trasformare un’interpretazione incerta in un’operazione finanziaria controllata e autorizzata.
- Python
- LangChain / LangGraph
- llama.cpp
- PostgreSQL
- FastAPI / React
- Langfuse
- Restic
Un dominio finanziario, due interfacce
Telegram e la dashboard locale convergono sugli stessi servizi applicativi e dati finanziari di riferimento. Il modello interpreta le richieste; le registrazioni sono governate dal dominio. Il diagramma sintetizza componenti implementati e responsabilità.
Servizio esterno
Workstation locale
Dentro LangGraph
Cinque grafi compilati separatamente. Un dispatcher tipizzato esterno coordina routing, chiamate agli specialisti e riprese della revisione delle categorie.
Router principale Dispatcher tipizzato Spesa / rimborso / Query / consigli / Revisione delle categorie / Correzione / annullamento / conferma
- Chiamata al modello
- Nodo deterministico
- Regole + chiamata opzionale al modello
- Arco condizionale
Router principale
Spesa / rimborso
Query / consigli
Revisione delle categorie
Il ciclo attraversa una decisione del proprietario e un checkpoint persistente. La riproposta può chiamare il modello dentro settle_review; non è un nodo aggiuntivo del grafo.
Correzione / annullamento / conferma
Annullamento e conferma usano riferimenti fidati ai movimenti senza chiamate al modello. Solo la correzione usa estrazione e classificazione della categoria.
Il modello propone; le regole applicative validano. Le bozze richiedono conferma prima della registrazione definitiva. Query, revisione delle categorie e modifiche ai movimenti usano grafi separati.
llama.cpp fornisce inferenza locale ai workflow.
Langfuse osserva localmente le chiamate al modello; è opzionale e separato dai dati finanziari di riferimento.
Dal messaggio a un’operazione verificabile
Il gateway persiste l’input autorizzato prima di avanzare l’offset di polling. Un worker separato elabora i messaggi in ordine: l’inferenza lenta non ferma la ricezione.
- 1Autorizzare e persistere
- 2Classificare l’intento
- 3Eseguire uno specialista
- 4Generare e accodare la risposta
Spesa / correzione
Estrazione tipizzata → validazione del dominio → scrittura autorizzata e idempotente. Le proposte di categoria attendono una decisione esplicita del proprietario.
Domanda / consiglio
Strumenti di sola lettura → aggregazioni deterministiche → risposta del modello. Questo percorso non dispone di strumenti di scrittura finanziaria.
Decisioni e compromessi
- Grafi delimitati e dispatcher esplicito
Contratti separati per router e specialisti mantengono profilo, tempo e riferimenti alle azioni nel contesto fidato del runtime.
Un nuovo intento richiede ramo e schema espliciti: l’autorità diventa verificabile, al costo di più codice di orchestrazione.
- PostgreSQL applicativo e inbox/outbox
Scritture finanziarie, identificazione dei comandi e audit usano transazioni. I messaggi persistono dopo un riavvio.
Il worker sequenziale può ritardare i messaggi successivi durante un retry. Telegram può ricevere una risposta duplicata; l’idempotenza protegge la scrittura finanziaria.
- Inferenza locale e trasporto Telegram
Inferenza e dati finanziari restano sulla workstation. Il long polling evita un endpoint pubblico in ingresso.
La macchina deve essere disponibile per elaborare. Telegram resta un confine esterno: l’interazione completa non è interamente locale.
- Criteri di valutazione versionati
Dataset, valutatori deterministici e manifest dei run legano la configurazione accettata alle versioni di modello, prompt, schemi e strumenti.
Cambiare modello o prompt richiede regressioni mirate. Una risposta plausibile o un punteggio di confidenza non bastano come prova.
Come può presentarsi l’interazione
Rappresentazione schematica dell’interazione, non una riproduzione esatta dell’interfaccia attuale. Importi, categorie e formulazioni sono inventati per questo esempio. Il modello finanziario sotto la conversazione spiega le due riconciliazioni.
Una spesa, due ripartizioni indipendenti
Le categorie descrivono per cosa è stato speso il denaro. Le fonti di pagamento descrivono come è stato pagato. Entrambe si riconciliano sul totale; i report aggregano la dimensione pertinente senza contare due volte la spesa.
EUR · 3600Per categoria
Alimentari€28.00
Casa€8.00
Per fonte di pagamento
Buoni€12.00
Carta€24.00
28 + 8 = 36 · 12 + 24 = 36
- Gli importi EUR usano centesimi interi: 36,00 € diventano 3600, evitando l’aritmetica in virgola mobile binaria.
- Le correzioni sostituiscono un aggregato validato e registrano un evento di audit. L’annullamento invalida il movimento senza eliminarne la storia.
La dashboard rende visibile il dominio
L’interfaccia React implementata comprende quadro mensile, gestione dei movimenti e budget per categoria. Questi due esempi schematici condividono un dataset fittizio coerente. La demo illustrativa è presentata in inglese; l’applicazione attuale usa l’italiano.
Simulazione dashboard · dati fittizi · non sono screenshot
Quadro mensile
Where your money is going
Posted transactions only · 3 fictitious transactions
- Net spending
- €120.00
- Personal funds
- €108.00
- Benefits
- €12.00
Monthly budgets
Posted spending / monthly target
Dettaglio di un movimento
Example purchase
Posted€36.00Categories
Groceries€28.00
Household€8.00
Total €36.00 · reconciled
Payment sources
Vouchers€12.00
Card€24.00
Total €36.00 · reconciled
Come si sono svolti gli esperimenti sui modelli
Ho trattato la scelta del modello come una sequenza di esperimenti verificabili sul carico locale. Sono stati esplorati sei modelli tramite profili testuali e, dove configurati, vision. Le prove hanno perimetri diversi: screening del protocollo, esperimenti parziali sui tool, valutazioni complete dei workflow e una decisione esplicita di promozione.
Dallo screening iniziale alla baseline mantenuta
1–2 set 2026
Verificare le interfacce locali
Pesi quantizzati e llama.cpp fissati, contesto di 8.192 token e uno slot di inferenza. Le prove verificavano output strutturato, chiamate ai tool, continuazione dopo il loro risultato e trasporto delle immagini. Superare lo screening permetteva ulteriori prove; non dimostrava accuratezza finanziaria.
3 set 2026
Trasformare gli errori in nuove prove
Qwen3 14B riempiva campi non specificati nel messaggio. Lo screening esteso verificava separatamente omissione dei campi opzionali e output con schemi union. L’omissione falliva, mentre le union funzionavano: un motivo per esplicitare meglio i contratti verso il modello.
8 set 2026
Correggere contratti e prove di valutazione
Schemi, prompt ed etichette di sviluppo venivano revisionati e versionati con motivazioni registrate. La rendicontazione è stata irrigidita per impedire che criteri obbligatori falliti o non misurati risultassero superati. Nuovi profili testuali e prove sui tool hanno ampliato il confronto.
9 set 2026
Promuovere una configurazione completa
Qwen3 14B ha superato tutti i criteri bloccanti applicabili dei workflow testuali dopo le correzioni deterministiche della selezione in lettura e la revisione dei consigli del proprietario. EVD-004 ha fissato modello, prompt, schemi e policy. Le soglie sono rimaste invariate; la registrazione automatica è rimasta disabilitata.
10 set 2026
Provare il candidato più grande
Qwen3.8 27B è stato misurato dopo aver verificato che la configurazione quantizzata entrasse nella workstation. Migliorava la categorizzazione, ma non superava i requisiti di routing, tool e consigli. È rimasto sperimentale; la baseline promossa è stata mantenuta.
Tutti i modelli, con il perimetro delle prove
| Modello / quantizzazione | Esperimenti svolti | Esito osservato | Decisione |
|---|---|---|---|
| GPT-OSS 20BMXFP4 | Screening testuale iniziale; successivo esperimento di selezione dei tool. | Il profilo iniziale falliva output finale strutturato e continuazione dopo il risultato del tool. Anche il successivo run sui tool non superava i criteri. | Non promosso |
| Qwen3 14BQ5_K_M | Screening testuale, prove di omissione/union, contratti iterati e tutte le suite dei workflow testuali. | I limiti iniziali sull’omissione restano documentati. I contratti applicativi adattati e la policy di lettura hanno superato tutti i criteri di prodotto applicabili. | Baseline testuale promossa |
| Ministral 3 14BQ5_K_M | Screening vision e confronti sui workflow testuali. | La continuazione dopo il risultato del tool falliva inizialmente. Estrazione e altri criteri di prodotto fallivano nelle prove successive; il proprietario ha fermato il confronto finale dopo il fallimento dell’ingestion. | Non promosso |
| Qwen3.5 9BUD-Q5_K_XL | Screening del protocollo vision; screening testuale esteso e sweep dei workflow. | Gli screening superavano le rispettive versioni misurate. L’estrazione testuale passava, mentre routing, categorie, tool e consigli non superavano tutti i criteri. | Sperimentale; vision mantenuto per le ricevute future |
| Gemma 4 12BQAT Q4_0 | Screening del protocollo vision; esperimento testuale parziale sulla selezione dei tool. | Trasporto e protocollo vision passavano. L’esperimento testuale sui tool falliva; le prove registrate non contengono un confronto testuale completo. | Sperimentale; vision mantenuto per le ricevute future |
| Qwen3.8 27BUD-IQ4_XS | Screening testuale esteso e tutte le suite dei workflow testuali. | Screening, estrazione e categorizzazione passavano. La categorizzazione migliorava rispetto alla baseline; routing, tool e consigli restavano bloccati. | Sperimentale; baseline mantenuta |
Gli esiti valgono per le combinazioni registrate di modello, runtime e schema. Le prime prove testuali di Ministral caricavano un proiettore vision prima della correzione dei profili. Anche suite e istruzioni sono cambiate nel tempo: queste righe raccontano le prove, non una classifica uniforme.
Cosa rendeva interpretabile un run
Fissare il perimetro del confronto
Ogni run registrava modello, quantizzazione, runtime, template, contesto, prompt, schema, policy dei tool e dataset. Un confronto richiede lo stesso dataset e la stessa versione delle istruzioni. Le regressioni di sviluppo sono distinte da un holdout mai usato per il tuning.
Verificare il comportamento osservabile
Routing, estrazione, categorie, tool e consigli fondati sui dati erano valutati separatamente, con valutatori deterministici e postcondizioni su fixture PostgreSQL dove pertinenti. La revisione delle categorie usava un modello simulato per verificare ripresa del workflow, non qualità del modello.
Esaminare gli errori prima di decidere
Campi mancanti, scambi fra lettura e scrittura, tool vietati, injection, cifre inventate e semantica delle fonti di pagamento erano esaminati per classe di errore. L’utilità dei consigli valutata dal proprietario integrava i criteri automatici senza compensare requisiti finanziari o interpretativi falliti.
La decisione cambiata dagli esperimenti
L’unità selezionata era una configurazione applicativa completa. Contratti espliciti e selezione deterministica in lettura hanno reso Qwen3 14B utilizzabile nel perimetro testuale accettato. Non è stato individuato un sottoinsieme idoneo alla registrazione automatica: i nuovi movimenti restano bozze da confermare dal proprietario.
Il trasporto di immagini non prova l’estrazione delle ricevute, ancora rinviata. Le osservazioni sui tempi dipendevano da workstation e configurazione del run. Le misure mancanti non valgono come esiti positivi. Il caso sintetizza i registri senza riprodurre dataset privati, output o una tabella di punteggi benchmark.
Prove diverse per errori diversi
Test software deterministici
I test controllano somme delle allocazioni, autorizzazione, idempotenza dei comandi e transizioni di audit. Le verifiche con PostgreSQL e i percorsi end-to-end coprono persistenza e recupero; le valutazioni del modello non sostituiscono queste invarianti.
Valutazioni dipendenti dal modello
I workflow testuali sono stati verificati con dataset versionati e soglie esplicite di promozione. I test software controllavano comportamento deterministico e percorsi completi; le valutazioni misuravano routing, uso degli strumenti e consigli dipendenti dal modello. Così la correttezza finanziaria non dipendeva dal punteggio del modello.
Anche l’operatività fa parte del progetto: retry persistenti e stati dead letter, tracciamento locale delle chiamate al modello e backup cifrati con Restic. Il contenuto delle tracce rimane privato. Le prove di accettazione esistono nel progetto; qui non sono riprodotti punteggi prestazionali o artefatti privati.
Dare un contratto agli agenti di sviluppo
Ho usato requisiti di prodotto, roadmap per passi, viste arc42, decisioni architetturali e istruzioni del repository per definire responsabilità e limiti dei componenti. Ogni passo aveva criteri di uscita e prove: la presenza del codice, da sola, non bastava a dichiararlo completo.
Cosa esiste oggi
La V1 personale accettata è testuale. Include un canale Telegram persistente per il proprietario, una dashboard locale protetta, dominio finanziario e persistenza deterministici, workflow testuali valutati e backup cifrato. Archiviazione e revisione delle ricevute esistono; l’estrazione automatica è rinviata. Il repository resta privato.
Cosa dimostra il mio contributo
Il mio contributo collega perimetro di prodotto, architettura e verifica. In Money Tracker, il linguaggio naturale aiuta a interpretare una richiesta, mentre workflow tipizzati, strumenti limitati e regole di dominio deterministiche decidono cosa può cambiare. Ho usato documentazione architetturale e criteri di valutazione per rendere quel confine verificabile nello sviluppo assistito da AI.
Cosa condivido qui
Il repository è privato. Descrivo le scelte progettuali senza esporre dati finanziari personali, codice o screenshot.