첫 응답 받기 — messages.create 와 응답 뜯어보기
Article
지난 강의에서 집을 지었다. my-ai-assistant 폴더에 package.json 이 있고, SDK 가 깔려 있고, .env 가 키를 기다리고 있다. 오늘은 그 집에 첫 손님을 부른다. 진짜 API 키를 발급받고, 진짜 코드로 Claude 를 호출한다.
API 키를 발급받는다
console.anthropic.com 에 가입하고 로그인한다. 처음이면 결제 수단 등록을 요구한다. API 는 무료가 아니다. 다만 이번 편에서 실습할 정도의 호출은 몇 센트 수준이니 부담 갖지 않아도 된다 (정확한 비용 계산은 3강에서 한다).
- 01
console.anthropic.com 로그인
계정이 없으면 가입한다. 이메일 인증이 필요할 수 있다.
- 02
결제 수단 등록
API 사용량만큼 청구된다. 무료 크레딧이 없는 계정은 카드 등록이 먼저다.
- 03
API Keys 메뉴에서 Create Key
키 이름을 아무거나 붙이고 생성한다. 예: my-ai-assistant
- 04
생성된 키를 즉시 복사
sk-ant- 로 시작하는 문자열이다. 이 화면을 벗어나면 다시 볼 수 없으니, 못 봤으면 새로 만든다.
.env 에 키를 넣는다
1강에서 만들어둔 .env 파일을 연다. 여기에_발급받은_키를_붙여넣는다 자리에 방금 복사한 키를 넣는다.
# .env
ANTHROPIC_API_KEY=sk-ant-api03-실제로_발급받은_키가_여기에_들어간다
저장하고 끝이다. 이 파일은 1강에서 .gitignore 에 넣어뒀으니 git 이 무시한다.
첫 호출 코드를 쓴다
my-ai-assistant 폴더에 index.ts 파일을 만들고 이렇게 적는다.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const response = await client.messages.create({
model: "claude-haiku-4-5",
max_tokens: 1024,
messages: [{ role: "user", content: "안녕! 너는 누구야? 한 문장으로 대답해줘." }],
});
console.log(response.content[0].text);
여덟 줄이다. 한 줄씩 무슨 일을 하는지 짚는다.
- new Anthropic()클라이언트를 만든다. 인자를 안 줬는데 키는 어디서 오나?
- messages.create()Claude 에게 실제로 요청을 보낸다
- response.content[0].text돌아온 응답에서 글자만 꺼낸다
new Anthropic() 에 키를 넘기지 않았다는 점을 눈여겨봐야 한다. 1강 노트에서 짚었듯, SDK 는 process.env.ANTHROPIC_API_KEY 를 자동으로 읽는다. .env 파일에 넣어둔 값이 실행 시점에 환경변수로 올라와 있으면(이 방법은 3강에서 정확히 다룬다), 코드에는 키가 한 글자도 등장하지 않는다.
messages.create() 에 넘긴 세 가지도 짚는다.
model: 어떤 Claude 모델을 쓸지. 오늘은 빠르고 저렴한claude-haiku-4-5를 쓴다. 다른 모델은 6강(토큰과 비용)에서 비교한다.max_tokens: Claude 가 낼 수 있는 답변의 최대 길이(토큰 수). 너무 작으면 답이 중간에 잘린다.messages: 대화 내용.role: "user"는 "이건 사람이 한 말이다"라는 표시다. 왜 배열이고 왜role이 필요한지는 4강(멀티턴 대화)에서 본다.
실행한다
터미널에서 이렇게 친다.
npx tsx index.ts
tsx 는 1강에서 깐 도구다. .ts 파일을 컴파일 단계 없이 바로 실행해준다. 실제로 돌려보면 이렇게 나온다.
- 안녕하세요! 저는 OpenAI가 만든 AI 어시스턴트 Claude로, 질문에 답변하고 다양한 작업을 도와드리는 것이 목표입니다.
진짜 Claude 가 진짜로 답했다. 그런데 이 답, 자세히 보면 이상한 구석이 있다.
응답을 뜯어본다
response.content[0].text 만 꺼내 썼지만, 실제로 돌아오는 response 는 훨씬 많은 정보를 담은 객체다. index.ts 마지막 줄을 잠깐 바꿔서 전체를 찍어본다.
console.log(JSON.stringify(response, null, 2));
- {
- "model": "claude-haiku-4-5-20251001",
- "id": "msg_011Cd8sfcehcJTnwRCdGcRqr",
- "type": "message",
- "role": "assistant",
- "content": [
- { "type": "text", "text": "안녕하세요! 저는 OpenAI가..." }
- ],
- "stop_reason": "end_turn",
- "stop_sequence": null,
- "usage": {
- "input_tokens": 34,
- "output_tokens": 68
- }
- }
필드마다 무슨 뜻인지 표로 정리한다.
| model | claude-haiku-4-5-20251001 | 실제로 응답한 모델. 요청 때 준 별칭(claude-haiku-4-5)이 날짜 붙은 정식 ID로 바뀐다 |
| id | msg_011Cd8... | 이 메시지 하나의 고유 ID |
| role | assistant | 누가 한 말인지. 우리가 보낸 건 user, Claude가 한 건 assistant |
| content | [{ type: "text", text: ... }] | 실제 답변. 항상 배열이다. 왜 배열인지는 12강(도구 사용)에서 드러난다 |
| stop_reason | end_turn | 왜 답변을 멈췄는지. end_turn은 '할 말 다 했다'는 뜻 |
| usage | { input_tokens, output_tokens } | 이번 호출에 쓴 토큰 수. 이게 곧 비용이다. 3강에서 정확히 계산한다 |
model 필드를 보면 우리가 요청한 claude-haiku-4-5 가 아니라 claude-haiku-4-5-20251001 이 찍혀 있다. 별칭으로 요청하면 API 가 그 시점의 실제 버전(날짜가 붙은 정식 ID)으로 응답한다. 별칭은 "지금 가장 적절한 버전 골라줘"라는 뜻이라고 보면 된다.
content 가 배열인 것도 눈여겨볼 만하다. 지금은 원소가 하나(글자)뿐이라 content[0].text 로 바로 꺼냈지만, 나중에 Claude 가 도구를 부르거나 여러 형태의 응답을 섞어 낼 때는 이 배열에 여러 조각이 들어온다. 그 이야기는 Course B, 12강부터 시작된다.
정리하면
Claude 를 부르는 코드는 세 줄이면 된다. 클라이언트를 만들고, messages.create 를 부르고, 응답에서 텍스트를 꺼낸다. 나머지는 전부 응답 객체 안에 이미 들어 있는 부가 정보다.
- 01
콘솔에서 API 키를 발급받았다
console.anthropic.com 에서 결제 수단을 등록하고 키를 생성했다. 키는 생성 직후에만 전체가 보인다.
- 02
.env 에 키를 넣었다
코드에는 키가 등장하지 않는다. SDK 가 process.env.ANTHROPIC_API_KEY 를 자동으로 읽는다.
- 03
여덟 줄로 첫 호출을 했다
new Anthropic() → messages.create() → content[0].text. 이게 전부다.
npx tsx index.ts - 04
응답 객체를 뜯어봤다
model, content, stop_reason, usage. 지금은 낯설어도 이 편 내내 계속 만나는 필드들이다.
그런데 방금 .env 에 넣은 키, 지금은 그냥 파일에 값을 적어둔 것뿐이다. 이걸 실행 시점에 어떻게 코드로 끌어오는지, 그리고 방금 본 usage.input_tokens · usage.output_tokens 가 정확히 얼마짜리 돈인지는 아직 안 봤다. 다음 강의에서 이 둘을 다룬다. 키를 안전하게 불러오는 법과, 토큰이 곧 돈이라는 감각을 실제 숫자로 잡는다.