시작하기가이드
API로 멀티턴 채팅하기: messages 배열 다시 보내기
모델은 요청 사이에 아무것도 기억하지 않습니다. messages 배열을 다시 보내는 Python 채팅 루프를 만들고 입력 토큰이 어떻게 늘어나는지 확인하세요.

두 번째 질문에 이상한 답이 오는 이유는 API가 첫 번째 질문을 본 적이 없기 때문입니다. 모델은 요청 사이에 아무것도 유지하지 않으므로, 채팅은 당신이 만드는 것입니다. 매 답변 후에 messages라는 리스트에 답변을 추가하고 전체 리스트를 다시 보냅니다. 이게 전부이고, 아래는 CheapTokens의 OpenAI 호환 API를 대상으로 한 동작하는 Python 루프입니다.
같은 내용을 설명하는 공식 문서가 두 개 있습니다. Anthropic의 Messages API 레퍼런스(2026년 10월 30일 확인)는 API를 상태가 없고 멀티턴이라고 부르며, 이전 턴은 messages 파라미터로 전달된다고 합니다. OpenAI의 텍스트 생성 가이드(2026년 10월 30일 확인)는 이전 턴을 역할 태그가 붙은 메시지로 보내고 다음 요청 전에 각 답변을 추가하여 컨텍스트를 유지하라고 합니다.
두 번째 질문이 멍한 반응을 얻는 이유#
What is a token?를 입력하고 답변을 읽은 뒤 Explain it shorter를 입력한다고 해봅시다. 당신에게 "그것"은 명백합니다. API에게 두 번째 요청은 낯선 사람의 한 줄 메시지일 뿐입니다. "그것"도 없고, 줄일 것도 없습니다. 더 짧은 설명이 아니라 추측이나 되묻는 질문이 돌아옵니다.
해결책은 두 번째 요청이 첫 번째 요청의 모든 것에 답변과 새 질문을 더해 담게 하는 것입니다. 두 페이로드를 비교해 보세요:
비교하기
요청 2, 히스토리 유무
히스토리 없음
messages = [
{"role": "user", "content": "Explain it shorter"},
]모델은 "그것"이 무엇인지 전혀 모릅니다.
히스토리 있음
messages = [
{"role": "user", "content": "What is a token?"},
{"role": "assistant", "content": "<the first answer>"},
{"role": "user", "content": "Explain it shorter"},
]이제 "그것"은 첫 번째 답변을 가리킵니다.
세 가지 역할이 모든 일을 합니다. system는 규칙(어조, 길이, 봇의 용도)을 한 번 설정합니다. user는 사용자가 입력한 것입니다. assistant는 모델이 앞서 말한 것입니다. 모델은 리스트를 위에서 아래로 읽고 다음 assistant 메시지를 작성합니다.
몇 줄로 끝나는 채팅 루프#
SDK를 pip install openai로 설치하고 키는 환경 변수에 보관하세요. API 키를 안전하게 저장하는 방법을 참고하세요. base URL과 모델 id는 CheapTokens 문서와 GET /v1/models에서 가져옵니다(자세한 내용은 정확한 id를 찾기 위한 모델 목록 참고). 학습용 루프에는 GLM-5.3-Flash가 잘 맞습니다: 390K 컨텍스트와 답변당 최대 8,192 출력 토큰.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.cheaptokens.dev/v1",
api_key=os.environ["CHEAPTOKENS_API_KEY"],
)
MODEL = "zai-org/GLM-5.3-Flash"
messages = [
{"role": "system", "content": "You are a patient tutor. Keep answers under 80 words."},
]
while True:
question = input("you> ").strip()
if question in ("", "exit"):
break
messages.append({"role": "user", "content": question})
response = client.chat.completions.create(
model=MODEL,
messages=messages,
max_tokens=400,
)
answer = response.choices[0].message.content
messages.append({"role": "assistant", "content": answer})
print(answer)
print(f"[input tokens this turn: {response.usage.prompt_tokens}]")실행하고 What is a token?을 물은 다음 Explain it shorter를 물어보세요. 이제 두 번째 답변이 첫 번째 답변을 참조합니다. 마지막 줄은 usage.를 출력하는데, 이는 해당 턴의 청구서 중 입력 측입니다. 질문마다 이 값이 올라가는 것을 지켜보세요.
루프 안의 순서가 중요하며, 초보자가 가장 자주 틀리는 부분입니다:
순서대로 배열하기
루프의 한 턴을 순서대로
항목을 드래그하거나 화살표를 사용하세요
- 사용자의 질문을 messages에 추가
- 전체 messages 리스트 전송
- 응답에서 답변 읽기
- 답변을 assistant 메시지로 추가
4단계를 건너뛰면 모델이 자기 답변을 잊어버리므로, "더 짧게 설명해줘"가 한 번은 되고 세 번째 질문에서 다시 깨집니다.
두 턴 후 리스트의 모습#
What is a token?와 Explain it shorter 후에 코드가 들고 있는 리스트에는 다섯 개 항목이 있습니다: 시스템 규칙, 첫 번째 질문, 첫 번째 답변, 두 번째 질문, 두 번째 답변. 다음 요청은 이 다섯 개에 세 번째 질문을 더해 보냅니다.

시스템 메시지는 매번 전송됩니다. API가 자기 쪽에 "보관"하는 것이 아니라 그저 리스트의 첫 항목일 뿐입니다. OpenAI의 가이드(2026년 10월 30일 확인)는 지시가 현재 요청에만 적용된다고 언급하는데, 이는 같은 개념을 반대 방향에서 본 것입니다. 첫 메시지를 조정하고 싶다면 시스템 프롬프트와 temperature 설명을 참고하세요.
채팅이 길어질 때 입력 토큰은 어떻게 되는가#
모든 요청은 전체 리스트에 대해 다시 입력 비용을 지불합니다. 1턴은 시스템 규칙과 질문 하나를 보냅니다. 10턴은 규칙, 이전의 아홉 개 질문-답변 쌍, 새 질문을 보냅니다. 따라서 각 메시지가 짧더라도 입력은 매 턴 늘어납니다.
다음 가정으로 10턴 채팅을 해봅시다: 시스템 규칙은 약 50 토큰, 각 질문은 약 150, 각 답변은 약 250. 1턴은 50 + 150 = 200 입력 토큰을 보냅니다. 이후 각 턴은 400 토큰 쌍(150 + 250 = 400)을 하나씩 더하므로, 열 턴에 걸친 총 입력은 200 × 10 + 400 × 45 = 20,000 토큰이며, 여기서 45는 0 + 1 + … + 9입니다. 출력은 250 × 10 = 2,500 토큰입니다. 당신의 메시지 열 개에 입력이 출력의 여덟 배입니다.

다음은 입력 20,000 토큰, 출력 2,500 토큰으로 이 전체 채팅을 실시간 요율로 계산한 것입니다:
| 모델 | 입력 $/1M | 출력 $/1M | 비용 | OpenRouter |
|---|---|---|---|---|
| GLM-5.3-Flash | $0.02 | $0.04 | $0.0005 | $0.001 |
| DeepSeek-V4-Flash | $0.015 | $0.10 | $0.00055 | $0.0013 |
| MiniMax-M2.7 | $0.05 | $0.15 | $0.0014 | $0.009 |
총 입력 20,000개 및 출력 2,500개 토큰입니다. 100만 토큰당 가격은 현재 기준이며 당사 요금제에 따라 함께 변경됩니다. OpenRouter 열은 동일한 작업량에 대한 참고 가격을 보여줍니다.
입력과 출력을 합산한 총액에서 GLM-5.3-Flash와 DeepSeek-V4-Flash는 여기서 OpenRouter보다 저렴하며, 둘 다 어느 시간대든 단일 가격을 유지합니다. 같은 채팅 루프에서 8,192 토큰보다 긴 답변이 필요하면 DeepSeek-V4-Flash는 380K 컨텍스트로 답변당 최대 32,768 출력 토큰을 허용합니다. 모델 id를 deepseek-로 바꾸면 루프의 다른 것은 아무것도 바뀌지 않습니다.
더 깊은 비용 이야기는 긴 AI 채팅이 더 비싼 이유에, 입력 vs 출력 토큰은 두 측면이 왜 따로 가격이 매겨지는지 설명합니다.
빠른 확인
당신의 채팅은 8턴입니다. 8턴에 대한 요청에는 무엇이 들어 있나요?
정답 보기
정답: 시스템 메시지와 모든 이전 질문 및 답변, 그리고 가장 최근 질문
API는 아무것도 기억하지 않으므로 매번 전체 리스트가 나갑니다. 이것이 입력 토큰이 턴마다 늘어나는 이유이기도 합니다.
긴 채팅을 통제하는 방법#
리스트는 영원히 커질 수 없습니다: 모델의 컨텍스트 윈도우에 맞아야 하고(컨텍스트 윈도우란 무엇인가 참고), 추가 턴마다 입력 비용이 듭니다. 프로토타입에서 합리적으로 유지하는 두 가지 습관:
- 가장 오래된 턴을 잘라내세요. 시스템 메시지와 마지막 몇 쌍을 유지하세요. 예를 들어 각 요청 전에
messages = messages[:1] + messages[-를 하세요. 질문이 답변을 잃지 않도록 쌍을 함께 버리세요.8:] - 새 주제에는 새 리스트를 시작하세요. 새 작업에는 이전 작업의 히스토리가 필요 없습니다.
오래 유지되는 규칙 세트를 가진 지원 봇도 같은 루프입니다: 시스템 메시지가 규칙을 한 번 설정하고, 각 사용자 턴과 답변이 추가되며, 리스트가 무거워지면 잘라냅니다. 첫 요청 자체는 CheapTokens로 하는 첫 API 요청을 참고하세요. 모델 목록과 가격은 가격 페이지에 있습니다.



