Automatyczne porównanie ofert z hurtowni cz. 3
Zestaw testów, którym pilnujemy odczytu ofert, w połowie składał się z dokumentów dostawcy, od którego nie dostaliśmy w tym roku ani jednej oferty.
W drugiej części artykułu opisaliśmy zestaw testów regresyjnych, który tworzymy na podstawie ofert dostawców sprawiających nam kłopot. Napisaliśmy tam, że jeden albo dwa takie pliki na firmę w zupełności wystarczają. Myliliśmy się. Rzeczywistość pokazała, że nasz zestaw testów nie pokrywał firm, od których dostajemy najwięcej ofert.
Wszystko zaczęło się od szukania sposobu na przyśpieszenie odczytu danych. Zgłosiła nam to pracownica działu logistyki, mówiąc, że odczyt oferty, który wcześniej trwał kilkanaście sekund, zaczął czasem zajmować kilka minut. Sprawdziliśmy to w logach z produkcji, na 780 udanych odczytach od kwietnia do sierpnia.
| miesiąc | odczytów | mediana | 90 % poniżej | najdłuższy | ponad minutę |
|---|---|---|---|---|---|
| kwiecień | 61 | 8,9 s | 26,0 s | 48,8 s | 0,0 % |
| maj | 174 | 8,9 s | 27,3 s | 112,4 s | 4,0 % |
| czerwiec | 183 | 8,9 s | 23,9 s | 188,5 s | 4,9 % |
| lipiec | 212 | 8,2 s | 22,3 s | 100,7 s | 3,3 % |
| sierpień | 150 | 10,1 s | 56,0 s | 254,5 s | 10,0 % |
Przez cztery miesiące odczyt zachowywał się stabilnie, jednak od sierpnia odczyty kilkuminutowe przestały być rzadkością. Mediana drgnęła o dwie sekundy, ale co dziesiąty odczyt trwa od tego czasu ponad minutę i to jest to, co użytkownicy zgłaszają jako „wolno”.
Powód znaliśmy: 31 lipca zmieniliśmy model, którym odczytujemy dokumenty, na Sonnet 5 firmy Anthropic z parametrem effort ustawionym na high, czyli pozwoliliśmy modelowi myśleć dłużej, zanim zwróci odpowiedź.
Zastanawialiśmy się, czy obniżenie effort do medium skróci ten czas przy zachowaniu oczekiwanej dokładności odczytu.
Niereprezentatywny zestaw testów
Żeby porównać działanie modelu z parametrem effort zmienionym na medium z high, stanęliśmy przed problemem mierzenia dokładności odczytu.
Mamy do tego zestaw testów opisany w drugiej części, tyle że liczył wtedy kilka dokumentów.
Blisko połowa z nich pochodziła od dostawcy, od którego przez cały rok wpłynęły do systemu dwa dokumenty.
W tym samym czasie dział logistyki wprowadził 1352 oferty od 122 kontrahentów.
Zestaw mierzył więc to, co kiedyś sprawiło nam kłopot, a nie to, co przez aplikację przechodzi dzisiaj.
W związku z tym naszą obawą stało się, że obniżenie parametru effort mogło popsuć odczyt u dostawcy, którego w zestawie w ogóle nie było, i nie mielibyśmy jak tego zobaczyć.
Claude Code z dostępem do środowiska produkcyjnego
System zamówień, o którym piszemy w tej serii, pracuje na platformie Azure razem z bazą danych i magazynem plików.
Claude Code dostał do nich osobne konto z uprawnieniem tylko do odczytu i narzędzie az w linii poleceń, przez które ma możliwość odczytu danych.
Uprawnienia do zapisu zostały przy koncie administracyjnym, do którego model dostępu nie ma.
Problemem w naszej konfiguracji było to, że pliki trzymane są poza bazą danych. Model językowy musiał więc połączyć dane pomiędzy kontenerem plików a naszą bazą danych po określonym identyfikatorze dokumentu. Tyle wystarczyło, żeby ustalić, którzy dostawcy naprawdę przysyłają oferty, ile ich jest i jak wyglądają ich dokumenty.
Kolejnym krokiem było policzenie ofert od każdego dostawcy oraz ułożenie listy dostawców według tej liczby. Wzięliśmy z niej pierwszą ósemkę, co dało nam od 313 do 37 ofert na dostawcę. Staraliśmy się przy tym, aby w obrębie jednego dostawcy do zbioru testowego trafiały dokumenty o różnych układach.
Jeden dzień pracy
Analiza pojedynczego dostawcy zajmowała modelowi z grubsza czterdzieści pięć minut, więc całość prac zamknęła się w jeden dzień. Większość tego czasu model pracował w tle, a my zajmowaliśmy się innymi zadaniami. Przeglądał oferty w bazie, dobierał do nich pliki, otwierał kolejne PDF-y i przepisywał z nich pozycje do testu. Do nas należała jedynie odpowiedź na pytanie, który z zaproponowanych dokumentów wchodzi do zestawu testowego.
Ręcznie ta sama praca wymagałaby od nas:
- przejrzenia ofert każdego dostawcy,
- odszukania plików,
- otwarcia kilkunastu PDF-ów,
- wybrania tych o różnych układach,
- przepisania pozycji i napisania testu.
Tydzień pracy dla człowieka wydaje nam się tu dość ostrożnym szacunkiem.
Dane produkcyjne i wzorzec do testu
Dane, które model przeglądał, nie były idealnie uporządkowane. Jest to jedna z naszych stałych obserwacji. Bardzo często zakłada się, że wystarczy pokazać modelowi, jak opisuje dane człowiek, nie biorąc przy tym pod uwagę, że człowiek też popełnia błędy. Około 20 % ofert nie miało pliku i te automatycznie odpadały z naszej analizy. Dodatkowo przy każdym z ośmiu wybranych dostawców trafił się dokument podpięty pod złego kontrahenta, w różnych wariantach:
- cudza oferta pod poprawnym dostawcą,
- poprawna oferta pod spółką o podobnej nazwie,
- dokument bez kontrahenta w ogóle.
Wygodnie byłoby wziąć wzorzec do testu prosto z bazy, bo pozycje tych ofert zostały już raz odczytane. To pułapka: są wynikiem pracy modelu, a nie treścią dokumentu. Pracownicy sprawdzają je z grubsza, ale nikt nie porównuje wiersz po wierszu, czy nazwy pozycji zgadzają się z ofertą. Wzorzec przepisujemy więc wyłącznie z pliku PDF.
Instrukcje pisane pod jeden dokument
Rozszerzony zestaw od razu pokazał błędy w instrukcjach dostawców. Cztery z ośmiu miały tę samą wadę - każda uogólniała format oferty na podstawie jedynego dokumentu, na którym powstała. „Producent to ostatni wyraz kolumny”, „ten szablon nigdy nie zawiera numeru oferty”, „dokument nie zawiera kodu dostawcy”, „druga linia to kod producenta” - każde z tych zdań jest prawdziwe dla pierwszego pliku i fałszywe dla pozostałych ofert tego samego dostawcy. Skutki widać wyraźnie na danych w bazie:
- u jednego dostawcy model wpisywał w kod dostawcy stan magazynowy z sąsiedniej kolumny,
- u innego zamieniał oba kody miejscami.
Te błędy odczytu nie miały wpływu na wybór dostawcy na poziomie firmy, bo ceny i ilości model wciąż odczytywał dobrze. Zostawały jednak w bazie, w polach z kodami, po których odnajdujemy potem ten sam produkt.
Stąd wyszły nam reguły pisania instrukcji.
- Opisujemy szablon, a nie jeden plik.
- Jeśli dostawca korzysta z kilku układów, opisujemy je wszystkie i podajemy, po czym je rozpoznać.
- Zdania bezwarunkowe piszemy w ostateczności oraz tylko o tym, co sprawdziliśmy na wszystkich obejrzanych plikach.
- Reguły opieramy na kształcie danych, a nie na położeniu kolumny. Kod produktu złożony z trzech liter i trzech cyfr da się rozpoznać także wtedy, gdy model pomyli kolumny.
- Piszemy wprost, czego dokument nie zawiera.
Ostatnia z reguł wygląda na zbędną, dopóki nie zobaczy się skutku jej braku. Kiedy szablon nie ma kolumny producenta ani kodu, model i tak znajdzie coś w nazwie produktu: u jednego dostawcy wyciął z niej wiodący indeks i wpisał go równocześnie w kod dostawcy i w kod producenta. Zdanie „ta kolumna nie istnieje, więc zostaw puste pole” jest równie potrzebne jak opis kolumn, które istnieją.
Czas odczytu a liczba pozycji
Na rozszerzonym zestawie danych pomiar w końcu miał sens.
Model językowy Sonnet 5 z effort na poziomie medium odczytał 27 ofert z 28 dokładnie tak samo jak wcześniej.
W tej jednej, odczytanej błędnie, model dokleił numer katalogowy na początek nazwy produktu.
Jedno i drugie było w tej samej komórce.
Dodatkowo było to w miejscu, gdzie tabela przechodziła na kolejną stronę.
Obiektywnie trudne miejsce.
Powtórzyliśmy ten test cztery razy i cztery razy wypadł identycznie, podczas gdy na high odczyt był poprawny za każdym razem.
Same czasy wykonania odczytu nie zmniejszyły się znacząco, a po to obniżaliśmy wartość parametru effort.
Najdłuższą ofertę z zestawu, 235 pozycji, model czytał 212 sekund, a drugą w kolejności, 131 pozycji, 136 sekund.
To te same okolice, które pokazują nasze dane produkcyjne, gdzie effort ustawiony jest na high.
Szybka analiza danych w Excelu pokazała, że czas jest niemal liniową funkcją liczby pozycji. Około sześciu sekund na start i po 0,8 sekundy na każdą pozycję oferty. Długiego odczytu nie powoduje więc myślenie, tylko sama odpowiedź modelu. Każda pozycja to osiem pól JSON-a, które model musi wypisać niezależnie od tego, jak długo się przed tym namyślał.
Ostatecznie zostajemy na wartości high.
Oferta na dwieście pozycji będzie się czytać kilka minut przy każdym ustawieniu modelu.
Nie jesteśmy w stanie przyśpieszyć tego procesu, musimy więc poprawić to, w jaki sposób przedstawiamy człowiekowi postęp odczytu.
Musi on widzieć poszczególne etapy odczytu zamiast prostego ekranu ładowania danych.
Wszystkie uruchomienia testów, razem z powtórkami tych samych dokumentów, kosztowały nas 20,44 dolara.
Zestaw liczy dziś 28 ofert od dziewięciu dostawców. Ośmiu z nich odpowiada za 970 z 1352 ofert, które wpłynęły do systemu w tym roku. To wciąż po kilka plików na dostawcę, ale wiemy już, których dostawców dotyczą i jaka część ruchu przez nich przechodzi.