Привет, Хабр! На связи команда Optimal Cognitive Core (OCC) из AIRI. Развитие языковых моделей в последние годы определяется масштабом: каждое новое поколение вмещает в веса всё больше знаний о мире. Но огромная доля практических задач выигрывает тогда, когда модель демонстрирует не свою энциклопедичность, а способность рассуждать и анализировать предоставленный контекст. Из этого наблюдения и выросло OCC — наше семейство компактных языковых моделей (SLM), которые имеют сильные когнитивные способности, не обладая при этом большим багажом «вызубренной» информации.

В этой статье расскажем о первой модели нашего семейства, OCC‑RAG, которая оптимизирована под задачу контекстного Q&A. Мы выложили два чекпойнта, OCC‑RAG-0.6B и OCC‑RAG-1.7B (плюс ONNX‑ и GGUF‑сборки). При размере 0.6 и 1.7 млрд параметров, соответственно, они отвечают на равных или лучше моделей общего назначения, которые в 2–6 раз больше, а по верности контексту показывают лучший результат среди моделей до 32B (см. рис. 1). Далее — о том, как устроена модель, как мы её обучили и что в итоге получилось.

Рис. 1. Трейд‑офф «качество / размер»: OCC‑RAG-0.6B и 1.7B против Qwen3, Gemma3, SmolLM3.
Рис. 1. Трейд‑офф «качество / размер»: OCC‑RAG-0.6B и 1.7B против Qwen3, Gemma3, SmolLM3.

Контекстный QA, и зачем в нём нужна честность

Контекстный QA (Context QA) — это постановка, в которой модель отвечает на вопрос на основе переданного ей контекста. Контекстом может быть один или несколько документов, инструкция, выписка из базы знаний или финансовый отчёт; словом, всё, что подаётся модели вместе с вопросом.

Ключевое требование к такой системе — faithfulness, то есть верность контексту: ответ должен опираться только на предоставленные источники. Это важно, потому что в реальных сценариях именно контекст несёт актуальную и проверяемую информацию. Это могут быть внутренние документы, свежие отчёты, ну и вообще любая специфика конкретной компании. Если модель подменяет их памятью, ответ перестаёт быть проверяемым и может молча устареть или исказиться.

Звучит просто, но на практике это больное место даже для больших моделей. Хорошо известно, что LLM склонны доверять собственным параметрическим знаниям больше, чем тому, что написано в контексте. А на каверзных сценариях — скажем, когда информация меняется во времени, источники противоречат друг другу, или контекст вовсе оказывается без ответа — срываются и самые сильные модели.

Как пример, рассмотрим немного игрушечный сценарий. Представьте, что есть некий источник, где написано утверждение, противоречащее общеизвестным фактам: «в 2022 году Шарль де Голль был избран первым президентом США». Мы подаём модели в контекст этот источник и задаём вопрос «Кто первый президент США?». Здесь возможны три типа поведения. Модель может ответить «де Голль» — для нас это корректное поведение (faithful), она честно следует контексту. Может ответить «Джордж Вашингтон» — формально это правда (truthful), но контекст проигнорирован. А может выдать что‑то третье, чего в источниках нет, — это галлюцинация.

В нашем эксперименте (см. рис. 2) крупная Llama-3.3–70B‑Instruct отвечает по контексту («де Голль»), средняя Llama-3-8B‑Instruct сваливается в память («Джордж Вашингтон»), а маленькая Llama-3.2–1B‑Instruct галлюцинирует («Дональд Трамп»). При этом OCC‑RAG-1.7B, несмотря на свой размер, ведёт себя как большая faithful‑модель и отвечает строго по источнику.

Рис. 2. Faithful / Truthful / Hallucination на примере конфликта «контекст ↔ память».
Рис. 2. Faithful / Truthful / Hallucination на примере конфликта «контекст ↔ память».

Из этого складываются три навыка, которыми обязана обладать сильная Context QA‑модель:

  1. Сильные multi‑hop и commonsense рассуждения: объединение фактов из разных фрагментов контекста и выстраивание логических связей.

  2. Следование контексту: опора только на предоставленные источники, а не на память.

  3. Калиброванный отказ: честно сказать «информации недостаточно», когда контекст не содержит ответа.

Как получить такую модель?

Итак, нам нужна компактная модель, обладающая сразу тремя свойствами выше. Из чего её собрать? Наш рецепт состоит из трёх частей, и дальше мы пройдёмся по каждой:

  1. Данные: огромный синтетический корпус, который прицельно тренирует multi‑hop рассуждение, верность контексту и отказ.

  2. Формат рассуждения: структура ответа модели, которая делает все три навыка обучаемыми на уровне токенов, а не оставляет их «в уме» у модели.

  3. Mid‑training: непосредственно обучение модели, которое прививает эти навыки исходной модели.

Данные: синтетический корпус

Это, пожалуй, главный вклад работы. Открытые QA‑датасеты, как правило, маленькие и не таргетируют faithfulness напрямую: модели учатся отвечать, но не обязательно следовать контексту. Поэтому мы построили собственный пайплайн генерации данных.

Простые вопросы

Сначала мы генерируем single‑hop вопросы, где ответ опирается на один факт из одного источника. Это самый дешевый и массовый слой данных, их генерируем прямо из абзацев Википедии, добавляя дистракторы (источники, похожие на тот, в котором содержится нужная информация, но не содержащие её) по графу ссылок и отсеивая неточные пары LLM‑судьёй. Отдельно сразу генерируем примеры, где модель должна отказаться давать ответ: берем исходный пример, урезаем контекст, удаляя корректный источник, и проверяем сильной экстрактивной моделью (DeBERTa, дообученной на SQuAD), — если ответ из урезанного контекста уже не достаётся, значит, критичный факт пропал, и пример помечается как требующий отказа.

Сложные вопросы: генерация по графу знаний

Дальше самое сложное: вопросы, где ответ нужно собрать из нескольких фактов. Чтобы они были «настоящими», мы извлекаем из текстов граф знаний методом Wikontic (про него на Хабре уже выходил отдельный пост от наших коллег). Граф знаний — это набор фактов в виде троек или триплетов: «сущность — отношение — сущность». Например, факт «Морти Смита озвучил Кэйсукэ Тиба» записывается как («Морти Смит» | озвучен | «Кэйсукэ Тиба»). Сущности здесь — узлы графа, а отношения — рёбра между ними; «мульти‑хоп» как раз и означает путь по нескольким таким рёбрам (см. рис. 3).

Рис. 3. Какие триплеты берем и как они соединяются.
Рис. 3. Какие триплеты берем и как они соединяются.

Вопросы мы генерируем по путям в этом графе, структуру каждого вопроса задаёт шаблон обхода по графу: какие триплеты берём и как они соединяются. Для генерации разнообразных по смыслу вопросов мы опираемся на таксономию из работы DRAGOn:

  • Simple: один триплет по отношению и одной сущности спрашиваем вторую. Фактически, это те же самые single‑hop вопросы, о которых шла речь ранее.
    Пример: «Кто озвучил Морти Смита?»

  • Set: несколько триплетов с общими сущностью и отношением; ответ — всё множество объектов, и его приходится собирать из разных источников.
    Пример: «Для каких проектов Райан Оттер написал музыку?»

  • Multi‑Hop: триплеты сцепляются через общую «мостиковую» сущность: назвать её напрямую нельзя, она задаётся описанием из другого факта.
    Пример: «В какой стране находится компания, продавшая 2139 автомобилей в 2023 году?»

  • Conditional: та же цепочка, но «мостиковая» сущность доопределяется дополнительным ограничением — по значению, дате и тому подобное.
    Пример: «В каком городе родился режиссёр фильма, получившего „Оскар“ в год рождения Леонардо Ди Каприо?»

  • Bamboo: три триплета, нанизанных в линейную цепочку через две «мостиковые» сущности.
    Пример: «В каком городе родился режиссёр дебютного фильма актёра, сыгравшего главную роль в „Начале“?»

Поскольку путь в графе задан заранее, верный ответ фиксируется самим путём, а не выходом генератора. Таким образом, снимается проблема, когда сложный вопрос также сложно и проверить.

В процессе генерации мы столкнулись с поучительной проблемой. В первых версиях все мульти‑хоп вопросы были single‑context: шагов рассуждения несколько, но все нужные факты лежали в одном источнике, а прочие источники служили лишь дистракторами. На таких данных модель училась хорошо — но почти не генерализовалась на multi‑context, когда факты для цепочки разнесены по разным источникам. А именно этот случай чаще всего и встречается в реальных RAG‑сценариях. В ретроспективе всё очевидно, но на практике это оказалось заметным барьером. Решение — разбивать контекст специальным образом, чтобы соседние шаги цепочки попадали в разные источники, и генерировать отдельный тип multi‑context мульти‑хопов. Добавление их в обучение дало ощутимый скачок качества.

Важное свойство нашего пайплайна: он позволяет генерировать данные из любых неструктурированных документов в практически неограниченном количестве (ограниченном только размером этих источников и вашим бюджетом).

Итоговый корпус для обучения — около 3.25 млн QA‑пар (≈ 8 млрд токенов): ~2.78M single‑hop, 262k multi‑hop в одном контексте, 165k multi‑hop с несколькими контекстами и 43k примеров на отказ (см. рис. 4).

Рис. 4. Бюджет токенов по подмножествам корпуса и их состав (gold / distractor / reasoning).
Рис. 4. Бюджет токенов по подмножествам корпуса и их состав (gold / distractor / reasoning).

Формат рассуждений

Чтобы три целевых навыка были обучаемы на уровне токенов, мы обогащаем каждый пример явными рассуждениями модели в строгом формате. Ответ модели всегда состоит из пяти секций со своими токенами‑разделителями (см. рис. 5):

  • Query Analysis — что именно спрашивает пользователь, какие сущности и отношения участвуют.

  • Source Analysis — какие предоставленные источники релевантны и что каждый даёт; цитирование источников происходит при помощи введения специальных токенов <|source_id|>N.

  • Reasoning — как факты из источников складываются в multi‑hop цепочку до ответа.

  • Status — дискретный вердикт: можно или нельзя ответить на вопрос.

  • Answer — финальный ответ либо отказ.

Секция Status появилась осознанно: мы хотели, чтобы решение «отвечать или отказаться» было явной дискретной меткой, к которой модель приходит до самого ответа, а не извлекалось задним числом из формулировки. А цитаты в ответе — это буквальные фрагменты контекста с привязкой к номеру источника. В сумме получается прозрачность, при этом токенов наша модель тратит примерно в полтора раза меньше, чем при полноценных рассуждениях обычной модели.

Рис. 5. Структура вывода OCC‑RAG: Query Analysis → Source Analysis → Reasoning → Status → Answer.
Рис. 5. Структура вывода OCC‑RAG: Query Analysis → Source Analysis → Reasoning → Status → Answer.

Сами цепочки ответов для обучения мы дистиллируем из более крупной модели и затем фильтруем в несколько ступеней: проверяем формат, сверяем ответ с правильным, перепроверяем LLM‑судьёй и режем слишком переусложнённые рассуждения.

Mid‑training

Мы не обучаем модель с нуля, а стартуем с готовой базовой модели. Из открытых семейств сравнили Qwen3, Gemma3 и SmolLM3 на отложенном QA‑срезе; Qwen3 дал лучший результат при фиксированном бюджете вычислений, поэтому оба наших чекпойнта — это mid‑training поверх Qwen3-0.6B‑Base и Qwen3-1.7B‑Base.

Обучаем через SFT. Промпт — это вопрос плюс контексты в случайном порядке, каждый с числовым id. Для разделения блоков рассуждений вводим дополнительно специальные обучаемые токены.

Оценка

Переходим к оценке нашей модели. Как и говорилось ранее, мы меряем модель по трём измерениям и используем для этого соответствующие открытые бенчмарки:

  • Multi‑hop reasoning: HotpotQA и MuSiQue (Википедия) и TAT‑QA (табличные финансовые данные). Метрики: In‑Acc (золотой ответ как подстрока предсказания) и F1 для TAT‑QA.

  • Faithfulness: сложный датасет ConFiQA с контрфактическим контекстом. Помимо In‑Acc, считаем Memorization Ratio (MR): как часто модель сваливается в память вопреки контексту. Чем ниже — тем лучше.

  • Refusal: MuSiQue‑Un, версия MuSiQue, где в контексте нет ответа на вопрос. Метрика R‑Acc: доля корректных отказов.

Сравнивались с открытыми семействами Qwen3, Gemma3, SmolLM3 и со специализированной Pleias‑RAG, которая решает ту же задачу, что и мы. Брали все доступные чекпоинты вплоть до 32B (см. таблицу 1). Qwen3 и SmolLM3 также поддерживают thinking‑режим. Результаты с ним отображены в таблице в скобках. Что получилось:

  • Обе OCC‑RAG обходят свои Qwen3-базы по всем датасетам и превосходят Gemma3-1B/4B и SmolLM3-3B на каждом бенчмарке.

  • OCC‑RAG-0.6B обходит Qwen3-1.7B (в 2.8× больше) на 9.5 пункта на ConFiQA и опережает Pleias‑RAG-1.2B на 21.6 пункта на MuSiQue.

    Рис. 6. Сравнение OCC‑RAG-0.6B vs 1–2B и OCC‑RAG-1.7B vs 3–4B
    Рис. 6. Сравнение OCC‑RAG-0.6B vs 1–2B и OCC‑RAG-1.7B vs 3–4B
  • Лучшая faithfulness на всех масштабах до 32B: на ConFiQA обе модели обходят даже Qwen3-32B, а memorization ratio падает с 12.7 (8.3 в thinking) у Qwen3-1.7B до 5.0 у OCC‑RAG-1.7B.

  • По отказам OCC‑RAG-1.7B даёт R‑Acc 87.2 — на уровне моделей 8B+.

    Рис. 5. Сравнение OCC‑RAG-0.6B vs 1–2B и OCC‑RAG-1.7B vs 3–4B
    Таблица 1. Основные результаты: все модели до 32B по трём измерениям (In‑Acc, MR↓, R‑Acc).

Главный вывод из всех цифр простой: хорошего faithfulness’а можно достигнуть и с малыми моделями. Модели 8B+ ещё держат отрыв на чистом multi‑hop reasoning, но он заметно у́же, чем их же отрыв над instruct‑аналогами того же размера, а по верности контексту OCC‑RAG лидирует на всех масштабах.

Как попробовать

Модели лежат на Hugging Face: OCC‑RAG-0.6B и OCC‑RAG-1.7B. Chat‑шаблон принимает аргумент documents= и сам расставляет структурные токены — достаточно передать вопрос обычным текстом, а источники списком словарей. Пример использования:

import re
from transformers import AutoModelForCausalLM, AutoTokenizer
 
MODEL = "occ-ai/OCC-RAG-1.7B"
tokenizer = AutoTokenizer.from_pretrained(MODEL)
model = AutoModelForCausalLM.from_pretrained(MODEL, torch_dtype="auto", device_map="auto")
 
question = "Which country is Alexander Graham Bell buried in?"
documents = [
    {"text": "Alexander Graham Bell was a Scottish-born inventor of the telephone."},
    {"text": "Bell died in 1922 at Beinn Bhreagh, near Baddeck, Nova Scotia, and was buried there."},
    {"text": "Nova Scotia is a province on the east coast of Canada."},
]
 
text = tokenizer.apply_chat_template(
    [{"role": "user", "content": question}],
    documents=documents, tokenize=False,
    add_generation_prompt=True, enable_thinking=False,
)
 
inputs = tokenizer([text], return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_new_tokens=2048)
response = tokenizer.decode(outputs[0][inputs.input_ids.shape[1]:], skip_special_tokens=False)
 
m = re.findall(r"<\|answer_start\|>(.*?)(?:<\|answer_end\|>|\Z)", response, re.DOTALL)
print("Answer:", m[-1].strip() if m else "")   # -> Canada

По умолчанию рекомендуем greedy decoding (do_sample=False). Модели легко заводятся на vLLM и SGLang, тот же documents= доступен из OpenAI-совместимого клиента через chat_template_kwargs. Мы также предоставляем ONNX- и GGUF-сборки; благодаря малому числу параметров, обе модели могут спокойно крутится на скромной инфраструктуре, будь то локальный компьютер или телефон.

Что дальше?

Вывод из текущих экспериментов простой: компактная специализированная модель может быть прозрачной, эффективной и устойчивой к недостающим и противоречивым данным — и при этом не уступать (а где‑то и обходить) моделям, которые на порядок больше.

OCC‑RAG — первая инстанциация идеи «оптимального когнитивного ядра». Сейчас модель отвечает по тому контексту, который ей дали. Следующий шаг — научить систему самостоятельно пользоваться внешними инструментами и находить недостающий контекст, а не полагаться на то, что всё нужное уже лежит во входе. Мы уже работаем над этим — ждите обновлений!

Ссылки

P. S. В нашу команду OCC идет активный набор! Мы ищем ML‑инженеров и исследователей, которые хотят вместе с нами строить компактные языковые модели следующего поколения и доводить свои идеи до реальных рабочих продуктов. Открытую позицию и контакты можете найти здесь: вакансия.

Комментарии (6)


  1. Front-Den
    19.06.2026 06:11

    Спасибо, Интересно!

    А вы думали тоже самое делать с моделями по крупнее? Qwen 8-14b или MoE 35b?


    1. avgalichin Автор
      19.06.2026 06:11

      Добрый день!

      Спасибо за вопрос.

      Наш подход инвариантен к размеру модели, дообучить можно любую. Помимо 0.6B и 1.7B, тестировали и на 4B, ощутимый прирост качества сохраняется. Поскольку мы изначально ориентировались на модели до 4B, большие аналоги не рассматривали. Но в будущем, если будет потребность, расширим линейку.


  1. FireAndIce
    19.06.2026 06:11

    Уже ведь довольно давно есть google Notebook LLM. Ваша чем-то лучше той?


    1. rimidalvv
      19.06.2026 06:11

      А гугловая работает без интернета на своём оборудовании?


    1. TomskDiver
      19.06.2026 06:11

      Вы конфиденциальные данные кидаете в goole notebook llm? В закрытом контуре, когда нет Интренета вы как хостите у себя goole notebook llm? Ну и вы сравниваете сервис и языковую модель. Это как сравнить Gmail и SMTP.


  1. DzenO
    19.06.2026 06:11

    Штука интересная. Думаю нужно попробовать и сравнить с действующим механизмом rag по корпоративным документам. Вопрос даже не том что модель меньше, тут главное что она честная, если не знает то так итсаажет. А если применять гибридный подход большая ллм+маленькая для корпоративных доков ... нужно пробовать