예측 출력(Predicted Outputs)

예측 출력(Predicted Outputs)

Predicted Outputs는 출력 토큰 중 상당 부분을 미리 알고 있을 때 Chat Completions의 API 응답을 더 빠르게 만들어 주는 기능이에요. 텍스트나 코드 파일을 약간만 수정해서 다시 생성하는 경우가 가장 흔한 사용처죠. Chat Completions의 prediction 요청 파라미터로 예측을 제공할 수 있습니다. 이 기능은 현재 최신 gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini, gpt-4.1-nano 모델에서 사용할 수 있어요.

출처: 공식문서

코드 리팩토링 예시

Predicted Outputs는 텍스트 문서와 코드 파일을 약간만 수정해 다시 생성할 때 특히 유용해요. GPT-4o 모델로 JavaScript 코드를 리팩토링해서 User 클래스의 username 속성을 email로 바꾼다고 생각해 볼게요.

class User {
  firstName = "";
  lastName = "";
  username = "";
}

export default User;

대부분의 파일은 위 4번째 줄을 빼고는 그대로예요. 코드 파일의 현재 텍스트를 예측으로 쓰면 전체 파일을 더 낮은 지연으로 다시 생성할 수 있죠. 이런 시간 절약은 파일이 커질수록 더 빨리 쌓여요.

SDK에서 prediction 파라미터를 써서 모델의 최종 출력이 원래 코드 파일과 매우 비슷할 것이라고 예측하는 예시를 볼게요. 예측 텍스트로 원래 코드 파일을 사용합니다.

from openai import OpenAI

code = """
class User {
  firstName = "";
  lastName = "";
  username = "";
}

export default User;
""".strip()

refactor_prompt = """
Replace the "username" property with an "email" property. Respond only
with code, and with no markdown formatting.
"""

client = OpenAI()

completion = client.chat.completions.create(
    model="gpt-4.1",
    messages=[
        {"role": "user", "content": refactor_prompt},
        {"role": "user", "content": code},
    ],
    prediction={"type": "content", "content": code},
)

print(completion)
print(completion.choices[0].message.content)
import OpenAI from "openai";

const code = `
class User {
  firstName = "";
  lastName = "";
  username = "";
}

export default User;
`.trim();

const openai = new OpenAI();

const refactorPrompt = `
Replace the "username" property with an "email" property. Respond only
with code, and with no markdown formatting.
`;

const completion = await openai.chat.completions.create({
  model: "gpt-4.1",
  messages: [
    {
      role: "user",
      content: refactorPrompt,
    },
    {
      role: "user",
      content: code,
    },
  ],
  store: true,
  prediction: {
    type: "content",
    content: code,
  },
});

// Inspect returned data
console.log(completion);
console.log(completion.choices[0].message.content);

리팩토링된 코드와 함께, choices 필드가 없는 축약된 모델 응답에는 이런 사용량(usage) 데이터가 담겨요.

{
  "id": "chatcmpl-xxx",
  "object": "chat.completion",
  "created": 1786652188,
  "model": "gpt-4.1-2025-04-14",
  "usage": {
    "prompt_tokens": 59,
    "completion_tokens": 24,
    "total_tokens": 83,
    "prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 14,
      "rejected_prediction_tokens": 2
    }
  },
  "system_fingerprint": "fp_6ddb4f7408"
}

usage 객체의 accepted_prediction_tokensrejected_prediction_tokens를 주목하세요. 이 예시에서는 예측에서 14개 토큰이 응답을 빠르게 만드는 데 쓰였고 2개는 버려졌어요. 버려진 토큰도 API가 생성한 다른 완성 토큰처럼 과금되므로, Predicted Outputs는 요청 비용을 높일 수 있다는 점을 기억하세요.

스트리밍 예시

Predicted Outputs의 지연 이득은 API 응답에 스트리밍을 쓸 때 더 커져요. 같은 코드 리팩토링 사례를 OpenAI SDK에서 스트리밍으로 쓴 예시입니다.

from openai import OpenAI

code = """
class User {
  firstName = "";
  lastName = "";
  username = "";
}

export default User;
""".strip()

refactor_prompt = """
Replace the "username" property with an "email" property. Respond only
with code, and with no markdown formatting.
"""

client = OpenAI()

stream = client.chat.completions.create(
    model="gpt-4.1",
    messages=[
        {"role": "user", "content": refactor_prompt},
        {"role": "user", "content": code},
    ],
    prediction={"type": "content", "content": code},
    stream=True,
)

for chunk in stream:
    if chunk.choices[0].delta.content is not None:
        print(chunk.choices[0].delta.content, end="")
import OpenAI from "openai";

const code = `
class User {
  firstName = "";
  lastName = "";
  username = "";
}

export default User;
`.trim();

const openai = new OpenAI();

const refactorPrompt = `
Replace the "username" property with an "email" property. Respond only
with code, and with no markdown formatting.
`;

const completion = await openai.chat.completions.create({
  model: "gpt-4.1",
  messages: [
    {
      role: "user",
      content: refactorPrompt,
    },
    {
      role: "user",
      content: code,
    },
  ],
  store: true,
  prediction: {
    type: "content",
    content: code,
  },
  stream: true,
});

// Inspect returned data
for await (const chunk of completion) {
  process.stdout.write(chunk.choices[0]?.delta?.content || "");
}

응답에서 예측 텍스트의 위치

예측 텍스트를 제공할 때, 그 예측은 생성된 응답의 어디에든 나타날 수 있고 여전히 응답 지연을 줄여 줘요. 예측 텍스트가 아래처럼 간단한 Hono 서버라고 해 볼게요.

import { serve } from "@hono/node-server";
import { serveStatic } from "@hono/node-server/serve-static";
import { Hono } from "hono";

const app = new Hono();

app.get("/api", (c) => {
  return c.text("Hello Hono!");
});

// You will need to build the client code first: `pnpm run ui:build`.
app.use(
  "/*",
  serveStatic({
    rewriteRequestPath: (path) => `./dist${path}`,
  })
);

const port = 3000;
console.log(`Server is running on port ${port}`);

serve({
  fetch: app.fetch,
  port,
});

모델에 이런 프롬프트로 파일을 다시 생성하라고 할 수 있어요.

Add a get route to this application that responds with
the text "hello world". Generate the entire application
file again with this route added, and with no other
markdown formatting.

이 프롬프트에 대한 응답은 대략 이렇게 나올 거예요.

import { serve } from "@hono/node-server";
import { serveStatic } from "@hono/node-server/serve-static";
import { Hono } from "hono";

const app = new Hono();

app.get("/api", (c) => {
  return c.text("Hello Hono!");
});

app.get("/hello", (c) => {
  return c.text("hello world");
});

// You will need to build the client code first: `pnpm run ui:build`.
app.use(
  "/*",
  serveStatic({
    rewriteRequestPath: (path) => `./dist${path}`,
  })
);

const port = 3000;
console.log(`Server is running on port ${port}`);

serve({
  fetch: app.fetch,
  port,
});

choices 필드가 없는 축약된 모델 응답을 보면, 예측 텍스트가 응답에 추가된 새 콘텐츠 앞뒤로 모두 나타났는데도 허용된 예측 토큰이 여전히 표시돼요.

{
  "id": "chatcmpl-xxx",
  "object": "chat.completion",
  "created": 1731014771,
  "model": "gpt-4o-2024-08-06",
  "usage": {
    "prompt_tokens": 203,
    "completion_tokens": 159,
    "total_tokens": 362,
    "prompt_tokens_details": { "cached_tokens": 0, "audio_tokens": 0 },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 60,
      "rejected_prediction_tokens": 0
    }
  },
  "system_fingerprint": "fp_9ee9e968ea"
}

이번에는 버려진 예측 토큰이 없어요. 예측했던 파일 전체 내용이 최종 응답에 그대로 쓰였기 때문이죠.

제약 사항

Predicted Outputs를 쓸 때 다음 요소와 한계를 고려해야 해요.

  • Predicted Outputs는 GPT-4o, GPT-4o-mini, GPT-4.1, GPT-4.1-mini, GPT-4.1-nano 모델 계열에서만 지원됩니다.
  • 예측을 제공할 때 최종 완성에 포함되지 않은 토큰도 완성 토큰 요율로 과금돼요. 최종 응답에서 쓰이지 않은 토큰 수는 usage 객체의 rejected_prediction_tokens 속성으로 확인할 수 있죠.
  • Predicted Outputs를 쓸 때는 다음 API 파라미터가 지원되지 않아요.
    • n: 1보다 큰 값 미지원
    • logprobs: 미지원
    • presence_penalty: 0보다 큰 값 미지원
    • frequency_penalty: 0보다 큰 값 미지원
    • audio: 오디오 입·출력과 호환되지 않음
    • modalities: text 모달리티만 지원
    • max_completion_tokens: 미지원
    • tools: 함수 호출은 현재 Predicted Outputs와 함께 지원되지 않음

더 알아보기 (Learn more)