고급 사용법

고급 사용법 (Advanced usage)

OpenAI 텍스트 생성 모델의 고급 기능을 다루는 가이드예요. 재현 가능한 출력(seeded outputs), 토큰 관리, 파라미터 세부 사항을 배워요.

출처: 문서

본문

OpenAI의 텍스트 생성 모델(종종 생성형 사전 학습 트랜스포머 또는 대규모 언어 모델이라고 불려요)은 자연어, 코드, 이미지를 이해하도록 학습되었어요. 이 모델들은 입력에 대한 응답으로 텍스트 출력을 제공해요. 이 모델들의 텍스트 입력은 "프롬프트(prompt)"라고도 불려요. 프롬프트를 설계하는 것이 기본적으로 대규모 언어 모델을 "프로그래밍"하는 방법이에요. 보통 작업을 성공적으로 완료하는 방법을 설명하는 지침이나 몇 가지 예시를 제공하는 방식으로요.

재현 가능한 출력 (Reproducible outputs)

Chat Completions는 기본적으로 비결정적(non-deterministic)이에요. 즉 모델 출력이 요청마다 다를 수 있어요. 그렇긴 하지만, seed 파라미터와 system_fingerprint 응답 필드에 접근할 수 있게 하여 어느 정도 결정적 출력을 제어할 수 있게 해드려요.

API 호출 전반에 걸쳐 (대부분) 결정적 출력을 받으려면:

  • seed 파라미터를 원하는 정수로 설정하고, 결정적 출력을 원하는 요청들에서 동일한 값을 사용하세요.
  • 다른 모든 파라미터(예: prompt 또는 temperature)가 요청 간에 정확히 동일하도록 하세요.

때로는 OpenAI가 저희 측에서 모델 설정에 필요한 변경을 함으로써 결정성이 영향받을 수 있어요. 이러한 변경을 추적할 수 있도록 system_fingerprint 필드를 노출해요. 이 값이 다르면, 저희 시스템의 변경으로 인해 다른 출력을 보게 될 수 있어요.

[Deterministic outputs

  Explore the new seed parameter in the OpenAI cookbook](https://developers.openai.com/cookbook/examples/reproducible_outputs_with_the_seed_parameter)

토큰 관리하기 (Managing tokens)

언어 모델은 토큰(token)이라는 청크 단위로 텍스트를 읽고 써요. 영어에서 토큰은 한 글자만큼 짧을 수도 있고 한 단어만큼 길 수도 있어요(예: a 또는 apple). 일부 언어에서는 토큰이 한 글자보다 더 짧거나 한 단어보다 더 길 수도 있어요.

대략적인 경험칙으로, 영어 텍스트의 경우 1 토큰은 약 4자, 또는 0.75 단어에 해당해요.

특정 문자열이 어떻게 토큰으로 변환되는지 테스트하려면 Tokenizer tool을 확인해 보세요.

예를 들어, "ChatGPT is great!" 문자열은 여섯 개의 토큰으로 인코딩돼요: ["Chat", "G", "PT", " is", " great", "!"].

API 호출의 총 토큰 수는 다음에 영향을 미쳐요:

  • API 호출 비용 — 토큰당 비용을 지불하니까요
  • API 호출 소요 시간 — 토큰을 더 많이 쓰면 더 오래 걸리거든요
  • API 호출이 작동하는지 여부 — 총 토큰이 모델 최대 한도 미만이어야 하기 때문이에요(gpt-3.5-turbo는 4097 토큰)

입력과 출력 토큰 모두 이 수량에 포함돼요. 예를 들어 API 호출이 메시지 입력에 10 토큰을 사용하고 메시지 출력에서 20 토큰을 받았다면 30 토큰으로 청구돼요. 다만 일부 모델의 경우 토큰당 가격이 입력과 출력에서 다를 수 있어요(pricing 페이지 참고).

API 호출이 사용한 토큰 수를 보려면 API 응답의 usage 필드를 확인하세요(예: response['usage']['total_tokens']).

gpt-3.5-turbo와 gpt-4-turbo-preview 같은 채팅 모델은 completions API에서 제공되는 모델과 같은 방식으로 토큰을 사용하지만, 메시지 기반 형식 때문에 대화에서 사용될 토큰 수를 세기가 더 어려워요.

다음은 gpt-3.5-turbo-0613에 전달된 메시지의 토큰 수를 세는 예시 함수예요.

메시지가 토큰으로 변환되는 정확한 방식은 모델마다 다를 수 있어요. 따라서 향후 모델 버전이 출시되면 이 함수가 반환하는 답은 근사값일 수 있어요.

def num_tokens_from_messages(messages, model="gpt-3.5-turbo-0613"):
    """Returns the number of tokens used by a list of messages."""
    try:
        encoding = tiktoken.encoding_for_model(model)
    except KeyError:
        encoding = tiktoken.get_encoding("cl100k_base")
    if model == "gpt-3.5-turbo-0613":  # note: future models may deviate from this
        num_tokens = 0
        for message in messages:
            num_tokens += (
                4  # every message follows <im_start>{role/name}\n{content}<im_end>\n
            )
            for key, value in message.items():
                num_tokens += len(encoding.encode(value))
                if key == "name":  # if there's a name, the role is omitted
                    num_tokens += -1  # role is always required and always 1 token
        num_tokens += 2  # every reply is primed with <im_start>assistant
        return num_tokens
    raise ValueError(
        f"num_tokens_from_messages() only supports gpt-3.5-turbo-0613, not {model}."
    )

이제 메시지를 만들어 위에서 정의한 함수에 전달해 토큰 수를 확인해 보세요. API의 usage 파라미터가 반환하는 값과 일치해야 해요:

messages = [
    {
        "role": "system",
        "content": "You are a helpful, pattern-following assistant that translates corporate jargon into plain English.",
    },
    {
        "role": "system",
        "name": "example_user",
        "content": "New synergies will help drive top-line growth.",
    },
    {
        "role": "system",
        "name": "example_assistant",
        "content": "Things working well together will increase revenue.",
    },
    {
        "role": "system",
        "name": "example_user",
        "content": "Let's circle back when we have more bandwidth to touch base on opportunities for increased leverage.",
    },
    {
        "role": "system",
        "name": "example_assistant",
        "content": "Let's talk later when we're less busy about how to do better.",
    },
    {
        "role": "user",
        "content": "This late pivot means we don't have time to boil the ocean for the client deliverable.",
    },
]

model = "gpt-3.5-turbo-0613"

print(f"{num_tokens_from_messages(messages, model)} prompt tokens counted.")
# Should show ~126 total_tokens

위 함수가 생성한 수가 API가 반환하는 값과 같은지 확인하려면 새 Chat Completion을 만들세요:

import OpenAI from "openai";

const client = new OpenAI();

const response = await client.chat.completions.create({
  model,
  messages,
  temperature: 0,
});

console.log(`${response.usage.prompt_tokens} prompt tokens used.`);
# example token count from the OpenAI API
from openai import OpenAI

client = OpenAI()

response = client.chat.completions.create(
    model=model,
    messages=messages,
    temperature=0,
)

print(f"{response.usage.prompt_tokens} prompt tokens used.")
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.chat.completions.ChatCompletionCreateParams;

ChatCompletionCreateParams params =
    ChatCompletionCreateParams.builder()
        .model("gpt-3.5-turbo-0613")
        .addUserMessage("Translate this sentence into plain English.")
        .temperature(0)
        .build();

var completion = client.chat().completions().create(params);
var usage =
    completion.usage().orElseThrow(() -> new IllegalStateException("No usage returned"));
System.out.println(usage.promptTokens() + " prompt tokens used.");

API 호출 없이 텍스트 문자열에 토큰이 몇 개인지 확인하려면 OpenAI의 tiktoken Python 라이브러리를 사용하세요. 예시 코드는 OpenAI Cookbook의 how to count tokens with tiktoken 가이드에서 찾을 수 있어요.

API에 전달되는 각 메시지는 content, role 및 기타 필드의 토큰 수에 배후 포맷팅을 위한 몇 개를 더한 만큼을 소비해요. 이는 향후 약간 바뀔 수 있어요.

대화에 토큰이 너무 많아 모델 최대 한도에 맞지 않으면(예: gpt-3.5-turbo는 4097 토큰 초과, gpt-4o는 128k 토큰 초과), 텍스트가 맞을 때까지 잘라내거나, 생략하거나, 줄여야 해요. 메시지 입력에서 메시지를 제거하면 모델이 그 메시지에 대한 모든 지식을 잃게 된다는 점에 유의하세요.

긴 대화는 불완전한 답변을 받을 가능성이 더 높아요. 예를 들어 4090 토큰 길이의 gpt-3.5-turbo 대화는 답변이 겨우 6 토큰 만에 잘릴 수 있어요.

파라미터 세부 사항

빈도 및 존재 패널티 (Frequency and presence penalties)

Chat Completions API와 Legacy Completions API에서 찾을 수 있는 빈도(frequency) 및 존재(presence) 패널티는 반복되는 토큰 시퀀스를 샘플링할 가능성을 줄이는 데 사용될 수 있어요.

이 패널티는 logits(정규화되지 않은 로그 확률)를 가산적 기여(additive contribution)로 직접 수정해 동작해요.

mu[j] = mu[j] - c[j] * alpha_frequency - float(c[j] > 0) * alpha_presence
mu[j] = mu[j] - c[j] * alpha_frequency - ((c[j] > 0) ? alpha_presence : 0.0)

여기서:

  • mu[j]는 j번째 토큰의 logits예요
  • c[j]는 현재 위치 이전에 그 토큰이 샘플링된 횟수예요
  • 존재 패널티는 c[j] > 0이면 alpha_presence를 빼고, 그 외에는 0을 빼요
  • alpha_frequency는 빈도 패널티 계수예요
  • alpha_presence는 존재 패널티 계수예요

보시다시피 존재 패널티는 한 번 이상 샘플링된 모든 토큰에 적용되는 일회성 가산 기여이고, 빈도 패널티는 특정 토큰이 이미 샘플링된 횟수에 비례하는 기여예요.

반복 샘플을 어느 정도 줄이는 것이 목표라면 패널티 계수의 합리적인 값은 약 0.1에서 1 사이예요. 반복을 강하게 억제하는 것이 목표라면 계수를 최대 2까지 높일 수 있지만, 그러면 샘플 품질이 눈에 띄게 저하될 수 있어요. 음수 값은 반복 가능성을 높이는 데 사용할 수 있어요.

토큰 로그 확률 (Token log probabilities)

Chat Completions API와 Legacy Completions API에서 찾을 수 있는 logprobs 파라미터는 요청 시 각 출력 토큰의 로그 확률과, 각 토큰 위치에서 가장 가능성 높은 제한된 개수의 토큰과 그 로그 확률을 제공해요. 이는 모델이 출력에 대해 갖는 자신감을 평가하거나, 모델이 줄 수 있었던 대체 응답을 검토하는 데 유용할 수 있어요.

기타 파라미터

자세한 내용은 전체 API reference documentation을 참고하세요.

더 알아보기 (Learn more)

관련 문서: 텍스트 생성 가이드와 프롬프트 엔지니어링 가이드를 참고하세요.