Это первая часть из задуманной серии статей про ИИ. Здесь мы на немного заступим в техническую часть памяти/контекста LLM моделей. Разберем, почему они частенько забывают или выдумывают факты и врут.
Как attention ломается на длинном контексте
Начнём с фундамента. Трансформер работает на self-attention - каждый токен смотрит на все остальные и решает, на что обратить внимание. Квадратичная сложность O(n²) - это причина, по которой модели вынуждены использовать оптимизации: FlashAttention-2/3, RoPE, ALiBi и прочее.
Эти оптимизации не бесплатны. Они создают позиционные смещения:
- Primacy bias - модель лучше всего помнит начало контекста
- Recency bias - и конец тоже помнит неплохо
- Всё, что в середине - получает ослабленное внимание
Представьте, что вы читаете книгу на 500 страниц за один присест. Первую главу помните, последнюю помните, а что было на странице 247? Модель работает примерно так же, только она ещё и не признается, что забыла - вместо этого уверенно додумает.)
Lost-in-the-Middle
Классическую работу Nelson Liu и коллег из Stanford (2023) знают, наверное, все, кто работает с RAG. U-образная кривая: точность падает на 30-50%, когда нужная информация оказывается в середине контекста из 20-30 документов.
С 2023 года модели конечно стали лучше, но проблема все еще остается.
В 2025-2026 годах команды из MIT и других лабораторий подтвердили: эффект Lost-in-the-Middle сохраняется даже у моделей с окном 1M+ токенов. Причина архитектурная - causal attention masking плюс decay в positional embeddings (тот самый RoPE). Чем длиннее окно, тем больше середина, и тем сильнее bias.
Проще говоря, увеличивая контекстное окно, мы не решаем проблему - мы увеличиваем зону, где модель тупит и забывает.
Бенчмарки 2025-2026
Needle-in-a-Haystack - тест Грега Камрадта из 2023-го. Спрячь факт в длинном тексте, спроси модель - найдёт или нет. Простой, наглядный, убедительный.
К 2025-2026 годам он превратился в целое семейство бенчмарков:
- U-NIAH (2026) - напрямую сравнивает long-context LLM и RAG
- NeedleBench, BABILong, LooGLE - проверяют не просто поиск одного факта, а синтез информации из разных частей контекста
Почему галлюцинации растут с длиной контекста
Появляется логичный вопрос, почему модель врет, а не говорит “хз”.
Вот три ключевых наблюдения из свежих исследований:
Vectara Hallucination Leaderboard (HHEM-2.3, февраль 2026): на документах 32K+ токенов уровень галлюцинаций стабильно выше, чем на коротких. Модели начинают додумывать связи между фактами, которых в тексте нет. Они видят фрагмент A и фрагмент C, не видят B посередине - и изобретают собственный B.
OpenAI research (декабрь 2025), “When More Becomes Less”: рост контекста увеличивает стоимость инференса, но не качество. Модель получает частичные доказательства и заполняет пробелы правдоподобно. Это буквально определение галлюцинации.
MIT (январь 2025): самое забавное и неприятное открытие - модели используют более уверенный язык именно при галлюцинациях в длинном контексте. Чем меньше модель видит реальный факт, тем увереннее она его выдумывает.
Если упростить: Длинный контекст -> больше шума -> внимание размывается -> модель не находит нужный факт -> но обучена всегда давать ответ -> начинает креативничать
Это не баг конкретной модели. Это следствие того, как работает архитектура трансформера в сочетании с RLHF, который учит модель быть полезной(всегда отвечать)
Что помогает в продакшене
Теперь немного техники
Chunking - 70% успеха RAG
Если у вас проблемы с галлюцинациями в RAG-системе, первое, на что стоит смотреть - это как вы нарезаете документы.
Не доверяйте дефолтному сплиттеру.
- RecursiveCharacterTextSplitter (LangChain) - рабочая лошадка. 400-512 токенов, overlap 10-20%. Простой, предсказуемый, хорошо работает на структурированных текстах.
- SemanticChunker - разбивает по смыслу через эмбеддинги. Даёт +15-20% точности на сложных документах, где логические блоки не совпадают с абзацами.
- HierarchicalNodeParser (LlamaIndex) - многоуровневые чанки (2048 → 512 → 128). Позволяет сначала найти нужный раздел, потом нужный абзац, потом нужное предложение.
Ключевая идея - не запихивайте в контекст модели 100K токенов “на всякий случай”. Дайте ей 3-5 релевантных чанков по 500 токенов. Меньше мусора - меньше галлюцинаций.
Пример chunking + reranking
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.retrievers import ContextualCompressionRetriever
from langchain_community.embeddings import HuggingFaceEmbeddings
from langchain_community.vectorstores import FAISS
# 1. Recursive + overlap
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=512,
chunk_overlap=100, # ~20%
separators=["\n\n", "\n", ". ", " ", ""]
)
# 2. Semantic splitter (для сложных документов)
from langchain.text_splitter import SemanticChunker
embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-mpnet-base-v2"
)
semantic_splitter = SemanticChunker(embeddings)
# 3. Reranking
from langchain.retrievers.document_compressors import CrossEncoderReranker
compressor = CrossEncoderReranker(
model_name="BAAI/bge-reranker-large"
)
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=vectorstore.as_retriever(
search_kwargs={"k": 20} # Достаём 20, reranker оставит топ-5
)
)
Достаём 20 чанков, reranker отбирает топ-5. Это критически важно. Без reranking вы отправляете в модель кучу почти релевантных чанков, которые только добавляют шума.
Verification layers
Даже с идеальным chunking модель может галлюцинировать. Поэтому нужен второй эшелон обороны.
Self-Consistency / Chain-of-Verification (CoVe) - просим модель сгенерировать ответ, потом сгенерировать вопросы для проверки этого ответа, потом ответить на эти вопросы.
Critic Agent - отдельный LLM (можно дешёвый и маленький) проверяет ответ на соответствие контексту. “Вот контекст, вот ответ. Всё ли в ответе подтверждается контекстом? Да/Нет + объяснение.”
Symbolic verification - после генерации прогоняем через Knowledge Graph или Pydantic-схему с Guardrails. Если ответ содержит дату, число, имя - проверяем программно.
Agentic workflows
Это уже паттерн 2026 года. Вместо одного вызова “контекст -> ответ” строим цикл из нескольких агентов:
- Planner - разбивает задачу на подзадачи
- Retriever Agent - ищет по чанкам для каждой подзадачи отдельно
- Executor - генерирует ответ
- Verifier Agent - проверяет и возвращает на доработку, если что-то не сходится
Это дороже. Это медленнее. Но в продакшене, где галлюцинация стоит денег или репутации - это окупается.
Вот минимальный пример verification loop:
from langchain.agents import create_react_agent, AgentExecutor
from langchain.tools import Tool
def verify_answer(answer: str, context: str) -> str:
"""Отдельная модель-критик проверяет ответ"""
prompt = (
"Проверь, соответствует ли ответ контексту. "
"Ответь YES/NO + объяснение.\n"
f"Context: {context}\n"
f"Answer: {answer}"
)
return llm.invoke(prompt)
tools = [
Tool(
name="Verifier",
func=verify_answer,
description="Проверяет ответ на соответствие контексту"
)
]
agent = create_react_agent(llm, tools, prompt=react_prompt)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
max_iterations=5 # Не больше 5 попыток
)
Hybrid neuro-symbolic
Для доменов с жёсткими требованиями к точности - юриспруденция, медицина, финансы - есть ещё один уровень.
Комбинация LLM + Knowledge Graph + symbolic verifier. Идея простая, LLM генерирует ответ, Knowledge Graph проверяет факты и связи, symbolic verifier валидирует логику.
Исследования 2025 года показывают снижение галлюцинаций на 60-80% в таких доменах. Но это тяжёлая инфраструктура. Нужен граф знаний, нужны правила, нужна команда, которая всё это поддерживает.
Если у вас чат-бот для интернет-магазина - это overkill.
По итогу: суй меньше - получишь лучше) Если данная статья была для вас интересна, но перегружена терминами - дайте знать, и я подготовлю версию, где простым языком все объясню.