当许多输出 Token 预先已知时,预测输出 可加快 Chat Completions 的 API 响应。这种情况最常见于对文本或代码文件进行少量修改后重新生成文件的场景。您可以使用 Chat Completions 中的 prediction 请求参数 提供预测内容。
目前,最新的 gpt-4o、gpt-4o-mini、gpt-4.1、gpt-4.1-mini 和 gpt-4.1-nano 模型均支持预测输出。继续阅读,了解如何使用预测输出降低应用程序的延迟。
预测输出特别适合对文本文档和代码文件进行少量修改后重新生成文件的场景。假设您希望 GPT-4o 模型 重构一段 JavaScript 代码,将 User 类的 username 属性改为 email:
1
2
3
4
5
6
7 class User {
firstName = "" ;
lastName = "" ;
username = "" ;
}
export default User;
除了上面的第 4 行,文件的大部分内容都不会改变。如果您将代码文件的当前文本用作预测内容,就可以以更低的延迟重新生成整个文件。对于较大的文件,累积节省的时间会相当可观。
以下示例展示了如何在我们的 SDK 中使用 prediction 参数。我们预计模型的最终输出将与原始代码文件非常相似,因此将该文件用作预测文本。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 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); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 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) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 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)
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 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); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 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); 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 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) 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 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 字段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 {
"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_tokens 和 rejected_prediction_tokens。在此示例中,预测内容中的 14 个 Token 被用于加快响应,另有 2 个被拒绝。
请注意,被拒绝的 Token 仍会像 API 生成的其他补全 Token 一样计费,因此使用预测输出可能会增加请求费用。
当您对 API 响应使用流式传输时,预测输出在降低延迟方面的效果会更加显著。以下示例沿用相同的代码重构场景,但改用 OpenAI SDK 中的流式传输功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 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 || "" );
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 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="") 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 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)
}
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 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);
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 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);
}
} 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 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) }
预测文本在响应中的位置
您提供的预测文本可以出现在生成的响应中的任何位置,仍然能够降低响应延迟。假设您的预测文本是如下所示的简单 Hono 服务器代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 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.
模型对该提示的响应可能如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 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 字段后的模型响应仍会显示已接受的预测 Token:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 {
"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"
}
这次没有被拒绝的预测 Token,因为作为预测内容的整个文件都用在了最终响应中。真不错!🔥
使用预测输出时,您应考虑以下因素和限制。
只有 GPT-4o、GPT-4o-mini、GPT-4.1、GPT-4.1-mini 和 GPT-4.1-nano 系列模型支持预测输出。
提供预测内容时,其中未包含在最终补全内容中的 Token 仍按补全 Token 的费率计费。查看 usage 对象的 rejected_prediction_tokens 属性 ,即可了解有多少 Token 未用于最终响应。
使用预测输出时,不支持以下 API 参数 :
n:不支持大于 1 的值
logprobs:不支持
presence_penalty:不支持大于 0 的值
frequency_penalty:不支持大于 0 的值
audio:预测输出与音频输入和输出 不兼容
modalities:仅支持 text 模态
max_completion_tokens:不支持
tools:预测输出目前不支持函数调用