OpenAI 预测输出

2026-11-04 17:09 更新

预测输出(Predicted Outputs)适用于事先已知大量输出词元的任务,可加快Chat Completions响应。常见场景是重新生成只有少量修改的文本或代码文件,通过prediction请求参数提交预测内容。

来源指南列出的能力适用范围是gpt-4o、gpt-4o-mini、gpt-4.1、gpt-4.1-mini和gpt-4.1-nano。这描述指南中的功能支持范围,不代表这些模型目前均可调用,也不能自动扩展到较新模型。

生命周期补注(2026年10月23日核对):官方旧GPT模型快照弃用记录将gpt-4.1-nano及gpt-4.1-nano-2025-04-14的关闭日期列为2026年10月23日;GPT-4系列弃用记录将其中列出的GPT-4o、GPT-4o-mini、GPT-4.1和GPT-4.1-mini模型及快照关闭日期列为2027年1月14日。下文保留来源示例,实施前须同时核对具体模型的生命周期、账户权限和接口能力;本稿未作真实调用。弃用记录中的替代建议本身不能证明替代模型支持预测输出。

<a id="code-refactoring-example"></a>

代码重构示例

例如,让GPT-4o重构下面的JavaScript,把User类的username属性改为email。

代码重构示例(来源示例1,javascript)

// [中文] 原User类的username将被改成email;其他属性用于组成可复用的预测文本。
class User {
  firstName = "";
  lastName = "";
  username = "";
}

export default User;

除了username属性需要改名为email,大部分文件不变。把当前文件文本作为预测,就能以较低延迟重新生成整个文件,文件越大,累计节省的时间越可观。以下SDK示例用原文件作为预测,预计最终输出与它非常相似。程序内完整任务是:“将User类的username属性替换为email,仅回复代码,不使用Markdown格式。”

代码重构示例(来源示例2,javascript)

// [中文] 把原文件作为prediction.content,修改要求仍放在消息中,预测文本不是最终答案保证。
// [中文] 读取choices中的补全文本;accepted/rejected预测词元位于usage.completion_tokens_details。
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);

代码重构示例(来源示例3,python)

## [中文] 把原文件作为prediction.content,修改要求仍放在消息中,预测文本不是最终答案保证。
## [中文] 读取choices中的补全文本;accepted/rejected预测词元位于usage.completion_tokens_details。
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)

代码重构示例(来源示例4,go)

// [中文] 把原文件作为prediction.content,修改要求仍放在消息中,预测文本不是最终答案保证。
// [中文] 读取choices中的补全文本;accepted/rejected预测词元位于usage.completion_tokens_details。
package main

import (
    "context"
    "fmt"
    "strings"

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

func main() {
    client := openai.NewClient()
    code := strings.TrimSpace(`
class User {
  firstName = "";
  lastName = "";
  username = "";
}

export default User;
`)
    refactorPrompt := strings.TrimSpace(`
Replace the "username" property with an "email" property. Respond only
with code, and with no markdown formatting.
`)
    completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{
        Model: shared.ChatModelGPT4_1,
        Messages: []openai.ChatCompletionMessageParamUnion{
            openai.UserMessage(refactorPrompt),
            openai.UserMessage(code),
        },
        Store: openai.Bool(true),
        Prediction: openai.ChatCompletionPredictionContentParam{
            Content: openai.ChatCompletionPredictionContentContentUnionParam{OfString: openai.String(code)},
        },
    })
    if err != nil {
        panic(err)
    }
    fmt.Println(completion.Choices[0].Message.Content)
}

代码重构示例(来源示例5,java)

// [中文] 把原文件作为prediction.content,修改要求仍放在消息中,预测文本不是最终答案保证。
// [中文] 读取choices中的补全文本;accepted/rejected预测词元位于usage.completion_tokens_details。
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
import com.openai.models.chat.completions.ChatCompletionPredictionContent;

String code =
    """
    class User {
      firstName: string = "";
      lastName: string = "";
      username: string = "";
    }

    export default User;
    """;
String refactorPrompt =
    "Replace the \"username\" property with an \"email\" property. "
        + "Respond only with code, and with no markdown formatting.";

ChatCompletionCreateParams params =
    ChatCompletionCreateParams.builder()
        .model("gpt-4.1")
        .addUserMessage(refactorPrompt)
        .addUserMessage(code)
        .prediction(ChatCompletionPredictionContent.builder().content(code).build())
        .store(true)
        .build();

client.chat().completions().create(params).choices().stream()
    .flatMap(choice -> choice.message().content().stream())
    .forEach(System.out::println);

代码重构示例(来源示例6,csharp)

// [中文] 把原文件作为prediction.content,修改要求仍放在消息中,预测文本不是最终答案保证。
// [中文] 读取choices中的补全文本;accepted/rejected预测词元位于usage.completion_tokens_details。
using OpenAI.Chat;
#pragma warning disable OPENAI001

string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-4.1";
ChatClient client = new(model, key);

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

    export default User;
    """;
ChatCompletionOptions options = new()
{
    OutputPrediction = ChatOutputPrediction.CreateStaticContentPrediction(code),
};
ChatCompletion completion = await client.CompleteChatAsync(
    [
        new UserChatMessage(
            "Replace the username property with an email property. Respond only with code, and with no markdown formatting."
        ),
        new UserChatMessage(code),
    ],
    options
);

Console.WriteLine(completion.Content[0].Text);

代码重构示例(来源示例7,ruby)

## [中文] 把原文件作为prediction.content,修改要求仍放在消息中,预测文本不是最终答案保证。
## [中文] 读取choices中的补全文本;accepted/rejected预测词元位于usage.completion_tokens_details。
require "openai"

client = OpenAI::Client.new
code = <<~CODE
  class User {
    firstName: string = "";
    lastName: string = "";
    username: string = "";
  }

  export default User;
CODE
refactor_prompt = <<~PROMPT
  Replace the "username" property with an "email" property. Respond only
  with code, and with no markdown formatting.
PROMPT
completion = client.chat.completions.create(
  model: "gpt-4.1",
  messages: [
    {
      role: :user,
      content: refactor_prompt
    },
    {
      role: :user,
      content: code
    }
  ],
  prediction: {
    type: :content,
    content: code
  },
  store: true
)

puts(completion.choices.fetch(0).message.content)

代码重构示例(来源示例8,bash)

## [中文] 把原文件作为prediction.content,修改要求仍放在消息中,预测文本不是最终答案保证。
## [中文] 读取choices中的补全文本;accepted/rejected预测词元位于usage.completion_tokens_details。
curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4.1",
    "messages": [
      {
        "role": "user",
        "content": "Replace the username property with an email property. Respond only with code, and with no markdown formatting."
      },
      {
        "role": "user",
        "content": "$CODE_CONTENT_HERE"
      }
    ],
    "prediction": {
        "type": "content",
        "content": "$CODE_CONTENT_HERE"
    }
  }'

除重构代码外,省略choices后的响应还包含用量:

代码重构示例(来源示例9,json)

{
  "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.completion_tokens_details.accepted_prediction_tokens和usage.completion_tokens_details.rejected_prediction_tokens。本例14个预测词元被接受用于加速,2个被拒绝。被拒绝词元仍像其他生成的输出词元一样收费,因此预测输出可能增加请求费用。

<a id="streaming-example"></a>

流式示例

与流式响应结合时,预测输出的延迟收益更明显。下面仍是同一重构任务,改用SDK流式处理。

流式示例(来源示例10,javascript)

// [中文] 把原文件作为prediction.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,
  },
  stream: true,
});

// [中文] 查看返回数据中的补全文本及用量。
// Inspect returned data
for await (const chunk of completion) {
  process.stdout.write(chunk.choices[0]?.delta?.content || "");
}

流式示例(来源示例11,python)

## [中文] 把原文件作为prediction.content,修改要求仍放在消息中,预测文本不是最终答案保证。
## [中文] 逐个读取流式增量并输出文本,空增量不应当作正文。
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="")

流式示例(来源示例12,go)

// [中文] 把原文件作为prediction.content,修改要求仍放在消息中,预测文本不是最终答案保证。
// [中文] 逐个读取流式增量并输出文本,空增量不应当作正文。
package main

import (
    "context"
    "fmt"
    "strings"

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

func main() {
    client := openai.NewClient()
    code := strings.TrimSpace(`
class User {
  firstName = "";
  lastName = "";
  username = "";
}

export default User;
`)
    refactorPrompt := strings.TrimSpace(`
Replace the "username" property with an "email" property. Respond only
with code, and with no markdown formatting.
`)
    stream := client.Chat.Completions.NewStreaming(context.Background(), openai.ChatCompletionNewParams{
        Model: shared.ChatModelGPT4_1,
        Messages: []openai.ChatCompletionMessageParamUnion{
            openai.UserMessage(refactorPrompt),
            openai.UserMessage(code),
        },
        Store: openai.Bool(true),
        Prediction: openai.ChatCompletionPredictionContentParam{
            Content: openai.ChatCompletionPredictionContentContentUnionParam{OfString: openai.String(code)},
        },
    })
    for stream.Next() {
        if len(stream.Current().Choices) > 0 {
            fmt.Print(stream.Current().Choices[0].Delta.Content)
        }
    }
    if err := stream.Err(); err != nil {
        panic(err)
    }
}

流式示例(来源示例13,java)

// [中文] 把原文件作为prediction.content,修改要求仍放在消息中,预测文本不是最终答案保证。
// [中文] 逐个读取流式增量并输出文本,空增量不应当作正文。
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.http.StreamResponse;
import com.openai.models.chat.completions.ChatCompletionChunk;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
import com.openai.models.chat.completions.ChatCompletionPredictionContent;

String code =
    """
    class User {
      firstName: string = "";
      lastName: string = "";
      username: string = "";
    }

    export default User;
    """;
String refactorPrompt =
    "Replace the \"username\" property with an \"email\" property. "
        + "Respond only with code, and with no markdown formatting.";

ChatCompletionCreateParams params =
    ChatCompletionCreateParams.builder()
        .model("gpt-4.1")
        .addUserMessage(refactorPrompt)
        .addUserMessage(code)
        .prediction(ChatCompletionPredictionContent.builder().content(code).build())
        .store(true)
        .build();

try (StreamResponse<ChatCompletionChunk> stream =
    client.chat().completions().createStreaming(params)) {
  stream.stream()
      .flatMap(chunk -> chunk.choices().stream())
      .flatMap(choice -> choice.delta().content().stream())
      .forEach(System.out::print);
}

流式示例(来源示例14,csharp)

// [中文] 把原文件作为prediction.content,修改要求仍放在消息中,预测文本不是最终答案保证。
// [中文] 逐个读取流式增量并输出文本,空增量不应当作正文。
using OpenAI.Chat;
#pragma warning disable OPENAI001

string key = Environment.GetEnvironmentVariable("OPENAI_API_KEY")!;
string model = "gpt-4.1";
ChatClient client = new(model, key);

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

    export default User;
    """;
ChatCompletionOptions options = new()
{
    OutputPrediction = ChatOutputPrediction.CreateStaticContentPrediction(code),
};

await foreach (
    StreamingChatCompletionUpdate update in client.CompleteChatStreamingAsync(
        [
            new UserChatMessage(
                "Replace the username property with an email property. Respond only with code, and with no markdown formatting."
            ),
            new UserChatMessage(code),
        ],
        options
    )
)
{
    foreach (ChatMessageContentPart part in update.ContentUpdate)
    {
        Console.Write(part.Text);
    }
}

流式示例(来源示例15,ruby)

## [中文] 把原文件作为prediction.content,修改要求仍放在消息中,预测文本不是最终答案保证。
## [中文] 逐个读取流式增量并输出文本,空增量不应当作正文。
require "openai"

client = OpenAI::Client.new
code = <<~CODE
  class User {
    firstName: string = "";
    lastName: string = "";
    username: string = "";
  }

  export default User;
CODE
refactor_prompt = <<~PROMPT
  Replace the "username" property with an "email" property. Respond only
  with code, and with no markdown formatting.
PROMPT
stream = client.chat.completions.stream(
  model: "gpt-4.1",
  messages: [
    {
      role: :user,
      content: refactor_prompt
    },
    {
      role: :user,
      content: code
    }
  ],
  prediction: {
    type: :content,
    content: code
  },
  store: true
)

stream.text.each { |text| print(text) }

<a id="position-of-predicted-text-in-response"></a>

预测文本在响应中的位置

预测文本可以出现在生成结果的任意位置,仍能降低延迟。假设预测内容是下面的简单Hono服务:

预测文本在响应中的位置(来源示例16,javascript)

// [中文] 先运行pnpm run ui:build构建客户端,再由Hono提供静态资源和请求路由。
// [中文] 此版本尚未加入返回hello world的GET路由;与原文件对照观察预测前缀及后缀复用。
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!");
});

// [中文] 先执行pnpm run ui:build构建客户端代码。
// 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,
});

可以提出以下任务:

预测文本在响应中的位置(来源示例17,text)

为此应用添加一个GET路由,返回文本"hello world"。加入该路由后重新生成整个应用文件,不附加任何Markdown格式。

模型可能给出:

预测文本在响应中的位置(来源示例18,javascript)

// [中文] 先运行pnpm run ui:build构建客户端,再由Hono提供静态资源和请求路由。
// [中文] 此版本已经加入返回hello world的GET路由;与原文件对照观察预测前缀及后缀复用。
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");
});

// [中文] 先执行pnpm run ui:build构建客户端代码。
// 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,
});

尽管预测文本分别出现在新增内容的前后,用量中仍有被接受的预测词元:

预测文本在响应中的位置(来源示例19,json)

{
  "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"
}

本次没有被拒绝的词元,因为预测文件的全部内容都用于最终响应。

<a id="limitations"></a>

限制

  • 来源指南的功能支持列表为GPT-4o、GPT-4o-mini、GPT-4.1、GPT-4.1-mini和GPT-4.1-nano系列;具体可用性还受前述关闭日期限制。
  • 提交预测后,未用于最终补全的词元仍按输出单价收费。通过usage.completion_tokens_details.rejected_prediction_tokens检查数量。
  • 使用预测输出时,下列参数受限:n不能大于1;不支持logprobs;presence_penalty和frequency_penalty不能大于0;不兼容audio音频输入输出;modalities只支持text;不支持max_completion_tokens;不支持tools函数调用。
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号