AI-кодинг-агенты сжигают контекст и токены: как сократить шум tool output на 98% и не терять память между сессиями
Я — Denis Shokhirev, Agentic AI Systems Architect из Freiburg im Breisgau, Germany, и в DennisCraft AI Studio я строю production AI-системы для DACH B2B на стеке Claude, Supabase, n8n, Doppler и self-hosted Postgres. Самая дорогая поломка в coding-agent пайплайне у меня обычно не в модели, а в том, что агент за 20 минут сжигает контекст на мусоре из tool output, а потом забывает, почему вообще менял файл. В regulated среде это быстро превращается не просто в лишние токены, а в потерю трассируемо
Я — Denis Shokhirev, Agentic AI Systems Architect из Freiburg im Breisgau, Germany, и в DennisCraft AI Studio я строю production AI-системы для DACH B2B на стеке Claude, Supabase, n8n, Doppler и self-hosted Postgres. Самая дорогая поломка в coding-agent пайплайне у меня обычно не в модели, а в том, что агент за 20 минут сжигает контекст на мусоре из tool output, а потом забывает, почему вообще менял файл. В regulated среде это быстро превращается не просто в лишние токены, а в потерю трассируемости решений между сессиями.
Проблема выглядит знакомо: агент запускает grep, semgrep, bandit, gitleaks, тесты, линтеры, diff, читает 15 файлов подряд и тащит обратно в prompt почти все. Через несколько ходов история уже состоит не из намерения и решений, а из простыней stdout. В итоге следующая сессия стартует с нуля, хотя фактически работа уже была сделана.
Где именно умирает контекст
Я вижу 3 типовых источника потерь:
| Источник шума | Что происходит | Последствие |
|---|---|---|
| Сырые tool outputs | В prompt попадает полный stdout/stderr | Контекст забит логами вместо решений |
| Повторное чтение файлов | Агент снова и снова тянет одни и те же куски | Лишние токены и дрейф внимания |
| Нет session memory | После рестарта нет сжатой истории решений | Повторные шаги и расхождение по архитектуре |
Anthropic в документации по prompt engineering и tool use постоянно подталкивает к структурированию контекста, а не к бесконтрольной передаче сырых инструментальных ответов. Это не академическая тонкость, а практический предел окна контекста. В OpenAI Cookbook в паттернах работы с длинным контекстом и retrieval тоже та же идея: передавать модели только релевантное сжатое состояние, а не весь журнал операций. Источники: Anthropic Docs, 2024–2025, https://docs.anthropic.com/ ; OpenAI Cookbook, 2024, https://cookbook.openai.com/.
На моих последних агентных внедрениях сокращение объема tool output, который реально попадал обратно в модель, доходило примерно до 98%. Не потому что инструментов стало меньше, а потому что в контекст шел не лог, а результат в нормализованной форме: статус, измененные файлы, найденные проблемы, следующий шаг.
Что хранить в prompt, а что выносить наружу
1. В prompt — только decision state
Модели нужен не полный stdout bandit, а 4 вещи: какие файлы затронуты, какие риски найдены, что уже исправлено, где нужен следующий вызов инструмента. Все остальное должно жить вне prompt.
2. Сырые артефакты — в Postgres или Supabase
Я обычно складываю полные outputs инструментов в Postgres: по run_id, tool_name, file_path, severity, raw_output, summary. В prompt попадает только summary. Если нужно обоснование, агент может точечно запросить первоисточник.
3. Межсессионная память — это не chat history
Session memory для coding agents — это не полный лог диалога. Это сжатое состояние задачи: цель, принятые решения, ограничения, открытые риски, последние измененные файлы, known bad paths. Такой объект можно передавать между сессиями без потери хода мысли.
from dataclasses import dataclass, asdict
import json
@dataclass
class SessionMemory:
task_goal: str
decisions: list[str]
touched_files: list[str]
open_risks: list[str]
next_step: str
def compact_memory(memory: SessionMemory) -> str:
payload = asdict(memory)
return json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
memory = SessionMemory(
task_goal="Fix SQL query parameterization",
decisions=["Use parameterized queries", "Keep repository API stable"],
touched_files=["db/repo.py", "tests/test_repo.py"],
open_risks=["Legacy helper still interpolates SQL"],
next_step="Inspect legacy helper and patch tests"
)Паттерн, который реально работает в production
Я использую простой цикл из 4 фаз: execute, normalize, persist, recall.
Execute
Инструмент выполняется как обычно: semgrep, bandit, gitleaks, тесты, git diff. Но агент не получает право без фильтра тащить все обратно в контекст.
Normalize
Каждый output сводится к короткой записи фиксированной формы. Например: tool=bandit, status=fail, findings=2, files=[...], top_risk=CWE-89 pattern, next_action=patch SQL call. Это дисциплинирует агента сильнее, чем любые разговоры про “будь кратким”.
Persist
Нормализованное состояние и сырые артефакты сохраняются отдельно. Для regulated клиентов это помогает с аудитом: можно показать не только итоговый код, но и цепочку решений.
Recall
Новая сессия поднимает не весь чат, а компактную memory plus точечные артефакты по запросу. Так агент продолжает работу, а не пересобирает картину мира заново.
type ToolSummary = {
tool: string
status: "ok" | "fail"
findings: number
files: string[]
nextAction: string
}
function summarizeBandit(raw: string): ToolSummary {
const findings = (raw.match(/>> Issue:/g) || []).length
const files = [...raw.matchAll(/Location:\s+(.+):\d+/g)].map(m => m[1])
return {
tool: "bandit",
status: findings > 0 ? "fail" : "ok",
findings,
files: [...new Set(files)].slice(0, 10),
nextAction: findings > 0 ? "patch flagged Python paths" : "continue"
}
}Почему это важно для безопасности и аудита
Когда coding agent тонет в логах, он начинает пропускать важное. Для кода это быстро упирается в CWE и OWASP-классы ошибок. OWASP регулярно указывает, что избыточная сложность и отсутствие контроля над цепочкой обработки данных повышают риск уязвимостей в приложениях. Для AI-кода риск тот же, только скорость выше: агент генерирует, правит и подтверждает себя сам, если вы не добавили внешние проверки. Источник: OWASP Top 10, 2021, https://owasp.org/www-project-top-ten/.
Поэтому у меня нормой стали внешние проверки перед тем, как что-то считать “сделанным”: semgrep для паттернов, bandit для Python, gitleaks для секретов, плюс тесты. Но критично то, что в модель возвращается только итог проверки в компактной форме.
#!/usr/bin/env bash
set -euo pipefail
semgrep --config auto --json > /tmp/semgrep.json || true
bandit -r . -f json -o /tmp/bandit.json || true
gitleaks detect --report-format json --report-path /tmp/gitleaks.json || true
python scripts/store_tool_results.py \
--run-id "$RUN_ID" \
--semgrep /tmp/semgrep.json \
--bandit /tmp/bandit.json \
--gitleaks /tmp/gitleaks.jsonМинимальная реализация без лишней сложности
Если у вас уже есть Claude Code, Anthropic SDK, n8n или просто собственный orchestrator, не надо перестраивать все. Достаточно ввести 3 объекта:
| Объект | Где хранить | Назначение |
|---|---|---|
| tool_runs | Postgres / Supabase | Сырые outputs и метаданные |
| session_memory | Postgres / Supabase | Сжатое состояние задачи |
| recall_policy | Код orchestrator | Что можно вернуть в prompt |
В n8n это обычно один узел для запуска проверки, один для нормализации JSON, один для записи в базу и один для сборки compact prompt перед следующим вызовом модели. Главная мысль простая: tool output — это журнал, а не prompt.
FAQ
Нужно ли сохранять всю историю чата?
Нет. Для coding agents полная история обычно хуже полезного состояния. Храните решения, ограничения, артефакты и ссылки на полные логи.
Когда RAG уместен, а когда нет?
RAG уместен для поиска по кодовой базе, документации и прошлым run. Но session memory лучше держать как отдельный структурированный объект, а не пытаться каждый раз “искать” собственное состояние.
Можно ли обойтись без Supabase?
Да. Обычный Postgres закрывает задачу полностью. Supabase просто ускоряет API-слой и удобен, если у вас уже есть этот контур.
Почему недостаточно просто увеличивать окно контекста?
Потому что проблема не только в размере, но и в качестве сигнала. Если вы заливаете в модель 200 KB логов, она не становится внимательнее к 3 важным решениям.
Как измерить эффект?
Смотрите 4 метрики: tokens per successful task, число повторных чтений файла, доля restart sessions без деградации результата и время до фикса после рестарта. На практике именно они показывают, что память стала рабочей.
Если у вас coding agent уже в production, на каком этапе у вас больше всего теряется качество после длинной цепочки вызовов — на сырых tool outputs, на повторном чтении файлов или на отсутствии нормальной межсессионной памяти? Я правда хочу это сравнить с тем, что вижу у своих клиентов.
Я провожу бесплатный 30-минутный stack audit для DACH founders, которые строят AI в regulated markets. Напишите мне в LinkedIn или в @ger_dennis_ai.
Превратить процесс в систему, которая работает
Продакшн-качество, а не демо.