Ваш первый продакшен-вызов API (с учётом стоимости)
Игрушечный вызов API занимает одну строку. А продакшен-вызов обрабатывает ошибки, передаёт вывод потоком, следит за стоимостью и держит секреты в безопасности. Давайте соберём такой, шаг за шагом.
Шаг 1 — Секреты и модель из конфигурации
export ANTHROPIC_API_KEY="sk-ant-..." # never in source control
Храните идентификатор модели в конфигурации, а не разбрасывайте литералы по коду — тогда миграция становится тривиальной (почему). Выбирайте её осознанно — Выбор модели.
Шаг 2 — Устойчивый вызов с потоковой передачей
- Python
- TypeScript
import os, time, random, anthropic
client = anthropic.Anthropic()
MODEL = os.environ.get("CLAUDE_MODEL", "claude-sonnet-4-6")
def ask_stream(prompt, system=None, max_tokens=1024):
for attempt in range(5):
try:
with client.messages.stream(
model=MODEL, max_tokens=max_tokens,
system=system or anthropic.NOT_GIVEN,
messages=[{"role": "user", "content": prompt}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
final = stream.get_final_message()
print()
usage = final.usage
print(f"\n[tokens in/out: {usage.input_tokens}/{usage.output_tokens}]")
return final
except (anthropic.RateLimitError, anthropic.APIStatusError):
if attempt == 4: raise
time.sleep(min(2 ** attempt + random.random(), 30))
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const MODEL = process.env.CLAUDE_MODEL ?? "claude-sonnet-4-6";
export async function askStream(prompt: string, system?: string, maxTokens = 1024) {
for (let attempt = 0; attempt < 5; attempt++) {
try {
const stream = client.messages.stream({ model: MODEL, max_tokens: maxTokens, system,
messages: [{ role: "user", content: prompt }] });
for await (const e of stream)
if (e.type === "content_block_delta") process.stdout.write(e.delta.text ?? "");
const final = await stream.finalMessage();
console.error(`\n[tokens in/out: ${final.usage.input_tokens}/${final.usage.output_tokens}]`);
return final;
} catch (e: any) {
if (attempt === 4 || ![429, 500, 529].includes(e?.status)) throw e;
await new Promise(r => setTimeout(r, Math.min(2 ** attempt * 1000, 30000)));
}
}
}
Шаг 3 — Следите за стоимостью
- Логируйте расход токенов (как выше), чтобы видеть, во сколько обходится каждый вызов.
- Подбирайте
max_tokensпо размеру и модель тоже; ограничивайте ввод сфокусированными промптами. - Для повторяющихся стабильных префиксов добавьте кэширование промптов.
- См. Токены и цены и Стоимость и задержка.
Шаг 4 — Обрабатывайте неблагоприятные сценарии
- Повторяйте временные ошибки (429/5xx) с экспоненциальной задержкой (как выше); не повторяйте 400-е.
- Изящно обрабатывайте отказы.
- Задавайте тайм-аут и бюджет по стоимости/итерациям для всего агентного.
Проверка
Запустите: вы должны увидеть потоковый вывод, строку с расходом токенов и корректное поведение при принудительной ошибке (например, неверный ключ → чистое сообщение, а не аварийное завершение).