# Jak tech lead bez pisania kodu stworzył system zakupów w Telegramie: case agentowej development
Kiedy wewnętrzne zakupy w zespole zamieniły się w chaos z zagubionymi wnioskami i niezsynchronizowanymi prośbami, lider techniczny postanowił stworzyć system oparty na Telegramie. Bez napisania ani jednej linijki kodu, korzystając z systemów agentowych i klarownej architektury, zbudował rozwiązanie z OCR, moderacją i bezpiecznym deployem. Opowiadamy, jak to zrobić, nie tracąc kontroli nad jakością.
Problem: chaos zamiast procesu zakupów
W małych zespołach zakupy często zaczynają się od nieformalnych ustaleń. Najpierw kartki, potem notatki, następnie osobny temat w Telegramie. Pojawia się regulamin: wrzucajcie link, cenę, ilość i uzasadnienie. Jednak w praktyce część wniosków gubi się, część przechodzi bokiem, w niektórych brakuje ceny lub uzasadnienia, a ludzie zapominają o swoich prośbach. W rezultacie tech lead traci czas nie na zarządzanie zakupami, lecz na walkę z formą chaosu. Kluczowy wniosek: jeśli proces wpływa na pieniądze, nie powinien istnieć jako swobodna korespondencja.
Wymagania infrastrukturalne: od „bota” do systemu
Początkowy pomysł — prosty Telegram-bot — szybko napotkał infrastrukturalne komplikacje. Z powodu niestabilnej pracy Telegrama bez VPN potrzebne były:
- Zagraniczny VPS
- Własny obwód VPN
- Niezawodny autostart
- Wygodny deploy
- Mechanizm rollbacku po nieudanym releasie
To już nie „skrypt na wieczór”, lecz pełnoprawny inżynieryjny obwód. Doświadczenie pokazuje: „prosta automatyzacja” często kryje pod sobą skomplikowaną infrastrukturę.
Agentowa development: akcelerator, a nie zamiennik myślenia
Projekt zrealizowano za pomocą ChatGPT i systemu agentowego, ale nie obyło się bez aktywnego udziału tech leada. Proces obejmował:
- Formułowanie zadania i rozdzielanie ról
- Doprecyzowanie logiki biznesowej
- Ręczne testowanie scenariuszy
- Wykrywanie sprzeczności i błędów
- Powrót do punktowych poprawek
- Ponowne testowanie
Agent wystąpił jako akcelerator cyklu: skrócił czas między wykryciem problemu a sprawdzeniem nowej implementacji. Główny wniosek: składnię kodu można delegować, ale systemowe myślenie i architektura pozostają kluczowe. Bez klarownego modelu procesu agent tylko przyspieszy realizację niedoskonałej logiki.
Rezygnacja z „magii”: przejście do scenariusza wizard
Pierwsza hipoteza — automatyczne wyodrębnianie danych z linku — okazała się nieżyciowa z powodu:
- Różnorodności stron
- Niestabilnej struktury stron
- Niejednoznacznych cen
- Skomplikowanego renderingu danych
- Wrogiej logiki marketplace'ów
Zamiast tego wdrożono scenariusz wizard:
- Dołącz screenshot
- Podaj link
- Napisz uzasadnienie
- Podaj ilość
- W razie potrzeby wprowadź cenę ręcznie (jeśli OCR nie rozpoznał)
- Sprawdź końcową kartę przed potwierdzeniem
To podejście mniej „wow”, ale zapewnia kontrolowalność — kluczowy czynnik dla procesów operacyjnych.
Dlaczego LLM nie stały się podstawą systemu
Chociaż pokusa użycia LLM do przetwarzania próśb była wielka, wybór padł na prosty stack:
- Python
- Telegram bot framework
- SQLite
- Lokalny OCR
- HTML-raporty na szablonach
- systemd dla serwisów i timerów
Uzasadnienie:
- Praca na słabym VPS
- Niezależność od zewnętrznych API w runtime
- Brak płatnego inference za każdy request
- Prostota debugowania
- Przewidywalność zachowania
To rozwiązanie podkreśla ważną zasadę: nie każde zadanie zyskuje na wdrożeniu AI. Czasem ścisła FSM i walidacja dają więcej pożytku niż skomplikowane modele.
System stanów: podstawa niezawodności
Wniosek okazał się encją z cyklem życia, obejmującym statusy:
- Szkic
- Oczekuje obrazu
- Oczekuje linku
- Oczekuje uzasadnienia
- Oczekuje potwierdzenia
- Na moderacji
- Zwrócona do poprawy
- Przeniesiona na następny okres
- Pilna
- Wysłana
Do zarządzania tym cyklem użyto FSM. Przykład kodu:
class PurchaseWizard(StatesGroup):
waiting_for_image = State()
waiting_for_link = State()
waiting_for_reason = State()
waiting_for_qty_lots = State()
waiting_for_lot_size = State()
waiting_for_manual_price = State()
waiting_for_confirmation = State()
i statusy domenowe:
class PurchaseStatus(str, Enum):
DRAFT = "draft"
AWAITING_IMAGE = "awaiting_image"
AWAITING_LINK = "awaiting_link"
AWAITING_REASON = "awaiting_reason"
AWAITING_QTY = "awaiting_qty_lots"
AWAITING_CONFIRMATION = "awaiting_confirmation"
COMPLETE = "complete"
PENDING_MODERATION = "pending_moderation"
RETURNED_FOR_REVISION = "returned_for_revision"
APPROVED = "approved"
CANCELLED = "cancelled"
SENT = "sent"
Kiedy w procesie biorą udział role, pieniądze i deadliny, trzeba przejść od przetwarzania wiadomości do zarządzania stanami.
Architektura: prostota jako znak dojrzałości
Schemat systemu:
Telegram user
↓
Bot handlers / FSM
↓
Purchase service
├── SQLite
├── OCR service
├── Moderation logic
├── HTML report builder
└── Reminder / maintenance jobs
↓
systemd service + timers
Struktura projektu:
purchase_bot/
├── app/
│ ├── bot/
│ ├── db/
│ ├── services/
│ ├── templates/
│ └── main.py
├── data/
│ ├── uploads/
│ ├── reports/
│ └── bot.db
├── scripts/
├── deploy/
└── README.md
Rezygnacja z Dockera i ciężkich baz danych w pierwszej wersji pozwoliła skupić się na funkcjonalności. Dla narzędzi wewnętrznych prosta architektura to znak dojrzałości, a nie słabości.
Telegram UX: interfejs zamiast strumienia wiadomości
Praca z Telegramem ujawniła trudności:
- Trwałe stare przyciski
- Nakładanie się kart
- Równoległe istnienie starych i nowych wersji wniosków
- Opóźnienia w powiadomieniach
- Niespójne zachowanie przycisku „Wstecz"
- Zapętlanie ekranów
- Śmieci w czacie
Rozwiązanie: projektować bota jak system ekranowy stanów. Główne zasady:
- Jeden aktualny ekran
- Usuwanie nieaktualnych wiadomości
- Bezpieczne obsługiwanie starych callback-przycisków
- Rozdzielanie reguł dla menu, powiadomień i kart roboczych
To podejście, choć nie błyszczące, zapewnia codzienną użyteczność systemu.
Rzeczywisty proces łamie symetrię
Wdrożenie moderacji, pilnych wniosków i przenosów między okresami pokazało, że rzeczywisty proces nie pasuje do schludnych schematów. Na przykład drugi etap moderacji może stać się zbędnym tarciem, jeśli pierwszy już w pełni przetworzył wniosek. Trzeba było przebudować logikę pod realne potrzeby, a nie pod diagramy. To znajomy tech leadom wzorzec: jeśli schemat przeszkadza w przepływie, łamać schemat.
Najpodstępniejsze bugi — na styku warstw
Krytyczne błędy pojawiały się nie w głównych ficzerach, lecz na styku warstw. Na przykład:
- Przycisk „Potwierdź” zawieszał się z powodu porównania obiektów timezone-aware i timezone-naive
- Niezgodność formatów danych między modułami
- Problemy synchronizacji stanów przy aktualizacji
Te bugi podkreślają znaczenie dokładnego projektowania interfejsów między komponentami.
Co ważne
- Architektura ważniejsza niż agenci: Nawet przy użyciu systemów agentowych klarowna architektura i systemowe myślenie pozostają obowiązkowe. Agenci przyspieszają realizację, ale nie zastępują projektowania.
- Kontrolowalność ponad „spryt”: Dla procesów operacyjnych niezawodność i prostota ważniejsze niż automatyzacja skomplikowanych zadań. Scenariusze wizard często efektywniejsze niż próby pełnej automatyzacji.
- Stany, a nie wiadomości: Przy rolach, pieniądzach i deadlinach trzeba projektować system jako kontrolowany cykl życia z jawnymi statusami.
- Prostota jako strategia: Dla narzędzi wewnętrznych unikaj otyłości architektonicznej. Minimalny stack na słabym sprzęcie zapewnia niezawodność i prostotę utrzymania.
- UX w Telegramie wymaga dyscypliny: Boty w Telegramie powinny być projektowane jak system ekranowy, a nie strumień wiadomości. Usuwanie nieaktualnych elementów i jeden ekran kluczowe dla doświadczenia użytkownika.
— Editorial Team
Brak komentarzy.