Промпт-инжиниринг для технической документации — как настроить ИИ-агента

Опубликовано 16.10.2026 05:02:00 в категории Искусственный интеллект

Какие документы можно доверить ИИ-агенту, что ему нужно явно запрещать, примеры плохих и правильных промптов для XML-комментариев, ADR и release notes, инструменты docs as code.

Документация — первое, что хочется отдать ИИ-агенту. Скучно, долго, а агент пишет быстро и грамотно. И именно здесь он ошибается чаще всего: уверенно, гладко и так, что ошибку не сразу заметишь.

Введение

В статье «Промпт-инжиниринг для Unit-тестов — как настроить ИИ-агента» я разбирал, как заставить агента писать тесты, которые действительно что-то проверяют. С документацией история похожая, но коварнее. Плохой тест хотя бы падает или подозрительно всегда проходит. Плохая документация не падает никогда: она просто тихо врёт, пока кто-нибудь ей не поверит.

Вот типичный результат, когда агента просят «добавить комментарии» без всяких правил:

/// <summary>
/// Gets the order.
/// </summary>
/// <param name="orderId">The order id.</param>
/// <returns>The order.</returns>
public Task<Operation<OrderDto, OrderError>> GetOrderAsync(Guid orderId, CancellationToken cancellationToken)

Формально всё на месте: summary есть, параметр описан, возвращаемое значение тоже. По сути — ноль информации. Всё это видно из сигнатуры метода. А то, ради чего комментарий вообще читают, не сказано: что будет, если заказа нет, какие ошибки бывают, есть ли у метода побочные эффекты.

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

В этой статье я покажу, как настроить ИИ-агента так, чтобы документация получалась полезной и честной. Разберём, какие документы вообще можно ему доверить, из чего состоит правильный промпт, что нужно агенту явно запрещать, и посмотрим примеры «плохой и правильный промпт» на трёх типах документов. В конце — инструменты, которые превращают документацию в часть кода, и где хранить правила для агента. Основной инструмент в примерах — Claude Code. Там, где у GitHub Copilot что-то устроено иначе, я добавил отдельные примечания.

Какие типы документов существуют и что можно доверить агенту

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

  • XML-комментарии (XML documentation comments) — описание публичного API прямо в коде. Из них строится справочник и подсказки IntelliSense, а в .NET 10 — ещё и описание операций в OpenAPI.
  • README — «входная дверь» проекта: что это, как запустить, где искать остальное.
  • Описание API (OpenAPI/Swagger) — контракт HTTP-интерфейса для потребителей сервиса.
  • Журнал изменений (changelog) — полный технический список изменений по версиям.
  • Заметки о выпуске (release notes) — то же самое, но для потребителя: что поменялось лично для него.
  • Описание пул-реквеста (pull request description) — что сделано, зачем и как проверить.
  • Записи архитектурных решений (Architecture Decision Records, ADR) — короткие документы о том, какое решение принято, почему и с какими последствиями.
  • Архитектурная документация — схемы (например, по модели C4), описание компонентов и их взаимодействия.
  • Инструкции по эксплуатации (runbook) — что делать при развёртывании, сбое, откате.
  • Техническое задание и спецификации требований — что система должна делать и с какими ограничениями.

Теперь главный вопрос: что из этого можно отдать агенту? Я пользуюсь простым критерием.

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

Агент отлично извлекает факты из кода: прочитает все ветки метода, найдёт все варианты ошибок, сопоставит коммиты с диффом. Но он не знает, почему команда выбрала RabbitMQ, какой SLA пообещали заказчику и кто имеет доступ к боевой базе. Когда фактов нет, а задачу поставили, агент их «достраивает». Это и есть галлюцинации (hallucinations) в документации.

Рис. 1. Карта доверия к типам документов

По этому критерию документы раскладываются на три группы.

«Можно доверить» не означает «можно не читать». Это значит, что все нужные факты агент может найти в коде сам, а вам остаётся бегло проверить результат на ревью.

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

«Не доверять» — здесь агент может помочь с оформлением и вопросами («что не описано в этом ТЗ?»), но содержание пишет человек. Обратите внимание: ADR попал сразу в две колонки. Оформить запись по шаблону агент может прекрасно. Придумать, почему решение было принято, — нет. Об этом подробнее в разделе «Примеры: ADR».

Анатомия правильного промпта для документации

Промпт (prompt) для документации отличается от промпта для кода. В коде результат проверяет компилятор и тесты. В документации проверяющего нет, поэтому все проверки нужно заложить в сам промпт. Я выделяю шесть обязательных частей.

Рис. 2. Из чего состоит промпт для документации

  1. Роль (role). Кто пишет. «Технический писатель в команде .NET» даёт другой текст, чем просто «ассистент».
  2. Аудитория (audience). Для кого. Документация для коллеги из своей команды и для внешнего потребителя API — это два разных текста.
  3. Источник истины (source of truth). Откуда брать факты. Самая важная часть: если её нет, агент берёт факты «из опыта», то есть из похожих проектов, которые он видел при обучении.
  4. Формат (format). Какие разделы, какие теги, какой шаблон.
  5. Запреты (constraints). Что делать нельзя ни при каких условиях. Этому посвящён весь следующий раздел.
  6. Критерии готовности (definition of done). Как понять, что работа закончена. Лучше всего — проверяемые: «нет предупреждений CS1591», «все варианты ошибок перечислены».

Посмотрим, как это выглядит на практике.

Плохой промпт

Напиши документацию для OrderService.

Непонятно, для кого писать, в каком формате, откуда брать факты и когда остановиться. Агент выберет всё это сам — и выберет «среднее по интернету».

Правильный промпт

Роль: ты технический писатель в команде .NET-разработки.

Задача: опиши публичные методы класса OrderService в XML-комментариях.

Аудитория: разработчик другой команды. Он вызывает сервис впервые
и не видит его исходный код.

Источник истины: только файл OrderService.cs и типы, на которые он
ссылается. Ничего не бери «из опыта» и из похожих проектов.

Формат:
- <summary> — одно предложение о результате метода;
- <param> — смысл параметра и ограничения на значение;
- <returns> — все варианты результата, включая ошибки;
- <remarks> — побочные эффекты и неочевидное поведение.

Запреты: не меняй код; не выдумывай исключения, которых метод
не бросает; если факт нельзя проверить по коду — напиши
TODO(doc): <вопрос автору> и не заполняй это место догадкой.

Готово, когда: у каждого публичного члена есть комментарий,
все варианты ошибок перечислены, сборка без предупреждений CS1591.

Длинно? Да. Но писать такой текст каждый раз не придётся: в разделе «Где хранить правила и как проверять результат» я покажу, как вынести его в файлы правил, после чего сам промпт сокращается до одной строки.

Обратите внимание на приём с TODO(doc). Агенту нужен легальный способ сказать «я не знаю». Если такого способа нет, он заполнит пустое место правдоподобной выдумкой: модель обучена давать ответ, а не оставлять пропуски. Маркер решает эту проблему, а заодно по нему легко найти все открытые вопросы обычным поиском.

Что нужно явно запрещать агенту

Это ключевой раздел статьи. Агент не знает ваших негласных правил. Для человека очевидно, что документирование — не повод исправлять код, а для агента это просто ещё одна полезная правка. Поэтому всё, что для вас «само собой разумеется», нужно написать явно.

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

Выдумывать факты

Агент дописывает параметры конфигурации, версии, лимиты, ссылки и цифры, которых нет в коде. Особенно опасно в README и runbook: читатель потратит час, разыскивая несуществующий ключ Orders:RetryCount.

Правило 1:

Используй только факты из переданного кода и файлов. Если для
документа нужен факт, которого там нет (версия, лимит, адрес,
поведение при ошибке), вставь TODO(doc): <вопрос> и продолжай.

Пересказывать сигнатуру

«Gets the order», «The order id», «The cancellation token». Комментарий есть, пользы нет, а предупреждение CS1591 исчезло — и создалась иллюзия, что API задокументирован.

Правило 2:

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

Менять код

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

Правило 3:

Задача — только документация. Разрешено менять XML-комментарии
и файлы *.md. Код не трогай. Если видишь ошибку в коде, опиши её
в ответе отдельным пунктом, но не исправляй.

Для этого запрета одного промпта мало: в документации Claude Code прямо сказано, что инструкции из CLAUDE.md — это контекст, а не принудительная настройка. Поэтому я подстраховываюсь проверкой в CI — она есть в разделе «Где хранить правила и как проверять результат».

Переписывать существующие разделы

Просили добавить раздел о настройке — агент «заодно улучшил» весь README: поменял структуру, переформулировал установку, удалил «устаревший» раздел, на который ссылаются из wiki.

Правило 4:

Не удаляй и не переписывай существующие разделы, если об этом
не просили. Новые сведения добавляй рядом. Если старый текст
противоречит коду — отметь это через TODO(doc), а не исправляй молча.

Раскрывать внутреннюю реализацию

В публичной документации API появляются имена таблиц, очередей и внутренних классов. Это и утечка лишней информации, и проблема на будущее: внутренности поменяются, а внешний документ продолжит их описывать.

Правило 5:

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

Вставлять секреты и боевые адреса

Агент видит appsettings.Production.json или переменные окружения в скрипте и «для наглядности» вставляет в пример настоящую строку подключения. Документация уходит в публичный репозиторий вместе с паролем.

Правило 6:

Никогда не вставляй в документацию строки подключения, ключи,
токены, пароли, реальные адреса серверов и имена из боевой
конфигурации. В примерах используй localhost, example.com
и значения вида <your-api-key>.

Додумывать причины, гарантии и обещания

В ADR появляются аргументы, которые никто не высказывал («выбрали RabbitMQ за высокую производительность»), а в README — гарантии, которые никто не давал. Через год по этому ADR будут принимать новые решения.

Правило 7:

Не формулируй причины решений, обещания и гарантии (SLA, время
ответа, «выдерживает N запросов»), если их нет в источниках.
Такие места помечай TODO(doc) — их заполняет человек.

Рекламный язык

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

Правило 8:

Пиши нейтрально и конкретно. Запрещены оценочные слова:
«мощный», «удобный», «гибкий», «современный», «лучший»,
«легко», «просто». Вместо оценки — факт или пример.

Придумывать свои термины

В одном документе «заказ», в соседнем «ордер», в третьем «покупка». Читатель вправе решить, что это три разных сущности.

Правило 9:

Используй термины из docs/glossary.md. Не придумывай синонимы:
если в проекте «заказ», то не «ордер» и не «запрос на покупку».

Все девять запретов вместе — это готовый файл правил. Полную его версию вы найдёте в разделе «Где хранить правила и как проверять результат».

Примеры: XML-комментарии к публичному API

Начнём с самого «доверяемого» типа документов. Возьмём метод отмены заказа. Для результата используется мой пакет Calabonga.Results: метод возвращает Operation<OrderDto, OrderError> — либо данные, либо ошибку, без исключений.

public async Task<Operation<OrderDto, OrderError>> CancelOrderAsync(
    Guid orderId,
    string reason,
    CancellationToken cancellationToken)
{
    var order = await _dbContext.Orders.FindAsync([orderId], cancellationToken);
    if (order is null)
    {
        return Operation.Error(OrderError.NotFound(orderId));
    }

    if (order.Status == OrderStatus.Cancelled)
    {
        return Operation.Result(order.ToDto());
    }

    if (order.Status == OrderStatus.Shipped)
    {
        return Operation.Error(OrderError.AlreadyShipped(orderId));
    }

    order.Cancel(reason, _timeProvider.GetUtcNow());
    await _dbContext.SaveChangesAsync(cancellationToken);
    return Operation.Result(order.ToDto());
}

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

Плохой промпт

Добавь XML-комментарии к методу CancelOrderAsync.

Результат:

/// <summary>
/// Cancels the order.
/// </summary>
/// <param name="orderId">The order id.</param>
/// <param name="reason">The reason.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>The result of the operation.</returns>
/// <exception cref="InvalidOperationException">
/// Thrown when the order cannot be cancelled.
/// </exception>

Три проблемы сразу. Пересказ сигнатуры вместо описания. Ни слова о том, какие бывают ошибки. И выдуманное исключение InvalidOperationException: агент «знает», что методы отмены обычно бросают исключения, хотя этот метод возвращает ошибку через Operation.Error. Разработчик, поверивший комментарию, обернёт вызов в try/catch и пропустит настоящую ошибку.

Правильный промпт

/doc-xml OrderService.CancelOrderAsync

Опиши метод по правилам из .claude/rules/xml-comments.md.
Дополнительно:
- пройди по всем веткам метода и перечисли в <returns> каждый
  вариант результата: успех и каждую ошибку OrderError;
- поведение при повторном вызове опиши в <remarks>, если оно
  видно из кода;
- исключения указывай только те, что метод бросает явно
  (throw в теле метода). Возврат Operation.Error — не исключение;
- язык комментариев — русский, как во всём проекте.

Результат:

/// <summary>
/// Отменяет заказ и возвращает его актуальное состояние.
/// </summary>
/// <param name="orderId">Идентификатор заказа.</param>
/// <param name="reason">
/// Причина отмены. Передаётся в <see cref="Order.Cancel"/>.
/// </param>
/// <param name="cancellationToken">Токен отмены операции.</param>
/// <returns>
/// Данные заказа (<see cref="OrderDto"/>) при успехе или ошибку:
/// <list type="bullet">
/// <item><description>
/// <see cref="OrderError.NotFound"/> — заказа с таким идентификатором нет;
/// </description></item>
/// <item><description>
/// <see cref="OrderError.AlreadyShipped"/> — заказ уже отгружен,
/// отменить его нельзя.
/// </description></item>
/// </list>
/// </returns>
/// <remarks>
/// Повторная отмена уже отменённого заказа ошибкой не считается:
/// метод вернёт текущее состояние заказа и ничего не изменит,
/// новая причина при этом не сохраняется.
/// TODO(doc): что происходит с оплатой при отмене — в этом методе не видно.
/// </remarks>

Каждое утверждение в этом комментарии можно проверить по коду. А там, где код ответа не даёт (что происходит с оплатой внутри Order.Cancel), агент честно оставил TODO(doc) вместо догадки.

Команда /doc-xml — это навык (skill) Claude Code, который хранится в репозитории. Как он устроен, покажу в разделе «Где хранить правила и как проверять результат».

И ещё один полезный приём. Включите генерацию файла документации в проекте:

<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

После этого компилятор выдаёт предупреждение CS1591 для каждого публичного члена без XML-комментария. Получается готовый список задач для агента и проверяемый критерий готовности. В .NET 10 есть и бонус: пакет Microsoft.AspNetCore.OpenApi с помощью генератора исходного кода (source generator) сам переносит XML-комментарии в OpenAPI-документ. Один хорошо описанный метод — и описание появляется сразу в двух местах.

Примеры: ADR

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

Плохой промпт

Напиши ADR о переходе на RabbitMQ.

Агент напишет образцовый ADR: высокая производительность, гарантированная доставка, масштабируемость, сравнение с Kafka и Azure Service Bus. Всё гладко и убедительно. Только ничего из этого команда не обсуждала: реальной причиной было то, что склад три раза падал в сентябре. Через год новый архитектор прочитает этот ADR и будет спорить с аргументами, которых никто не высказывал.

Правильный промпт

/adr docs/adr/discussions/2026-10-orders-warehouse.md

Составь ADR по шаблону docs/adr/template.md (формат MADR).

Источник: только приложенное обсуждение. Сообщения в нём
пронумерованы — после каждого утверждения ставь ссылку
на номер сообщения, например [сообщение 8].

Правила:
- статус — «предложено». «Принято» ставит человек;
- варианты, которые не обсуждались, не добавляй;
- если для раздела нет данных — напиши TODO(adr): <вопрос>;
- причины и последствия бери только из обсуждения,
  даже если «и так понятно».

Результат:

# ADR-0007. Обмен сообщениями между заказами и складом через RabbitMQ

- Статус: предложено
- Дата: 2026-10-14
- Участники: команда заказов, команда склада, архитектор

## Контекст

Сервис заказов вызывает склад по HTTP при каждом оформлении заказа.
В сентябре было три инцидента: склад недоступен, и заказ
не оформляется [сообщения 3, 8].

## Решение

Резервирование товара отправляется командой в очередь RabbitMQ.
Заказ оформляется сразу, результат резерва приходит событием
[сообщение 14].

## Рассмотренные варианты

- Повторные HTTP-вызовы с Polly — отклонено: не помогает, если склад
  недоступен дольше минуты [сообщение 9].
- TODO(adr): Kafka упомянута в сообщении 11, но не обсуждалась.
  Рассматривали ли её всерьёз?

## Последствия

- Заказ может быть оформлен до подтверждения резерва [сообщение 15].
- TODO(adr): в обсуждении нет решения, что делать, если склад
  отказал в резерве.

Здесь работают три приёма. Ссылки на номера сообщений превращают каждое утверждение в проверяемое: на ревью легко открыть сообщение 9 и убедиться, что про Polly говорили именно это. Статус «предложено» оставляет решение за людьми. А два TODO(adr) — это, пожалуй, самая ценная часть результата: агент нашёл дыры в обсуждении, которые команда пропустила. Что делать при отказе склада в резерве, никто не решил, и лучше узнать об этом сейчас, а не в день запуска.

Примеры: release notes из истории коммитов

Release notes — промежуточный случай. Факты есть в истории коммитов, но их нужно переписать для другого читателя: потребителю API неинтересно, что вы обновили пакеты и добавили тесты. Вот история коммитов с прошлого выпуска:

9f3e1a2 feat(api): отмена заказа через API
4c7d0b8 fix(orders): двойное списание при повторной оплате
e2a9f61 feat!: OrderDto.Total стал decimal
b81c3f0 chore: обновлены пакеты
7d2e4aa test: тесты для OrderService
a1b2c3d fix
c0ffee1 docs: README

Плохой промпт

Сделай release notes по git log с прошлого тега.

Результат:

## Что нового в версии 2.4.0

- Добавлена мощная функция отмены заказа через API
- Исправлена ошибка двойного списания
- Улучшена производительность и стабильность
- Обновлены пакеты
- Добавлены тесты для OrderService
- Различные исправления
- Обновлён README

Служебные коммиты попали в список. Рекламное «мощная функция» на месте. «Улучшена производительность» взялась из ниоткуда. Невнятный коммит fix превратился в «различные исправления» и спрятал реальное изменение. А главное — ломающее изменение типа OrderDto.Total затерялось среди прочих строк. Клиенты узнают о нём, когда у них упадёт десериализация.

Правильный промпт

/release-notes v2.3.0..HEAD

Аудитория: разработчики, которые используют наш API и пакет
клиента. Внутренняя кухня им не интересна.

Группы: «Новое», «Исправлено», «Ломает совместимость»,
«Требует уточнения». Пустые группы не выводи.

Правила:
- коммиты chore, test, ci, refactor, docs пропускай, если они
  не меняют поведение для пользователя;
- коммит с «!» после типа или с BREAKING CHANGE — только
  в группу «Ломает совместимость»;
- если из сообщения непонятно, что изменилось, посмотри дифф
  (git show <hash>). Пиши только то, что в нём видно.
  Не понял и после диффа — коммит в «Требует уточнения» с хешем;
- никаких «улучшена производительность» без замеров в коммите.

Результат:

## Версия 2.4.0

### Новое

- Заказ можно отменить через API.

### Исправлено

- Повторная оплата больше не приводит к двойному списанию.

### Ломает совместимость

- Поле `OrderDto.Total` теперь имеет тип `decimal`. Клиентам
  нужно обновить модели и пересобрать проект.
  TODO(release): указать прежний тип и шаги миграции.

### Требует уточнения

- `a1b2c3d fix` — ни из сообщения, ни из диффа непонятно,
  что исправлено для пользователя.

Рис. 3. От коммитов к заметкам о выпуске

Обратите внимание на правило с диффом. Claude Code умеет сам выполнить git show и посмотреть, что на самом деле изменилось в коммите. Это сильно повышает качество, но только при жёстком условии «пиши только то, что видно в диффе». Иначе агент посмотрит дифф, ничего не поймёт и всё равно напишет что-нибудь правдоподобное.

И честное замечание: лучший способ получить хорошие release notes — хорошие сообщения коммитов. Если команда пишет коммиты по соглашению Conventional Commits, агенту остаётся только редактура. Если в истории сплошные fix и wip, никакой промпт этого не исправит.

Инструменты для ведения документации как кода (docs as code)

Всё, о чём шла речь выше, работает в полную силу только при одном условии: документация "живёт" рядом с кодом. Этот подход называют «документация как код» (docs as code). Тексты хранятся в репозитории в виде Markdown, изменения проходят ревью через пул-реквесты, а сборку и проверки выполняет CI.

Для работы с ИИ-агентом это принципиально. Агент может прочитать и изменить файл в репозитории, но не может отредактировать страницу в Confluence, которую никто не выгружал. А линтеры в CI ловят то, что не удержат даже самые строгие запреты в промпте. Промпт задаёт правила, инструменты проверяют, что правила соблюдены.


Рис. 4. Путь изменения документации в подходе docs as code

Генераторы сайтов документации

  • DocFX — самый «родной» вариант для .NET: собирает справочник API из XML-комментариев и объединяет его со статьями на Markdown. Важная оговорка: Microsoft Learn больше не использует DocFX и с ноября 2022 года не поддерживает проект. Теперь его развивает сообщество под крылом .NET Foundation. Проект живой, последняя стабильная версия (на момент написания статьи) — 2.78.5 от февраля 2026 года.
  • MkDocs + Material for MkDocs — очень популярная связка, но начинать с неё новый проект я бы уже не стал. Окончание поддержки Material for MkDocs запланировано на 5 ноября 2026 года, до этой даты выходят только критические исправления. Развитие перенесено в Zensical — новый генератор с открытым исходным кодом от той же команды. Он умеет собирать существующие проекты с файлом mkdocs.yml, хотя полного паритета функций пока нет.
  • Docusaurus — хороший выбор, если команда и так живёт в экосистеме React и Node.js.
  • Writerside от JetBrains — отдельная IDE закрыта с 20 марта 2025 года, но плагин для IDE от JetBrains поддерживается и стал бесплатным. Подойдёт тем, кто работает в Rider.

Описание API

В .NET 9 и новее — пакет Microsoft.AspNetCore.OpenApi, а для просмотра Scalar или Swagger UI. Как я уже упоминал в разделе «Примеры: XML-комментарии к публичному API», в .NET 10 этот пакет подтягивает XML-комментарии в OpenAPI-документ автоматически. Хорошие комментарии от агента сразу становятся хорошим описанием API.

Диаграммы как код

Mermaid, PlantUML и Structurizr (для модели C4). Текстовую диаграмму агент может создать и обновить, когда меняется код. Картинку в PNG — нет. Если схема хранится как текст, она перестаёт устаревать молча.

ADR

Шаблон MADR (Markdown Architectural Decision Records) или классический формат Майкла Найгарда. Шаблон — это готовый раздел «формат» для промпта: положите его в docs/adr/template.md и ссылайтесь на него, как в примере из раздела «Примеры: ADR».

Журнал изменений

Соглашение Conventional Commits плюс генераторы вроде git-cliff или release-please. Генератор делает механическую часть — группирует коммиты по типам. Агент делает то, что генератору не по силам: переписывает изменения на языке потребителя и замечает невнятные коммиты.

Проверка текста

  • markdownlint — единообразная разметка Markdown.
  • Vale — проверка стиля по вашим правилам.
  • cspell — орфография, в том числе русская (через словарь @cspell/dict-ru_ru).
  • lychee — поиск битых ссылок.

Vale заслуживает отдельного внимания, потому что напрямую связан с разделом «Что нужно явно запрещать агенту». Запрет на рекламный язык можно продублировать правилом Vale, и он станет проверкой в CI, а не просьбой к модели:

# .vale/styles/Calabonga/Marketing.yml
extends: existence
message: "Оценочное слово «%s» — замените фактом или примером"
level: error
ignorecase: true
tokens:
  - мощн[а-яё]*
  - удобн[а-яё]*
  - гибк[а-яё]*
  - современн[а-яё]*
  - лучш[а-яё]*
# .vale.ini
StylesPath = .vale/styles
MinAlertLevel = suggestion

[*.md]
BasedOnStyles = Calabonga

Vale написан на Go, а в регулярных выражениях Go \w совпадает только с латиницей. Поэтому для русских слов используйте явный класс [а-яё]*, как в примере выше, иначе правило молча не сработает.

Полный набор проверок для CI выглядит примерно так:

# разметка Markdown
npx markdownlint-cli2 "docs/**/*.md"

# стиль текста, включая запреты из промпта
vale docs/

# орфография (для русского нужен словарь @cspell/dict-ru_ru)
npx cspell "docs/**/*.md"

# битые ссылки
lychee docs/

# сборка сайта документации
docfx docfx.json

Где хранить правила и как проверять результат

Длинный промпт из раздела «Анатомия правильного промпта для документации» неудобно копировать каждый раз. Правила должны жить в репозитории — рядом с кодом и под версионным контролем. Тогда их видит вся команда, изменения правил проходят ревью, а промпт в чате сокращается до одной команды.

Вот структура, к которой я пришёл в Claude Code:

CLAUDE.md                    # общие правила проекта
.claude/
  rules/
    docs.md                  # правила для всех *.md в docs/
    xml-comments.md          # правила для XML-комментариев
  skills/
    doc-xml/SKILL.md         # команда /doc-xml
    adr/SKILL.md             # команда /adr
    release-notes/SKILL.md   # команда /release-notes
docs/
  glossary.md                # термины проекта
  adr/
    template.md              # шаблон ADR

CLAUDE.md — общие правила проекта, которые Claude Code загружает в начале каждой сессии. Про документацию там достаточно нескольких строк:

CLAUDE.md

# Проект Orders

## Документация

- Правила для документации лежат в .claude/rules/docs.md
  и .claude/rules/xml-comments.md. Они обязательны.
- Термины — только из docs/glossary.md.
- Задача на документацию никогда не включает изменение кода.

.claude/rules/ — правила по темам. Поле paths в заголовке файла говорит Claude Code загружать правило только при работе с подходящими файлами. Правила для Markdown не мешают, когда вы пишете код, и наоборот. Вот файл со всеми запретами из раздела «Что нужно явно запрещать агенту»:

.claude/rules/docs.md

---
paths:
  - "docs/**/*.md"
  - "README.md"
---

# Правила для документации

## Источник истины
- Только код репозитория и файлы, которые приложены к задаче.
- Нет факта — пиши TODO(doc): <вопрос>. Догадки запрещены.

## Запрещено
- Менять код. Разрешены только файлы *.md и XML-комментарии.
- Удалять или переписывать существующие разделы без запроса.
- Описывать внутреннюю реализацию в публичных документах.
- Вставлять секреты, строки подключения, реальные адреса.
- Формулировать причины решений, гарантии и SLA без источника.
- Оценочные слова: «мощный», «удобный», «гибкий», «лучший».
- Синонимы вместо терминов из docs/glossary.md.

## Стиль
- Русский язык, обращение на «вы».
- Короткие абзацы, один абзац — одна мысль.
- Примеры кода — только компилируемые, с localhost и example.com.

И правила для XML-комментариев:

.claude/rules/xml-comments.md

---
paths:
  - "src/**/*.cs"
---

# Правила для XML-комментариев

- Описывай только публичные члены.
- <summary> — одно предложение о результате, а не пересказ имени.
- <returns> — все варианты результата, включая каждую ошибку.
- <exception> — только для явного throw в теле метода.
- <remarks> — побочные эффекты, повторный вызов, неочевидное.
- Ссылки на типы — через <see cref="..."/>, а не текстом.

.claude/skills/ — навыки, то есть повторяемые сценарии с именем. Навык doc-xml вызывается командой /doc-xml, которую мы использовали в примерах:

.claude/skills/doc-xml/SKILL.md

---
name: doc-xml
description: Добавляет XML-комментарии к указанному публичному члену
  по правилам проекта. Используй, когда просят задокументировать метод
  или класс.
---

1. Прочитай указанный член и все типы из его сигнатуры.
2. Пройди по всем веткам кода и выпиши варианты результата.
3. Напиши комментарий по .claude/rules/xml-comments.md.
4. Собери проект и убедись, что для этого члена нет CS1591.
5. В ответе перечисли все TODO(doc), которые остались.

Для GitHub Copilot

Структура та же, отличаются только имена файлов:

структура для Copilot

 

.github/
  copilot-instructions.md            # аналог CLAUDE.md
  instructions/
    docs.instructions.md             # аналог .claude/rules/docs.md
    xml-comments.instructions.md
  prompts/
    doc-xml.prompt.md                # аналог команды /doc-xml

Вместо поля paths используется applyTo со списком масок через запятую, а суффикс .instructions.md в имени файла обязателен:

.github/instructions/docs.instructions.md

---
applyTo: "docs/**/*.md,README.md"
---

# Правила для документации
...

Если в команде пользуются обоими агентами, удобно держать общие правила в AGENTS.md. Copilot читает его напрямую, а Claude Code — либо тоже напрямую (если в проекте нет CLAUDE.md), либо через импорт: строка @AGENTS.md внутри CLAUDE.md.

Как проверять результат

Правила — половина дела. Вторая половина — проверка, и её я делю на автоматическую и ручную.

Автоматически проверяется всё, что можно формализовать: линтеры из раздела «Инструменты для ведения документации как кода (docs as code)», отсутствие CS1591 и запрет №3 — «не менять код». Для последнего у меня есть простой скрипт: в пул-реквестах с меткой «docs» он проверяет, что в файлах *.cs изменились только строки с ///:

check-docs-only.sh

#!/usr/bin/env bash
# Проверка для PR с меткой docs: в *.cs изменились только комментарии ///
changed=$(git diff -U0 origin/main -- '*.cs' \
  | grep -E '^[+-]' \
  | grep -vE '^(\+\+\+|---)' \
  | grep -vE '^[+-][[:space:]]*///' \
  | grep -vE '^[+-][[:space:]]*$')

if [ -n "$changed" ]; then
  echo "В PR с документацией изменён код:"
  echo "$changed"
  exit 1
fi

Вручную на ревью я прохожу короткий чек-лист:

  • Каждое утверждение можно проверить по коду или по источнику. Выборочно проверяю два-три самых «уверенных».
  • Все TODO(doc) либо закрыты, либо у них есть ответственный.
  • В документе нет ничего, чего не должен видеть внешний читатель: внутренних имён, адресов, секретов.
  • Существующие разделы не переписаны без причины. Смотрю дифф, а не итоговый файл.
  • Текст понятен человеку, который видит проект впервые. Для этого иногда прошу прочитать коллегу из другой команды.

Заключение

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

Отсюда и рецепт:

  • доверяйте агенту документы, факты для которых есть в коде, и проверяйте остальное;
  • в каждом промпте задавайте источник истины и давайте легальный способ сказать «не знаю» — TODO(doc);
  • явно запрещайте выдумывать, менять код, переписывать чужое, раскрывать внутренности и рекламировать;
  • храните правила в репозитории, а не в голове и не в истории чата;
  • дублируйте важные запреты автоматическими проверками — линтерами и скриптами в CI.

Документация, написанная агентом по таким правилам, получается скучной в лучшем смысле слова: каждое утверждение проверяемо, а там, где фактов нет, честно стоит вопрос. Именно такой и должна быть техническая документация.

Использованные пакеты и инструменты

  • Calabonga.Results (2.0.1) — результат операции Operation<T, TError> в примере с XML-комментариями.
  • Microsoft.EntityFrameworkCore — доступ к данным в примере метода CancelOrderAsync.
  • Microsoft.AspNetCore.OpenApi — генерация OpenAPI-документа с XML-комментариями в .NET 10.
  • Claude Code — основной ИИ-агент в примерах: CLAUDE.md, .claude/rules, навыки.
  • GitHub Copilot — альтернативный агент: copilot-instructions.md, файлы инструкций и промптов.
  • DocFX — сборка сайта документации для .NET.
  • Vale, markdownlint-cli2, cspell, lychee — проверка текста, разметки, орфографии и ссылок.

Ссылки

Комментарии к статье ()

Загрузка...

Что-то пошло не по сценарию и завершилось ошибкой. Перезагрузить страницу (F5) 🗙

Переподключаем сервер...

Переподключение сломалось... Пробуем еще раз сек.

Не получилось переподключится.
Пожалуйста, обновите страницу F5

Сессия была поставлена сервером на паузу.

Восстановить сессию не получилось.
Пожалуйста, обновите страницу F5.