첫 프로덕션 API 호출(비용을 인지한)
- 프로덕션 호출을 장난감 한 줄과 구분하는 네 가지 규율의 이름 짓기: 시크릿, 스트리밍, 비용, 오류 처리
- 일시적 실패(429/5xx)를 백오프로 재시도하고 — 400은 절대 재시도하지 않는 견고한 스트리밍 호출 작성
- 모델 ID를 설정에 두어 모델 전환이 검색 및 바꾸기가 아닌 한 줄 변경이 되도록
- 매 호출에서 토큰 비용을 지켜보고 신중하게 상한을 두기
장난감 API 호출 은 한 줄입니다. 프로덕션 호출은 오류를 처리하고, 출력을 스트리밍하고, 비용을 감시하고, 시크릿을 안전하게 지킵니다. 그것을 단계별로 만들어봅시다.
1단계 — 설정에서 시크릿과 모델
export ANTHROPIC_API_KEY="sk-ant-..." # never in source control
모델 ID를 설정에 두세요, 흩어진 리터럴이 아니라. 그래야 마이그레이션이 사소합니다(이유). 신중하게 고르세요 — Choosing a Model.
2단계 — 견고한, 스트리밍 호출
- Python
- TypeScript
import os, time, random, anthropic
client = anthropic.Anthropic()
MODEL = os.environ.get("CLAUDE_MODEL", "claude-sonnet-5")
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-5";
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)));
}
}
}
무엇에든 연결하기 전에 스모크 테스트하세요 — 하나의 작은 호출이 스트림, 토큰 라인, 키 모두가 작동함을 증명합니다:
첫 스모크 테스트 (Python REPL)
ask_stream("Say hello in one sentence.", max_tokens=64)3단계 — 비용에 유의
- 토큰 사용량을 로깅 하세요(위) — 그래야 각 호출이 얼마인지 볼 수 있습니다.
max_tokens와 모델을 적절히 크기 조정하세요; 집중된 프롬프트로 입력에 상한을 두세요.- 반복되는 안정적 접두사에는 프롬프트 캐싱 을 추가하세요.
- Tokens & Pricing 와 Cost & Latency 를 보세요.
4단계 — 불행한 경로 처리
- 일시적 오류(429/5xx)는 백오프로 재시도(위); 400은 재시도하지 마세요.
- 거부 를 우아하게 처리하세요.
- 에이전트적인 무엇에든 타임아웃 과 비용/반복 예산 을 설정하세요.
검증
각 경로를 강제하고 무슨 일이 일어나는지 보세요 — 프로덕션 호출은 단지 성공하는 것이 아니라 잘 실패함으로써 그 이름을 얻습니다:
Guided walkthrough1 of 4
- 텍스트가 끝에 하나의 블로킹 청크로 아닌, 생성되면서 점진적으로 인쇄됩니다. 그것이 사용자가 느끼는 지연 시간 이득입니다.
- 응답 후에 [tokens in/out: …] 라인이 보입니다. 그것이 매 호출에 로깅되는 호출당 비용 계량기입니다.
- ANTHROPIC_API_KEY를 잘못된 값으로 설정하고 다시 실행하세요 — 스택 트레이스 크래시가 아닌 깨끗한 오류를 받아야 합니다.
- 429/5xx 오류는 최대 5번 백오프로 재시도합니다; 잘못된 형식의 400 요청은 무의미하게 재시도하는 대신 즉시 표면화되어야 합니다.
스스로 확인해 보세요
0/3- 프로덕션 호출은 한 줄짜리 위에 층층이 쌓은 네 가지 규율입니다: 소스 밖의 시크릿, 스트리밍된 출력, 감시된 비용, 처리된 오류
- 일시적 실패(429/5xx)는 지연에 지터를 더한 지수 백오프로 재시도 — 그리고 400은 절대 재시도하지 마세요, 그것은 반드시 수정해야 할 요청 버그입니다
- 모델 ID를 설정에 두어 모델 전환이 코드베이스 전반의 검색 및 바꾸기가 아닌 한 줄이 되도록
- 매 호출에서 토큰 사용량을 로깅: 그것이 요청당 비용 계량기이고 추가 비용이 없습니다
- 스트리밍은 지각된 지연을 개선합니다; 타임아웃과 비용/반복 예산은 에이전트 루프가 폭주하지 않게 유지합니다