Глава 8: Работа с контекстом
Принцип
Контекст — ограниченный ресурс. Эффективное использование контекстного окна определяет качество ответа.
Лимиты контекста
| Модель | Контекст | ≈ Страниц A4 |
|---|---|---|
| GPT-4 Turbo | 128K токенов | ~200 |
| Claude 3 | 200K токенов | ~300 |
| Gemini 1.5 Pro | 1M токенов | ~1500 |
Оценка размера
Коэффициент языка :
-
Английский: 1.0
-
Русский: 1.5-2.0
-
Код Python: 0.8-1.0
-
JSON: 0.9
def estimate\_tokens(text: str, lang: str = 'en') -\> int:
"""Грубая оценка числа токенов."""
k = \{'en': 1.0, 'ru': 1.7, 'code': 0.9\}
return int(len(text) / 4 \* k.get(lang, 1.0))
Проблема "Lost in the Middle"
Информация в середине длинного контекста получает меньше внимания.
Визуализация attention
Позиция в контексте:
Начало ████████████████ Высокий attention
Середина ████░░░░░░░░░░░░ Низкий attention ← проблемная зона
Конец ████████████████ Высокий attention
Стратегии решения
Пример 1: Критичное — в начало и конец
"КЛЮЧЕВЫЕ ТРЕБОВАНИЯ:
- Формат: JSON
- Только уязвимости безопасности
КОНТЕКСТ:
$500 строк кода$
НАПОМИНАНИЕ:
- Формат: JSON
- Только уязвимости безопасности"
Пример 2: Резюме перед деталями
"РЕЗЮМЕ ЗАДАЧИ:
Найти SQL injection в функции get\_user()
ПОЛНЫЙ КОД:
$весь код$
ФОКУС: функция get\_user(), строки 45-60"
Пример 3: Структурированные секции
"\#\# ЗАДАЧА
$описание$
\#\# КРИТИЧНЫЙ КОНТЕКСТ
$самое важное$
\#\# ДОПОЛНИТЕЛЬНЫЙ КОНТЕКСТ
$менее важное$
\#\# ФОРМАТ ОТВЕТА
$структура$"
Сжатие контекста
Техники сжатия
Пример 1: Сигнатуры вместо реализаций
Вместо:
\`\`\`python
class UserService:
def \_\_init\_\_(self, db: Database):
self.db = db
self.cache = \{\}
self.logger = logging.getLogger(\_\_name\_\_)
async def get\_user(self, user\_id: int) -\> User | None:
if user\_id in self.cache:
return self.cache$user\_id$
user = await self.db.fetch\_one(
"SELECT \* FROM users WHERE id = $1",
user\_id
)
if user:
self.cache$user\_id$ = User(\*\*user)
return self.cache.get(user\_id)
\# ... ещё 200 строк
Сжато:
class UserService:
async def get\_user(self, user\_id: int) -\> User | None: ...
async def create\_user(self, data: UserCreate) -\> User: ...
async def update\_user(self, user\_id: int, data: UserUpdate) -\> User: ...
async def delete\_user(self, user\_id: int) -\> bool: ...
Пример 2: Схема вместо данных Вместо:
Сжато: "Данные: JSON массив объектов Схема: {'id': int, 'name': str, 'email': str, 'created_at': datetime} Размер: 1000 записей Особенности: email уникален, created_at в ISO формате"
Пример 3: Описание вместо кода Вместо:
Сжато: "Архитектура:
-
models.py: User, Order, Product (SQLAlchemy)
-
services.py: UserService (CRUD), OrderService (create, process, cancel)
-
api.py: REST endpoints, FastAPI router
-
Зависимости: services инжектятся в api через Depends"
\#\#\# Когда сжимать
| Ситуация | Решение |
|----------|---------|
| Нужен обзор архитектуры | Сигнатуры + описание |
| Нужно изменить конкретную функцию | Полный код функции + сигнатуры остального |
| Нужен анализ данных | Схема + примеры (3-5 записей) |
| Отладка конкретного бага | Релевантный код + traceback |
\#\# Chunking (разбиение)
\#\#\# Когда применять
- Документ больше контекстного окна
- Нужна обработка по частям
- Задача допускает инкрементальную обработку
\#\#\# Стратегии разбиения
Пример 1: Фиксированный размер "Документ разбит на части по 2000 токенов. Часть 3 из 10. Задача: извлеки ключевые факты. Формат: JSON массив для последующего объединения.
"
Пример 2: Семантическое разбиение "Анализ по модулям. Сейчас: модуль auth (часть 2/5).
Предыдущие модули:
-
core: базовые утилиты, exceptions
-
models: SQLAlchemy модели User, Session
Текущий модуль:
Задача: найти зависимости от предыдущих модулей."
Пример 3: Map-Reduce "Шаг 1 (Map): Для каждого файла извлеки:
-
Публичные функции
-
Импорты
-
TODO/FIXME комментарии
Файл: src/utils.py
Формат: JSON для агрегации на шаге Reduce."
\#\#\# Агрегация результатов
\`\`\`python
\# Пример Map-Reduce для анализа кодовой базы
\# Map: для каждого файла
map\_prompt = """
Файл: \{filename\}
Извлеки:
\{
'functions': $str$,
'imports': $str$,
'todos': $str$
\}
"""
\# Reduce: агрегация
reduce\_prompt = """
Результаты анализа файлов:
\{map\_results\}
Задача:
1. Граф зависимостей (какой модуль что импортирует)
2. Общий список TODO по приоритету
3. Публичный API проекта
"""
Grounding (привязка к источнику)
Снижение галлюцинаций
Пример 1: Строгий grounding
"Ответь ТОЛЬКО на основе предоставленного контекста.
Если информации недостаточно — ответь 'Недостаточно данных'.
НЕ используй знания, которых нет в контексте.
КОНТЕКСТ:
$текст$
ВОПРОС:
$вопрос$"
Пример 2: Цитирование
"Для каждого утверждения укажи источник.
Формат: 'утверждение' $файл:строка$
ФАЙЛЫ:
$код с номерами строк$
ЗАДАЧА:
Найди потенциальные уязвимости."
Пример 3: Разделение фактов и выводов
"Формат ответа:
\#\# Факты из контекста
$только прямые цитаты или пересказ$
\#\# Мои выводы
$логические заключения на основе фактов$
\#\# Предположения
$что не подтверждено контекстом, но вероятно$
\#\# Неизвестно
$на что нельзя ответить по контексту$"
Многошаговые диалоги
Накопление контекста
Диалог 1:
User: "Вот код класса User: $код$"
Assistant: "Понял. Класс User имеет поля id, email, created\_at..."
Диалог 2:
User: "Теперь добавь валидацию email"
Assistant: $использует контекст из диалога 1$
Диалог 3:
User: "И добавь метод для смены пароля"
Assistant: $использует контекст из диалогов 1 и 2$
Сброс контекста
"Забудь предыдущий контекст.
Новая задача:
$описание$"
Явная ссылка на историю
"В предыдущем сообщении ты написал функцию validate\_email.
Теперь:
1. Добавь проверку MX записи
2. Сохрани остальную логику без изменений"
Приоритизация контекста
Что включать (по приоритету)
-
Критичное: код, который нужно изменить/проанализировать
-
Важное: интерфейсы зависимостей
-
Полезное: примеры использования, тесты
-
Опциональное: документация, комментарии
Пример структурированного контекста
"\#\# КРИТИЧНОЕ (полный код)
Функция для изменения:
\`\`\`python
$полный код функции$
ВАЖНОЕ (сигнатуры)
Зависимости:
class Database:
async def execute(self, query: str, \*args) -\> list$Row$: ...
async def fetch\_one(self, query: str, \*args) -\> Row | None: ...
СПРАВОЧНОЕ
Пример использования:
result = await db.fetch\_one('SELECT \* FROM users WHERE id = $1', user\_id)
ЗАДАЧА
Добавить кэширование результатов на 5 минут."