Головна / Статті / Вікно Gemini на 1M замінило мені векторне сховище, але затримка й походження відповідей заперечили

Вікно Gemini на 1M замінило мені векторне сховище, але затримка й походження відповідей заперечили

Порівняння повного контексту і RAG на 500 питаннях підтримки: точність, затримка й вартість, чому важливе походження відповіді та яка гібридна схема зберегла переваги обох підходів.

836 слів

Видаляємо векторну таблицю

Уявіть асистента підтримки, яким користуються дев'ять тисяч працівників компанії. Будь-яку його відповідь людина може переслати клієнтові, тож помилка чи відповідь без пояснення коштують дорого.

Під ним працює шар пошуку: чанкер, задача побудови ембедингів, векторне сховище і в самому кінці реранкер, який підкручували стільки разів, що ніхто вже не може обґрунтувати його параметри.

user ─► embed ─► vector db ─► rerank ─► 4k ctx ─► model ─► answer
                    ▲
                 chunker
                    ▲
              nightly reindex

Експлуатація — це чотири сервіси й два чергові алерти, плюс баг, що постійно повертається: футер PDF тихо псує половину чанків. Водночас сам шлях запиту крихітний:

q = embed(text)
hits = db.search(q, k=8)
ctx = "\n".join(h.doc for h in hits)
ans = llm(f"{ctx}\n\nQ: {text}")

Увесь біль живе навколо цих чотирьох рядків.

І тут напрошується спокуслива думка. Gemini приймає мільйон токенів і майже ідеально їх пам'ятає, а весь корпус займає лише 640 000 токенів. Він вміщається. Тож у вівторок увечері хтось видаляє таблицю на 2,3 мільйона ембедингів і замінює весь пайплайн ось цим:

docs = load_all()
ans = gem(f"{docs}\n\nQ: {text}")

Ні чанкера, ні задачі переіндексації, ні реранкера з константою, яку ніхто не може пояснити. Це працює, і годин шість відчуття таке, ніби списав на іспиті й не попався.

Що показав наступний ранок

Затримка зростає приблизно пропорційно до розміру входу. Це не секрет, але по-справжньому це відчуваєш, лише коли починає скаржитися підтримка. Для порівняння через кожну схему прогнали 500 реальних питань. Точність оцінювала друга модель, звіряючи кожну відповідь з еталоном, написаним вручну, а шістдесят таких оцінок перевірили руками, щоб переконатися, що суддя не підсуджує.

setup               p50      p95     cost/query   accuracy
-----------------------------------------------------------
RAG, 4k ctx         1.9s     3.4s      $0.004       71%
full stuff, 640k   28.7s    41.2s      $0.81        74%
cached, 640k        9.4s    15.1s      $0.11        74%

Медіана у 28 секунд — довге очікування для вікна чату. Кешування промптів цей час скорочує, і ним варто користуватися, але воно має обмеження: мінімальний розмір промпту, час життя кешу, за підтримку якого ви платите, і одна слабкість, яка тут ударила найболючіше. Корпус змінюється приблизно сорок разів на день, кожна правка скидає кеш, і цілий день пішов на те, щоб платити за повторне збирання 640 000 токенів.

Питання, яке виявилося важливішим

Точність зросла на три пункти, і це майже приховало справжню проблему. Керівниця підтримки поставила просте питання: звідки взялася ця відповідь?

Пошук дає конкретну відповідь: чанк 4112 на дев'ятій сторінці, остання правка в березні. З повним вікном модель видає впевнений абзац, зібраний десь усередині 640 000 токенів, і показати їй нічого. Назвімо це перевіркою походження. Питання не в тому, чи може модель відповісти, а в тому, чи можете ви довести, звідки взялася відповідь. Це проблема продукту, а не моделі, з тих, що закінчують кар'єри, а не спринти.

Може, просто реранкер був поганий?

Хтось одразу заперечить: налаштуйте реранкер, візьміть дешевший тариф, ріжте на чанки розумніше. Слушно, реранкер справді був посереднім. Але навіть добре налаштований реранкер передає далі вісім фрагментів і сподівається на краще, а жодне налаштування не дасть посилання на джерело з вікна, яке проковтнуло все одразу.

Схема, яка прижилася

Векторна база повернулася, а реранкер ні.

ids = db.search(embed(q), k=40)
docs = fetch(ids)
ans = gem(f"{docs}\n\nQ: {q}", cache=c)

Пошук більше не шукає відповідь. Його завданням стало звузити коло, а читає вже довге вікно.

user ─► embed ─► vector db (k=40, no rerank)
                       │
                       ▼
             ~90k ctx + cached policy docs
                       │
                       ▼
                    model ─► answer + doc ids

Ті самі 500 питань пройшли через того самого суддю:

hybrid, 90k ctx     3.1s     5.2s      $0.021       88%

Сорок не надто відфільтрованих чанків лишають моделі простір для міркувань, тоді як реранкеру довелося б вгадувати ідеальну вісімку. І кожна відповідь несе ідентифікатори того, на що вона спиралася.

Великі вікна не вбили пошук, вони покінчили з пошуком, де все вирішує точність. Старе завдання було виснажливим: знайти вісім ідеальних чанків, бо бюджет дозволяв лише вісім. З цим завданням покінчено, і сумувати за ним ніхто не має.