SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor

Как подключить Claude API к приложению на Python на VPS

Пошаговое руководство по настройке Claude API на Ubuntu 24.04. Вы научитесь безопасно хранить ключи, внедрять потоковую передачу данных и настраивать лимиты затрат для Python.

Что вы создаете

Инструмент командной строки на чистой Ubuntu 24.04 VPS, в который вы передаете сообщение об ошибке или фрагмент лога через pipe, а в ответ получаете диагностику на обычном английском языке: journalctl -u nginx -n 50 | explain. Это примерно шестьдесят строк кода на Python, которые задействуют все необходимое для реального приложения на базе Claude API: правильно сохраненный ключ, virtualenv, структуры ответов SDK, потоковую передачу, цепочку типизированных исключений и юнит systemd, чтобы программа работала без вашего участия.

Я выбрал этот проект намеренно. Большинство руководств по созданию «первого API-приложения» предлагают сделать чат-бота, который вы больше никогда не откроете. Анализатор логов приносит пользу серверу с первого же дня и заставляет вас столкнуться с двумя вещами, в которых новички действительно ошибаются: правильное чтение объекта ответа и контроль расходов. API тарифицируется за токен без верхнего предела, кроме тех, что вы установите сами, поэтому контроль затрат здесь является проектным требованием, а не второстепенной задачей. Это та же дисциплина, которая потребуется вам, когда вы перейдете к запуску Claude Code на этой же VPS в tmux.

Получение API-ключа в консоли

Доступ к API управляется через консоль Anthropic по адресу platform.claude.com. Зарегистрируйтесь и создайте ключ в разделе Settings → API Keys (документация содержит прямую ссылку platform.claude.com/settings/keys). Консоль предложит задать имя ключа, выбрать срок действия и привязать его к вашей учетной записи или сервисному аккаунту. Anthropic рекомендует использовать ключи сервисных аккаунтов для производственных сервисов и любых общих ресурсов. Ключ отображается только один раз, начинается с sk-ant- и не может быть просмотрен повторно. Скопируйте его сразу или удалите и создайте заново.

О расходах: по состоянию на октябрь 2026 года постоянного бесплатного уровня для API не существует. Согласно документации Anthropic, новые пользователи получают небольшое количество бесплатных кредитов для тестирования. Точная сумма отображается в консоли при регистрации. После того как кредиты закончатся, необходимо пополнить счет, чтобы запросы начали выполняться. Это не связано с подпиской claude.ai: API-ключ не предоставляет доступ к чат-приложению. План Pro не включает кредиты для API, однако планы Max и Team их содержат. По состоянию на октябрь 2026 года это 100 долларов в месяц для Max 5x и 200 долларов для Max 20x (в плане Team начисляется 20 долларов за стандартное место и 100 долларов за премиальное, с ограничением в 500 долларов). Кредиты активируются путем привязки организации из консоли в настройках биллинга claude.ai. Неиспользованные кредиты сгорают в конце каждого расчетного периода и не распространяются на Claude Code. Подробности доступны в разделе как работают ежемесячные API-кредиты для планов Max и Team. Если вы выбираете между подпиской и API, этот вопрос рассматривается отдельно: какой план Claude вам действительно нужен.

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

Храните ключи вне .bashrc

Рефлекторное действие — это export ANTHROPIC_API_KEY=sk-ant-... в ~/.bashrc. Не делайте этого. Возникают три отдельные проблемы:

  • Каждый процесс наследует ключ. Переменная окружения, экспортированная в вашей оболочке входа, распространяется на всё, что вы запускаете: веб-приложение, отчет об ошибках, который любезно выгружает окружение в лог, или страницу phpinfo(), которую кто-то оставил включенной. Поверхность атаки для ключа расширяется до «всего, что когда-либо запускает этот пользователь».
  • Ввод ключа сохраняется в ~/.bash_history. Выполните команду export вручную один раз, и ваш ключ навсегда останется в текстовом файле, попадая во все резервные копии домашнего каталога.
  • Ключ недоступен, когда он нужен systemd. Сервисы не читают ваш .bashrc, поэтому этот подход перестает работать именно тогда, когда вы переводите скрипт в статус юнита, что обычно проявляется как загадочная ошибка 401 в 6 утра.

Правильный подход на сервере — использование выделенного файла окружения с правами 600, который загружается только тем процессом, которому он необходим:

sudo mkdir -p /opt/explain
sudo install -m 600 -o root -g root /dev/null /etc/claude-explain.env
printf 'ANTHROPIC_API_KEY=sk-ant-YOUR-KEY-HERE\n' | sudo tee /etc/claude-explain.env >/dev/null

Используйте tee через printf, а не текстовый редактор, если хотите избежать попадания ключа во временные файлы редактора; в любом случае проверьте с помощью ls -l /etc/claude-explain.env, что файл имеет права -rw------- и принадлежит пользователю root. Интерактивные оболочки получают ключ при каждом вызове через обертку (см. ниже), а systemd получает его через EnvironmentFile=. Пользователь root считывает файл до понижения привилегий, поэтому пользователю сервиса не требуется доступ на чтение к этому файлу. Ключ никогда не появляется в коде, в git, в выводе ps или в истории командной оболочки.

Установка SDK в venv

В Ubuntu 24.04 поставляется Python 3.12 с принудительным соблюдением PEP 668, поэтому обычная команда pip install anthropic для системного интерпретатора завершается ошибкой error: externally-managed-environment. Эта ошибка означает, что ОС работает штатно; используйте virtualenv:

sudo apt update && sudo apt install -y python3-venv
sudo python3 -m venv /opt/explain/venv
sudo /opt/explain/venv/bin/pip install anthropic

На сервере не требуется выполнять активацию: прямой вызов /opt/explain/venv/bin/python всегда использует пакеты из venv.

Первый вызов и корректное чтение ответа

import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from the environment

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1000,
    messages=[{"role": "user", "content": "Explain what a systemd unit file is in three sentences."}],
)

for block in response.content:
    if block.type == "text":
        print(block.text)

Две детали в этих двенадцати строках определяют основную концепцию API. Во-первых, anthropic.Anthropic() без аргументов считывает ключ из переменных окружения; никогда не передавайте его в виде строкового литерала. Во-вторых, response.content — это список блоков контента, а не строка. Если вывести его напрямую, вы получите результат, типичный для новичка:

[TextBlock(citations=None, text='A systemd unit file is...', type='text')]

Это не ошибка, а представление объекта (repr). Ответы могут содержать блоки разных типов (текст, вызовы инструментов, процесс мышления), поэтому необходимо перебирать их в цикле и проверять block.type == "text" перед обращением к .text. В Opus 5.5 это важно с самого первого вызова: процесс мышления включен всегда, поэтому, если модель не пропускает его для простого запроса, список начинается с блока thinking, текст которого по умолчанию пуст, а response.content[0].text не является вашим ответом. Реализуйте этот цикл с первого дня, и целый класс проблем вида «выводится мусор» будет исключен.

Используйте точный идентификатор модели claude-opus-5-5. Начиная с поколения 4.6, идентификаторы моделей не содержат дат и представляют собой закрепленные снимки (snapshots). Не поддавайтесь мышечной памяти (или советам из старых статей), предлагающей добавлять суффикс с датой к текущей модели; это приведет к ошибке 404, о которой сказано ниже. Для более старых моделей логика обратная: канонический идентификатор Haiku 4.5 включает дату — claude-haiku-4-5-20251001.

Сам инструмент: пояснение

Ниже представлена полная программа, принимающая данные из stdin, выводящая потоковую диагностику и обрабатывающая ошибки:

#!/usr/bin/env python3
"""explain: pipe an error or log excerpt in, get a diagnosis out."""
import sys
import anthropic

MODEL = "claude-opus-5-5"

def main() -> int:
    text = sys.stdin.read().strip()
    if not text:
        print("usage: journalctl -u nginx -n 50 | explain", file=sys.stderr)
        return 1

    client = anthropic.Anthropic()
    try:
        with client.messages.stream(
            model=MODEL,
            max_tokens=4096,
            system=(
                "You are a senior Linux sysadmin. The user pipes you server "
                "logs or error output. Name the most likely cause outright, "
                "then give the commands to confirm and fix it. Be terse."
            ),
            messages=[{"role": "user", "content": text}],
        ) as stream:
            for chunk in stream.text_stream:
                print(chunk, end="", flush=True)
        print()
    except anthropic.RateLimitError as e:
        retry_after = e.response.headers.get("retry-after", "60")
        print(f"rate limited; retry in {retry_after}s", file=sys.stderr)
        return 2
    except anthropic.APIStatusError as e:
        print(f"API error {e.status_code}: {e.message}", file=sys.stderr)
        return 2
    except anthropic.APIConnectionError:
        print("network error reaching the API", file=sys.stderr)
        return 2
    return 0

if __name__ == "__main__":
    sys.exit(main())

Сохраните её как /opt/explain/explain.py, затем добавьте обёртку, которая загружает ключ для интерактивного использования:

sudo tee /usr/local/bin/explain >/dev/null <<'EOF'
#!/bin/sh
set -a; . /etc/claude-explain.env; set +a
exec /opt/explain/venv/bin/python /opt/explain/explain.py "$@"
EOF
sudo chmod 755 /usr/local/bin/explain

(Обёртка должна запускаться через sudo, либо файл окружения должен принадлежать группе, в которую входит ваш администратор; выберите один из вариантов, вместо того чтобы ослаблять права доступа к файлу до 644.)

Почему потоковая передача. client.messages.stream выводит токены по мере их поступления, а не ожидает завершения всей генерации в тишине. Это позволяет избежать таймаутов HTTP при длинных ответах; SDK фактически отклоняет очень большие значения max_tokens при не потоковых вызовах именно по этой причине. text_stream возвращает только текст ответа, а при стандартном отображении процесса мышления в Opus 5.5 текст рассуждений не передаётся в поток, поэтому вывод остаётся чистым. Если вам нужен собранный объект впоследствии, вызовите stream.get_final_message() внутри блока with.

Почему именно такой порядок исключений. SDK генерирует типизированные исключения, начиная с наиболее специфичных: RateLimitError — это ошибка 429, содержащая заголовок retry-after, который указывает время ожидания; APIStatusError охватывает другие ответы, отличные от 2xx (проверьте e.status_code >= 500 на наличие проблем на стороне сервера); APIConnectionError означает, что запрос вообще не получил ответа. И прежде чем создавать цикл повторных попыток: SDK уже самостоятельно повторяет запросы при ошибках 429 и 5xx, по умолчанию дважды с экспоненциальной задержкой (max_retries на стороне клиента). К моменту, когда срабатывает ваш блок except, все попытки повтора уже исчерпаны, поэтому правильным действием в CLI будет вывод сообщения об ошибке и завершение работы, а не ожидание и повторная отправка запросов.

Контроль расходов

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

max_tokens — это ваш потолок затрат на один вызов. Выходные токены — самая дорогая часть; в модели Opus 5.5 они стоят в пять раз дороже входных, а max_tokens является жестким ограничением на количество токенов, которые модель может сгенерировать. «Убежавший» промпт не сможет стоить больше, чем вы разрешили. В моделях 5.5 этот лимит также покрывает процесс «мышления»: токены мышления учитываются в max_tokens и оплачиваются как выходные, даже если текст мышления не возвращается вам. Подбирайте размер под задачу: 4,096 токенов оставляют место для краткого анализа логов с учетом мышления перед ним; для задачи классификации требуется гораздо меньше. Если ответы обрываются с stop_reason: "max_tokens", значит, вы установили слишком малый лимит. Увеличивайте его осознанно (или снижайте уровень усилий, чтобы модель меньше «думала), вместо того чтобы по умолчанию ставить огромные значения.

Считайте перед отправкой. Входные данные тоже стоят денег, а логи бывают объемными. В API есть бесплатный эндпоинт для подсчета токенов (у него свои лимиты частоты запросов, отличные от создания сообщений):

count = client.messages.count_tokens(
    model="claude-opus-5-5",
    messages=[{"role": "user", "content": big_log_text}],
)
print(count.input_tokens)

Используйте его, чтобы случайно не отправить лог размером 2 GB через инструмент, и указывайте ту модель, которую будете использовать: Claude 4.7 и более поздние модели используют новый токенизатор, который создает примерно на 30% больше токенов для того же текста, чем ранние модели Claude. Не используйте tiktoken для этого — это токенизатор OpenAI, а не Claude, поэтому его подсчеты не совпадут с тем, что будет выставлено в счете.

Выбирайте модель под задачу, а не из лояльности. По состоянию на октябрь 2026 года, Opus 5.5 (claude-opus-5-5) стоит $4 за миллион входных токенов и $20 за миллион выходных; Haiku 5.5 (claude-haiku-5-5) стоит $0.10/$0.50 для промптов до 100,000 токенов ($0.50/$2.50 свыше этого) при контексте 1M; Sonnet 5.5 (claude-sonnet-5-5) находится посередине с ценами $2/$10. Конкретно: фрагмент лога на 2,000 токенов с ответом на 500 токенов стоит около $0.018 на Opus и $0.00045 на Haiku, плюс затраты на мышление модели, которые оплачиваются как выходные токены. Начинайте с Opus, пока оцениваете качество ответов, затем пробуйте те же промпты на Haiku: для простых преобразований в больших объемах она часто не уступает по качеству, будучи в сорок раз дешевле за токен. Проверяйте актуальные цифры на странице с ценами, прежде чем жестко прописывать их в бюджете.

Используйте пакетную обработку для всего, что может подождать. Batches API обрабатывает запросы асинхронно за 50% от стандартной цены, и большинство пакетов завершаются в течение часа. Ночные сводки, заполнение данных, массовая классификация — все, что не требует немедленного ответа от человека, должно выполняться там.

Кэширование промптов для повторяющегося контекста. Если каждый вызов повторно отправляет один и тот же большой системный промпт или руководство, пометьте его как кэшируемый:

response = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1000,
    system=[{
        "type": "text",
        "text": RUNBOOK_TEXT,  # the same 30K tokens on every call
        "cache_control": {"type": "ephemeral"},
    }],
    messages=[{"role": "user", "content": question}],
)
print(response.usage.cache_read_input_tokens)  # non-zero from the second call on

Запись в кэш стоит 1.25x от цены входных данных при TTL 5 минут, а чтение из кэша стоит 0.05x на Opus 5.5 и Sonnet 5.5 (0.1x на большинстве других моделей), поэтому второй вызов в рамках этого окна уже окупает первый. Есть два нюанса. Кэшируемый префикс должен соответствовать минимальному требованию модели — 512 токенов для Opus 5.5, поэтому очень короткий системный промпт не будет кэшироваться вовсе. И если cache_read_input_tokens остается нулевым при идентичных вызовах, значит, что-то в вашем префиксе меняется при каждом запросе (обычно виновата метка времени).

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

Запуск под управлением systemd

Преимущество использования файлов окружения: таймер, который каждое утро суммирует ошибки за вчерашний день.

# /etc/systemd/system/log-digest.service
[Unit]
Description=Daily error-log digest via the Claude API

[Service]
Type=oneshot
User=explain
Group=systemd-journal
EnvironmentFile=/etc/claude-explain.env
ExecStart=/bin/sh -c 'journalctl -p err --since yesterday | /opt/explain/venv/bin/python /opt/explain/explain.py >> /var/log/log-digest.txt'
# /etc/systemd/system/log-digest.timer
[Unit]
Description=Run the log digest every morning

[Timer]
OnCalendar=06:15
Persistent=true

[Install]
WantedBy=timers.target
sudo useradd -r -s /usr/sbin/nologin explain
sudo touch /var/log/log-digest.txt && sudo chown explain /var/log/log-digest.txt
sudo systemctl daemon-reload
sudo systemctl enable --now log-digest.timer
sudo systemctl start log-digest.service   # test it once, right now

Обратите внимание, что дает использование EnvironmentFile=: systemd считывает файл, принадлежащий root с правами 600, до смены прав на непривилегированного пользователя explain. Таким образом, процесс получает переменную, в то время как пользователь не может прочитать файл с ключом. Группа systemd-journal предоставляет доступ к логам. Протестируйте конфигурацию с помощью ручного запуска systemctl start и проверьте journalctl -u log-digest.service; не ждите 06:15, чтобы обнаружить опечатку. Когда этот шаблон перерастет возможности конвейера командной оболочки, такой же подход с ключами в файле окружения можно будет напрямую перенести в рабочие процессы n8n на базе Claude на том же сервере.

Типовые ошибки и сообщения о них

401 при использовании рабочего ключа. Исключение выглядит так:

anthropic.AuthenticationError: Error code: 401 - {'type': 'error', 'error': {'type': 'authentication_error', 'message': 'invalid x-api-key'}, 'request_id': 'req_011CSHoEeqs5C35K2UUqR7Fy'}

Если ключ работает в командной строке, но сервис возвращает 401, значит, сервис его не получил. Помните, что systemd не считывает .bashrc; убедитесь, что EnvironmentFile= указывает на верный путь. Другие причины: кавычки, попавшие в файл переменных окружения (ANTHROPIC_API_KEY="sk-ant-...", systemd удаляет кавычки, но . file в вашей оболочке может сохранить их в значении, если вы использовали их некорректно), лишние пробелы, ключ, который вы отозвали в консоли на прошлой неделе, или ключ, срок действия которого истёк.

404 из-за опечатки в названии модели. Самая частая причина — добавление даты к идентификатору модели, у которой нет версий с датой:

anthropic.NotFoundError: Error code: 404 - {'type': 'error', 'error': {'type': 'not_found_error', 'message': 'model: claude-opus-5-5-20260922'}, 'request_id': 'req_011CSJqymAvNw4bT3qmDdMbA'}

Идентификаторы моделей текущего поколения пишутся точно так, как указано: claude-opus-5-5, claude-sonnet-5-5, claude-haiku-5-5, claude-fable-5-1. Исключение составляют модели до поколения 4.6: claude-haiku-4-5 — это удобный псевдоним для датированного идентификатора claude-haiku-4-5-20251001, оба варианта работают. Копируйте идентификаторы из документации по моделям, не полагайтесь на память или старые руководства.

429 rate_limit_error. Тип ошибки — rate_limit_error, ответ содержит заголовок retry-after с количеством секунд ожидания. SDK уже выполнил две попытки повторного запроса с экспоненциальной задержкой, прежде чем вы увидели исключение. Постоянные ошибки 429 означают, что ваш стабильный темп запросов превышает лимиты тарифа. Группируйте задачи или распределяйте их во времени, не сокращайте интервалы между повторными попытками.

Выводится объект, а не текст. Вывод выглядит как [TextBlock(citations=None, text='...', type='text')]. Вы вывели response.content вместо того, чтобы перебрать блоки и считать .text из тех, где block.type == "text". Все примеры SDK выше делают это правильно; скопируйте цикл.

error: externally-managed-environment. Вы запустили pip install для системного Python в Ubuntu 24.04. Используйте venv, никогда не запускайте --break-system-packages на сервере, который вам дорог.

Обрезанные ответы. response.stop_reason == "max_tokens" означает, что модель достигла лимита вывода в процессе генерации. Это штатное поведение; намеренно увеличьте лимит и помните, что в моделях 5.5 процесс «мышления» расходует тот же лимит.

Когда ваше первое приложение заработает, создание AI-агента с Claude позволит превратить эти же вызовы API в агента, использующего инструменты.

FAQ

Сколько стоит тестирование Claude API?

Совсем немного для инструмента такого уровня. По состоянию на октябрь 2026 года, Opus 5.5 стоит 4 доллара за миллион входных токенов и 20 долларов за миллион выходных. Типичный анализ логов (несколько тысяч токенов на входе, несколько сотен на выходе) обойдется примерно в два цента, не считая токенов рассуждения (которые тарифицируются как выходные). При использовании Haiku 5.5 (0.10/0.50 доллара) стоимость составит менее десятой доли цента. Месяц ежедневных сводок обойдется дешевле чашки кофе. Риск заключается не в цене за запрос, а в бесконечных циклах и неконтролируемых max_tokens, поэтому в данном руководстве оба параметра задаются явно.

Существует ли бесплатный тариф для Claude API?

По состоянию на октябрь 2026 года постоянного бесплатного тарифа нет. Согласно документации Anthropic, новые пользователи получают небольшое количество бесплатных кредитов для тестирования API — это разовая пробная акция. Точная сумма отображается в консоли при регистрации, после чего необходимо пополнить баланс аккаунта. Исключение составляют подписчики Max и Team: их тарифные планы включают ежемесячные кредиты на использование API, о которых сказано выше. Если ваша цель — нулевая стоимость каждого запроса, а не максимальное качество, альтернативой будет самостоятельный запуск модели с открытыми весами через Ollama, где вы платите оперативной памятью, а не токенами.

Как обеспечить безопасность API-ключа на сервере?

Никогда не храните его в коде, не добавляйте в git, не экспортируйте из .bashrc и не вводите в оболочке, где он сохранится в истории команд. Разместите его в файле, принадлежащем root, с правами доступа 600. Загружайте ключ для каждого процесса отдельно, используйте скрипт-обертку для интерактивной работы, EnvironmentFile= для systemd и создавайте по одному ключу на сервер или проект. Это позволит отозвать скомпрометированный ключ точечно, а не отключать всё сразу. Если ключ попал в публичный доступ или в git-коммит, немедленно аннулируйте его в консоли; удаление коммита не отменяет утечку.

С какой модели Claude лучше начать?

Начните с claude-opus-5-5, пока оцениваете качество ответов и пригодность модели для ваших задач. Используйте её, чтобы оценить идею при максимальном качестве; при небольших объемах разница в стоимости составит лишь несколько центов. После того как промпт будет отлажен, протестируйте реальные данные на claude-haiku-5-5. Для задач суммаризации, классификации и сортировки логов эта модель часто справляется достаточно хорошо, при этом стоимость за токен в 40 раз ниже. Переходите на Haiku или Sonnet на основе измерений, а не по умолчанию.