Publikováno 20. dubna 2026

Kdy se složitý retrieval nevyplatí: doporučovací chatbot nad videoarchivem

Postavil jsem embeddings, BM25 a reranking — a nakonec nasadil celý katalog v promptu. Co k tomu řekla měření a kde je hranice, za kterou to přestane platit.

Postavil jsem doporučovací systém nad archivem YouTube videí. Uživatel nemusí hádat správné klíčové slovo — popíše problém vlastními slovy a chatbot vybere videa, která k tomu dávají smysl.

Není to volný poradenský chatbot a to bylo omezení od začátku. Systém nemá radit mimo zdroje, které zná. Jeho práce je najít nejlepší obsah v daném katalogu, vysvětlit výběr a říct na rovinu, když nic vhodného nemá.

Zajímavější než výsledek je ale cesta k němu. Postavil jsem plnou retrieval pipeline, potom zkusil mnohem hloupější řešení — a měření mi nakonec řeklo něco jiného, než jsem čekal.

Nejdřív bylo potřeba udělat pořádek ve videích

Chatbot je až poslední vrstva. Nejdřív jsem musel z videoarchivu udělat data: seznam videí, metadata z YouTube, přepisy, strukturovaná shrnutí a kompaktní katalog pro výběr doporučení. Všechno drží pohromadě přes video_id, takže se dá bezpečně propojit video, přepis, shrnutí i pozdější odkaz na konkrétní čas.

Přepisy vznikly lokálně modelem large-v3 na grafické kartě. Nepotřeboval jsem přepis přesný do posledního slova — potřeboval jsem spolehlivě poznat téma, problém, část těla a doporučení. Pro tuhle úlohu byla kvalita lokálního přepisu dostatečná a k externímu Whisper API jsem sáhnout nemusel.

Ke každému videu potom vzniklo strukturované shrnutí: témata, typické problémy uživatelů, části těla, doporučení a příznak, jestli se video vůbec hodí doporučovat. Název videa totiž často nestačí — video může mít obecný titulek a řešit velmi konkrétní situaci, nebo naopak vypadat relevantně a pro daný dotaz se nehodit.

Nejdřív jsem postavil ten složitý retrieval

První verze vyhledávání byla učebnicová: embeddings nad shrnutími i segmenty přepisů ve Weaviate, k tomu BM25, slučování obou výsledků přes reciproční pořadí a nakonec přerovnání kandidátů modelem.

Fungovalo to. Na gold setu čtyřiceti dotazů trefila tahle cesta správné chování ve všech případech a správné video mezi prvními třemi v 96,7 % hodnocených dotazů.

Potom jsem zkusil tupé řešení

Katalog má kolem 290 videí. Napadlo mě, že by se možná celý vešel do promptu.

Neposílají se přepisy — to by nedávalo smysl ani při tomhle počtu. Každé video je jeden řádek:

[video_id] Název || problémy: ... || části těla: ... || témata: ...

Celý katalog v téhle podobě vyjde asi na 23 tisíc tokenů. Model dostane katalog, aktuální otázku a krátkou historii konverzace, a vybírá výhradně z pevného seznamu video_id, která v katalogu doslova jsou. Kromě výběru musí určit kvalitu shody — silná, částečná, žádná, nebo potřeba doptat se — a česky vysvětlit, proč právě tahle videa.

Měření řeklo něco jiného, než jsem čekal

Tady je pointa celého projektu, a není to „jednodušší řešení vyhrálo“.

Na stejném gold setu vyšel plný katalog v pořadí hůř. Trefil správné chování v 93 % případů, ale správné video mezi prvními třemi jen v 64 %. Proti 96,7 % u semantic pipeline to vypadalo jako jasná prohra.

Když jsem si ale ty čtyři propadlé případy přečetl jeden po druhém, žádný z nich nebyl špatné doporučení. Na dotaz o bolesti zad při sezení vrátil model videa o sezení a bolesti zad. Na dotaz o krku vrátil videa o trapézech. Byla to relevantní videa, která jsem jen neměl ve svém ručně psaném seznamu správných odpovědí.

Archiv obsahuje k jednomu tématu spoustu blízkých videí. Ručně vybraný gold set proto systematicky podhodnocuje každý přístup, který vybere jiné správné video, než jaké mě zrovna napadlo. Slabým místem nebyl systém, ale můj měřicí nástroj.

To byl důležitější závěr než samotné skóre. Přestal jsem ladit proti gold setu, který neumí rozhodnout, a zapnul logování reálných dotazů, aby další verze gold setu vznikla z provozu, ne z mojí představy.

Proč jsem nakonec nasadil ten jednodušší

Rozhodovalo, že přesnost chování byla vysoká, propady byly vysvětlené a cesta je výrazně jednodušší na údržbu: žádná synchronizace vektorové databáze, žádné ladění vah mezi BM25 a embeddingy, žádný samostatný reranker.

Semantic pipeline jsem nesmazal. Zůstala v kódu za přepínačem jako fallback, takže návrat je změna proměnné prostředí, ne přepis.

Kde to přestane platit

Tohle je otázka, kterou si u „celý katalog do promptu“ položí každý: co až bude videí tisíc?

Znám odpověď, protože jsem si ji musel spočítat.

Velikost katalogu se měří při startu aplikace — pro češtinu vychází zhruba 3,5 znaku na token. Nad padesáti tisíci tokeny padá varování do logu. Kolem šedesáti tisíc začíná u dlouhého seznamu klesat spolehlivost výběru uprostřed kontextu, což je známý efekt „lost in the middle“. Nad tou hranicí se zapne embedding prefilter, který nechá jen několik desítek nejbližších kandidátů a zbytek do promptu vůbec nepošle. Ta cesta je hotová a vypnutá, protože při 290 videích není potřeba.

Praktičtější limit přišel dřív a odjinud. Účet u poskytovatele má strop 30 tisíc tokenů za minutu, takže dvě souběžná volání po 23 tisících ho překročí a druhé skončí chybou 429. Během evaluace, která pustila patnáct dotazů ve dvou minutách, to vypadalo jako katastrofa: odezvy 48 až 67 sekund a jeden tvrdý pád.

Jenže to nebyl obraz reálného provozu. Jedno nezatížené volání trvá 4,2 sekundy. Při desítkách uživatelů denně rozložených v čase je to v pořádku. Ošetřil jsem proto 429 srozumitelnou hláškou místo chyby a poznamenal si, že jakmile začnou být souběžné dotazy běžné, řeší se to zvýšením limitu účtu nebo zapnutím prefilteru.

Co si z toho odnáším

Nejužitečnější věc nebyla volba mezi jednoduchým a složitým řešením. Byla to chvíle, kdy měření ukázalo horší číslo a stálo za to zjistit proč, místo abych podle něj rovnou zahodil funkční přístup.

Skóre z gold setu je nástroj, ne pravda. Když se rozchází s tím, co vidíš v jednotlivých odpovědích, je stejně pravděpodobné, že je špatně gold set, jako že je špatně systém.

Tenhle chatbot je jedna z komponent větší AI vrstvy, kterou pro stejného klienta provozuju — popisuju ji v článku Jak jsem z e-mailového agenta postavil AI vrstvu pro celý online business.