Automatyzacja faktur krok po kroku (OCR + AI): jak zbudowaliśmy własny system na Claude Code

Automatyzacja faktur krok po kroku: OCR i AI, system MTZN

Jest taki rytuał, który zna każdy przedsiębiorca. Zbliża się termin wysyłki dokumentów do księgowej, a Ty otwierasz skrzynkę i zaczynasz archeologię. Faktura od Google gdzieś była, przecież ją widziałeś. Ta od Stripe przyszła chyba na drugi adres. Twilio wysłało coś w załączniku, ElevenLabs dało tylko link, a połowa "faktur" okazuje się paragonami, potwierdzeniami i newsletterami, które mają słowo VAT w stopce. Po dwóch godzinach masz otwarte czternaście kart, trzy pobrane duplikaty i cichą pewność, że czegoś i tak brakuje.

U nas ten rytuał pochłaniał co miesiąc kilka godzin i regularnie kończył się mailem od księgowej z listą braków. W końcu pękliśmy. Postanowiliśmy problem zautomatyzować, ale nie gotowym SaaS-em, tylko własnym narzędziem zbudowanym na Claude Code, czyli agencie AI działającym z linii poleceń. To jest opowieść o tym wdrożeniu: z błędami, ślepymi uliczkami, gotowym promptem do skopiowania i paczką narzędzi do pobrania na końcu.

Najpierw mapa terenu

Zanim napisaliśmy pierwszą linijkę kodu, spisaliśmy, skąd w ogóle przychodzą do nas dokumenty. I to było pierwsze otrzeźwienie. Faktury nie mieszkają w jednym miejscu: większość przychodzi na skrzynkę firmową w Google Workspace (głównie przez Stripe), ale spora część historycznie trafiała na prywatnego Gmaila, bo ktoś kiedyś założył subskrypcję "na chwilę". Do tego dochodzą faktury w załącznikach PDF, faktury ukryte za linkiem "kliknij i pobierz", portale dostawców, z których dokument trzeba wynieść własnymi rękami, i wyciągi bankowe, które też chcemy mieć w komplecie, bo księgowa pyta o nie równie często.

Stąd pierwsza lekcja, którą oddajemy za darmo: automatyzacja faktur to nie jest "podłącz OCR do skrzynki". To system, który musi ogarnąć kilka źródeł, kilka formatów i całe morze szumu. Kto tego nie zaplanuje na starcie, będzie dobudowywał na kolanie później. Wiemy, bo dobudowywaliśmy.

Jak to w końcu działa

Schemat systemu automatyzacji faktur: dwie skrzynki, pre-filtr, dwuetapowa klasyfikacja AI, Dysk i rejestr

Sercem systemu są dwa przebiegi sztucznej inteligencji, ustawione jak sito o dwóch gęstościach. Najpierw tani i szybki model dostaje sam tekst maila i odpowiada na jedno pytanie: czy to w ogóle sprawa księgowa? Newslettery, powiadomienia i marketing odpadają już tutaj, zanim ktokolwiek zapłaci za czytanie PDF-ów. Dopiero to, co przeszło, trafia do mocniejszego modelu, który czyta wyciągnięty z PDF-a tekst i zwraca konkret: typ dokumentu, sprzedawcę, nabywcę, numer, kwoty, rok i miesiąc.

Dalej dzieje się już zwykła, nudna informatyka. Plik ląduje na dysku współdzielonym w folderze rok/miesiąc, a do arkusza-rejestru dopisuje się wiersz: jeden dokument, jeden wiersz. Nuda jest tu komplementem. Na nudzie można polegać.

Dlaczego akurat Claude Code, a nie gotowa wtyczka? Z trzech powodów, które odkrywaliśmy po kolei. Po pierwsze, reguły w stylu "jak w mailu jest słowo faktura, to jest faktura" umierają przy pierwszym paragonie ze Stripe. Model językowy rozumie kontekst: odróżni fakturę od paragonu, przypisze dokument do miesiąca po dacie sprzedaży, a nie dacie maila, i pozna po treści, że wyciąg "za okres 1-31 maja" należy do maja, choć przyszedł w czerwcu. Po drugie, OCR dostaliśmy w standardzie: skan bez warstwy tekstowej agent po prostu czyta wizyjnie. Po trzecie, mieliśmy dwie skrzynki o zupełnie różnych interfejsach, Gmail API po stronie firmowej i IMAP po prywatnej. Napisaliśmy dwa cienkie adaptery o identycznym interfejsie i reszta systemu do dziś nie wie, skąd przyszedł mail. I nie musi wiedzieć.

Perypetie, czyli miesiące dopieszczania

Wersja pierwsza powstała w jeden wieczór i klasyfikowała wszystko jak leci. Byliśmy zachwyceni przez mniej więcej dobę. Potem zaczęła się prawdziwa robota, rozłożona na miesiące krótkich iteracji, z których każda zostawiała ślad w systemie.

Najpierw okazało się, że przepuszczanie każdego maila przez AI jest wolne i drogie. Tak powstał pre-filtr: okno dat plus około 57 słów kluczowych po polsku i angielsku, plus lista realnych nadawców billingowych, od Stripe po Hetznera. Ta lista rosła z każdym miesiącem, bo każdy dostawca ma swój dialekt. Potem Stripe zaskoczył nas mailem, w którym była i faktura, i paragon do tej samej płatności; rejestr zaczął puchnąć od duplikatów, więc faktura dostała bezwzględny priorytet nad paragonem. Następnie banki i kurierzy nauczyli nas, że "załącznik" to pojęcie względne: potrafią wrzucić do jednego maila kilkanaście ikonek i logotypów, które system próbował czytać jak dokumenty. Dziś odsiewamy je po rozmiarze pliku, zanim ktokolwiek je otworzy.

Był też odcinek z duplikatami, który nauczył nas pokory. Ten sam dokument potrafi przyjść na obie skrzynki naraz. Plik na dysku łatwo zdedupować po nazwie i numerze faktury, ale wiersze w rejestrze celowo zostawiamy oba, z adnotacją "możliwy duplikat, oryginał w wierszu N". Chcemy widzieć, że coś przyszło dwoma kanałami, zamiast udawać, że przyszło raz.

I wreszcie rzecz, z której jesteśmy dziwnie dumni: system umie powiedzieć "nie wiem". Faktura dostępna tylko za linkiem? Wielki skan, którego nie warto OCR-ować w ciemno? Zamiast zgadywać, do rejestru trafia jasny status i krótka lista do ręcznego domknięcia. Automatyzacja, która zna swoje granice, jest warta więcej niż taka, która udaje wszechmoc.

Pamięć systemu, czyli dlaczego z czasem jest tylko lepiej

Z całego wdrożenia najważniejsza jest jedna obserwacja: wartość nie siedzi w modelu AI, tylko w utrwalonej wiedzy wokół niego. Każdy miesiąc dokładał cegiełki. Nowy nadawca do filtra. Nowa reguła klasyfikacji. Nowy status brzegowy. Nowa procedura w runbooku. Model można jutro wymienić na inny; tej pamięci wymienić się nie da, bo to ona jest wdrożeniem.

Wykres poglądowy: spadek udziału dokumentów wymagających ręcznej poprawki z 38 do 4 procent w 6 miesięcy

Wykres jest poglądowy: ilustruje dynamikę naszego wdrożenia, nie laboratoryjny pomiar. Na początku ręcznie poprawialiśmy sporą część klasyfikacji: złe miesiące, paragony udające faktury, pominięci nadawcy. Z każdą iteracją odsetek malał, aż został twardy rdzeń dokumentów, których w mailu po prostu nie ma.

Mechanizm jest banalnie prosty i to jest w nim najpiękniejsze. Błąd pojawia się raz, zostaje opisany jako reguła i nigdy nie wraca. Po roku takiej akumulacji uruchomienie agenta to jedno polecenie, a jego "doświadczenie" to setki utrwalonych decyzji, których nikt nie musi podejmować ponownie.

Pętla doskonalenia: błąd klasyfikacji staje się trwałą regułą systemu

Wyciągi bankowe domykają obieg

W pewnym momencie dołożyliśmy do systemu klasę dokumentu "wyciąg". Wyciągi są rozpoznawane automatycznie i katalogowane do miesiąca, którego dotyczy okres wyciągu, więc w folderze każdego miesiąca leżą obok siebie faktury i zestawienie z rachunku. A skoro jedno i drugie jest już w jednym miejscu, zbudowaliśmy na tych klockach kolejny moduł: weryfikator kompletności.

Agent czyta transakcje z wyciągu i najpierw je kategoryzuje, bo ZUS, podatki i opłaty bankowe faktury z definicji nie mają i nie powinny nikogo straszyć na liście braków. Resztę dopasowuje do faktur z rejestru: punktuje zgodność kwoty i waluty, bliskość dat, nazwę kontrahenta i numer faktury w tytule przelewu. A kiedy do jednej transakcji pasuje kilka dokumentów albo kwoty nie zgadzają się wprost, bo faktura jest w dolarach, a karta pobrała złotówki po przewalutowaniu, spór rozstrzyga zagnieżdżony, tani model AI. Dostaje transakcję i kandydatów, oddaje wybór z uzasadnieniem i oceną pewności. Na końcu powstaje zestawienie: co ma fakturę, co jej nie ma (to jest właściwa lista braków dla księgowej), co faktury nie wymaga i które faktury nie mają swojej transakcji, bo zapłacono je z innego rachunku. Zamiast pytania "czy mam wszystko?" dostajesz listę konkretów z kwotami. To dokładnie ten moment, w którym księgowa zaczyna wierzyć w AI.

A co z fakturami, których nie ma w mailu?

Zawsze zostanie grupa dostawców, którzy faktur nie wysyłają, tylko trzymają je w portalu. Tu kolejność ataku jest prosta. Jeśli portal ma API, używamy API, bo to droga stabilna i bezobsługowa. Jeśli API nie ma, zostaje automatyzacja przeglądarkowa: Playwright do powtarzalnych skryptów albo agent AI z dostępem do przeglądarki tam, gdzie logowanie i nawigacja bywają kapryśne. Z dwiema uwagami z życia: automatyzujcie wyłącznie własne konta i sprawdźcie regulamin portalu, a do pól z hasłami i płatnościami niech siada człowiek. To, czego nie da się pobrać żadną z tych dróg, system przynajmniej wykrywa i wpisuje do rejestru jako pozycję do ręcznego pobrania. Krótka lista zamiast archeologii to już zupełnie inna jakość życia.

Ten sam wzorzec działa zresztą dalej: źródłem nie musi być skrzynka. Dropbox, Google Drive, OneDrive, kanał na Slacku, na który ktoś wrzuca skan "faktury z delegacji". Schemat się nie zmienia: źródło, pobranie pliku, klasyfikacja, katalog i rejestr. Im więcej strumieni wpada do jednego rejestru, tym mniej dokumentów kończy żywot w folderze "Pobrane" na czyimś laptopie. A gdy skrypty przestają wystarczać, bo obiegowi dokumentów potrzebny jest panel, uprawnienia i historia zmian, naturalnym kolejnym krokiem jest dedykowana aplikacja spinająca wszystkie kanały w jedno.

Prompt, od którego można zacząć

Nie musisz wierzyć nam na słowo, że klasyfikacja działa. Poniżej uproszczona wersja promptu z naszego drugiego przebiegu. Wklej do dowolnego agenta AI, który umie czytać PDF-y, podmień nazwę firmy i patrz, co się dzieje:


prompt-klasyfikacja.txt

Jesteś asystentem księgowym. Dostajesz tekst dokumentu wyciągnięty z pliku PDF.
Przeanalizuj go i zwróć WYŁĄCZNIE poprawny JSON, bez komentarzy:

{
  "typ": "faktura" | "paragon" | "wyciag" | "inne",
  "faktura_vat": true/false,
  "sprzedawca": "nazwa wystawcy lub null",
  "nabywca": "nazwa odbiorcy lub null",
  "numer_faktury": "numer dokumentu lub null",
  "kwota_brutto": liczba lub null,
  "waluta": "PLN/EUR/USD lub null",
  "rok": RRRR,
  "miesiac": MM,
  "kierunek": "koszt" | "sprzedaz_wlasna" | "nieznany"
}

Zasady:
- rok i miesiąc ustal z DATY SPRZEDAŻY, potem z daty wystawienia; ignoruj datę maila.
- dla wyciągu bankowego miesiąc = KONIEC okresu ("za okres 1-31 maja" to 05),
  a kierunek ZAWSZE "nieznany" (wyciąg to nie koszt ani sprzedaż).
- jeśli sprzedawca zawiera "TWOJA_FIRMA", kierunek "sprzedaz_wlasna";
  jeśli nabywca zawiera "TWOJA_FIRMA", kierunek "koszt".
- paragon i potwierdzenie płatności to NIE faktura; przy wątpliwości typ "inne".
- nie zgaduj numerów ani kwot: brak danych = null.

Dwie rady na drogę: każcie modelowi zwracać czysty JSON i walidujcie go po swojej stronie, a spory "faktura czy paragon" rozstrzygajcie dodatkowo po nazwie pliku, bo Invoice-* i Receipt-* bywają szczersze niż treść dokumentu.

Zanim wystartujesz u siebie, przemyśl jeszcze cztery rzeczy, o które i tak byś się potknął. Prywatność: klasyfikacja oznacza wysyłanie treści maili do modelu AI, a przy skrzynce prywatnej to prywatna korespondencja, więc podejmij tę decyzję świadomie. Dostępy: najwygodniej pracuje się z kontem serwisowym i delegacją domenową, które czyta skrzynkę i pisze na dysk bez logowania człowieka. Koszty: agent na dużym miesiącu potrafi zjeść zaskakująco dużo tokenów, więc przetwarzaj małymi oknami, tydzień zamiast miesiąca. I idempotencja: każdy przebieg musi dać się bezpiecznie powtórzyć, bo pady się zdarzają, a dedup po numerze faktury i identyfikatorze maila sprawia, że wznowienie niczego nie dubluje.

Zabierz nasze narzędzia do domu

Zamiast opowiadać, po prostu dajemy kod. Spakowaliśmy prawdziwe narzędzia z naszego wdrożenia (usunęliśmy tylko dane firmy) w paczkę startową: pobieranie maili przez Gmail API i IMAP, dwuetapowa klasyfikacja, katalogowanie na Dysku, rejestr w Arkuszu i weryfikator wyciągów. Całość jest opakowana w skill, czyli plik instrukcji dla dowolnego agenta AI. To celowo zalążek, nie produkt: przy pierwszym uruchomieniu agent ma obowiązek przepytać Cię, skąd pobierać dokumenty, jakie typy Cię interesują, dokąd je składać i jakie masz dostępy, a dopiero potem dostosowuje narzędzia do Twojego układu i rusza z małym testem. Zaszyliśmy w nim też zasadę, od której wszystko zależy: każdy błąd ma prawo wystąpić raz, potem staje się regułą.

Paczka startowa do pobrania

Skill: automatyzacja faktur dla Twojego agenta AI

Kompletny pipeline z naszego wdrożenia: skrzynki, klasyfikacja, rejestr, weryfikator wyciągów. Wgraj do folderu, uruchom agenta, resztę ustalicie między sobą.

Pobierz paczkę (ZIP, 38 KB)
Python + Claude Code CLI · instrukcja w środku

Rok później

Dziś zbieranie faktur wygląda u nas tak: agent odpalany jednym poleceniem przechodzi skrzynki, kataloguje dokumenty i aktualizuje rejestr, a do ręcznego domknięcia zostaje krótka lista pozycji z portali. Rytuał archeologii się skończył. Księgowa dostaje komplet, a mail z listą braków przychodzi coraz rzadziej, i to raczej z pytaniem, jak my to właściwie robimy.

Paczka startowa, którą pobrałeś wyżej, wystarczy na dobry początek. Ale jeśli Twoja firma potrzebuje czegoś więcej, projektujemy i wdrażamy agentów AI oraz automatyzacje procesów szyte na miarę: z głębszą integracją z systemami, w których naprawdę żyją Twoje dane (ERP, CRM, systemy księgowe, API bankowe, KSeF), z większą liczbą kanałów pozyskiwania dokumentów (portale dostawców, EDI, skrzynki zespołowe, SharePoint czy Dropbox) i z bardziej zaawansowanym przetwarzaniem: od OCR trudnych skanów, przez walidację i uzgadnianie danych, po raportowanie, które samo trafia na biurko zarządu. Budujemy takie obiegi od audytu procesu, przez wdrożenie, po utrzymanie i rozwój.

Napisz na hello@mtzn.pl, a pokażemy Ci na Twojej własnej skrzynce, ile faktur ucieka Ci co miesiąc. Spoiler: więcej, niż myślisz.