8.2 · Эксперимент: chunking A vs B
Неделя 8 · Evals · ⏱ ~4 ч · Проект
Зачем это AI-инженеру
Заголовок раздела «Зачем это AI-инженеру»Это первый полный эксперимент Проекта 3: гипотеза → одно изменение → прогон evals → вывод с цифрами. Именно такой цикл и есть ежедневная работа AI-инженера, а не «попробовали, вроде лучше». Чанкинг выбран не случайно: плохое разбиение — частая причина, почему RAG находит не то, и эффект обычно достаточно крупный, чтобы его было видно на нашем наборе.
Анатомия эксперимента
Заголовок раздела «Анатомия эксперимента» 1. гипотеза (письменно, ДО прогона) «чанки по заголовкам дадут +X п.п. hit@5, потому что ответ на вопрос обычно лежит внутри одного раздела» 2. одно изменение chunking: fixed-512 → headings 3. всё остальное фиксировано эмбеддинги, k, ответчик, промпт, судья, набор 4. прогон evals baseline ×3, вариант ×3 (или ≥1 + известный разброс) 5. сравнение общие метрики + парное сравнение + срезы 6. разбор на каких вопросах разница и почему 7. вывод принять / отклонить / «тенденция», строка в таблицеЭто та же дисциплина, что в A/B-тесте страницы магазина: меняем один параметр, остальное не трогаем, сравниваем на одних и тех же данных и не объявляем победу, пока результат не выйдет за пределы шума (8.1). Дальше разбираем шаги по порядку на нашем примере: гипотеза, выбор двух вариантов, условия честного сравнения, прогоны, разбор и журнал.
Гипотеза: как написать
Заголовок раздела «Гипотеза: как написать»Гипотеза пишется до первого прогона, иначе её легко подогнать под полученную цифру. Хорошая гипотеза содержит три части: что меняем, какую метрику и насколько ожидаем сдвинуть, почему (механизм). Пример:
Если резать
kb/по заголовкам разделов (H2/H3) с путём заголовков в начале куска, ограничением 800 токенов, таблицами как неделимыми «атомами» и склейкой коротких разделов страниц товаров, вместо фиксированных кусков по 512 токенов с перекрытием 64, то hit@5 вырастет на 8–15 п.п., а сильнее всего на вопросах с тегамиtableиsimilar_products, потому что сейчас строки таблицы тарифов попадают в кусок без шапки (вес, зона), а раздел «Гарантия» со страницыlamp-light-mini.md— в кусок без названия лампы. Correctness вырастет меньше, чем hit@5. Стоимость ответа может измениться вместе со средним размером куска.
Здесь hit@5 — доля вопросов, у которых хотя бы один релевантный кусок попал в первые 5 найденных, а п.п. — процентные пункты: рост с 0,70 до 0,80 — это +10 п.п. Зачем записывать «почему»: в разборе проверяем не только цифру, но и механизм. Если hit rate вырос, но на других вопросах, чем предсказывали, гипотеза о механизме неверна, даже если цифра совпала.
Какие стратегии сравнивать
Заголовок раздела «Какие стратегии сравнивать»Гипотеза называет два конкретных способа резать kb/. Стратегии мы уже реализовали в 4.3 и выбрали одну из них для index.db по 10 вопросам. Теперь проверяем выбор на полном наборе и со всеми метриками. Варианты, которые имеет смысл сравнить на базе знаний магазина:
| Стратегия | Как работает | Ожидаемая сильная сторона | Риск |
|---|---|---|---|
| A: fixed + overlap | Куски по N токенов с перекрытием | Предсказуемый размер | Режет таблицы тарифов и гарантии; кусок не знает, о каком он товаре |
| B: по заголовкам | Раздел = кусок с путём заголовков («Товары > Лампа «Свет мини» > Гарантия») в начале; длинные делятся по абзацам, короткие склеиваются | Смысловая целостность, лампы различаются по пути | Куски разного размера |
| B’: заголовки + LLM-контекст | B плюс 1–2 предложения контекста от модели (contextualize.py, index_ctx.db из 5.2) |
Поиск лучше понимает, о чём кусок | Длиннее куски, стоит вызовов модели |
Для эксперимента выбираем две: baseline и одну альтернативу. Остальное — следующими экспериментами. Дальше в главе A — fixed-512 с перекрытием 64, B — заголовки. Даже если index.db уже построен по заголовкам, оба варианта собираем заново в отдельные файлы: одна версия kb/, один код загрузки.
Честное сравнение: ловушка размера куска
Заголовок раздела «Честное сравнение: ловушка размера куска»Варианты выбраны, но сравнивать их «в лоб» нельзя: стратегия чанкинга меняет не только границы кусков, но и их размер. Самая частая ошибка в экспериментах с чанкингом: варианты с крупными кусками выигрывают по hit@k просто потому, что k крупных кусков покрывают больше текста. Это не лучший чанкинг, а больший контекст. При этом растут стоимость и латентность ответа, и модель хуже находит нужное в длинном контексте.
В kb/ ловушка смотрит в другую сторону: разделы короткие (страница товара — несколько разделов по паре абзацев), средний кусок B (~370 токенов) меньше, чем у A (512), и при одинаковом k фору получает baseline.
Два способа сравнивать честно:
- Равный бюджет контекста. Подбираем k так, чтобы средний объём контекста в токенах был близок: fixed-512 при k=5 (~2560 токенов) против headings (средний кусок ~370 токенов) при k=7 (~2590 токенов).
- Показываем оба: hit@k при одинаковом k и среднее число токенов контекста. Тогда читатель видит компромисс.
В таблицу результатов обязательно добавляем колонки «средний размер куска» и «токенов контекста на вопрос».
Пересчёт релевантности после смены чанкинга
Заголовок раздела «Пересчёт релевантности после смены чанкинга»Вторая вещь, которую смена чанкинга ломает незаметно, — сама разметка релевантности: по ней считаются hit@k и MRR. Ключи чанков в новом индексе другие: chunk_key = sha256(url + section + text) меняется вместе с текстом и путём заголовков, поэтому source_chunk_keys из набора не годятся. Именно для этого в 6.3 мы храним evidence: функция is_relevant из 6.4 находит релевантные чанки в любом индексе по цитате. Перед прогоном проверяем:
- для каждого вопроса (кроме
unanswerable) в новом индексе есть хотя бы один чанк, содержащий цитату; - если нет, причина либо в разрезанной цитате (fixed-чанкинг разрезал фразу или строку таблицы
| 1–3 | 350 ₽ | 470 ₽ | 590 ₽ |пополам), либо в отличии загрузки текста (по-разному обработан front matter).
Если в варианте A цитату разрезало у 5 вопросов, а в B нет, A получит 5 промахов, которые на самом деле не промахи поиска. Учитываем это: либо считаем частичное совпадение (большая часть цитаты внутри куска), либо отмечаем такие случаи в разборе.
Индексы рядом, а не вместо
Заголовок раздела «Индексы рядом, а не вместо»Проверять цитаты, сравнивать при разном k и повторять прогоны удобно, только если оба варианта доступны одновременно. Поэтому единственный индекс не перестраиваем: держим оба варианта одновременно, отдельными файлами sqlite-vec, с именем в конфиге:
projects/02-support-kb-rag/ index.db # week-4 index, untouched index_fixed512.db # A: fixed 512 tokens, overlap 64 index_headings.db # B: headings + breadcrumbs, max 800 tokens eval/configs/ chunk_fixed512.json {"index": "index_fixed512.db", "k": 5, ...} chunk_headings.json {"index": "index_headings.db", "k": 5, ...} chunk_headings_k7.json {"index": "index_headings.db", "k": 7, ...} # equal context budgetТак любой прогон воспроизводим, и через неделю можно вернуться к baseline без пересборки. Папки прогонов получают имя по индексу: eval/runs/2027-01-05T10-12_index_headings_hybrid_k5/. Эмбеддинги локальные и денег не стоят, но перестройка занимает время: заранее считаем число кусков и токенов в каждом варианте.
Метрики поиска vs метрики ответа
Заголовок раздела «Метрики поиска vs метрики ответа»Индексы и конфиги готовы; осталось решить, что именно прогонять. Чанкинг напрямую влияет на поиск, поэтому главная метрика эксперимента — hit@k/MRR/recall. Но обязательно смотрим и на correctness и faithfulness: бывает, что hit rate вырос, а correctness нет, потому что модель тонет в длинных кусках или ответ уже упирается в генерацию. Вывод тогда честный: «поиск стал лучше, но узкое место — генерация». Счётчик archived_in_context тоже проверяем: без метаданных archived в контекст вернётся returns-2025.md.
Метрики поиска детерминированы и дёшевы: их можно прогнать без генерации и судьи (флаг --retrieval-only у eval/run.py), быстро перебрать несколько размеров и только для финалистов запустить полный прогон.
Анализ по вопросам
Заголовок раздела «Анализ по вопросам»Прогоны дают две общие цифры, но их разница — ещё не вывод. Общая цифра говорит «сколько», анализ по вопросам — «где» и «почему». После прогона строим таблицу переходов: для каждого вопроса смотрим, нашёл ли его вариант A и нашёл ли вариант B. Пример: dev-набор из 56 вопросов, без 8 unanswerable — 48:
B: hit B: miss A: hit 34 3 ← регрессии: что B сломал? A: miss 9 2 ← улучшения: что B починил?hit@5: A — 37/48 = 0,77, B — 43/48 = 0,90, разница +12,5 п.п. Дальше смотрим глазами:
- 9 улучшений: подтверждают ли они механизм гипотезы (таблица тарифов теперь в одном куске с шапкой, гарантия «Свет мини» — в куске с названием лампы)?
- 3 регрессии: почему новый вариант их потерял (крупный раздел размыл эмбеддинг, микро-раздел товара остался без контекста)?
- 2 «оба промахнулись»: проблема не в чанкинге. Это материал для 8.4.
- Срезы по
type,categoryи тегамtags: может, заголовки помогаютdelivery.mdиwarranty.mdс таблицами и вредят страницамproducts/, где разделы по две строки.
Тут же применяем тест знаков из 8.1 на расхождениях (9 против 3): совпавшие вопросы ничего не говорят о разнице, считаются только те, где варианты разошлись. Здесь p ≈ 0,15, то есть по правилу значимости это пока «тенденция».
Журнал эксперимента
Заголовок раздела «Журнал эксперимента»Всё, что выше, — гипотеза, условия, прогоны, цифры, разбор — должно остаться в одном месте, иначе через неделю не восстановить, что сравнивали. Каждый эксперимент оформляем коротко и одинаково, в experiments/EXP-01-chunking.md:
# EXP-01: chunking fixed512-o64 vs headings (index_fixed512.db vs index_headings.db)Date: 2027-01-05 | dataset <sha> (dev, n=56) | git abc1234
## Hypothesis...
## SetupChanged: chunking. Fixed: embeddings bge-m3, hybrid search, k=5, answer prompt answer_v2, judge judge_v2.Runs: eval/runs/2027-01-05T...
## Results| config | hit@5 | MRR | correctness | faithfulness | ctx tokens | cost/100q | p50 latency ||---|---|---|---|---|---|---|---|
Paired hit@5: improved 9 / regressed 3, sign test p=0.15
## AnalysisWhere it helped / hurt, examples (question ids), by type, by category, by tags (table, similar_products).
## ConclusionAccept / reject / trend. Next step.Из этих журналов потом собирается таблица в README (8.5).
DeepSeek и Ollama: как это сделать у нас
Заголовок раздела «DeepSeek и Ollama: как это сделать у нас»Теория не зависела от провайдера; на нашем стеке у неё есть две практические стороны: чем строить два индекса и как размер кусков отражается на ответчике и его цене. Чанкинг — эксперимент про поиск, и главный провайдер здесь не DeepSeek, а модель эмбеддингов. Сверено в ноябре 2026 по api-docs.deepseek.com и docs.ollama.com.
Эмбеддинги для двух индексов — локально
Заголовок раздела «Эмбеддинги для двух индексов — локально»Эндпоинта эмбеддингов в официальной документации DeepSeek нет, поэтому оба индекса строятся локально: Ollama (/api/embed) или Sentence Transformers — тем же бэкендом, что индекс недели 4 (EMBED_BACKEND, EMBED_MODEL). Деньги это не стоит, стоит времени, и это хорошо для эксперимента: перестроить индекс с другим размером кусков можно сколько угодно раз. База знаний публичная, но правило проекта прежнее: настоящие сообщения клиентов в облако не уходят.
# illustrative: build index B with the same embedding model as index Aimport ollama
EMBED_MODEL = "bge-m3" # fixed in config for both indexes; never change it together with chunking
def embed_batch(texts: list[str]) -> list[list[float]]: # /api/embed returns L2-normalized vectors return ollama.embed(model=EMBED_MODEL, input=texts)["embeddings"]Ловушка, которой нет у облачных эмбеддингов: окно модели эмбеддингов. У каждой модели эмбеддингов ограниченный контекст: у bge-m3 8192 токена, у embeddinggemma 2K, у маленьких моделей бывает всего несколько сотен токенов. Если кусок длиннее, хвост может быть отброшен при вычислении эмбеддинга, и это ломает сравнение: вариант «по заголовкам», где таблица тарифов — неделимый атом в конце раздела, будет искаться только по началу куска. Перед построением индекса:
- смотрим контекст модели:
ollama show <model>или страница модели на ollama.com/library; - считаем, сколько кусков каждого индекса длиннее этого окна;
- помним про
truncate: по справочнику API Ollama у/api/embedон по умолчаниюtrue, то есть вход длиннее окна молча обрезается (какая часть отбрасывается, справочник не уточняет). Сtruncate: falseпридёт ошибка — для эксперимента это лучше, так мы узнаем о каждом слишком длинном куске. promptfoo, например, специально шлётtruncate: false.
Если в варианте B много кусков длиннее окна, это не «чанкинг по заголовкам хуже», а «модель эмбеддингов не видит конец куска». Либо ограничиваем размер куска окном модели, либо берём модель с большим окном для обоих индексов.
Генерация и судья
Заголовок раздела «Генерация и судья»Ответчик и судья не меняются (deepseek-flash и deepseek-v4-pro без thinking, как в главе 6.4 · Скрипт оценки: retrieval + faithfulness). Два эффекта от размера кусков:
- Стоимость DeepSeek растёт с токенами контекста, а кеш почти не помогает: в кеш попадает общий префикс (системный промпт), а куски у каждого вопроса свои. Считаем «$ / 100 q» через
eval/cost.pyс полями кеша и временем пик/вне пика; прогоны A и B делаем в одно и то же окно цен, иначе разница в цене будет про время суток. - Если ответчик локальный, крупные куски могут не влезть в контекст сервера Ollama (по умолчанию 4k токенов, если видеопамяти меньше 24 ГБ) — проиграет вариант с более длинным контекстом, из-за обрезки, а не из-за чанкинга. Проверяем
ollama ps; подниматьOLLAMA_CONTEXT_LENGTHна машине с 8 ГБ можно лишь осторожно, поэтому для этого эксперимента ответчиком лучше оставитьdeepseek-flash.
Сравнение провайдеров для этой главы
Заголовок раздела «Сравнение провайдеров для этой главы»| Что нужно эксперименту | Claude | OpenAI | DeepSeek | Ollama |
|---|---|---|---|---|
| Эмбеддинги для индексов | своих нет | эндпоинт эмбеддингов, платно | в документации нет | /api/embed, бесплатно, локально |
| Стоимость перестройки индекса | — | за токены | — | $0, только время |
| Риск обрезки длинного куска | — | лимит модели смотрим в документации | — | окно модели эмбеддингов; поведение truncate проверяем |
| Генерация на крупных кусках | платим за вход | платим за вход | платим за вход, кеш почти не помогает | бесплатно, но нужен достаточный контекст сервера |
Практика этой главы делается без изменений в дизайне: оба индекса на одной локальной модели эмбеддингов, генерация и судья на DeepSeek. Отдельным экспериментом позже можно сравнить и модели эмбеддингов (например, две модели из библиотеки Ollama) — но не вместе с чанкингом.
Маршрут изучения
Заголовок раздела «Маршрут изучения»- Перечитываем свои итоги 4.3 в
experiments/chunking/RESULTS.md(≈10 мин): какая стратегия выиграла на 10 вопросах и почему. Это исходная точка для гипотезы. - Открываем Pinecone: Chunking strategies → разделы про структурный (document-specific) чанкинг и выбор размера (≈20 мин). Обратим внимание на мысль, что размер зависит от длины запросов и от того, что делается с найденным дальше.
- Открываем Anthropic: Contextual Retrieval → раздел, где добавление контекста к куску сравнивается с обычным (≈15 мин). Это обоснование варианта B’ и пример того, как оформлять сравнение с цифрами.
- Открываем Hamel: A Field Guide to Rapidly Improving AI Products → раздел про эксперименты и порядок работы (≈20 мин): почему сначала разбор ошибок, потом изменение, потом измерение.
- Перечитываем правило значимости из 8.1 (≈5 мин) и держим его перед глазами при выводе.
- Открываем Ollama: Embeddings и справочник Ollama API: /api/embed (≈15 мин). Находим параметр
truncate(по умолчаниюtrue) и полеprompt_eval_count; выписываем контекст своей модели эмбеддингов (ollama show <model>).
На что обратить внимание
Заголовок раздела «На что обратить внимание»- Изменение двух вещей сразу (чанкинг и k, или чанкинг и промпт) делает вывод невозможным: непонятно, что сработало.
- Крупные куски выигрывают hit@k «бесплатно». Сравниваем при равном бюджете контекста или показываем токены. В
kb/крупнее обычно куски fixed, а не заголовков. - Цитата разрезана границей куска — ложный промах поиска; проверяем до прогона.
- Таблицы тарифов и сроков гарантии: если чанкер режет markdown-таблицу, кусок «| 1–3 | 350 ₽ | 470 ₽ |» без шапки и пути раздела бесполезен. Проверяем глазами несколько кусков нового индекса, прежде чем гонять evals.
- Похожие товары: кусок «Гарантия — 6 месяцев» без названия одинаково близок к «Свет» и «Свет мини»; различает их путь заголовков.
- Микро-разделы страниц товаров («## Уход» из двух строк) засоряют выдачу — склеиваем с соседом.
- Смена загрузки текста вместе с чанкингом (иначе обработан front matter, вырезан повторяющийся блок «Остались вопросы?») — это второе изменение.
rag/load.pyдолжен быть одинаковым. - Смена модели эмбеддингов вместе с чанкингом — второе изменение.
embed_modelв конфиге одинаковый у обоих индексов. - Модель эмбеддингов не видит конец длинного куска. Окно локальной модели эмбеддингов может быть короче кусков варианта B. Считаем заранее, сколько кусков длиннее окна.
- Потерянные метаданные: без
archivedу новых кусковarchived_in_contextперестанет быть нулём. - Прогон на holdout в этом эксперименте не нужен: holdout — только для финальной конфигурации.
- Рапорт «стало лучше на 4 п.п.» без разброса — нарушение собственного правила из 8.1.
- Прогоны A и B в разные окна цен DeepSeek — «стоимость» начинает зависеть от времени суток. Запускаем подряд или пересчитываем по одной цене.
Практика
Заголовок раздела «Практика»- Создаём
experiments/EXP-01-chunking.mdи до любых прогонов записываем гипотезу: что меняем, какая метрика, ожидаемая величина, механизм. - Выписываем контекст своей модели эмбеддингов (
ollama show <model>) и в конфиги прогонов добавляем"embed_model"(точный тег Ollama); проверяем, что он одинаковый уchunk_fixed512.jsonиchunk_headings.json. - Строим оба индекса рядом с
index.db:index_fixed512.dbиindex_headings.db(ingest.pyс параметрами стратегии и файла индекса); та же загрузкаkb/, те же эмбеддинги,truncate: false, чтобы слишком длинный кусок падал с ошибкой, а не обрезался молча. Читаем глазами по 10 кусков каждого, включаяdelivery.md,warranty.mdи лампы. - Считаем для обоих индексов: число кусков, средний и максимальный размер в токенах, сколько таблиц разрезано и сколько кусков длиннее окна модели эмбеддингов. Записываем в журнал эксперимента.
- Проверка цитат: для каждого вопроса находим релевантные куски в обоих индексах по
evidence; выписываем вопросы, где цитата не находится ни в одном куске. - Добавляем в
eval/run.pyфлаг--retrieval-onlyи полеctx_tokens(токенов контекста на вопрос). - Прогоняем только поиск для: fixed k=5, headings k=5, headings с k под равный бюджет контекста.
- Полный прогон (с генерацией и судьёй) для baseline и лучшего варианта; если уже есть 3 прогона baseline из 8.1, делаем 3 прогона и варианта (или минимум 1 и сравниваем с разбросом). Оба полных прогона делаем в одном окне цен DeepSeek (пик или вне пика), стоимость считаем
eval/cost.pyс полями кеша. -
eval/compare.py: парное сравнение hit@5 и correctness, тест знаков, срезы поtype,categoryи тегам (table,similar_products). - Таблица переходов hit/miss; читаем все улучшения и регрессии, выписываем по 2–3 характерных примера (id вопроса + объяснение).
- Заполняем разделы Results, Analysis, Conclusion. Вывод формулируем по своему правилу: принято / отклонено / тенденция.
- Добавляем строку в таблицу экспериментов (
experiments/README.mdили будущий README проекта).
Готово, когда
Заголовок раздела «Готово, когда»- Гипотеза записана до прогона, с механизмом и ожидаемой величиной.
- Есть строка в таблице экспериментов: hit@5, MRR, correctness, faithfulness, токены контекста, стоимость, латентность, разброс, расхождения +/−, вывод.
- В журнале перечислены конкретные вопросы, где разница, и объяснение почему.
-
archived_in_contextравен 0 в прогонах обоих вариантов.
Тест для самопроверки
Заголовок раздела «Тест для самопроверки»Вопрос 1
Какие три части обязательны в хорошей гипотезе?
Что меняется; какая метрика и на сколько должна сдвинуться; механизм (почему).
Вопрос 2
Почему нельзя одновременно менять чанкинг и k?
Нельзя будет понять, какое изменение дало эффект; эксперимент должен менять одну переменную.
Вопрос 3
Вариант с кусками по 1500 токенов дал hit@5 выше, чем по 500. Почему это ещё не значит, что он лучше?
Крупные куски при том же k покрывают больше текста: это больший контекст, а не лучший поиск; растут стоимость, латентность, и модель хуже находит нужное в длинном контексте.
Вопрос 4
Какие два способа позволяют честно сравнить стратегии чанкинга?
Сравнивать при равном бюджете контекста (подобрать k по токенам) или показывать hit@k вместе со средним числом токенов контекста.
Вопрос 5
Почему для эксперимента с чанкингом нужны цитаты evidence, а не source_chunk_keys?
chunk_key = sha256(url + section + text) меняется при новом разбиении, ключи из набора в новом индексе не существуют; цитата позволяет найти релевантные куски в любом индексе.
Вопрос 6
Таблица переходов: A hit → B miss = 3, A miss → B hit = 9. Что делать с этими числами?
b. 9:3 может быть шумом (p ≈ 0,15); нужно проверить тестом знаков и прочитать вопросы, чтобы понять механизм улучшений и причины регрессий.
Вопрос 7
Hit@5 вырос на 12 п.п., correctness не изменилась. Как это интерпретировать?
Поиск улучшился, но узкое место в генерации (модель не использует найденное, тонет в длинном контексте) или в наборе/судье. Следующий эксперимент — про генерацию; нужен разбор ошибок.
Вопрос 8
Что не так с этим журналом эксперимента?
EXP-01. Поменял чанкинг на заголовки, поправил загрузку текста и увеличил k до 8.hit@8 = 0.91 (было hit@5 = 0.78). Стало лучше, оставляю.Три изменения сразу (чанкинг, загрузка текста, k); метрики не сравнимы (hit@8 против hit@5); нет гипотезы, разброса, парного сравнения, correctness, стоимости, токенов контекста и анализа по вопросам.
Вопрос 9
Зачем хранить оба индекса одновременно?
Для воспроизводимости и быстрых сравнений: любой прогон можно повторить, к baseline можно вернуться без пересборки.
Вопрос 10
Как быстро и дёшево перебрать несколько размеров кусков?
Прогон только поиска (--retrieval-only): он детерминирован и не требует генерации и судьи; полный прогон — только для финалистов.
Вопрос 11
Вариант «по заголовкам» с таблицами-атомами неожиданно проиграл по hit@5 на вопросах про тарифы, хотя глазами куски выглядят лучше. Какая причина специфична для локальных эмбеддингов и как её проверить?
Окно модели эмбеддингов короче куска: по умолчанию /api/embed молча обрезает длинный вход (truncate: true), эмбеддинг считается по началу куска, и таблица тарифов в конце раздела в поиске не участвует. Проверить контекст модели (ollama show), долю кусков длиннее окна и поведение truncate; при необходимости ограничить размер куска (длинную таблицу резать по строкам с повтором шапки) или взять модель с большим окном для обоих индексов.
Вопрос 12
Почему автоматический кеш DeepSeek почти не снижает стоимость ответов в этом эксперименте?
Кеш срабатывает на совпадающем префиксе запросов, а это в основном системный промпт; куски контекста у каждого вопроса разные и идут по цене кеш-промаха.
Что дальше
Заголовок раздела «Что дальше»Следующий эксперимент меняет не поиск, а модели: в 8.3 · Эксперимент: модели и реранкер сравниваем большую и маленькую модель и вариант с реранкером по качеству, цене и скорости.