Plan-Code-Execute: агент создает инструменты на лету | Гайд 2026 | AiManual
AiManual Logo Ai / Manual.
04 Фев 2026 Гайд

Архитектура Plan-Code-Execute: как создать агента, который сам пишет себе инструменты

Пошаговый гайд по созданию AI-агента с архитектурой Plan-Code-Execute. Агент сам пишет инструменты для анализа данных и ML моделей. Примеры кода на Python.

Проблема: ваш агент тупой, потому что у него нет нужного инструмента

Представьте ситуацию. Вы даете агенту задачу: "Проанализируй эту графовую нейронную сеть и объясни, почему она плохо предсказывает на узлах с высокой степенью". Агент думает. Проверяет свои инструменты. У него есть pandas.read_csv(), matplotlib.plot(), даже networkx.draw(). Но нет инструмента для анализа центральности узлов в контексте ошибок предсказания GNN.

Что делает обычный агент? Пишет: "Извините, у меня нет такого инструмента". Конец. Вы вручную пишете скрипт, тратите час. Агент ждет. Бесполезно.

Традиционные агенты ограничены своим набором инструментов. Как швейцарский нож с фиксированными лезвиями. Хотите открыть консерву - нет открывашки. Хотите починить очки - нет отвертки. Вы либо таскаете с собой 50 килограммовый набор, либо постоянно возвращаетесь домой.

Решение: агент, который сам кует себе лезвия

Архитектура Plan-Code-Execute меняет парадигму. Вместо статического набора инструментов - динамическая генерация. Агент анализирует задачу, понимает, каких инструментов не хватает, пишет их код, проверяет, выполняет.

Три этапа, которые звучат просто, но реализация - ад:

  1. Plan: Агент разбирает задачу на подзадачи. Определяет, какие вычисления нужны. Ищет пробелы в своих возможностях.
  2. Code: Пишет Python-функции для填补 пробелов. Не просто скрипты, а переиспользуемые инструменты с типами, обработкой ошибок.
  3. Execute: Запускает новый инструмент в изолированной среде. Проверяет результат. Если работает - использует. Если нет - дебажит.
💡
На 04.02.2026 эта архитектура стала стандартом для сложных аналитических задач. Claude 3.7 Sonnet (последняя версия на эту дату) показывает accuracy 89% в генерации рабочего кода инструментов. GPT-4.5 Turbo - 84%. Разница в 5% - это разница между "работает" и "надо дебажить 2 часа".

Пошаговый разбор: строим агента с нуля

Забудьте про LangChain. Забудьте про LlamaIndex. Мы будем использовать чистый Claude SDK (версия 2.8.0 на 04.02.2026) и кастомную логику. Потому что готовые фреймворки добавляют слои абстракции, которые ломаются при первой же нестандартной задаче.

1 База: агент с REPL-средой

Первое - создаем безопасную среду выполнения. Агент будет генерировать код, и этот код нужно запускать. Но не на вашей машине. Никогда не запускайте код от агента на своей машине.

import ast
import sys
import tempfile
import subprocess
from typing import Dict, Any

class SafeREPL:
    """Изолированная среда для выполнения кода от агента"""
    def __init__(self):
        self.allowed_modules = {
            'math', 'datetime', 'json', 'collections',
            'numpy', 'pandas', 'networkx', 'sklearn'
        }
        self.globals = {
            '__builtins__': {
                'len': len, 'str': str, 'int': int,
                'list': list, 'dict': dict, 'range': range
            }
        }
    
    def execute(self, code: str) -> Dict[str, Any]:
        """Выполняет код и возвращает результат или ошибку"""
        # Проверка синтаксиса
        try:
            tree = ast.parse(code)
        except SyntaxError as e:
            return {'error': f'Syntax error: {e}'}
        
        # Проверка импортов
        for node in ast.walk(tree):
            if isinstance(node, ast.Import):
                for alias in node.names:
                    if alias.name not in self.allowed_modules:
                        return {'error': f'Disallowed import: {alias.name}'}
            
            if isinstance(node, ast.ImportFrom):
                if node.module not in self.allowed_modules:
                    return {'error': f'Disallowed import from: {node.module}'}
        
        # Выполнение в изолированном процессе
        with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
            f.write(code)
            f.flush()
            
            try:
                result = subprocess.run(
                    [sys.executable, f.name],
                    capture_output=True,
                    text=True,
                    timeout=10
                )
                
                if result.returncode == 0:
                    return {'output': result.stdout}
                else:
                    return {'error': result.stderr}
            except subprocess.TimeoutExpired:
                return {'error': 'Execution timeout'}

Этот REPL выполняет код в отдельном процессе, ограничивает импорты и убивает выполнение через 10 секунд. Медленно? Да. Безопасно? Относительно. (Абсолютной безопасности не существует, но это лучше, чем eval()).

2 Планировщик: как агент понимает, чего ему не хватает

Сердце архитектуры. Агент должен уметь декомпозировать задачу и выявлять пробелы в своих возможностях. Здесь нужна мощная LLM. На 04.02.2026 я рекомендую Claude 3.7 Sonnet для баланса цены и качества.

from anthropic import Anthropic

class PlanningAgent:
    def __init__(self, api_key: str):
        self.client = Anthropic(api_key=api_key)
        self.existing_tools = [
            "read_csv(filepath)",
            "plot_graph(nodes, edges)",
            "calculate_statistics(data)",
            "train_linear_model(X, y)"
        ]
    
    def analyze_task(self, task: str) -> Dict:
        """Анализирует задачу и возвращает план с недостающими инструментами"""
        prompt = f"""
Задача: {task}

Существующие инструменты: {', '.join(self.existing_tools)}

Проанализируй задачу и определи:
1. Какие подзадачи нужно решить
2. Какие инструменты уже есть для каждой подзадачи
3. Какие инструменты нужно создать с нуля

Верни JSON:
{{
  "subtasks": ["task1", "task2"],
  "missing_tools": [
    {{
      "name": "название_функции",
      "purpose": "что делает",
      "input_params": ["param1", "param2"],
      "output": "что возвращает"
    }}
  ]
}}
"""
        
        response = self.client.messages.create(
            model="claude-3-7-sonnet-20250226",
            max_tokens=1000,
            temperature=0.1,
            messages=[{"role": "user", "content": prompt}]
        )
        
        import json
        try:
            return json.loads(response.content[0].text)
        except json.JSONDecodeError:
            # Fallback: парсим текстовый ответ
            return self._parse_text_response(response.content[0].text)

Температура 0.1 - не ошибка. Для планирования нужна максимальная детерминированность. Креативность оставьте для генерации контента, здесь нужна точность.

3 Генератор кода: превращаем спецификацию в работающий инструмент

Самый сложный этап. Агент должен писать не просто код, а production-ready инструменты. С типами, обработкой ошибок, документацией.

class CodeGenerator:
    def __init__(self, api_key: str):
        self.client = Anthropic(api_key=api_key)
    
    def generate_tool(self, tool_spec: Dict) -> str:
        """Генерирует код инструмента по спецификации"""
        prompt = f"""
Создай Python-функцию для инструмента:

Название: {tool_spec['name']}
Назначение: {tool_spec['purpose']}
Входные параметры: {tool_spec['input_params']}
Выходные данные: {tool_spec['output']}

Требования:
1. Добавь type hints для всех параметров и возвращаемого значения
2. Обработай возможные ошибки (используй try-except)
3. Добавь docstring с примерами использования
4. Функция должна быть самодостаточной (не зависит от внешних переменных)
5. Включи базовые тесты в docstring

Верни только код функции, без объяснений.
"""
        
        response = self.client.messages.create(
            model="claude-3-7-sonnet-20250226",
            max_tokens=1500,
            temperature=0.3,
            messages=[{"role": "user", "content": prompt}]
        )
        
        return response.content[0].text

Обратите внимание на temperature 0.3 - здесь нужна небольшая вариативность, чтобы избежать шаблонных решений. Но не больше 0.5, иначе получите рандомный код.

4 Интеграция: собираем все вместе

Теперь связываем компоненты в единого агента. Важный момент - кэширование. Если агент уже создавал инструмент для анализа центральности узлов, не нужно генерировать его снова.

class PlanCodeExecuteAgent:
    def __init__(self, api_key: str):
        self.planner = PlanningAgent(api_key)
        self.coder = CodeGenerator(api_key)
        self.repl = SafeREPL()
        self.tool_cache = {}  # Кэш созданных инструментов
    
    def execute_task(self, task: str):
        """Основной метод: принимает задачу, возвращает результат"""
        print(f"Задача: {task}")
        
        # 1. Планирование
        print("\n[1/3] Планирование...")
        plan = self.planner.analyze_task(task)
        print(f"Найдено подзадач: {len(plan['subtasks'])}")
        print(f"Недостающих инструментов: {len(plan['missing_tools'])}")
        
        # 2. Создание недостающих инструментов
        created_tools = []
        for tool_spec in plan['missing_tools']:
            tool_name = tool_spec['name']
            
            # Проверяем кэш
            if tool_name in self.tool_cache:
                print(f"Инструмент '{tool_name}' уже в кэше")
                continue
            
            print(f"\n[2/3] Создание инструмента: {tool_name}")
            
            # Генерация кода
            tool_code = self.coder.generate_tool(tool_spec)
            
            # Тестирование в REPL
            test_result = self.repl.execute(tool_code)
            
            if 'error' in test_result:
                print(f"Ошибка: {test_result['error'][:100]}...")
                # Здесь можно добавить логику повторной попытки
            else:
                print(f"Успех! Инструмент создан")
                self.tool_cache[tool_name] = tool_code
                created_tools.append(tool_name)
        
        # 3. Выполнение задачи со всеми инструментами
        print(f"\n[3/3] Выполнение задачи с {len(created_tools)} новыми инструментами...")
        # Здесь интегрируем новые инструменты и выполняем финальную задачу
        return self._execute_final(task, created_tools)

Реальный пример: анализ графовой нейронной сети

Допустим, мы тренируем GNN для рекомендательной системы. Модель работает хорошо в среднем, но на "владельцах групп" (узлы с высокой степенью) предсказания откровенно плохие. Почему?

Даем агенту задачу: "Проанализируй GNN модель из файла 'gnn_model.pth' и датасета 'social_graph.pkl'. Определи, почему ошибка предсказания коррелирует со степенью узла".

Что происходит внутри агента:

  1. Plan: Агент определяет, что нужны: загрузка модели, загрузка графа, вычисление степени узлов, расчет ошибок предсказания, анализ корреляции, визуализация.
  2. Code: Из существующих инструментов есть только загрузка файлов. Нужно создать: calculate_node_degrees(), compute_prediction_errors(), correlate_metrics(), plot_degree_vs_error().
  3. Execute: Агент пишет каждый инструмент, тестирует, затем запускает весь пайплайн. Результат - график и статистика, показывающая, что GNN плохо обобщает на узлах с более чем 50 связями.
💡
В статье про архитектуру универсального AI-агента мы разбирали REPL-подход для работы с файлами. Plan-Code-Execute идет дальше - это REPL на стероидах, где агент создает не просто команды, а целые библиотеки.

Ошибки, которые сломают вашу систему (и как их избежать)

Я видел десятки попыток внедрить Plan-Code-Execute. 90% проваливаются на этих подводных камнях:

Ошибка Последствия Решение
Запуск кода без изоляции Агент удаляет все файлы или майнит крипту Docker-контейнеры или как минимум subprocess с таймаутом
Нет кэширования инструментов На каждую задачу тратятся доллары на генерацию одного и того же кода Локальная база с хешами спецификаций инструментов
Слишком креативная генерация Инструмент работает, но его невозможно понять людям Строгие prompt-ограничения на стиль и документацию
Отсутствие валидации входных данных Агент создает инструмент, который падает на реальных данных Автоматические тесты с edge cases в prompt

Самая частая ошибка - дать агенту слишком много свободы. Помните: агент оптимизирует за выполнение задачи, а не за читаемость кода или безопасность. Вы должны задавать границы.

Когда эта архитектура бесполезна (да, бывает и так)

Plan-Code-Execute - не серебряная пуля. В трех случаях она проигрывает простым инструментам:

  1. Простые, повторяющиеся задачи: Если вам каждый день нужно делать одно и то же (скачать данные, посчитать среднее, построить график), создайте один скрипт. Не заставляйте агента генерировать его заново каждый раз.
  2. Критичные по безопасности задачи: Анализ логов продакшена, работа с персональными данными. Здесь нельзя допускать выполнение сгенерированного кода.
  3. Задачи с жесткими latency требованиями: Генерация инструмента занимает 10-30 секунд. Если нужно ответить за 200 мс, эта архитектура не подходит.

Для таких случаев лучше подходят предобученные skills, как в статье про сборку агентов из LEGO.

Что будет дальше? Прогноз на 2027 год

Сейчас (на 04.02.2026) мы в начале пути. Claude 3.7 генерирует рабочий код в 89% случаев. Через год, с выходом Claude 4.0 или GPT-5, accuracy поднимется до 95+%. Но проблема не в генерации кода.

Проблема в архитектуре. Нужно не просто генерировать инструменты, а создавать экосистему:

  • Инструменты, которые создают инструменты: Мета-уровень. Агент анализирует свои провалы в генерации и создает улучшенные шаблоны.
  • Коллективное обучение: Агент в команде А обучался создавать инструмент для анализа временных рядов. Агент в команде Б получает этот инструмент через shared repository.
  • Специализированные языки: Не Python, а DSL для описания инструментов. Меньше свободы - больше безопасности и предсказуемости.

Если вы хотите глубоко разобраться в архитектурных решениях, курс Архитектор ПО дает системное понимание. Не для кодинга агентов, а для проектирования систем, которые не развалятся через месяц.

Последний совет: начните с малого. Не пытайтесь сразу сделать агента, который анализирует GNN. Начните с задачи "посчитай статистику по этому CSV и найди аномалии". Посмотрите, какие инструменты агент создает. Поймите его логику.

Потом усложняйте. Добавьте визуализацию. Потом - машинное обучение. Через месяц у вас будет агент, который решает 80% ваших аналитических задач. А вы сможете заниматься тем, что действительно требует человеческого мышления.

И да, не забудьте про технический долг. Агент создает код быстрее, чем вы успеваете его проверить. Но это уже другая история.