Средний

Набор навыков для работы с AI-агентами

Алексей Кузнецов
Алексей Кузнецов
Системный администратор28 октября 2026 г.14 мин чтения

Разбираем репозиторий mattpocock/skills: как структурировать инструкции и навыки для создания предсказуемых и эффективных автономных AI-агентов.

Набор навыков для работы с AI-агентами

Разбираем репозиторий mattpocock/skills: как структурировать инструкции и навыки для создания предсказуемых и эффективных автономных AI-агентов.

Зачем агентам специализированные навыки

Зачем агентам специализированные навыки

Когда мы говорим об автономных AI-агентах, многие совершают одну и ту же ошибку: пытаются скормить модели огромный системный промпт, в котором описаны все задачи сразу. Это напоминает попытку выдать инструкции по эксплуатации авиалайнера человеку, который одновременно должен быть и поваром, и водителем такси. В итоге агент начинает «галлюцинировать» или путаться в приоритетах.

С практической точки зрения, агент без четко разделенных навыков — это непредсказуемый инструмент. Чтобы система работала стабильно, её нужно строить на базе специализированных функций, которые модель вызывает только тогда, когда это действительно необходимо.

Проблема размытых промптов

Основная беда больших промптов — деградация внимания модели. Чем больше в инструкции условий «если..., то...», тем выше вероятность, что агент проигнорирует критически важную часть логики. В системном администрировании мы называем это раздутым конфигом: когда в одном файле смешаны настройки сети, пользователи и правила брандмауэра, найти ошибку становится крайне сложно.

Если мы посмотрим на типичный плохой подход, то увидим попытку описать всё в одном блоке:

text
// Плохой пример: размытый системный промпт
Ты — универсальный помощник. Ты умеешь читать файлы, 
анализировать логи, отправлять уведомления в Slack 
и перезагружать Docker-контейнеры. Если видишь ошибку 
в логах, сначала проанализируй её, потом реши, 
нужно ли перезагрузить сервис, и обязательно 
напиши об этом в Slack.

Здесь заложена фундаментальная проблема: агент не обладает четким алгоритмом. Он пытается удержать в контексте слишком много связей. В результате, при возникновении ошибки, он может отправить уведомление в Slack до того, как проведёт анализ, или вовсе забыть про перезагрузку, потому что «внимание» модели распределилось слишком тонким слоем по всему тексту.

Принцип модульности в управлении AI

Чтобы добиться предсказуемости, нужно использовать модульный подход. Вместо одного гигантского промпта мы создаём набор атомарных навыков (skills). Каждый навык — это изолированная единица логики с чётко определённым входом и выходом.

В репозитории mattpocock/skills концепция структурирования навыков строится на том, что агент не «знает» всё, а «умеет пользоваться инструментами». Это очень похоже на работу системного инженера: у вас есть набор скриптов на Bash или Ansible-плейбуков. Вы не держите весь код в голове, вы вызываете нужный инструмент в нужный момент.

С точки зрения архитектуры, это выглядит как разделение на:

  1. Core Logic (ядро) — понимание намерения пользователя.
  2. Skill Definition (описание навыка) — когда и зачем использовать инструмент.
  3. Tool Execution (выполнение) — сам код или команда.

Если мы переложим это на структуру конфигурации (например, в формате JSON, который часто используется для описания инструментов в API), то получим нечто подобное:

json
{
  "skill_name": "docker_container_restart",
  "description": "Перезагружает конкретный Docker-контейнер по его имени.",
  "parameters": {
    "container_name": {
      "type": "string",
      "description": "Имя контейнера, например, 'nginx-proxy'"
    }
  },
  "execution_logic": "docker restart {{container_name}}"
}

Такой подход даёт нам три преимущества:

  • Предсказуемость: мы точно знаем, какие параметры ожидает навык.
  • Тестируемость: каждый навык можно проверить отдельно, не запуская всю систему.
  • Масштабируемость: если вам нужно добавить новый функционал (например, очистку старых образов), вы просто добавляете новый модуль, не переписывая основной промпт.

Разделение ответственности — это единственный способ превратить хаотичный чат-бот в надёжный инженерный инструмент.

Архитектура навыков из репозитория mattpocock

Архитектура навыков из репозитория mattpocock

Когда мы переходим от простого чата с LLM к созданию автономных агентов, мы сталкиваемся с проблемой деградации логики. Если вы просто скормите модели огромный системный промпт, она начнет путаться в контексте, галлюцинировать или игнорировать часть инструкций. С практической точки зрения, работа с агентами — это не про «написание хорошего текста», а про проектирование модульной системы.

Подход, предложенный Мэттом Пококом в репозитории mattpocock/skills, строится на принципе разделения ответственности. Вместо одного монолитного файла мы создаём набор атомарных навыков, которые агент может вызывать по мере необходимости. Это обеспечивает предсказуемость: агент берет ровно ту инструкцию, которая нужна для текущей задачи.

Структура директории .agents

Чтобы система не превратилась в свалку текстовых файлов, важно придерживаться строгой иерархии. В методологии Покока предполагается, что все инструкции агента хранятся в специализированной директории, например .agents. Это позволяет легко версионировать навыки через Git и подключать их к разным проектам.

Я рекомендую структурировать хранилище так, чтобы разделять общие правила поведения и специфические инструменты. Если мы посмотрим на логику организации файлов, то получим следующую схему:

text
.agents/
├── core/                # Базовые инструкции (persona, tone of voice)
│   ├── identity.md      # Кто такой агент
│   └── constraints.md   # Что агенту делать категорически нельзя
├── skills/              # Атомарные навыки (инструменты)
│   ├── file_manager.md  # Навык работы с файловой системой
│   ├── web_search.md    # Навык поиска в сети
│   └── sql_executor.md  # Навык выполнения запросов
└── workflows/           # Сложные сценарии, объединяющие навыки
    └── report_gen.md    # Сценарий создания отчета

Такая структура напоминает работу с модулями в Python или пакетами в Debian: каждый компонент выполняет одну задачу и имеет четкие границы. Если вам нужно обновить логику работы с базой данных, вы правите только sql_executor.md, не рискуя сломать общую личность агента, описанную в identity.md.

Форматирование инструкций для предсказуемого результата

Самая большая ошибка при написании навыков — использование расплывчатых формулировок вроде «будь полезным» или «делай это аккуратно». Для агента это пустой звук. Чтобы результат был предсказуемым, инструкции должны быть декларативными и структурированными.

В репозитории mattpocock/skills акцент делается на использовании четких маркеров и разделов. Хорошо сформулированный навык должен содержать:

  1. Название и описание: что это за инструмент.
  2. Условия вызова (Trigger): в какой момент агент должен обратиться к этому навыку.
  3. Входные данные (Input): что именно агент должен подготовить перед вызовом.
  4. Ожидаемый результат (Output): в каком формате навык должен вернуть ответ.

Рассмотрим пример оформления файла skills/file_manager.md. Вместо длинного текста мы используем структурный подход:

markdown
# Skill: File Manager

## Description
Provides capabilities to read, write, and list files in the local workspace.

## Trigger
Use this skill when the user asks to create, modify, delete, or inspect 
the contents of a file.

## Constraints
- NEVER attempt to access directories outside of the `./workspace` folder.
- If a file does not exist, return a specific error: "FILE_NOT_FOUND".
- Always verify write permissions before attempting to save.

## Input Schema
- `action`: [read | write | list | delete]
- `path`: relative path to the file
- `content`: (only for 'write' action) string content

## Output Format
Return a JSON object:
{
  "status": "success | error",
  "message": "description of the result",
  "data": "optional payload"
}

С точки зрения инженера, такой формат превращает текстовую инструкцию в подобие программного интерфейса (API). Мы уходим от «общения» к «вызову функций». Когда агент видит четкий Input Schema, вероятность того, что он передаст в инструмент неверный тип данных или неполный путь, снижается в разы. Это и есть фундамент надежной автономной системы.

Практическое применение навыков в разработке

Интеграция навыков в рабочий процесс инженера

Когда мы переходим от простых чат-ботов к автономным агентам, подход к работе меняется. Если раньше мы писали один огромный системный промпт, пытаясь впихнуть в него всю логику, то теперь мы работаем с набором атомарных навыков. Это напоминает переход от монолитного приложения к микросервисной архитектуре: каждый навык должен решать одну конкретную задачу и иметь предсказуемый интерфейс.

С практической точки зрения, интеграция навыков из репозитория mattpocock/skills в рабочий процесс выглядит как проектирование API. Вы не просто даёте агенту доступ к инструменту, вы описываете правила игры.

Чтобы агент не превратился в «черный ящик», который тратит токены на бесконечные размышления, я рекомендую структурировать описание навыка по принципу: Контекст — Действие — Ожидаемый результат.

Пример того, как может выглядеть описание навыка для работы с файловой системой в JSON-формате (если ваш фреймворк использует структурированные вызовы):

json
{
  "skill_name": "read_config_file",
  "description": "Считывает содержимое конфигурационного файла для анализа параметров системы.",
  "parameters": {
    "file_path": {
      "type": "string",
      "description": "Абсолютный путь к файлу, например, /etc/nginx/nginx.conf"
    }
  },
  "constraints": [
    "Разрешено чтение только файлов с расширением .conf, .yaml, .json",
    "Запрещено попытки чтения системных файлов /etc/shadow или /etc/sudoers"
  ],
  "expected_output": "Текстовое содержимое файла или ошибка доступа"
}

Во-первых, такая строгость обеспечивает предсказуемость. Во-вторых, вы сразу ограничиваете область поиска ошибок. Если агент пытается прочитать /etc/shadow, вы увидите это в логах не как «галлюцинацию», а как нарушение конкретного правила (constraint), прописанного в навыке.

Тестирование и отладка поведения агента

Главная проблема автономных систем — их нелинейность. Вы можете изменить одно слово в описании навыка, и агент внезапно решит, что вместо выполнения команды ls ему нужно вызвать find. Поэтому тестирование должно быть системным.

Я разделяю процесс отладки на два этапа: проверка синтаксиса навыка и проверка логики поведения.

Для проверки синтаксиса и того, как LLM интерпретирует описание, удобно использовать небольшие скрипты на Python. Сначала убедитесь, что ваш агент корректно парсит описание навыка. Если вы используете LangChain или подобные библиотеки, проверьте, как именно инструмент (tool) передаёт аргументы.

Пример простого теста на Python, который проверяет, правильно ли агент формирует запрос к навыку:

python
import json

def test_skill_parsing(agent_output, expected_tool):
    """
    Проверяет, что агент выбрал правильный инструмент и передал нужные аргументы.
    """
    try:
        # Предположим, агент возвращает JSON с выбором инструмента
        call = json.loads(agent_output)
        
        if call['tool'] != expected_tool:
            print(f"Ошибка: ожидался инструмент {expected_tool}, получен {call['tool']}")
            return False
            
        # Проверяем наличие обязательного поля path
        if 'file_path' not in call['args']:
            print("Ошибка: в аргументах отсутствует 'file_path'")
            return False
            
        print("Тест пройден: инструмент и аргументы корректны")
        return True
    except Exception as e:
        print(f"Ошибка при парсинге ответа агента: {e}")
        return False

# Пример входных данных от модели
mock_response = '{"tool": "read_config_file", "args": {"file_path": "/etc/nginx/nginx.conf"}}'
test_skill_parsing(mock_response, "read_config_file")

Если синтаксис в порядке, переходим к отладке поведения. Здесь важно использовать логирование каждого шага размышления (Chain of Thought). Если агент зацикливается, значит, в описании навыка есть двусмысленность.

При отладке всегда смотрите на «граничные условия». Что произойдет, если навык вернёт ошибку? Если ваш навык read_config_file вернёт Permission denied, агент должен уметь обработать это сообщение и, например, предложить пользователю проверить права доступа, а не пытаться прочитать файл снова и снова.

Предсказуемость агента напрямую зависит от того, насколько детально вы описали не только «что делать», но и «что делать, если не получилось».

Заключение

Предсказуемость через структуру

Когда мы переходим от простых чат-ботов к автономным агентам, главная проблема смещается из плоскости «как написать промпт» в плоскость «как обеспечить воспроизводимость результата». Если агент получает размытую инструкцию, он начинает импровизировать. В системном администрировании мы называем это дрейфом конфигурации, и в мире AI это приводит к тому, что агент в один день выполняет задачу, а в другой — уходит в бесконечный цикл рассуждений.

Использование подхода из репозитория mattpocock/skills позволяет превратить хаотичные инструкции в набор атомарных, проверяемых навыков. Вместо того чтобы просить модель «сделай бэкап и отправь в облако», мы разбиваем это на три четких навыка: check_disk_space, create_archive и upload_to_s3.

С практической точки зрения, это напоминает создание модульного конфига в Ansible. Вы не пишете один огромный скрипт на 1000 строк, а собираете систему из маленьких, предсказуемых ролей.

Практическое применение: от текста к навыкам

Чтобы агент работал стабильно, его навыки должны иметь четко описанные входные параметры и ожидаемый результат. Если мы проектируем агента для управления домашней лабораторией, его «навыки» в формате JSON или YAML должны выглядеть не как пожелания, а как спецификации API.

Пример того, как можно структурировать описание навыка для агента, который должен проверять статус контейнеров:

yaml
skill: check_container_status
description: Проверяет состояние конкретного Docker-контейнера и возвращает статус.
parameters:
  container_name:
    type: string
    description: Имя или ID контейнера
    required: true
expected_output:
  status: string # running, exited, paused
  uptime: duration

Такая структура позволяет нам внедрить этап валидации. Если агент вернул ответ, не соответствующий схеме, мы не просто «надеемся на лучшее», а можем программно обработать ошибку, как при проверке синтаксиса в nginx.conf.

Итоги по внедрению

Разделение логики на навыки — это не усложнение, а способ контролировать сложность. Если вы строите систему на базе агентов, придерживайтесь трёх правил:

  1. Атомарность. Один навык — одна простая операция. Если навык требует от агента принять больше двух решений подряд, его нужно разбить.
  2. Типизация. Всегда определяйте, что агент получает на вход и что он обязан вернуть. Это залог предсказуемости.
  3. Модульность. Навыки должны быть переиспользуемыми. Навык read_log_file может пригодиться и агенту-диагносту, и агенту-монитору.

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

FAQ

Как правильно оформить навык для агента?

Чтобы агент работал предсказуемо, навык должен описывать не просто «что сделать», а четкий алгоритм с описанием входных и выходных данных. Если вы дадите агенту размытую инструкцию, он начнет галлюцинировать или зацикливаться.

Хороший навык по методологии из репозитория mattpocock/skills состоит из трёх частей: контекста, чёткого действия и формата ответа. С практической точки зрения это похоже на написание хорошего системного юнита в systemd: у вас есть описание сервиса, параметры запуска и то, что считается успешным завершением.

Пример структуры навыка в формате Markdown:

markdown
# Skill: Fetch_System_Logs

## Description
Извлекает последние 50 строк системного журнала через journalctl для анализа ошибок.

## Input
- service_name (string): имя юнита systemd (например, 'nginx' или 'docker').

## Steps
1. Выполни команду `journalctl -u {service_name} -n 50 --no-pager`.
2. Проверь наличие ключевых слов 'error', 'failed' или 'critical'.
3. Если ошибки найдены, выдели их в отдельный блок.

## Output
JSON-объект с полями:
- `status`: 'success' или 'error'.
- `logs`: массив строк с логами.
- `errors_found`: boolean.

Чем навыки отличаются от обычных промптов?

Разница заключается в области применения и уровне абстракции. Обычный промпт — это разовое указание модели, как обработать текст. Навык — это атомарная единица функциональности, которую агент может вызывать многократно в рамках сложной задачи.

Если промпт — это просьба «напиши код», то навык — это полноценная функция в библиотеке. Навыки позволяют разгрузить контекстное окно: вместо того чтобы запихивать в модель огромную инструкцию «как быть системным администратором», вы даёте ей набор узкоспециализированных инструментов. Это повышает предсказуемость, так как агент не пытается угадать логику, а следует строгому протоколу.

Можно ли использовать эти инструкции в Claude или GPT?

Да, эти принципы универсальны. Архитектура навыков не привязана к конкретной модели, она привязана к логике работы LLM (Large Language Models) через Tool Calling или Function Calling.

Claude (через Anthropic Tool Use) и GPT (через OpenAI Function Calling) работают наиболее эффективно, когда описание инструмента максимально структурировано. Если вы используете Claude, вы можете передавать эти навыки в параметре tools. Для GPT формат будет аналогичным, но с небольшими отличиями в описании JSON-схемы. Главное — сохранять строгость определений, которую предлагает автор подходов.

Нужно ли хранить навыки в отдельном репозитории?

С точки зрения управления инфраструктурой — да. Я сторонник того, чтобы конфигурация была отделена от кода приложения. Если вы строите систему агентов, навыки — это по сути ваша «библиотека компетенций».

Хранение навыков в отдельном Git-репозитории даёт несколько преимуществ:

  1. Версионирование: вы можете обновить навык Analyze_Logs, не ломая при этом другие части системы.
  2. Тестирование: вы можете прогнать автоматические тесты (например, через Python-скрипт) на каждом новом файле навыка, чтобы убедиться, что описание не стало противоречивым.
  3. Единый источник истины: несколько разных агентов (например, один на базе GPT, другой на базе Claude) могут использовать одни и те же инструкции.

Организуйте структуру так, чтобы каждый навык лежал в отдельном файле:

bash
# Пример структуры репозитория навыков
skills-repo/
├── network/
│   ├── check_connectivity.md
│   └── scan_ports.md
├── system/
│   ├── get_disk_usage.md
│   └── restart_service.md
└── README.md

Часто задаваемые вопросы

Нужно ли описывать каждый шаг работы агента в промпте?

Нет, это как раз то, чего стоит избегать. Вместо того чтобы прописывать пошаговый алгоритм действий внутри системной инструкции, лучше предоставить агенту набор инструментов (skills), которые он сможет вызывать самостоятельно. Ваша задача — описать не «как делать», а «что умеет делать» каждый конкретный навык и в каких ситуациях его стоит применить.

Чем подход с навыками отличается от обычного промпт-инжиниринга?

Обычный промпт-инжиниринг пытается управлять поведением модели через текстовые инструкции, что часто приводит к потере фокуса при усложнении задач. Подход с навыками переносит логику из области текста в область функциональных возможностей. Вы превращаете агента из «собеседника, который пытается угадать ваши намерения» в «оператора, который использует конкретные инструменты для достижения результата».

Как понять, что навык пора выделять в отдельную функцию?

Если вы замечаете, что описание какой-то задачи в системном промпте занимает больше нескольких абзацев или содержит сложные логические ветвления «если — то», этот навык пора выносить. С практической точки зрения, если инструкция начинает напоминать запутанный конфигурационный файл, который трудно отлаживать, значит, пора дробить её на специализированные модули.

Можно ли использовать навыки, если модель не поддерживает Tool Calling?

Технически это возможно через имитацию, когда модель должна выдать строго определённый текстовый паттерн, который затем перехватит ваш код. Однако для предсказуемости системы лучше использовать модели с нативной поддержкой вызова функций. Это гарантирует, что агент будет передавать параметры в нужном формате, а не просто имитировать выполнение команды.

Поделиться:TelegramX / TwitterVK