Продвинутый

CLAUDE.md: исправляем ошибки LLM при кодировании

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

A single CLAUDE.md file to improve Claude Code behavior, derived from Andrej Karpathy's observations on LLM coding pitfalls.

CLAUDE.md: LLM Coding Pitfalls Fixes and Recommendations

A single CLAUDE.md file to improve Claude Code behavior, derived from Andrej Karpathy's observations on LLM coding pitfalls. This guide addresses common errors in code generation, provides practical fixes, and explains how to align LLM outputs with real-world infrastructure requirements.

LLM Coding Pitfalls Analysis

Common Pitfalls in LLM Code Generation

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

Первая ловушка — предположения о контексте. Модель часто генерирует код, который работал бы в идеальном мире, но в реальной инфраструктуре просто падает с ошибкой. Например, вот типичный сценario:

bash
# Что модель может сгенерировать:  
docker run -d nginx  

# Что нужно на самом деле:  
docker run -d \  
  --name nginx-proxy \  
  -p 80:80 -p 443:443 \  
  -v /opt/nginx/conf.d:/etc/nginx/conf.d:ro \  
  -v /opt/nginx/ssl:/etc/nginx/ssl:ro \  
  --restart unless-stopped \  
  nginx:2.27-alpine  

Вторая проблема — игнорирование существующей архитектуры. Модель может предложить решение, которое противоречит вашим правилам безопасности или стандартам. На прошлой неделе кто-то попросил написать скрипт деплоя, и модель сразу предложила curl | bash. Это как питьё из утечки — может сработать, но последствия предсказуемы.

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

yaml
# Неполный docker-compose.yml от LLM:  
version: '3.8'  
services:  
  postgres:  
    image: postgres  
    environment:  
      POSTGRES_PASSWORD: secret  

# Как это должно выглядеть в продакшене:  
version: '3.8'  
services:  
  postgres:  
    image: postgres:16-alpine  
    container_name: postgres-main  
    restart: unless-stopped  
    environment:  
      POSTGRES_DB: app_production  
      POSTGRES_USER: app_user  
      POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password  
    volumes:  
      - postgres_data:/var/lib/postgresql/data  
      - ./init-scripts:/docker-entrypoint-initdb.d:ro  
    secrets:  
      - postgres_password  
    healthcheck:  
      test: ['CMD-SHELL', 'pg_isready -U app_user']  
      interval: 30s  
      timeout: 10s  
      retries: 3  
    logging:  
      driver: journald  
    networks:  
      - backend  

volumes:  
  postgres_data:  
    driver: local  

secrets:  
  postgres_password:  
    file: ./secrets/postgres_password.txt  

networks:  
  backend:  
    driver: bridge  

Understanding Model Limitations

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

Контекстное окно — не панацея. Даже если вы передали весь репозиторий, модель может просто не заметить важный файл. Я стал вручную проверять каждый вывод после того, как один LLM «пропустил» ./.env.production и сгенерировал конфиг с тестовыми ключами API.

Отсутствие реального опыта. Модели не могут сказать: «О, этот подход уже не работает на ядре 6.x» или «В этой версии баг #1234 исправлен иначе». Их знания ограничены датой обрезки (cutoff date), и после этого они как Кролик — продолжают верить в свою правоту, хотя мир уже изменился.

Проблема с актуальностью данных. На моём сервере Сова недавно отказывалась запускаться после того, как модель предложила использовать устаревший синтаксис docker-compose. Версия 2.27 сломала profiles, а модель продолжала его использовать. Ситуация напоминает мне выход Kubernetes 1.28 — я три недели объяснял коллегам, что podsecurity больше не существует.

Невозможность тестирования граничных случаев. Модель может написать идеальный скрипт для 100 запросов в секунду, но никогда не проверит, как он поведёт себя при 10 000. В домашней лаборатории это приводит к ситуациям, когда Plex успешно тестируется на десяти фильмах, а потом падает при попытке выдать сотню потоков одновременно.

Понимание этих ограничений помогает писать CLAUDE.md с учётом реального поведения модели, а не идеализированных сценариев.

Implementation Strategies

Code Structure Optimization

Во-первых, вынесение логики в небольшие, самодостаточные модули повышает предсказуемость работы агента. С практической точки зрения удобно разделять инфраструктурный слой (Docker-compose, сетевые настройки) от прикладного кода (приложения, обработчики).

yaml
# docker-compose.yml  
version: "3.9"  
services:  
  api:  
    build: ./api  
    ports:  
      - "8000:8000"  
    environment:  
      - DB_HOST=postgres  
      - REDIS_URL=redis://redis:6379  
    depends_on:  
      - postgres  
      - redis  
  worker:  
    build: ./worker  
    depends_on:  
      - redis  
      - postgres  

Команда запуска:

bash
docker compose up -d  
docker compose logs -f  

Если требуется итеративно менять конфигурацию, используйте docker compose config для проверки итогового файла перед применением.

Error Handling Techniques

Согласно рекомендациям из CLAUDE.md, явно задавайте стратегии отката и логирование ошибок.

bash
#!/usr/bin/env bash  
set -euo pipefail  

log_file="/var/log/myapp.log"  

handle_error() {  
  echo "$(date '+%Y-%m-%d %H:%M:%S') ERROR: $*" >> "$log_file"  
  exit 1  
}  

trap 'handle_error "Unexpected exit"' ERR  

# Пример обработки ошибки при подключении к БД  
psql -h "$DB_HOST" -U "$DB_USER" -d "$DB_NAME" <<SQL  
  INSERT INTO metrics (value) VALUES (1);  
SQL || handle_error "DB insert failed"  

В Docker-контексте добавьте HEALTHCHECK-директиву, чтобы система автоматически отменяла нерабочие контейнеры:

dockerfile
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \  
  CMD curl -f http://localhost/health || exit 1  

Эти практики позволяют поддерживать предсказуемость и быстро реагировать на сбои без ручного вмешательства.


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

Monitoring and Iteration

Performance Tracking

Для отслеживания эффективности CLAUDE.md в реальном времени используйте следующую команду в терминале:

bash
# Запуск скрипта анализа метрик  
python3 analyze_claude_performance.py --input claude.md --output metrics.json  

Этот скрипт измеряет:

  • Среднее время генерации кода (например, 2.3 секунды на задачу уровня "medium")
  • Частоту ошибок в первом проходе (например, 15% ошибок в примере с генерацией Dockerfile)
  • Соответствие кода стандартам PEP8 (например, 92% соответствия после применения форматирования через black)

Пример результата в metrics.json:

json
{  
  "code_generation_speed": {  
    "mean_seconds": 2.3,  
    "std_deviation": 0.4  
  },  
  "error_rate": {  
    "first_pass": "15%",  
    "post_fix": "2%"  
  }  
}  

Continuous Improvement

Реализуйте итеративное улучшение CLAUDE.md с использованием:

  1. Автоматизированного рефакторинга
bash
# Пример команды для обновления шаблонов  
sed -i 's/CLAUDE_CODE_TEMPLATE_1/CLAUDE_CODE_TEMPLATE_2/g' claude.md  
  1. Мониторинг через Prometheus

Создайте правило в prometheus.yml для отслеживания метрик:

yaml
- job_name: 'claude-monitoring'  
  static_configs:  
  - targets: ['localhost:8000']  
  metrics_path: '/metrics'  
  1. Обратная связь от пользователей

Добавьте в конец файла CLAUDE.md форму для комментариев:

markdown
## Пользовательские комментарии  
Если вы заметили ошибку в этом шаблоне, отправьте отчет через:  
[Отправить отчет об ошибке](https://example.com/report)  
  1. A/B тестирование

Сравните версии шаблонов с помощью:

bash
# Генерация кода для двух версий  
CLAUDE_VERSION=1 ./generate_dockerfile.sh  
CLAUDE_VERSION=2 ./generate_dockerfile.sh  

Пример сравнения результатов:

bash
# Проверка соответствия стандартам  
diff -u <(black --check dockerfile_v1.py) <(black --check dockerfile_v2.py)  

Дополнительные рекомендации по оптимизации LLM

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

Почему Claude генерирует код, который не работает в моей инфраструктуре?

LLM-модели, в том числе Claude, обучены на идеализированных примерах из открытых источников. Когда вы просите «запустить nginx», модель генерирует минимальный рабочий пример, не зная о ваших сетевых ограничениях, правилах безопасности и существующей архитектуре. Это как если бы IKEA продавал мебель без учёта высоты потолков. Чтобы исправить это, нужно явно описывать контекст: ОС, версии ПО, сетевые ограничения, volume-ы и restart-политику. В моём опыте хватает 3–5 предложений контекста, чтобы модель перестала «гадать» и начала генерировать применимый код.

Как проверить, что предложенное LLM решение не нарушит безопасность?

Первым делом изучите каждую команду: curl | bash — это всегда красный флаг, особенно в продакшене. Модели часто забывают про user namespaces, capabilities, read-only root filesystem и другие механизмы изоляции. Сравню с реальностью: в моей домашней лаборатории я никогда не запускаю контейнеры без --security-opt=no-new-privileges и ограничения прав на запись. Проверьте, есть ли в решении restart-политика, volume-ы с правильными правами, использование pinned версий образов. Если модель не указала конкретные версии (например, nginx:1.27-alpine вместо просто nginx), это повод задать уточняющий вопрос.

Что такое CLAUDE.md и как он помогает исправить ошибки LLM?

CLAUDE.md — это файл конфигурации поведения Claude Code, где вы описываете правила вашего проекта. В нём можно указать стандарты кода, архитектурные ограничения, используемые технологии и даже примеры «как не надо делать». Представьте это как инструкцию для нового сотрудника: без неё он будет делать как задумалось, а с ней — так, как принято в вашей команде. В моём случае такой файл фиксирует требование использовать Alpine-образы, всегда указывать restart-политику и хранить конфиги в /opt с правами 0644. Это экономит часы на ревью и исправление вариантов, сгенерированных моделью.

Нужно ли вручную править каждый код, который генерирует Claude?

Не каждый, но значительную часть — да. LLM отлично подходит для прототипирования и «скелетонов», но детали работы на вашем оборудовании остаются вашей ответственностью. В моей практике я всегда проверяю три аспекта: предсказуемость (конфиги не должны ломаться после обновления), безопасность (изоляция, права, pinned версии) и интеграцию с существующей инфраструктурой. Например, если вы уже используете Consul для service discovery, а модель предлагает решение на основе host networking — это противоречие, которое нужно исправить. Автоматизировать этот процесс можно через pre-commit хуки с shellcheck и hadolint.

Какие есть практические примеры исправления LLM-кода для Docker?

Рассмотрим типичный случай: модель генерирует docker run redis, а нужно запустить кеш в продакшене. Исправленный вариант включает: образ с pinned версией (redis:7.2-alpine), restart-политику (--restart unless-stopped), volume для persistence (/opt/redis/data:/data), настройку maxmemory и LRU-политику. Конкретнее: docker run -d --name redis-cache --restart unless-stopped -v /opt/redis/data:/data -e REDIS_MAXMEMORY=256mb -e REDIS_MAXMEMORY_POLICY=allkeys-lru redis:7.2-alpine redis-server --appendonly yes. Такой подход гарантирует, что контейнер выживет после перезагрузки сервера и не превратит кеш в «мусорную корзину» при нехватке памяти.

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