Observability для Cursor и Claude Code: хуки, трассировка агентов | AiManual
AiManual Logo Ai / Manual.
13 Янв 2026 Гайд

Когда твой AI-агент тупит и молчит: полный гайд по observability для Cursor и Claude Code

Пошаговое руководство по настройке хуков и трассировки AI-агентов в Cursor и Claude Code. Hooks.json, жизненный цикл агента, отладка промптов.

Вы даете промпт. Агент "думает" три минуты. В ответ - тишина. Или код, который ломает продакшен. Или бесконечное "я понял, сейчас сделаю". Знакомо?

Работа с AI-агентами в Cursor и Claude Code похожа на управление черным ящиком. Внутри происходит какая-то магия, но когда что-то ломается - понять причину невозможно. Нет логов. Нет трейсов. Нет метрик.

Почему observability для AI-агентов - это не опция, а обязаловка

Представьте: у вас есть junior-разработчик, который:

  • Никогда не говорит, что делает
  • Не показывает промежуточные результаты
  • При ошибке молчит и ждет следующей задачи
  • Забывает контекст через 5 минут

Вы бы такого взяли на работу? Нет. Но именно так работают AI-агенты без observability.

Самый частый вопрос в чатах разработчиков: "Почему агент сделал это, а не то?" Ответа нет. Потому что вы не видите, как он принимал решения.

Hooks.json: конфиг, который превращает черный ящик в прозрачный

В Cursor и Claude Code есть скрытая фича - хуки. Это как middleware для вашего агента. Каждое событие в жизненном цикле агента можно перехватить, логировать, модифицировать.

💡
Хуки работают и в Cursor, и в Claude Code. Разница только в расположении конфига. В Cursor - в настройках IDE, в Claude Code - в папке проекта.

1 Создаем hooks.json

Для Cursor создайте файл в папке настроек:

# Для macOS
~/Library/Application\ Support/Cursor/User/hooks.json

# Для Windows
%APPDATA%\\Cursor\\User\\hooks.json

# Для Linux
~/.config/Cursor/User/hooks.json

Для Claude Code - в корне проекта:

touch .claude/hooks.json

2 Базовый конфиг для логирования

Вот минимальный hooks.json, который покажет все события агента:

{
  "hooks": [
    {
      "name": "log-everything",
      "pattern": ".*",
      "command": "echo '[HOOK] ${event.type} - ${event.timestamp}' >> /tmp/agent-hooks.log",
      "runInBackground": true
    }
  ]
}

Этот хук логирует все события в файл. Примитивно, но уже лучше, чем ничего.

Полный жизненный цикл агента: что можно перехватить

Агент в Cursor/Claude Code проходит через 12 этапов. Каждый этап - событие, которое можно ловить хуком.

Событие Когда срабатывает Что содержит
agent.start Агент запущен prompt, context, model
agent.thinking Начало "размышлений" current_step, max_steps
agent.tool.call Вызов инструмента tool_name, arguments
agent.tool.result Результат инструмента tool_name, result, duration
agent.error Ошибка агента error_message, stack_trace
agent.complete Задача завершена final_output, total_tokens, duration

Самое важное событие - agent.tool.call. Когда агент вызывает инструмент (читает файл, запускает команду, ищет в интернете), вы видите что именно и с какими аргументами.

Продвинутая настройка: трассировка с контекстом

Логировать события в файл - для новичков. Профессионалы отправляют данные в системы observability. Вот пример хука для OpenTelemetry:

{
  "hooks": [
    {
      "name": "opentelemetry-trace",
      "pattern": "agent.*",
      "command": "python3 -c \"
import json
import sys
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter

# Получаем данные события из stdin
event_data = json.load(sys.stdin)

# Настраиваем трейсер
trace.set_tracer_provider(TracerProvider())
tracer = trace.get_tracer(__name__)

# Создаем span
with tracer.start_as_current_span(event_data['type']) as span:
    span.set_attributes({'agent.id': event_data.get('agent_id', 'unknown')})
    span.set_attributes({'event.duration': event_data.get('duration', 0)})
    
    # Логируем дополнительные данные
    if 'prompt' in event_data:
        span.add_event('prompt', {'text': event_data['prompt'][:100]})
    
    print(f'Traced: {event_data["type"]}')
\"",
      "runInBackground": true,
      "passEventData": true
    }
  ]
}

Этот хук:

  • Передает все данные события в скрипт Python через stdin
  • Создает span в OpenTelemetry для каждого события
  • Добавляет атрибуты и события в span
  • Отправляет данные в Jaeger/Tempo/Grafana

Ключевой параметр "passEventData": true передает полные данные события в команду хука. Без него вы получите только тип события.

Keywords AI: секретное оружие для контекстных подсказок

Keywords AI в Cursor - это система, которая автоматически добавляет релевантные файлы в контекст агента. Работает по принципу semantic search. Но как понять, какие файлы были добавлены?

Хук для мониторинга Keywords AI:

{
  "hooks": [
    {
      "name": "keywords-ai-monitor",
      "pattern": "keywords.*",
      "command": "echo 'Keywords AI: ${event.type} - added ${event.added_files?.length || 0} files' >> /tmp/keywords.log",
      "runInBackground": true
    }
  ]
}

События Keywords AI:

  • keywords.search - поиск релевантных файлов
  • keywords.context_update - обновление контекста агента
  • keywords.cache_hit - использование кэшированных результатов

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

Отладка промптов: почему агент делает не то

Самая частая проблема - промпт написан криво, но вы об этом не знаете. Агент пытается выполнить невыполнимое, зацикливается или делает что-то совершенно не то.

Хук для анализа промптов:

{
  "hooks": [
    {
      "name": "prompt-analyzer",
      "pattern": "agent.start",
      "command": "python3 -c \"
import json
import sys
import re

event = json.load(sys.stdin)
prompt = event.get('prompt', '')

# Анализируем промпт
print('=== PROMPT ANALYSIS ===')
print(f'Length: {len(prompt)} chars')
print(f'Lines: {prompt.count(chr(10)) + 1}')

# Ищем типичные проблемы
if len(prompt) > 4000:
    print('WARNING: Prompt too long, agent may truncate')

if re.search(r'делай.*и.*сразу', prompt, re.IGNORECASE):
    print('WARNING: Multiple instructions without clear steps')

if not re.search(r'шаг.*\d+|сначала.*потом', prompt, re.IGNORECASE):
    print('INFO: No clear step-by-step instructions')

# Сохраняем для дальнейшего анализа
with open('/tmp/prompt-analysis.json', 'a') as f:
    json.dump({
        'timestamp': event['timestamp'],
        'prompt_preview': prompt[:200],
        'analysis': {
            'length': len(prompt),
            'has_steps': bool(re.search(r'шаг|step', prompt, re.IGNORECASE))
        }
    }, f)
    f.write('\n')
\"",
      "runInBackground": true,
      "passEventData": true
    }
  ]
}

Этот скрипт проверяет:

  • Длину промпта (если больше 4000 символов - могут быть проблемы)
  • Наличие четких шагов
  • Множественные инструкции в одном предложении
  • Сохраняет метаданные для анализа трендов

Интеграция с существующими системами мониторинга

Observability бесполезна, если данные лежат в отдельных лог-файлах. Нужна интеграция с вашим стеком мониторинга.

Grafana + Prometheus

{
  "hooks": [
    {
      "name": "prometheus-metrics",
      "pattern": "agent.*",
      "command": "python3 -c \"
import json
import sys
import requests
from datetime import datetime

event = json.load(sys.stdin)

# Отправляем метрики в Pushgateway
metrics = []
metrics.append(f'agent_events_total{{type=\"{event["type"]}\"}} 1')

if 'duration' in event:
    metrics.append(f'agent_event_duration_seconds{{type=\"{event["type"]}\"}} {event["duration"]}')

if 'error_message' in event:
    metrics.append(f'agent_errors_total{{type=\"{event["type"]}\"}} 1')

# Отправляем в Prometheus Pushgateway
try:
    response = requests.post(
        'http://localhost:9091/metrics/job/agent_hooks',
        data='\n'.join(metrics)
    )
except Exception as e:
    print(f'Failed to send metrics: {e}')
\"",
      "runInBackground": true,
      "passEventData": true
    }
  ]
}

Elasticsearch для полнотекстового поиска по логам

{
  "hooks": [
    {
      "name": "elasticsearch-logger",
      "pattern": "agent.(start|complete|error)",
      "command": "python3 -c \"
import json
import sys
from datetime import datetime
import requests

event = json.load(sys.stdin)

# Формируем документ для Elasticsearch
doc = {
    '@timestamp': datetime.utcnow().isoformat() + 'Z',
    'event_type': event['type'],
    'agent_id': event.get('agent_id', 'unknown'),
    'duration_ms': event.get('duration', 0) * 1000 if 'duration' in event else None,
    'has_error': 'error_message' in event
}

# Добавляем превью промпта для поиска
if 'prompt' in event:
    doc['prompt_preview'] = event['prompt'][:500]

# Отправляем в Elasticsearch
try:
    response = requests.post(
        'http://localhost:9200/agent-events/_doc',
        json=doc,
        headers={'Content-Type': 'application/json'}
    )
except Exception as e:
    print(f'Elasticsearch error: {e}')
\"",
      "runInBackground": true,
      "passEventData": true
    }
  ]
}

Типичные ошибки и как их избежать

Ошибка 1: Хуки замедляют работу агента. Решение: используйте "runInBackground": true и асинхронные вызовы в командах.

Ошибка 2: Хук падает и ломает работу агента. Решение: оборачивайте код в try-catch, логируйте ошибки хуков отдельно.

Ошибка 3: Слишком много данных, система observability тонет. Решение: фильтруйте события на уровне хуков, не логируйте все подряд.

Готовый production-конфиг

Вот полный hooks.json, который я использую в продакшене:

{
  "hooks": [
    {
      "name": "critical-events-log",
      "pattern": "agent.(start|error|complete)",
      "command": "logger -t cursor-agent '[${event.type}] ${event.agent_id} - duration: ${event.duration || 0}s'"
    },
    {
      "name": "prompt-sampling",
      "pattern": "agent.start",
      "command": "python3 /opt/scripts/sample_prompts.py",
      "runInBackground": true,
      "passEventData": true
    },
    {
      "name": "performance-metrics",
      "pattern": "agent.complete",
      "command": "curl -X POST -H 'Content-Type: application/json' -d '{\"agent_id\": \"${event.agent_id}\", \"duration\": ${event.duration}, \"tokens\": ${event.total_tokens || 0}}' http://metrics-service/api/agent-metrics",
      "runInBackground": true
    },
    {
      "name": "error-alert",
      "pattern": "agent.error",
      "command": "python3 /opt/scripts/send_alert.py --level ERROR --message 'Agent ${event.agent_id} failed: ${event.error_message}'"
    }
  ]
}

Этот конфиг:

  • Логирует критические события в системный лог
  • Сэмплирует промпты для анализа качества
  • Отправляет метрики производительности
  • Отправляет алерты при ошибках

Что дальше? Будущее observability для AI-агентов

Сейчас мы наблюдаем только события. Но следующий шаг - инструментирование самого процесса "мышления" агента. Claude обещает в будущих версиях дать доступ к цепочке мыслей (chain-of-thought). Когда это случится, хуки смогут перехватывать не только что агент сделал, но и почему он это сделал.

Пока этого нет, самый мощный инструмент - комбинация хуков и контекстных файлов. Если вы еще не читали про AGENTS.md и CLAUDE.md, сделайте это сейчас. Эти файлы + observability дают полный контроль над агентом.

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

P.S. Если ваш агент все еще тупит после настройки observability, возможно, проблема в его навыках. Посмотрите как заставить ИИ-агента помнить инструкции.