토큰 계산하기

토큰 계산하기 (Counting tokens)

출처: 문서

토큰 계산(token counting)을 사용하면 요청이 모델로 전송되기 전에 얼마나 많은 입력 토큰을 사용할지 결정할 수 있어요. 다음과 같은 용도로 사용해요:

  • 프롬프트 최적화: 컨텍스트 한도 안에 맞도록 프롬프트를 최적화해요.
  • 비용 추정: API 호출 전에 비용을 추정해요.
  • 요청 라우팅: 크기에 따라 요청을 라우팅해요(예: 더 작은 프롬프트를 더 빠른 모델로).
  • 이미지·파일 놀라움 방지: 더 이상 문자 기반 추정을 하지 않아요.

입력 토큰 계산 엔드포인트는 Responses API와 동일한 입력 형식을 받아요. 텍스트, 메시지, 이미지, 파일, 도구 또는 대화를 전달하면 API가 모델이 받을 정확한 토큰 수를 반환해요.

이 카운트에는 메시지 역할과 경계와 같은 요청 구조를 나타내는 데 사용되는 포맷팅 토큰이 포함돼요. 이 토큰들은 로컬에서 토큰화한 텍스트나 필드에는 나타나지 않을 수 있어요.

토큰 계산 API를 왜 사용하나요?

tiktoken 같은 로컬 토크나이저는 일반 텍스트에는 작동하지만 한계가 있어요:

  • 이미지와 파일은 지원되지 않아요 — characters / 4 같은 추정은 부정확해요.
  • 도구와 스키마는 로컬에서 세기 어려운 토큰을 추가해요.
  • 모델별 동작이 토큰화를 변경할 수 있어요(예: reasoning, caching).

토큰 계산 API는 이 모든 것을 처리해요. responses.create에 보낼 것과 동일한 페이로드를 사용해 정확한 카운트를 얻어요. 그런 다음 결과를 메시지 검증 또는 비용 추정 흐름에 연결해요.

기본 메시지의 토큰 계산하기

단순 텍스트 입력

import OpenAI from "openai";

const client = new OpenAI();

const response = await client.responses.inputTokens.count({
  model: "gpt-6-astra",
  input: "Tell me a joke.",
});

console.log(response.input_tokens);
from openai import OpenAI

client = OpenAI()

response = client.responses.input_tokens.count(
    model="gpt-6-astra", input="Tell me a joke."
)
print(response.input_tokens)
package main

import (
	"context"
	"fmt"

	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/responses"
)

func main() {
	client := openai.NewClient()
	count, err := client.Responses.InputTokens.Count(context.Background(), responses.InputTokenCountParams{
		Model: openai.String("gpt-6-astra"),
		Input: responses.InputTokenCountParamsInputUnion{OfString: openai.String("Tell me a joke.")},
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(count.InputTokens)
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.inputtokens.InputTokenCountParams;

var count =
    client
        .responses()
        .inputTokens()
        .count(
            InputTokenCountParams.builder()
                .model("gpt-6-astra")
                .input("Tell me a joke.")
                .build());

System.out.println(count.inputTokens());
require "openai"

client = OpenAI::Client.new

count = client.responses.input_tokens.count(
  model: "gpt-6-astra",
  input: "Tell me a joke."
)

puts(count.input_tokens)
curl https://api.openai.com/v1/responses/input_tokens \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-astra",
    "input": "Tell me a joke."
  }'
openai responses:input-tokens count \
  --model gpt-6-astra \
  --input "Tell me a joke." \
  --raw-output \
  --transform input_tokens

대화의 토큰 계산하기

다중 턴 대화

import OpenAI from "openai";

const client = new OpenAI();

const response = await client.responses.inputTokens.count({
  model: "gpt-6-astra",
  input: [
    { role: "user", content: "What is 2 + 2?" },
    { role: "assistant", content: "2 + 2 equals 4." },
    { role: "user", content: "What about 3 + 3?" },
  ],
});

console.log(response.input_tokens);
from openai import OpenAI

client = OpenAI()

response = client.responses.input_tokens.count(
    model="gpt-6-astra",
    input=[
        {"role": "user", "content": "What is 2 + 2?"},
        {"role": "assistant", "content": "2 + 2 equals 4."},
        {"role": "user", "content": "What about 3 + 3?"},
    ],
)
print(response.input_tokens)
package main

import (
	"context"
	"fmt"

	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/responses"
)

func main() {
	client := openai.NewClient()
	input := []responses.ResponseInputItemUnionParam{
		responses.ResponseInputItemParamOfMessage("What is 2 + 2?", responses.EasyInputMessageRoleUser),
		responses.ResponseInputItemParamOfMessage("2 + 2 equals 4.", responses.EasyInputMessageRoleAssistant),
		responses.ResponseInputItemParamOfMessage("What about 3 + 3?", responses.EasyInputMessageRoleUser),
	}
	count, err := client.Responses.InputTokens.Count(context.Background(), responses.InputTokenCountParams{
		Model: openai.String("gpt-6-astra"),
		Input: responses.InputTokenCountParamsInputUnion{OfResponseInputItemArray: input},
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(count.InputTokens)
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.inputtokens.InputTokenCountParams;
import java.util.List;

var count =
    client
        .responses()
        .inputTokens()
        .count(
            InputTokenCountParams.builder()
                .model("gpt-6-astra")
                .inputOfResponseInputItems(
                    List.of(
                        ResponseInputItem.ofEasyInputMessage(
                            EasyInputMessage.builder()
                                .role(EasyInputMessage.Role.USER)
                                .content("What is 2 + 2?")
                                .build()),
                        ResponseInputItem.ofEasyInputMessage(
                            EasyInputMessage.builder()
                                .role(EasyInputMessage.Role.ASSISTANT)
                                .content("2 + 2 equals 4.")
                                .build()),
                        ResponseInputItem.ofEasyInputMessage(
                            EasyInputMessage.builder()
                                .role(EasyInputMessage.Role.USER)
                                .content("What about 3 + 3?")
                                .build())))
                .build());

System.out.println(count.inputTokens());
require "openai"

client = OpenAI::Client.new
conversation = [
  {
    role: :user,
    content: "What is 2 + 2?"
  },
  {
    role: :assistant,
    content: "2 + 2 equals 4."
  },
  {
    role: :user,
    content: "What about 3 + 3?"
  }
]

count = client.responses.input_tokens.count(
  model: "gpt-6-astra",
  input: conversation
)

puts(count.input_tokens)
curl https://api.openai.com/v1/responses/input_tokens \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-astra",
    "input": [
      {"role": "user", "content": "What is 2 + 2?"},
      {"role": "assistant", "content": "2 + 2 equals 4."},
      {"role": "user", "content": "What about 3 + 3?"}
    ]
  }'
openai responses:input-tokens count \
  --raw-output \
  --transform input_tokens <<'YAML'
model: gpt-6-astra
input:
  - role: user
    content: What is 2 + 2?
  - role: assistant
    content: 2 + 2 equals 4.
  - role: user
    content: What about 3 + 3?
YAML

지침(instructions)과 함께 토큰 계산하기

시스템 지침이 있는 입력

import OpenAI from "openai";

const client = new OpenAI();

const response = await client.responses.inputTokens.count({
  model: "gpt-6-astra",
  instructions: "You are a helpful assistant that explains concepts simply.",
  input: "Explain quantum computing in one sentence.",
});

console.log(response.input_tokens);
from openai import OpenAI

client = OpenAI()

response = client.responses.input_tokens.count(
    model="gpt-6-astra",
    instructions="You are a helpful assistant that explains concepts simply.",
    input="Explain quantum computing in one sentence.",
)
print(response.input_tokens)
package main

import (
	"context"
	"fmt"

	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/responses"
)

func main() {
	client := openai.NewClient()
	count, err := client.Responses.InputTokens.Count(context.Background(), responses.InputTokenCountParams{
		Model:        openai.String("gpt-6-astra"),
		Instructions: openai.String("You are a helpful assistant that explains concepts simply."),
		Input:        responses.InputTokenCountParamsInputUnion{OfString: openai.String("Explain quantum computing in one sentence.")},
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(count.InputTokens)
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.inputtokens.InputTokenCountParams;

var count =
    client
        .responses()
        .inputTokens()
        .count(
            InputTokenCountParams.builder()
                .model("gpt-6-astra")
                .input("Explain quantum computing in one sentence.")
                .instructions("You are a helpful assistant that explains concepts simply.")
                .build());

System.out.println(count.inputTokens());
require "openai"

client = OpenAI::Client.new

count = client.responses.input_tokens.count(
  model: "gpt-6-astra",
  instructions: "You are a helpful assistant that explains concepts simply.",
  input: "Explain quantum computing in one sentence."
)

puts(count.input_tokens)
curl https://api.openai.com/v1/responses/input_tokens \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-astra",
    "instructions": "You are a helpful assistant that explains concepts simply.",
    "input": "Explain quantum computing in one sentence."
  }'
openai responses:input-tokens count \
  --raw-output \
  --transform input_tokens <<'YAML'
model: gpt-6-astra
instructions: You are a helpful assistant that explains concepts simply.
input: Explain quantum computing in one sentence.
YAML

이미지와 함께 토큰 계산하기

이미지는 크기와 세부 수준(detail level)에 따라 토큰을 소비해요. 토큰 계산 API는 추측 없이 정확한 카운트를 반환해요.

이미지가 있는 입력

import OpenAI from "openai";

const client = new OpenAI();

const response = await client.responses.inputTokens.count({
  model: "gpt-6-astra",
  input: [
    {
      role: "user",
      content: [
        {
          type: "input_image",
          image_url: "https://example.com/chart.png",
          detail: "auto",
        },
        { type: "input_text", text: "Summarize this chart." },
      ],
    },
  ],
});

console.log(response.input_tokens);
from openai import OpenAI

client = OpenAI()

# Use file_id from uploaded file, or image_url for a URL
response = client.responses.input_tokens.count(
    model="gpt-6-astra",
    input=[
        {
            "role": "user",
            "content": [
                {
                    "type": "input_image",
                    "image_url": "https://example.com/chart.png",
                },
                {"type": "input_text", "text": "Summarize this chart."},
            ],
        }
    ],
)
print(response.input_tokens)
package main

import (
	"context"
	"fmt"

	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/responses"
)

func main() {
	client := openai.NewClient()
	input := []responses.ResponseInputItemUnionParam{
		responses.ResponseInputItemParamOfMessage(
			responses.ResponseInputMessageContentListParam{
				{OfInputImage: &responses.ResponseInputImageParam{ImageURL: openai.String("https://example.com/chart.png"), Detail: responses.ResponseInputImageDetailAuto}},
				{OfInputText: &responses.ResponseInputTextParam{Text: "Summarize this chart."}},
			},
			responses.EasyInputMessageRoleUser,
		),
	}
	count, err := client.Responses.InputTokens.Count(context.Background(), responses.InputTokenCountParams{
		Model: openai.String("gpt-6-astra"),
		Input: responses.InputTokenCountParamsInputUnion{OfResponseInputItemArray: input},
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(count.InputTokens)
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.ResponseInputImage;
import com.openai.models.responses.ResponseInputItem;
import com.openai.models.responses.inputtokens.InputTokenCountParams;
import java.util.List;

var count =
    client
        .responses()
        .inputTokens()
        .count(
            InputTokenCountParams.builder()
                .model("gpt-6-astra")
                .inputOfResponseInputItems(
                    List.of(
                        ResponseInputItem.ofMessage(
                            ResponseInputItem.Message.builder()
                                .role(ResponseInputItem.Message.Role.USER)
                                .addContent(
                                    ResponseInputImage.builder()
                                        .detail(ResponseInputImage.Detail.AUTO)
                                        .imageUrl(
                                            "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg")
                                        .build())
                                .addInputTextContent("Summarize this chart.")
                                .build())))
                .build());

System.out.println(count.inputTokens());
require "openai"

client = OpenAI::Client.new

count = client.responses.input_tokens.count(
  model: "gpt-6-astra",
  input: [
    {
      role: :user,
      content: [
        {
          type: :input_image,
          image_url: "https://api.nga.gov/iiif/a2e6da57-3cd1-4235-b20e-95dcaefed6c8/full/!800,800/0/default.jpg",
          detail: :auto
        },
        {
          type: :input_text,
          text: "Summarize this chart."
        }
      ]
    }
  ]
)

puts(count.input_tokens)
curl https://api.openai.com/v1/responses/input_tokens \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-astra",
    "input": [{
      "role": "user",
      "content": [
        {"type": "input_image", "image_url": "https://example.com/chart.png"},
        {"type": "input_text", "text": "Summarize this chart."}
      ]
    }]
  }'
openai responses:input-tokens count \
  --raw-output \
  --transform input_tokens <<'YAML'
model: gpt-6-astra
input:
  - role: user
    content:
      - type: input_image
        image_url: https://example.com/chart.png
      - type: input_text
        text: Summarize this chart.
YAML

file_id(Files API) 또는 image_url(URL 또는 base64 data URL)을 사용할 수 있어요. 자세한 내용은 images and vision을 참고해요.

도구와 함께 토큰 계산하기

도구 정의(function 스키마, MCP 서버 등)는 컨텍스트에 토큰을 추가해요. 입력과 함께 계산해요:

function 도구가 있는 입력

import OpenAI from "openai";

const client = new OpenAI();

const response = await client.responses.inputTokens.count({
  model: "gpt-6-astra",
  tools: [
    {
      type: "function",
      name: "get_weather",
      description: "Get the current weather in a location",
      strict: true,
      parameters: {
        type: "object",
        properties: { location: { type: "string" } },
        required: ["location"],
        additionalProperties: false,
      },
    },
  ],
  input: "What is the weather in San Francisco?",
});

console.log(response.input_tokens);
from openai import OpenAI

client = OpenAI()

response = client.responses.input_tokens.count(
    model="gpt-6-astra",
    tools=[
        {
            "type": "function",
            "name": "get_weather",
            "description": "Get the current weather in a location",
            "parameters": {
                "type": "object",
                "properties": {"location": {"type": "string"}},
                "required": ["location"],
            },
        }
    ],
    input="What is the weather in San Francisco?",
)
print(response.input_tokens)
package main

import (
	"context"
	"fmt"

	"github.com/openai/openai-go/v3"
	"github.com/openai/openai-go/v3/responses"
)

func main() {
	client := openai.NewClient()
	parameters := map[string]any{
		"type": "object",
		"properties": map[string]any{
			"location": map[string]any{"type": "string"},
		},
		"required":             []string{"location"},
		"additionalProperties": false,
	}
	tool := responses.ToolParamOfFunction("get_weather", parameters, true)
	tool.OfFunction.Description = openai.String("Get the current weather in a location")
	count, err := client.Responses.InputTokens.Count(context.Background(), responses.InputTokenCountParams{
		Model: openai.String("gpt-6-astra"),
		Input: responses.InputTokenCountParamsInputUnion{OfString: openai.String("What is the weather in San Francisco?")},
		Tools: []responses.ToolUnionParam{tool},
	})
	if err != nil {
		panic(err)
	}
	fmt.Println(count.InputTokens)
}
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.FunctionTool;
import com.openai.models.responses.inputtokens.InputTokenCountParams;
import java.util.List;
import java.util.Map;

var count =
    client
        .responses()
        .inputTokens()
        .count(
            InputTokenCountParams.builder()
                .model("gpt-6-astra")
                .input("What is the weather in San Francisco?")
                .addTool(
                    FunctionTool.builder()
                        .name("get_weather")
                        .description("Get the current weather in a location")
                        .strict(true)
                        .parameters(
                            FunctionTool.Parameters.builder()
                                .putAdditionalProperty("type", JsonValue.from("object"))
                                .putAdditionalProperty(
                                    "properties",
                                    JsonValue.from(
                                        Map.of("location", Map.of("type", "string"))))
                                .putAdditionalProperty(
                                    "required", JsonValue.from(List.of("location")))
                                .putAdditionalProperty(
                                    "additionalProperties", JsonValue.from(false))
                                .build())
                        .build())
                .build());

System.out.println(count.inputTokens());
require "openai"

client = OpenAI::Client.new

count = client.responses.input_tokens.count(
  model: "gpt-6-astra",
  input: "What is the weather in San Francisco?",
  tools: [
    {
      type: :function,
      name: "get_weather",
      description: "Get the current weather in a location",
      strict: true,
      parameters: {
        type: "object",
        properties: { location: { type: "string" } },
        required: ["location"],
        additionalProperties: false
      }
    }
  ]
)

puts(count.input_tokens)
curl https://api.openai.com/v1/responses/input_tokens \
  -H "Authorization: Bearer ***" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-astra",
    "tools": [{
      "type": "function",
      "name": "get_weather",
      "description": "Get the current weather in a location",
      "parameters": {
        "type": "object",
        "properties": {"location": {"type": "string"}},
        "required": ["location"]
      }
    }],
    "input": "What is the weather in San Francisco?"
  }'
openai responses:input-tokens count \
  --raw-output \
  --transform input_tokens <<'YAML'
model: gpt-6-astra
tools:
  - type: function
    name: get_weather
    description: Get the current weather in a location
    parameters:
      type: object
      properties:
        location:
          type: string
      required:
        - location
input: What is the weather in San Francisco?
YAML

파일과 함께 토큰 계산하기

File inputs(현재 PDF)이 지원돼요. responses.create와 마찬가지로 file_id, file_url, 또는 file_data를 전달해요. 토큰 수는 모델의 완전히 처리된 입력을 반영해요.

출력 토큰 수 이해하기

보고되는 출력 토큰 사용량은 응답에 보이는 텍스트뿐 아니라 모델이 생성한 모든 토큰을 포함해요. Responses API는 이 총합을 output_tokens로 보고하며, Chat Completions API는 completion_tokens로 보고해요.

GPT-5 모델을 포함한 일부 모델은 응답 채널, 도구 호출 및 기타 메시지 구조를 포맷하거나 구분하는 데 사용되는 토큰을 생성해요. 이 포맷팅 토큰은 메시지 콘텐츠나 logprobs에 나타나지 않으며, 사용량에서 별도로 항목화되지 않을 수도 있어요. 그 결과 보고되는 출력 또는 완료 토큰 수는 보이는 토큰이나 logprobs에 포함된 토큰 수보다 높을 수 있으며, 보고된 reasoning_tokens 값이 0이어도 마찬가지예요.

max_output_tokens와 max_completion_tokens 파라미터는 보이지 않는 토큰을 포함해 모델이 생성하는 모든 토큰을 제한해요. 보이지 않는 토큰의 수는 모델과 응답 형태에 따라 다르므로, 보고된 사용량과 보이는 출력 사이에 고정된 차이가 있다고 가정하지 마세요. 특정 양의 보이는 출력이 필요할 때는 이 한도에 여유(headroom)를 두세요.

API 참조

전체 파라미터와 응답 형태는 Count input tokens API reference를 참고해요. 엔드포인트는 다음과 같아요:

POST /v1/responses/input_tokens

응답에는 input_tokens(정수)와 object: "response.input_tokens"가 포함돼요.