The task
Technotochka sells large appliances: fridges, washing machines, cookers, water heaters. Shoppers write to the store’s Telegram and Viber, and the questions are almost always specific. Dimensions, number of burners, delivery with carry-up to the floor, bank instalments, order status. During working hours managers answer these. At night and on weekends there is nobody, and a shopper who did not get an answer goes to another store.
We measured how many people actually wait before the night rule existed. Over 14 days the chats received 133 messages outside working hours: 18 people waited more than an hour, 3 never got an answer at all. One case we took apart separately: a shopper with a UAH 32,300 order waited 12 h 34 min and wrote that she would cancel. That measurement is where the rule came from: at night the bot runs every chat.
The task sounded simple: take the repetitive questions off the managers and stop losing people outside working hours. The hard part was elsewhere. A bot that confidently names the wrong price or promises “in stock” creates a problem for the store. So the main job was not teaching the bot to answer. It was making sure the bot does not say what it does not know.
Why, and what the idea was
The idea is that the model’s answer never goes to the customer directly. Between the model and the chat sits a layer of code: a local copy of the catalogue with the site’s filters, the store’s delivery rules, a warranty table by brand, queries to 1C. The model composes an answer from this data, and then a set of code checks reads the finished text. A price with no source, a claim about stock, an invented action like “I have placed your order”, a phone number, a list in the wrong format: none of it gets through. The model rewrites the answer with a hint, and if it fails, the customer gets a safe fallback text.
The second part of the idea: do not wait for complaints. Every day a separate run reviews all dialogues with a bot reply and scores each one, so error classes are visible the next morning. Every day on schedule a snapshot of the catalogue filters is compared with the live site. Every gauge has a number you can verify, not a feeling that “it seems better”.
Several decisions were made by the store owner and are fixed in code. The bot says neither “in stock” nor “out of stock”, because it has no access to inventory, and the code check is symmetrical. Asked directly “are you a bot?”, it honestly says it is an AI consultant. It asks for a phone number once and never comes back to it.
How it went
| Stage | What happened |
|---|---|
| Stage 1 | First version: Telegram bot, site parsing, SQLite, Claude Sonnet 4.5 |
| Stage 2 | Cascading catalogue search, photo recognition, handover to a manager, first answer checks in code. Third council on selling the bot to other stores: not yet, first a regression suite and automatic signals |
| Stage 3 | Moved from a bare SendPulse webhook to their API. The direct Telegram bot switched off: in 14 days not a single live customer came through it, while SendPulse carried 328 messages a day |
| Stage 4 | A 5-part audit, 76 findings fixed in a day. Viber review: the SendPulse flow was never published, fixes were not reaching customers |
| Stage 5 | First regular audit by our own 13-step prompt: 32 commits and two releases in a day, 24 of 34 findings closed. Production model switched to Sonnet 5 after a measurement on 10 live questions |
| Stage 6 | Daily review of live dialogues starts. Night rule: outside working hours the bot runs every chat, but if a manager wrote in the last 20 minutes, the bot stays silent |
| Stage 7 | 7 and 10 releases a day driven by live cases. 1C started returning the Nova Poshta waybill number, verified on 50 live orders |
| Stage 8 | Found the root of the mismatch between the stored history and what the customer saw. The instalment range is now assembled by code, not the model. Test suite at 8,059 of 8,059 |
The test suite grew with the project: 3,766, then 5,260, 7,154 and 8,059. All green at the moment of every release. Releases only from a separate clone, after a green suite and on the owner’s word, with a rollback tag on each.
Tools and method
Channels: the store’s Telegram and Viber are connected through SendPulse. SendPulse calls our webhook, the answer goes back into the chat. A separate process catches up on messages that never reached the webhook and sends replies through the SendPulse API.
Models: customer answers are written by Claude Sonnet 5. Cheap tasks go to Claude Haiku 4.5: detect the customer’s intent, the product category, parse a photo. The prompt consists of a core with a hard length limit plus sections that attach by topic: credit, clearance, promotions, pickup. The core is cached, the cache is warmed every 15 minutes, which by our calculation saves around $31 a month.
Data: a local copy of the tt.ua catalogue with the site’s filters (after the fix the bot knows 5,283 filters, 90% coverage of the site’s sections), a category map, a warranty table by brand, delivery rules. Storage in SQLite: dialogue history, a separate table of customer numbers, a log of everything sent. Integrations: the store’s 1C over HTTP for order statuses, public Nova Poshta tracking.
Where it runs: a Linux VPS, two systemd services, the webhook and the catch-up process. Keys in .env, not in code. A pre-push hook searches for phone numbers, IBANs are masked in logs.
How decisions were made. At every major fork five AI advisors (a skeptic, an architect, a visionary, an outsider, a pragmatist) analyze the situation independently, review each other, and a chair delivers the verdict. In one audit the cross-review refuted 16 claims made by the auditor itself. Code review before every release: one day two reviews found 11 problems in the changes, another day a review found 3 real bugs in a fix to the complaints dictionary, and it did not go to production. All rules live in a “do not repeat” register, numbered up to 390 plus 262 early unnumbered ones. Before any change to the bot the register is opened first.
Result
The customer writes in plain words, Ukrainian or Russian: “a Samsung fridge under 15 thousand”, “a 50 by 50 cooker”, “a black water heater, not white”. The bot searches the catalogue copy with the site’s filters, shows items with links and prices from the product card, and offers an alternative if the exact model is missing. Send a product screenshot: the bot recognizes the model and finds it in the catalogue, 32 of 34 photos parsed over a two-week measurement.
Delivery and payment: city first, no amounts without a city. It calculates delivery and carry-up by the store’s rules and suggests pickup points. Order status: it asks 1C by order number and answers, 1C returns the Nova Poshta waybill number. When the customer is ready to buy, the bot collects the product, price, delivery, full name, address and phone number, and hands the lead to a manager as a separate signal. Complaints, cancellations and disputed warranty go to a human right away.
At night the bot runs every chat, even those assigned to a manager, but never interrupts a live person. The 20-minute window was chosen by measurement: from 20:00 to 22:00 managers still write, from 23:00 to 07:00 none. The rule itself grew out of a measurement taken two weeks before it: of 133 night-time messages, 112 got a reply within an hour, 18 waited longer, 3 never heard back. The rule exists for those 21.
What the gauges showed. All live traffic comes through SendPulse: 328 messages a day against zero through the direct Telegram bot over the same 14 days, so the direct bot was switched off and one channel kept. Four days in a row with zero invented prices or specs when checked against the live site, 7 to 10 prices a day. The history-versus-sent check after the fix: 41 sent, 41 in history, 0 mismatches. Claude API costs over a 14-day measurement $26.25, roughly $56 a month, about $0.025 per customer answer. Switching to Sonnet 5 on 10 live questions saved 21%.
What is not done yet: the same error class sometimes resurfaces, and the daily reviews show it. The code checks occasionally do more harm than the model. The question of a product for other stores stays open: the regression suite and daily gauges exist, legal liability toward someone else’s store has not been worked through.
Mistakes and what we took from them





