carBot: jak z rozbitých inzerátů stavíme automotive inteligenci.
carBot je interní systém pro čtení automobilového trhu. Bere chaotické listingy, dává jim strukturu, počítá s nejistotou a z výsledku staví deal scoring, alerty a analytický dashboard.
Na papíře to zní banálně: auto má cenu, rok, nájezd, motorizaci, fotky a prodejce. Jenže reálný trh se nechová jako čistá tabulka. Titulky jsou zkrácené, popisy míchají češtinu, zkratky, výbavu a obchodní omáčku, stejné auto se umí objevit na více místech a některé hodnoty jsou spíš přání než data. carBot vznikl přesně kvůli téhle šedé zóně.
Problém: listing není datový model.
Automobilový inzerát je hlavně textový kompromis mezi prodejcem, formulářem a tím, co se zrovna vešlo do titulku. Pro člověka je to čitelné. Pro algoritmus je to past. Číslo v popisu může být nájezd, cena, datum, výkon, objem motoru nebo jen část telefonního čísla. A když se podobná chyba dostane do tržní baseline, scoring začne vypadat přesvědčivě, ale nebude pravdivý.
carBot proto nepracuje stylem "něco jsem našel, tak tomu budu věřit". Každé důležité pole nese hodnotu, confidence a informaci, odkud pochází. Systém si uchovává syrové evidence, ale do modelu pouští jen data, která prošla normalizací a guard rails. Nudné? Ano. Přesně proto to funguje.
Architektura.
Jádro je asynchronní Python pipeline nad PostgreSQL. Nad tím běží FastAPI vrstva pro inspekci a řízení a Next.js dashboard pro každodenní práci. Jednotlivé zdroje mají vlastní adaptéry, ale po načtení se data převádějí do stejného tvaru: listing, historie ceny, stav dostupnosti, enrichment, tržní kohorta a scoring detail.
| Vrstva | Úloha | Proč je důležitá |
|---|---|---|
| Source adapters | Najdou kandidáty, načtou detail a vytvoří source-neutral payload. | Každý zdroj se může měnit jinak, ale zbytek systému zůstává stabilní. |
| Parser | Extrahuje cenu, rok, nájezd, značku, model, trim, palivo, výkon, převodovku a VIN. | Confidence skóre zabraňuje tomu, aby nejistý výsledek vypadal jako fakt. |
| Market model | Počítá srovnatelné kohorty a fallbacky pro tenké segmenty. | Levné auto není automaticky dobrý deal. Musí být levné proti správným autům. |
| Scoring | Kombinuje regresní odhad, kohortový fallback a penalizace. | Výsledkem je čitelné score a důvod, proč score vzniklo. |
Parser, který se nebojí říct "nevím".
Největší chyba podobných systémů je přehnané sebevědomí. carBot raději označí pole jako nízkou jistotu, než aby si vymyslel jistotu tam, kde není. To pomáhá i vývoji parseru: low-confidence queue ukazuje, kde normalizační pravidla zaostávají a kde se musí doplnit katalog aliasů, trimů nebo kontextových guardů.
# konceptuální kontrakt parseru, ne produkční zdroj
field = extract_mileage(text)
if field.confidence == "low":
send_to_review_queue(listing_id, field.raw_value)
else:
persist_normalized_value(
listing_id=listing_id,
name="mileage_km",
value=field.value,
confidence=field.confidence,
)
Tržní baseline a scoring.
Deal score se neopírá o průměr celého trhu. carBot nejdřív hledá srovnatelnou kohortu podle značky, modelu, roku, paliva, výkonového pásma a typu prodejce. Čerstvá data mají přednost. Pokud je kohorta tenká, systém jde do historie nebo opatrně rozšíří year band. Extrémy se ořezávají přes IQR, protože jeden špatný inzerát nemá rozhodovat o celé realitě.
# zjednodušený scoring flow
estimate = regression_3d(listing) or regression_2d(listing) or cohort_median(listing)
if estimate is None:
return unscored("no_comparable_market")
deal_pct = (estimate.expected_price - listing.price_czk) / estimate.expected_price
score = clamp(50 + deal_pct * 250 - damage_penalty(listing), 0, 100)
Regrese pomáhá tam, kde je dost vzorků a dává smysl započítat nájezd, stáří a výkon. Kohortový medián je fallback, ne ostuda. V praxi je lepší poctivý jednodušší model než efektní model, který si z malých dat dělá horoskop.
VIN, SPZ a identita vozidla.
Auto není jen jeden řádek v tabulce. Může zmizet, vrátit se, změnit cenu, objevit se v aukci a později znovu v inzerci. carBot skládá identitní historii přes VIN-aware profily a SPZ/OCR enrichment. Veřejně popisujeme architekturu, ne privátní data: žádné reálné VINy, SPZ, telefonní čísla ani dumpy listingů sem nepatří.
K čemu je to užitečné.
- Řazení potenciálně zajímavých aut podle expected value, ne podle syrové ceny.
- Hlídání price dropů a nových listingů podle watch filtrů.
- Kontrola kvality parseru přes low-confidence frontu.
- Market research: mediány, kohorty, výbava, zdroje, stav prodeje.
- Operativní dashboard pro běžící pipeline, zdraví zdrojů a alerty.
Bezpečnostní a publikační hranice.
Tento článek záměrně neukazuje credentials, privátní endpointy, source-specific request recepty, raw listing dumpy, identifikátory vozidel, kontakty ani obcházení ochran zdrojů. Pro čtenáře je důležitý model systému: evidence, normalizace, confidence, tržní baseline, scoring a provozní kontrola.
Kam dál.
Největší prostor je v lepší zpětné vazbě mezi review frontou a parserem. Každý ručně potvrzený slabý případ může skončit jako test, catalog update nebo nové guard pravidlo. A přesně tam se z "máme data" stává "máme systém, kterému věříme".