Языковые модели стали полноценным инструментом в арсенале разработчика. Но между «спросить ChatGPT» и «получить реально полезный ответ» — пропасть. Разница в том, как вы формулируете промпт.
В этом гайде собраны готовые промпты для ключевых задач разработки: от code review до архитектурных решений. Каждый промпт можно скопировать и адаптировать под свой проект.
[...] на свои данные. Промпты работают с любой современной моделью: Claude, ChatGPT, GigaChat, Gemini.Code review (ревью кода) — одна из самых частых задач, где AI экономит часы работы. Модель проверяет код по нескольким измерениям одновременно: баги, безопасность, производительность, стиль.
Сделай code review этого Python-кода. Проверь по следующим критериям:
1. Баги и потенциальные ошибки
2. Безопасность (SQL-инъекции, XSS, утечки данных)
3. Производительность (N+1, лишние аллокации)
4. Читаемость и соответствие PEP 8
5. Обработка ошибок
Для каждой проблемы укажи серьёзность (critical / warning / info) и предложи исправленный код.
```python
def get_user(id):
user = db.query(f"SELECT * FROM users WHERE id = {id}")
return user[0]
def get_users_with_orders():
users = db.query("SELECT * FROM users")
result = []
for user in users:
orders = db.query(f"SELECT * FROM orders WHERE user_id = {user['id']}")
user['orders'] = orders
result.append(user)
return result
```1. SQL-инъекция — get_user() и get_users_with_orders()
Строковая интерполяция в SQL-запросах открывает путь для SQL-инъекций.
# Было
db.query(f"SELECT * FROM users WHERE id = {id}")
# Стало
db.query("SELECT * FROM users WHERE id = %s", (id,))
2. N+1 запрос — get_users_with_orders()
Для 1000 пользователей будет 1001 запрос к БД.
# Стало — один JOIN-запрос
def get_users_with_orders():
return db.query("""
SELECT u.*, json_agg(o.*) as orders
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
GROUP BY u.id
""")
3. Нет обработки «не найдено» — get_user() упадёт с IndexError.
4. Нет типизации — отсутствуют аннотации типов.
5. SELECT * вместо конкретных полей — тянет лишние данные.
При рефакторинге важно дать модели контекст: какой стек, какие паттерны предпочитаете, что именно не устраивает в текущем коде.
Отрефактори эту функцию. Требования:
- Разбей на мелкие функции с единой ответственностью
- Добавь типизацию (TypeScript)
- Убери дублирование
- Сохрани ту же внешнюю логику
```typescript
async function processOrder(order: any) {
// validate
if (!order.items || order.items.length === 0) {
throw new Error('No items')
}
if (!order.userId) {
throw new Error('No user')
}
// calculate total
let total = 0
for (const item of order.items) {
total += item.price * item.quantity
if (item.discount) {
total -= item.discount
}
}
// apply promo
if (order.promoCode) {
const promo = await db.promos.findOne({ code: order.promoCode })
if (promo && promo.active) {
total = total * (1 - promo.discount / 100)
}
}
// save
const saved = await db.orders.create({
userId: order.userId,
items: order.items,
total: total,
status: 'pending'
})
// notify
await sendEmail(order.userId, 'Order created', `Order #${saved.id}`)
return saved
}
```interface OrderItem {
price: number
quantity: number
discount?: number
}
interface CreateOrderInput {
userId: string
items: OrderItem[]
promoCode?: string
}
function validateOrder(order: CreateOrderInput): void {
if (!order.items?.length) throw new Error('No items')
if (!order.userId) throw new Error('No user')
}
function calculateSubtotal(items: OrderItem[]): number {
return items.reduce((sum, item) => {
const itemTotal = item.price * item.quantity
return sum + itemTotal - (item.discount ?? 0)
}, 0)
}
async function applyPromo(subtotal: number, promoCode?: string): Promise<number> {
if (!promoCode) return subtotal
const promo = await db.promos.findOne({ code: promoCode })
if (promo?.active) {
return subtotal * (1 - promo.discount / 100)
}
return subtotal
}
async function processOrder(input: CreateOrderInput) {
validateOrder(input)
const subtotal = calculateSubtotal(input.items)
const total = await applyPromo(subtotal, input.promoCode)
const saved = await db.orders.create({
userId: input.userId,
items: input.items,
total,
status: 'pending',
})
await sendEmail(input.userId, 'Order created', `Order #${saved.id}`)
return saved
}
Что изменилось: Типизация через интерфейсы, каждая функция делает одно дело, убрана вложенность, reduce вместо мутабельной переменной.
AI особенно хорош в генерации тестов: он видит edge cases, которые разработчик может пропустить.
Напиши юнит-тесты для функции calculateSubtotal на TypeScript (vitest). Покрой:
- Обычный случай (несколько товаров)
- Товар со скидкой
- Пустой массив
- Отрицательные значения
- Очень большие числа (проверка на overflow)
```typescript
function calculateSubtotal(items: OrderItem[]): number {
return items.reduce((sum, item) => {
const itemTotal = item.price * item.quantity
return sum + itemTotal - (item.discount ?? 0)
}, 0)
}
```import { describe, it, expect } from 'vitest'
import { calculateSubtotal } from './order'
describe('calculateSubtotal', () => {
it('рассчитывает сумму для нескольких товаров', () => {
const items = [
{ price: 100, quantity: 2 },
{ price: 50, quantity: 1 },
]
expect(calculateSubtotal(items)).toBe(250)
})
it('учитывает скидку на товар', () => {
const items = [
{ price: 100, quantity: 1, discount: 10 },
]
expect(calculateSubtotal(items)).toBe(90)
})
it('возвращает 0 для пустого массива', () => {
expect(calculateSubtotal([])).toBe(0)
})
it('корректно обрабатывает нулевую скидку', () => {
const items = [{ price: 100, quantity: 1, discount: 0 }]
expect(calculateSubtotal(items)).toBe(100)
})
it('обрабатывает большие числа без overflow', () => {
const items = [
{ price: 999_999, quantity: 999 },
]
expect(calculateSubtotal(items)).toBe(999_999 * 999)
})
})
Вместо того чтобы часами искать баг, опишите модели симптомы, контекст и код — и получите гипотезы для проверки.
Помоги найти баг. Симптомы:
- API-эндпоинт /api/users иногда возвращает 500
- Происходит только при большом количестве параллельных запросов
- В логах: "Connection pool exhausted"
- Стек: Node.js, Express, PostgreSQL, pg-pool
Код подключения:
```javascript
const pool = new Pool({
max: 5,
connectionString: process.env.DATABASE_URL
})
app.get('/api/users', async (req, res) => {
const client = await pool.connect()
const result = await client.query('SELECT * FROM users')
res.json(result.rows)
})
```
Что не так и как исправить?Проблема найдена: утечка соединений.
Вы вызываете pool.connect(), но нигде не вызываете client.release(). Каждый запрос забирает соединение из пула и не возвращает его. При max: 5 после пятого запроса пул исчерпан.
Исправление 1 — с release:
app.get('/api/users', async (req, res) => {
const client = await pool.connect()
try {
const result = await client.query('SELECT * FROM users')
res.json(result.rows)
} finally {
client.release() // всегда возвращаем соединение
}
})
Исправление 2 — без ручного управления (рекомендуемый):
app.get('/api/users', async (req, res) => {
const result = await pool.query('SELECT * FROM users')
res.json(result.rows)
})
pool.query() сам берёт и возвращает соединение.
Дополнительно: увеличьте max до 20-50 и добавьте idleTimeoutMillis: 30000.
Когда вы стоите перед архитектурным выбором, модель помогает структурировать trade-offs.
Помоги выбрать подход для системы уведомлений. Контекст: - Микросервисная архитектура на Go - 50k пользователей, до 1M уведомлений/день - Каналы: push, email, SMS - Требования: доставка за < 5 секунд, at-least-once, приоритизация Сравни два варианта: 1. Очередь сообщений (RabbitMQ / Kafka) 2. Event-driven через Redis Streams Для каждого: архитектура, плюсы, минусы, когда выбрать. Дай рекомендацию.
Архитектура: Producer → Kafka topic (partitioned by user_id) → Consumer groups (push-worker, email-worker, sms-worker)
Плюсы: гарантия доставки, replay, горизонтальное масштабирование, приоритизация через отдельные топики. Минусы: сложность инфраструктуры, latency 50-200ms (не критично при SLA 5s), overhead для 1M/day.
Архитектура: XADD → stream per channel → consumer groups с XREADGROUP
Плюсы: минимальная latency (< 10ms), простота, вы уже используете Redis. Минусы: нет replay по умолчанию, ограничение по памяти, менее надёжен при сбоях.
При 1M/day и at-least-once — Kafka. Это overengineering для текущей нагрузки, но правильный выбор с учётом роста. Redis Streams подойдёт как MVP, но при росте до 10M/day придётся мигрировать.
Напиши JSDoc-документацию для этого модуля. Для каждой функции опиши:
- Что делает
- Параметры с типами
- Возвращаемое значение
- Возможные исключения
- Пример использования
```typescript
export async function retryWithBackoff<T>(
fn: () => Promise<T>,
maxRetries: number = 3,
baseDelay: number = 1000
): Promise<T> {
let lastError: Error
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn()
} catch (error) {
lastError = error as Error
if (attempt < maxRetries) {
const delay = baseDelay * Math.pow(2, attempt)
await new Promise(resolve => setTimeout(resolve, delay))
}
}
}
throw lastError!
}
```/**
* Выполняет асинхронную функцию с автоматическими повторами
* и экспоненциальной задержкой между попытками.
*
* Задержка удваивается с каждой попыткой:
* попытка 0 — мгновенно, попытка 1 — 1с, попытка 2 — 2с, попытка 3 — 4с.
*
* @template T — тип возвращаемого значения функции
* @param fn — асинхронная функция для выполнения
* @param maxRetries — максимальное число повторов (по умолчанию 3)
* @param baseDelay — базовая задержка в мс (по умолчанию 1000)
* @returns Promise с результатом fn
* @throws Последнюю ошибку, если все попытки исчерпаны
*
* @example
* const data = await retryWithBackoff(
* () => fetch('https://api.example.com/data').then(r => r.json()),
* 5, // до 5 повторов
* 2000 // начальная задержка 2 секунды
* )
*/
export async function retryWithBackoff<T>(
fn: () => Promise<T>,
maxRetries: number = 3,
baseDelay: number = 1000
): Promise<T>
1. Что нужно обязательно включить в промпт для code review?
2. Почему лучше ставить одну задачу на промпт?
3. Какой формат ответа стоит запрашивать для автоматизации (CI/CD)?