Lors d’interactions de longue durée, le compactage permet de réduire la taille du contexte tout en conservant l’état nécessaire aux échanges suivants.
À mesure que la conversation s’allonge, le compactage vous aide à trouver un équilibre entre qualité, coût et latence.
Pour savoir comment préserver le raisonnement lorsque vous modifiez l’historique de la conversation, consultez le guide Conserver le préfixe inchangé.
Pour activer le compactage côté serveur dans une requête de création de réponse de l’API Responses (POST /responses ou client.responses.create), configurez context_management en y indiquant compact_threshold.
- Lorsque le nombre de tokens du contexte après rendu dépasse le seuil configuré, le serveur compacte le contexte.
- Dans ce mode, aucun appel distinct à
/responses/compact n’est nécessaire.
- Le flux de réponse contient l’élément de compactage chiffré.
- Le compactage côté serveur est compatible avec la politique de non-conservation des données (ZDR) si vous définissez
store=false dans vos requêtes de création de réponse de l’API Responses.
L’élément de compactage renvoyé transmet à l’exécution suivante les informations essentielles de l’état et du raisonnement antérieurs, avec moins de tokens. Son contenu est opaque et n’est pas conçu pour être interprété par une personne.
Pour enchaîner des requêtes sans état à l’aide de tableaux d’entrée, ajoutez les éléments de sortie comme d’habitude. Si vous utilisez previous_response_id, transmettez uniquement le nouveau message de l’utilisateur à chaque tour. Dans les deux cas, l’élément de compactage contient le contexte nécessaire à la fenêtre suivante.
Une fois les éléments de sortie ajoutés à la suite des éléments d’entrée précédents, vous pouvez supprimer tout ce qui précède le dernier élément de compactage. Vous réduisez ainsi la taille des requêtes et la latence des appels les plus lents. Le dernier élément de compactage contient le contexte nécessaire pour poursuivre la conversation. Si vous enchaînez les requêtes avec previous_response_id, ne supprimez aucun élément manuellement.
- Appelez
/responses comme d’habitude, en incluant context_management avec compact_threshold pour activer le compactage côté serveur.
- Si la taille du contexte dépasse le seuil pendant la transmission de la réponse, le serveur déclenche le compactage, émet un élément de compactage dans le même flux de sortie et réduit le contexte avant de poursuivre l’inférence.
- Pour poursuivre la boucle, choisissez l’une des deux méthodes. Pour enchaîner les requêtes sans état, ajoutez les éléments de sortie, y compris les éléments de compactage, à votre prochain tableau d’entrée. Pour les enchaîner avec
previous_response_id, transmettez uniquement le nouveau message de l’utilisateur à chaque tour et reprenez l’identifiant de la réponse précédente.
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
40import OpenAI from "openai";
import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";
import { createInterface } from "node:readline";
const client = new OpenAI();
const conversation = [
{
type: "message",
role: "user",
content: "Let's begin a long coding task.",
},
];
// Subscribe before generation so piped follow-up turns are not lost.
const lines = createInterface({ input: process.stdin, crlfDelay: Infinity });
const turns = lines[Symbol.asyncIterator]();
async function respond() {
const response = await client.responses.create({
model: "gpt-5.3-codex",
input: conversation,
store: false,
context_management: [{ type: "compaction", compact_threshold: 200_000 }],
});
conversation.push(...toResponseInputItems(response.output));
console.log(response.output_text);
}
try {
await respond();
for await (const line of turns) {
if (!line.trim()) continue;
conversation.push({ type: "message", role: "user", content: line });
await respond();
}
} finally {
lines.close();
}
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
29conversation = [
{
"type": "message",
"role": "user",
"content": "Let's begin a long coding task.",
}
]
while keep_going:
response = client.responses.create(
model="gpt-5.3-codex",
input=conversation,
store=False,
context_management=[{"type": "compaction", "compact_threshold": 200000}],
)
conversation.extend(response.output)
try:
next_input = get_next_user_input()
except EOFError:
break
conversation.append(
{
"type": "message",
"role": "user",
"content": next_input,
}
)
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
47
48
49
50
51
52
53
54
55
56package main
import (
"bufio"
"context"
"encoding/json"
"fmt"
"os"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
conversation := []responses.ResponseInputItemUnionParam{
responses.ResponseInputItemParamOfMessage("Let's begin a long coding task.", responses.EasyInputMessageRoleUser),
}
scanner := bufio.NewScanner(os.Stdin)
for {
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-5.3-codex",
Store: openai.Bool(false),
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: conversation},
ContextManagement: []responses.ResponseNewParamsContextManagement{{
Type: "compaction", CompactThreshold: openai.Int(200000),
}},
})
if err != nil {
panic(err)
}
conversation = append(conversation, outputAsInput(response.Output)...)
fmt.Println(response.OutputText())
if !scanner.Scan() {
break
}
conversation = append(conversation,
responses.ResponseInputItemParamOfMessage(scanner.Text(), responses.EasyInputMessageRoleUser),
)
}
if err := scanner.Err(); err != nil {
panic(err)
}
}
func outputAsInput(output []responses.ResponseOutputItemUnion) []responses.ResponseInputItemUnionParam {
input := make([]responses.ResponseInputItemUnionParam, 0, len(output))
for _, item := range output {
var converted responses.ResponseInputItemUnion
if err := json.Unmarshal([]byte(item.RawJSON()), &converted); err != nil {
panic(err)
}
input = append(input, converted.ToParam())
}
return input
}
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
47
48import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseInputItem;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
var conversation = new ArrayList<ResponseInputItem>();
conversation.add(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("Let's begin a long coding task.")
.build()));
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-5.3-codex")
.inputOfResponse(conversation)
.store(false)
.putAdditionalBodyProperty(
"context_management",
JsonValue.from(List.of(Map.of("type", "compaction", "compact_threshold", 200000))))
.build();
var response = client.responses().create(params);
response.output().stream()
.map(item -> JsonValue.from(item).convert(ResponseInputItem.class))
.forEach(conversation::add);
conversation.add(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("Now implement the next step.")
.build()));
client
.responses()
.create(params.toBuilder().inputOfResponse(conversation).build())
.output()
.stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.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
34require "openai"
client = OpenAI::Client.new
conversation = [
{
type: :message,
role: :user,
content: "Let's begin a long coding task."
}
]
loop do
response = client.responses.create(
model: "gpt-5.3-codex",
input: conversation,
store: false,
context_management: [
{
type: :compaction,
compact_threshold: 200_000
}
]
)
conversation.concat(response.output)
puts(response.output_text)
line = $stdin.gets
break unless line
conversation << {
type: :message,
role: :user,
content: line.chomp
}
end
Pour choisir quand compacter le contexte dans un workflow de longue durée, utilisez le point de terminaison de compactage autonome, qui fonctionne sans état.
Ce point de terminaison est entièrement sans état et compatible avec la politique de non-conservation des données (ZDR).
Envoyez une fenêtre de contexte complète (messages, outils et autres éléments). Le point de terminaison renvoie une nouvelle fenêtre de contexte compactée que vous pouvez transmettre lors de votre prochain appel à /responses.
La fenêtre compactée renvoyée contient un élément de compactage chiffré qui conserve les informations essentielles de l’état et du raisonnement antérieurs avec moins de tokens. Le contenu de cet élément est opaque et n’est pas conçu pour être interprété par une personne.
En général, la fenêtre compactée ne contient pas uniquement l’élément de compactage. Elle peut aussi conserver des éléments de la fenêtre précédente.
Ne supprimez aucun élément de la sortie de /responses/compact. La fenêtre renvoyée constitue votre prochaine fenêtre de contexte. Transmettez-la telle quelle lors de votre prochain appel à /responses.
- Utilisez
/responses comme d’habitude en envoyant des éléments d’entrée qui comprennent les messages de l’utilisateur, les sorties de l’assistant et les interactions avec les outils.
- Lorsque votre fenêtre de contexte devient volumineuse, appelez
/responses/compact pour générer une nouvelle fenêtre de contexte compactée. La fenêtre que vous envoyez à /responses/compact doit encore tenir dans la fenêtre de contexte de votre modèle.
- Lors des appels suivants à
/responses, transmettez en entrée la fenêtre compactée renvoyée, y compris l’élément de compactage, à la place de l’historique complet des échanges.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import OpenAI from "openai";
const client = new OpenAI();
const conversation = [{ role: "user", content: "Plan a trip to Kyoto." }];
const compacted = await client.responses.compact({
model: "gpt-6-astra",
input: conversation,
});
const nextInput = [
...compacted.output.map((item) => item),
{ role: "user", content: "Add two more days to the itinerary." },
];
const response = await client.responses.create({
model: "gpt-6-astra",
input: nextInput,
store: false,
});
console.log(response.output_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# Full window collected from prior turns
long_input_items_array = [{"role": "user", "content": "Plan a trip to Kyoto."}]
# 1) Compact the current window
compacted = client.responses.compact(
model="gpt-6-astra",
input=long_input_items_array,
)
# 2) Start the next turn by appending a new user message
next_input = [
*compacted.output, # Use compact output as-is
{
"type": "message",
"role": "user",
"content": user_input_message(),
},
]
next_response = client.responses.create(
model="gpt-6-astra",
input=next_input,
store=False, # Keep the flow ZDR-friendly
)
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
47
48
49
50
51
52
53
54package main
import (
"bufio"
"context"
"encoding/json"
"fmt"
"os"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
longInputItems := []responses.ResponseInputItemUnionParam{
responses.ResponseInputItemParamOfMessage("Plan a trip to Kyoto.", responses.EasyInputMessageRoleUser),
}
compacted, err := client.Responses.Compact(context.Background(), responses.ResponseCompactParams{
Model: "gpt-6-astra",
Input: responses.ResponseCompactParamsInputUnion{OfResponseInputItemArray: longInputItems},
})
if err != nil {
panic(err)
}
scanner := bufio.NewScanner(os.Stdin)
if !scanner.Scan() {
return
}
nextInput := append(outputAsInput(compacted.Output),
responses.ResponseInputItemParamOfMessage(scanner.Text(), responses.EasyInputMessageRoleUser),
)
nextResponse, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Store: openai.Bool(false),
Input: responses.ResponseNewParamsInputUnion{OfInputItemList: nextInput},
})
if err != nil {
panic(err)
}
fmt.Println(nextResponse.OutputText())
}
func outputAsInput(output []responses.ResponseOutputItemUnion) []responses.ResponseInputItemUnionParam {
input := make([]responses.ResponseInputItemUnionParam, 0, len(output))
for _, item := range output {
var converted responses.ResponseInputItemUnion
if err := json.Unmarshal([]byte(item.RawJSON()), &converted); err != nil {
panic(err)
}
input = append(input, converted.ToParam())
}
return input
}
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
47
48
49
50
51
52import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.responses.EasyInputMessage;
import com.openai.models.responses.ResponseCompactParams;
import com.openai.models.responses.ResponseCompactionItemParam;
import com.openai.models.responses.ResponseCreateParams;
import com.openai.models.responses.ResponseInputItem;
import java.util.ArrayList;
var compacted =
client
.responses()
.compact(
ResponseCompactParams.builder()
.model("gpt-6-astra")
.input("Plan a trip to Kyoto.")
.build());
var input = new ArrayList<ResponseInputItem>();
for (var item : compacted.output()) {
item.message().map(ResponseInputItem::ofResponseOutputMessage).ifPresent(input::add);
item.reasoning().map(ResponseInputItem::ofReasoning).ifPresent(input::add);
item.compaction()
.map(
value ->
ResponseInputItem.ofCompaction(
ResponseCompactionItemParam.builder()
.id(value.id())
.encryptedContent(value.encryptedContent())
.build()))
.ifPresent(input::add);
}
input.add(
ResponseInputItem.ofEasyInputMessage(
EasyInputMessage.builder()
.role(EasyInputMessage.Role.USER)
.content("Add restaurant recommendations.")
.build()));
client
.responses()
.create(
ResponseCreateParams.builder()
.model("gpt-6-astra")
.inputOfResponse(input)
.store(false)
.build())
.output()
.stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.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
27require "openai"
client = OpenAI::Client.new
long_input = [
{
role: :user,
content: "Plan a trip to Kyoto."
}
]
compaction = client.responses.compact(
model: "gpt-6-astra",
input: long_input
)
next_input = [
*compaction.output,
{
type: :message,
role: :user,
content: "Add restaurant recommendations."
}
]
response = client.responses.create(
model: "gpt-6-astra",
input: next_input,
store: false
)
puts(response.output_text)