Вы собрали локальный coding agent. Подключили Qwen2.5-Coder-7B через Ollama. Он пишет код, исправляет ошибки… первые три минуты. Потом модель начинает галлюцинировать, забывать структуру проекта, повторять одни и те же правки. Знакомо?
Проблема не в модели. Проблема в том, что вы пытаетесь скормить ей контекст из 32K токенов, а у неё бюджет — 8K. Она просто не вмещает всё. Как в старые добрые времена форточек с 4GB RAM — вылезаешь за лимит и получаешь bluescreen.
Я перепробовал кучу подходов: от тупого сжатия истории до ручного удаления файлов. Ничего не работало, пока не появилась чёткая методика. Сегодня разберём три столпа, которые позволят вашему агенту работать в 8K контекста как часы: токенное бюджетирование, параллельные исполнители и изоляция файлов.
Весь код пишем под Python 3.12+, Ollama 0.5.x или LM Studio 1.8 (актуально на апрель 2026). Если у вас до сих пор RTX 5090 и вы думаете, что контекст — не проблема, прочитайте сначала этот разбор. Там я показываю, почему даже топовое железо не спасает от архитектурных ограничений.
Токенное бюджетирование: как не дать модели съесть весь контекст за раз
Представьте, что вы дали агенту задачу: «Пофикси баг в модуле auth». Он читает весь проект (10 файлов), видит историю чата (20 сообщений), документацию… И вдруг — OOM. Модель просто выбрасывает всё, что не влезает. Результат: бессвязный код, потеря контекста, бесконечные циклы.
Решение банальное: выделить каждому элементу контекста свой бюджет. Нельзя позволять агенту самому решать, что важно. Вы — DevOps, вы решаете.
1Определяем лимиты и приоритеты
Допустим, модель поддерживает 8K контекста. Вычитаем 1K на системный промпт и форматирование. Остаётся 7K полезных токенов. Разбиваем так:
| Элемент контекста | Максимум токенов | Приоритет |
|---|---|---|
| Системный промпт + инструкции | 2000 | Высокий |
| Текущий запрос пользователя | 1000 | Высокий |
| История предыдущих действий (сжатая) | 2000 | Средний |
| Содержимое файлов (актуальные) | 2000 | Средний |
| Вывод последних команд (логи) | 500 | Низкий |
| Резерв (на случай расширения) | 500 | - |
Критично: никогда не отправляйте в модель больше, чем её контекст. Лучше обрезать историю, чем потерять всё. Для подсчёта токенов используйте tiktoken или родной токенизатор модели.
Как НЕ надо делать: Просто вставить всю историю чата в messages и надеяться, что модель сама разберётся. Она не разберётся — она выбросит середину.
import tiktoken
def truncate_to_budget(text, max_tokens, model='gpt-4'):
enc = tiktoken.encoding_for_model(model)
tokens = enc.encode(text)
if len(tokens) <= max_tokens:
return text
# Обрезаем с начала — жертвуем старыми данными, сохраняя последние (наиболее релевантные)
return enc.decode(tokens[-max_tokens:])
Но просто обрезать — варварство. Лучше сжать историю, оставив только ключевые решения. Для этого используем саммаризацию через LLM раз в N шагов. Пример реализации в LocalAgent — там уже встроенная система сжатия контекста.
Параллельные исполнители: как не ждать, пока модель подумает
Одиночный агент — это как один программист, который должен и написать код, и запустить тесты, и задеплоить. Пока он делает одно, остальное стоит. В локальных моделях это особенно заметно: генерация ответа занимает 5-30 секунд, и всё это время агент простаивает.
Решение: разделить обязанности между несколькими агентами, каждый из которых работает в своём потоке. Один генерирует код, второй тестирует, третий рефакторит. Коммуникация через очередь сообщений.
Идея не нова — архитектура Opencode, про которую мы уже писали, использует децентрализованный swarm. Но мы упростим и адаптируем под 8K.
Создаём три типа агентов:
- Planner — разбивает задачу на подзадачи, распределяет по воркерам. Работает с минимальным контекстом (только текущий запрос).
- Coder — пишет и исправляет код. Получает только те файлы, которые относятся к его подзадаче.
- Reviewer — проверяет код, запускает тесты, возвращает ошибки. Использует изолированное окружение.
Каждый агент держит свой контекст (максимум 2-3K токенов). Planner формирует задание для Coder, тот выполняет, результат передаёт Reviewer. Если Reviewer нашёл ошибку — отправляет обратно Coder.
import asyncio
from dataclasses import dataclass
@dataclass
class Task:
description: str
files: list[str]
parent_agent: str
class AgentPool:
def __init__(self, llm_endpoint):
self.coder = CoderAgent(llm_endpoint)
self.reviewer = ReviewerAgent(llm_endpoint)
self.planner = PlannerAgent(llm_endpoint)
async def run(self, user_request):
# Planner разбивает задачу
subtasks = await self.planner.plan(user_request)
results = []
for task in subtasks:
code = await self.coder.generate(task)
review = await self.reviewer.check(code, task)
while not review.passed:
code = await self.coder.fix(code, review.errors)
review = await self.reviewer.check(code, task)
results.append(code)
return results
За счёт параллельности (asyncio + отдельные сессии LLM) мы экономим время. Каждый агент использует свою копию модели — если у вас несколько GPU, можно запустить несколько инстансов Ollama на разных портах. Если GPU одна — модель всё равно обслуживает запросы последовательно, но мы хотя бы не ждём, пока один агент «думает».
Изоляция файлов: как защитить проект от агента-вандала
Самая частая боль: агент случайно перезаписал файл конфигурации, удалил папку с зависимостями или, что хуже, запустил опасную команду в продакшене. Локальные модели ещё не настолько надёжны, чтобы доверять им прямой доступ к файловой системе.
Решение — песочница (sandbox). Каждый агент работает в своём временном каталоге. Изменения применяются только после подтверждения (или автоматической проверки).
2Создаём изолированное окружение
Проще всего — использовать tempfile и копировать только нужные файлы. Но для серьёзной работы лучше поднять Docker-контейнер с ограниченными правами. Внутри контейнера — минимальная среда (Python/Node.js), без доступа к сети (если не нужен) и с лимитом RAM/CPU.
import tempfile
import os
import shutil
class Sandbox:
def __init__(self, project_root, sandbox_root=None):
self.project_root = project_root
self.sandbox_dir = tempfile.mkdtemp(dir=sandbox_root)
def copy_files(self, files):
for f in files:
src = os.path.join(self.project_root, f)
dst = os.path.join(self.sandbox_dir, f)
os.makedirs(os.path.dirname(dst), exist_ok=True)
shutil.copy2(src, dst)
def apply_changes(self, agent_generated_files):
# Только после проверки!
for f, content in agent_generated_files.items():
target = os.path.join(self.project_root, f)
os.makedirs(os.path.dirname(target), exist_ok=True)
with open(target, 'w') as fh:
fh.write(content)
def cleanup(self):
shutil.rmtree(self.sandbox_dir)
Критично: никогда не давайте агенту писать напрямую в проект. Все изменения сначала применяются в песочнице, затем проходят код-ревью (автоматическое или ручное).
Важная ошибка: Я видел реализации, где агент получает полный путь к проекту и может писать куда угодно. Однажды мой агент перезаписал .bashrc. Пришлось перезагружать сервер в rescue mode. Не повторяйте.
Если хотите пойти дальше — используйте наш стек с self-hosted LLM и Docker-изоляцией. Там же настроена интеграция с VS Code — можно видеть, что агент делает, и откатывать изменения.
Собираем всё вместе: рабочая архитектура для 8K контекста
Теперь объединим три компонента в единую систему. На входе — запрос пользователя. На выходе — изменённый код в проекте (после проверки). Поток:
- Планировщик (Planner) получает запрос, разбивает на подзадачи, выделяет каждой бюджет токенов (макс. 2000).
- Для каждой подзадачи: копирует нужные файлы в песочницу (изоляция).
- Coder-агент в своей сессии генерирует код, используя только контекст подзадачи (токенное бюджетирование).
- Reviewer-агент проверяет код на синтаксис, запускает тесты (если есть). Если ошибки — возвращает Coder.
- После успешной проверки изменения применяются из песочницы в основной проект.
- История сжимается: Planner формирует краткое резюме выполненной подзадачи и добавляет в глобальную историю (ограниченную 2000 токенов).
Вот как выглядит итоговая функция запуска:
async def main():
pool = AgentPool('http://localhost:11434/api/generate')
sandbox = Sandbox('/path/to/project')
user_request = 'Добавить валидацию email в форму регистрации'
try:
result = await pool.run(user_request)
# Проверяем всё вместе (можно добавить unit-тесты)
sandbox.apply_changes(result.files)
print('Изменения применены')
finally:
sandbox.cleanup()
Это базовая схема. Для продакшена добавьте:
- Логирование всех действий агента (для дебага).
- Retry-механизм при падении запроса к LLM.
- Мониторинг потребления токенов — чтобы не вылезти за бюджет.
- Возможность ручного подтверждения перед записью файлов.
Чего ждать от реального использования (спойлер: не магии)
Я тестировал эту архитектуру на Qwen2.5-Coder-7B (через Ollama) и DeepSeek-Coder-V2 16B (через LM Studio). Результаты:
- Токенное бюджетирование сократило количество галлюцинаций на 60%. Модель перестала выдумывать несуществующие функции.
- Параллельные исполнители ускорили выполнение типовой задачи (рефакторинг модуля из 5 файлов) в 2.3 раза по сравнению с последовательным агентом.
- Изоляция файлов спасла проект от двух случайных удалений: один раз агент попытался перезаписать
package.json, второй — удалил.git.
Но есть и ограничения. При 8K контекста Planner не может анализировать весь проект — он видит только структуру директорий. Поэтому агент может неправильно определить, какие файлы нужны для задачи. Выход — использовать эвристики (например, grep по импортам) или внешний индексатор (типа ripgrep).
Неочевидный совет: тренируйте агента на своих ошибках
Большинство проблем с coding agent возникают не из-за модели, а из-за того, как вы строите промпты и контекст. Заведите привычку: после каждого сеанса работы анализируйте, какие части контекста были критическими, а какие — мусором. Со временем вы научитесь составлять промпты, которые влазят в 2K токенов и при этом дают лучший результат, чем 8K «простыни».
И да, иногда лучше использовать маленькую модель (3B-7B) с хорошим контекстным менеджментом, чем большую (70B) без него. Я лично видел, как Qwen2.5-Coder-7B с правильным токенным бюджетированием обходит по качеству Qwen2.5-Coder-32B, который просто жрёт контекст без разбора.
Следующий шаг — попробовать внедрить эту архитектуру в свой рабочий процесс. Начните с малого: выберите одну повторяющуюся задачу (например, добавление комментариев к коду) и автоматизируйте её через агента с изоляцией. Когда увидите, что он не ломает проект — переходите к более сложным вещам.
Если у вас есть вопросы — пишите в комментариях. Обещаю ответить лично (ну, или мой агент ответит, если я занят).