Контекст важнее промптов
Долгое время обсуждали "prompt engineering" -- искусство формулирования запросов к AI. Но практика показала: контекст важнее промпта. Промпт -- это инструкция ("что сделать"), а контекст -- это знания ("что ты знаешь о проекте, архитектуре, бизнесе").
Промпт без контекста:
"Напиши сервис для обработки заказов"
→ Генерический код, не подходящий для вашего проекта
Промпт с контекстом:
"Напиши сервис для обработки заказов.
Проект: Symfony 7.4, PHP 8.4.
Архитектура: Hexagonal, DDD.
Существующие сущности: Order, OrderItem, Product.
Бизнес-правила: заказы > 10,000 руб. требуют ручной проверки.
Паттерны: CQRS для операций записи."
→ Код, который вписывается в ваш проект
Context engineering -- это практика систематического предоставления AI правильной информации для получения качественного вывода.
Аналогия
Представьте, что вы наняли нового разработчика. В первый день вы не говорите ему "напиши сервис заказов". Вы:
- Показываете кодовую базу
- Объясняете архитектуру
- Рассказываете о бизнес-правилах
- Показываете coding conventions
- Даете примеры существующего кода
AI-ассистент -- это "новый разработчик" при каждом запросе. Контекстная инженерия -- это процесс онбординга AI в ваш проект.
Типы контекста
1. Проектный контекст
Общая информация о проекте, его технологическом стеке, архитектуре и соглашениях.
# CLAUDE.md (или .cursorrules, AGENTS.md)
## Project Overview
E-commerce platform for digital products.
Backend: Symfony 7.4 + PHP 8.4
Frontend: Nuxt 4 + Vue 3.6
Database: PostgreSQL 18
Queue: RabbitMQ 4 via Symfony Messenger
Cache: Redis 7
## Architecture
- Hexagonal architecture (ports & adapters)
- CQRS for write operations
- Event-driven async processing
- Domain-Driven Design for core business logic
## Coding Standards
- PHP: PSR-12, PHPStan level 9, strict_types always
- All classes final by default
- Constructor property promotion
- Readonly properties for DTOs
- Enums for statuses (never strings/ints)
## Directory Structure
src/
Domain/ # Entities, Value Objects, Repository Interfaces
Application/ # Use Cases (Commands, Queries, Handlers)
Infrastructure/ # Repository implementations, External Services
Presentation/ # Controllers, CLI Commands
## Naming Conventions
- Services: {Domain}Service (e.g., OrderService)
- Repositories: {Entity}Repository (e.g., UserRepository)
- DTOs: {Action}{Entity}DTO (e.g., CreateOrderDTO)
- Events: {Entity}{Action}Event (e.g., OrderCreatedEvent)
- Commands: {Action}{Entity}Command (e.g., CreateOrderCommand)
Как хранить проектный контекст
| Инструмент | Файл контекста | Описание |
|---|---|---|
| Claude Code | CLAUDE.md |
В корне проекта или в .claude/ |
| Cursor | .cursorrules |
В корне проекта |
| GitHub Copilot | .github/copilot-instructions.md |
В директории .github/ |
| Windsurf | .windsurfrules |
В корне проекта |
| Универсальный | AGENTS.md |
Стандарт от Google (2025) |
Структура файлов контекста:
project/
├── CLAUDE.md # Main AI instructions
├── .cursorrules # Cursor-specific rules
├── .github/
│ └── copilot-instructions.md # Copilot-specific rules
├── AGENTS.md # Universal agent instructions
└── docs/
├── adr/ # Architecture Decision Records
│ ├── 001-hexagonal.md
│ ├── 002-cqrs.md
│ └── 003-event-sourcing.md
└── coding-standards.md
2. Кодовый контекст
Релевантные файлы, интерфейсы и паттерны из вашей кодовой базы.
<?php
declare(strict_types=1);
// CONTEXT: Show AI your existing patterns
// 1. Base controller pattern
abstract class AbstractApiController extends AbstractController
{
protected function validationError(ConstraintViolationListInterface $violations): JsonResponse
{
$errors = [];
foreach ($violations as $violation) {
$errors[$violation->getPropertyPath()][] = $violation->getMessage();
}
return $this->json(['errors' => $errors], Response::HTTP_UNPROCESSABLE_ENTITY);
}
protected function notFound(string $message): JsonResponse
{
return $this->json(['error' => $message], Response::HTTP_NOT_FOUND);
}
}
// 2. Repository interface pattern
interface OrderRepositoryInterface
{
public function findById(Uuid $id): ?Order;
public function save(Order $order): void;
public function findByUser(Uuid $userId, Pagination $pagination): PaginatedResult;
}
// 3. DTO pattern
final readonly class CreateOrderDTO
{
public function __construct(
#[Assert\NotBlank]
#[Assert\Valid]
public array $items,
#[Assert\NotBlank]
public string $shippingAddressId,
public ?string $couponCode = null,
) {}
}
Когда вы показываете AI существующие паттерны, он генерирует код, который следует тем же паттернам. Без этого контекста AI будет использовать "стандартный" стиль, который может не совпадать с вашим проектом.
3. Доменный контекст
Бизнес-правила и ограничения, которые AI не может знать из общедоступных данных:
## Business Rules: Order Processing
### Order Creation
- Minimum order amount: 500 RUB
- Maximum items per order: 50
- Orders > 10,000 RUB require manager approval
- Repeat orders within 1 hour from same user: flag for fraud review
### Order Cancellation
- Free cancellation within 24 business hours
- After 24h: 20% cancellation fee
- Shipped orders: only return process, no cancellation
- Admin can override any cancellation restriction
### Pricing
- All prices stored in minor units (kopeks, cents)
- Currency: RUB only (no multi-currency)
- Tax: included in price (not calculated separately)
- Discounts: percentage only, max 50%, never below cost price
### Compliance
- Order data retention: 5 years (152-FZ)
- PII must be encrypted at rest
- Audit log for all price changes
- No deletion of completed orders (soft delete only)
AI без доменного контекста сделает "разумные" предположения, которые будут неправильными для вашего конкретного бизнеса.
4. Задачный контекст
Конкретная информация о текущей задаче:
## Task: Add Bulk Order Import
### What
API endpoint to import orders from CSV file uploaded by admin.
### Why
Managers currently create orders manually (5 min each).
With 50+ orders/day from phone channel, this is unsustainable.
### Acceptance Criteria
- [ ] POST /api/admin/orders/import accepts CSV file
- [ ] CSV format: customer_email, product_sku, quantity, shipping_address
- [ ] Validate each row independently (don't reject entire file for 1 bad row)
- [ ] Return: { imported: N, failed: N, errors: [{row: N, error: "..."}] }
- [ ] Max file size: 10 MB (~50,000 orders)
- [ ] Processing time: < 60 seconds
- [ ] Send notification to admin when import completes
### Constraints
- Must use existing OrderService.create() for each order
- Must respect all business rules (min amount, stock check, etc.)
- Must be idempotent (re-importing same file doesn't create duplicates)
- Must log all imports for audit
### Edge Cases
- Empty CSV
- CSV with only headers
- Duplicate orders in same file
- Non-existent product SKU
- Customer email doesn't exist (create customer?)
- Out of stock during import
- Server crash during import (partial import recovery)
Управление контекстным окном
AI-модели имеют ограниченное контекстное окно -- максимальное количество токенов, которое модель может обработать за один запрос.
Контекстное окно (2025-2026):
┌────────────────────────────────────────────────────────────┐
│ Claude Opus 4.5: 200K tokens (~150K слов) │
│ Claude Sonnet 4: 200K tokens (~150K слов) │
│ GPT-4o: 128K tokens (~96K слов) │
│ Gemini 2.0: 1M+ tokens (~750K слов) │
└────────────────────────────────────────────────────────────┘
Типичные размеры контекста:
CLAUDE.md: ~2K tokens
Один файл кода (200 строк): ~1K tokens
Спецификация задачи: ~500 tokens
10 релевантных файлов: ~10K tokens
Итого типичный контекст: 15-20K tokens из 200K доступных
Приоритизация контекста
Не все данные одинаково полезны. Приоритизируйте:
Приоритет 1 (ВСЕГДА включать):
├─ Coding conventions и стандарты
├─ Архитектурные решения
└─ Бизнес-правила для текущей задачи
Приоритет 2 (включать для связанных задач):
├─ Интерфейсы, которые нужно реализовать
├─ Существующие паттерны (примеры кода)
└─ Тесты, которые нужно пройти
Приоритет 3 (включать при необходимости):
├─ Связанные сущности и сервисы
├─ Database schema
└─ API-контракты зависимых сервисов
Приоритет 4 (НЕ включать без необходимости):
├─ Весь исходный код проекта
├─ Историю изменений
└─ Документацию, не связанную с задачей
Инкрементальный контекст
Вместо того чтобы дать AI весь контекст сразу, предоставляйте его поэтапно:
Этап 1: Обзор
"Вот структура проекта, архитектура, основные паттерны."
Этап 2: Специфика
"Вот интерфейс, который нужно реализовать.
Вот существующий сервис, от которого нужно наследовать логику."
Этап 3: Детали
"Вот тесты, которые должны пройти.
Вот edge cases, которые нужно обработать."
Анти-паттерны контекстной инженерии
1. Весь проект в контекст
# BAD: dumping entire codebase
"Вот мой проект (500 файлов). Напиши новый сервис."
Проблемы:
- AI "тонет" в нерелевантной информации
- Контекстное окно переполнено
- Модель не может приоритизировать
- Результат: генерический код, игнорирующий ваши паттерны
2. Нет контекста вообще
# BAD: no context at all
"Напиши UserService на PHP"
Проблемы:
- AI использует "стандартный" стиль
- Не соответствует архитектуре проекта
- Не учитывает бизнес-правила
- Результат: переписывать с нуля
3. Противоречивый контекст
# BAD: contradictory instructions
## In CLAUDE.md:
"Use repository pattern for all database access"
## In task description:
"Just use Doctrine EntityManager directly in the controller"
# AI не знает, чему следовать → непредсказуемый результат
4. Устаревший контекст
# BAD: outdated context file
## CLAUDE.md (not updated in 6 months):
"Database: MySQL 5.7"
"Framework: Symfony 5.4"
"PHP: 8.1"
# Реальность:
# Database: PostgreSQL 18
# Framework: Symfony 7.4
# PHP: 8.4
# AI генерирует код для устаревшего стека
5. Слишком общие инструкции
# BAD: vague instructions
"Write clean code"
"Follow best practices"
"Make it scalable"
# GOOD: specific instructions
"All classes must be final unless explicitly designed for extension"
"All methods must have return type declarations"
"Use constructor property promotion for dependency injection"
"Use cursor-based pagination (never OFFSET)"
Структура файла CLAUDE.md
Практическое руководство по созданию эффективного файла контекста:
# Project: [Name]
## Overview
[1-2 sentences about what the project does]
## Tech Stack
- Language: [version]
- Framework: [version]
- Database: [version]
- Cache: [version]
- Queue: [version]
## Architecture
[Brief description of architectural approach]
### Directory Structure
[Show key directories and their purpose]
## Coding Standards
### Naming
- Classes: PascalCase, final by default
- Methods: camelCase, verb-first (getUser, createOrder)
- Variables: camelCase, descriptive
- Constants: UPPER_SNAKE_CASE
- Database: snake_case, plural tables
### Patterns Required
- Constructor injection (never service locator)
- DTOs for data transfer (readonly)
- Enums for statuses (never magic strings)
- Value Objects for domain concepts (Money, Email, etc.)
### Patterns Forbidden
- God classes (max 300 lines)
- Service locator pattern
- Static methods for business logic
- Array as return type for structured data
## Testing
- Framework: PHPUnit 11
- Coverage: minimum 80%
- Types: unit, integration, functional
- Naming: test{Action}{Scenario}{ExpectedResult}
## Security
- All inputs validated
- SQL: parameterized queries only
- Passwords: bcrypt, cost 12
- API: JWT authentication
- Sensitive data: never in logs
## Common Commands
```bash
# Run tests
vendor/bin/phpunit
# Static analysis
vendor/bin/phpstan analyse
# Format code
vendor/bin/php-cs-fixer fix
Business Rules
[Key business rules that affect code decisions]
Known Limitations
[Technical debt, workarounds, things to be aware of]
---
## Architecture Decision Records (ADR)
ADR -- один из самых ценных типов контекста для AI. Они объясняют **почему** принято определенное решение, а не только **что** решено.
```markdown
# ADR-003: Event Sourcing for Order Processing
## Status
Accepted
## Context
Order processing requires full audit trail, ability to replay events,
and support for complex compensating transactions (refunds, partial cancellations).
## Decision
Use event sourcing for Order aggregate:
- All state changes represented as domain events
- Event store: PostgreSQL with events table
- Projection: rebuild read models from events
- Snapshots: every 100 events
## Consequences
### Positive
- Complete audit trail
- Ability to replay and debug
- Natural support for compensation
### Negative
- Higher complexity
- Eventual consistency for read models
- Need for snapshotting at scale
## Alternatives Considered
1. CRUD with audit log table -- simpler but loses event sequence
2. Change Data Capture -- infrastructure dependency, less control
## Code Pattern
```php
// Creating an order produces events
$order = Order::create($command);
// $order->getUncommittedEvents() returns [OrderCreatedEvent, ...]
// Cancelling produces compensation events
$order->cancel($reason);
// $order->getUncommittedEvents() returns [OrderCancelledEvent, ...]
Когда AI видит ADR, он понимает не только текущее состояние кода, но и **причины** архитектурных решений. Это значительно повышает качество генерации.
---
## Практические примеры
### Пример 1: Правильный контекст для нового эндпоинта
```markdown
## Задача
Добавить эндпоинт GET /api/v1/orders/{id}/invoice для генерации счета.
## Проектный контекст
См. CLAUDE.md (прикреплен к сессии)
## Кодовый контекст
Существующий контроллер (паттерн для подражания):
```php
#[Route('/api/v1/orders/{id}', methods: ['GET'])]
#[IsGranted('VIEW', subject: 'order')]
public function show(
#[MapEntity] Order $order,
): JsonResponse {
return $this->json(
OrderDTO::fromEntity($order),
);
}
Существующий сервис:
interface InvoiceGeneratorInterface
{
public function generate(Order $order): InvoiceDTO;
}
Доменный контекст
- Счет доступен только для оплаченных заказов (status = PAID)
- Формат: PDF (через DomPDF) или JSON
- Номер счета: INV-{year}-{sequence}, например INV-2026-00042
- Счет кэшируется (immutable после генерации)
Задачный контекст
- Формат ответа определяется заголовком Accept
- Accept: application/pdf → PDF файл
- Accept: application/json → JSON с данными счета
- По умолчанию: JSON
### Пример 2: Контекст для рефакторинга
```markdown
## Задача
Отрефакторить NotificationService: разделить на отдельные каналы.
## Текущее состояние (проблема)
```php
// Current: God class with all channels mixed
final class NotificationService
{
public function notify(User $user, Notification $notification): void
{
// 200+ lines mixing email, SMS, push, telegram logic
// Hard to test, hard to extend, violates SRP
}
}
Желаемое состояние
// Target: strategy pattern
interface NotificationChannelInterface
{
public function supports(NotificationType $type): bool;
public function send(User $user, Notification $notification): void;
}
// Each channel: separate class, independently testable
// Channels: EmailChannel, SmsChannel, TelegramChannel, PushChannel
// Dispatcher: iterates channels, finds supported, sends
Ограничения
- НЕ менять публичный API NotificationService
- Существующие тесты должны продолжать проходить
- Постепенная миграция: сначала extract, потом рефакторинг
---
## Инструменты для управления контекстом
### Автоматическая генерация контекста
```bash
# Generate project context automatically
# Architecture overview
find src/ -name "*.php" -path "*/Interface/*" | head -20
# List all public API endpoints
grep -rn "#\[Route" src/Controller/ --include="*.php"
# List all entities
find src/Entity/ -name "*.php" -exec basename {} \; | sort
# List all services
grep -rn "^final class.*Service" src/ --include="*.php"
# Database schema
pg_dump --schema-only learning_db > schema.sql
Валидация контекста
Периодически проверяйте, что ваш CLAUDE.md актуален:
## Context Freshness Checklist (monthly)
- [ ] Tech stack versions correct?
- [ ] Directory structure matches reality?
- [ ] Coding standards reflect current practices?
- [ ] Business rules up to date?
- [ ] Common commands still work?
- [ ] Known limitations still relevant?
- [ ] ADRs cover recent decisions?
Ключевые выводы
-
Контекст > промпт. Правильный контекст превращает генерический вывод AI в код, подходящий для вашего проекта.
-
Четыре типа контекста: проектный (архитектура, стек), кодовый (паттерны, интерфейсы), доменный (бизнес-правила), задачный (конкретные требования).
-
CLAUDE.md / .cursorrules -- живой документ, который нужно обновлять при каждом значимом изменении проекта.
-
ADR -- самый ценный тип контекста, потому что объясняет "почему", а не только "что".
-
Инкрементальный контекст эффективнее, чем весь проект сразу: давайте AI только то, что релевантно текущей задаче.
-
Анти-паттерны убивают качество: весь проект в контекст, нет контекста вообще, противоречивые инструкции, устаревшие данные.
Контекстная инженерия -- это инвестиция. Час, потраченный на хороший CLAUDE.md, экономит десятки часов на исправлении некачественного AI-вывода. Это как документация: кажется, что замедляет, а на самом деле ускоряет.