Para mantener interacciones de larga duración, puedes usar la compactación para reducir el tamaño del contexto
sin perder el estado necesario para los turnos posteriores.
La compactación te ayuda a equilibrar la calidad, el costo y la latencia a medida que las conversaciones crecen.
Puedes habilitar la compactación del lado del servidor en una solicitud de creación de Responses
(POST /responses o client.responses.create) al configurar
context_management con compact_threshold.
- Cuando la cantidad de tokens renderizados supera el umbral configurado, el servidor
ejecuta la compactación del lado del servidor.
- En este modo no se requiere una llamada independiente a
/responses/compact.
- El flujo de respuesta incluye el elemento de compactación cifrado.
- Nota sobre ZDR: la compactación del lado del servidor es compatible con ZDR cuando configuras
store=false
en tus solicitudes de creación de Responses.
El elemento de compactación devuelto conserva los aspectos clave del estado y el razonamiento previos para
la siguiente ejecución usando menos tokens. Es opaco y no está diseñado para que
lo interpreten personas.
Para el encadenamiento sin estado mediante arreglos de entrada, agrega los elementos de salida como de costumbre. Si usas
previous_response_id, pasa solo el nuevo mensaje del usuario en cada turno. En ambos
casos, el elemento de compactación contiene el contexto necesario para la siguiente ventana.
Consejo sobre latencia: después de agregar los elementos de salida a los elementos de entrada anteriores, puedes
eliminar los elementos que preceden al elemento de compactación más reciente para reducir el tamaño de las solicitudes
y la latencia de las respuestas más lentas. El elemento de compactación más reciente contiene el
contexto necesario para continuar la conversación. Si usas el encadenamiento mediante
previous_response_id, no elimines elementos manualmente.
- Llama a
/responses como de costumbre, pero incluye context_management con
compact_threshold para habilitar la compactación del lado del servidor.
- Durante la transmisión de la respuesta, si el tamaño del contexto supera el umbral, el servidor
inicia una pasada de compactación, emite un elemento de salida de compactación en el mismo flujo
y recorta el contexto antes de continuar la inferencia.
- Continúa el bucle con uno de estos patrones: encadenamiento sin estado mediante arreglos de entrada (agrega
la salida, incluidos los elementos de compactación, al siguiente arreglo de entrada) o
encadenamiento mediante
previous_response_id (pasa solo el nuevo mensaje del usuario en cada turno y
usa ese ID en el siguiente).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import OpenAI from "openai";
import { toResponseInputItems } from "openai/lib/responses/ResponseInputItems";
const client = new OpenAI();
const conversation = [
{
type: "message",
role: "user",
content: "Let's begin a long coding task.",
},
];
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);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25conversation = [
{
"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)
conversation.append(
{
"type": "message",
"role": "user",
"content": get_next_user_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
34
35
36
37
38
39
40require "openai"
client = OpenAI::Client.new
conversation = [
{
type: :message,
role: :user,
content: "Let's begin a long coding task."
}
]
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)
conversation << {
type: :message,
role: :user,
content: "Now implement the next step."
}
next_response = client.responses.create(
model: "gpt-5.3-codex",
input: conversation,
store: false,
context_management: [
{
type: :compaction,
compact_threshold: 200_000
}
]
)
puts(next_response.output_text)
Para tener un control explícito, usa el
punto de acceso de compactación independiente para
realizar la compactación sin estado en flujos de trabajo de larga duración.
Este punto de acceso funciona completamente sin estado y es compatible con ZDR.
Envías una ventana de contexto completa (mensajes, herramientas y otros elementos), y el
punto de acceso devuelve una nueva ventana de contexto compactada que puedes pasar a tu siguiente
llamada a /responses.
La ventana compactada devuelta incluye un elemento de compactación cifrado que
conserva los aspectos clave del estado y el razonamiento previos usando menos tokens. Es opaco y no
está diseñado para que lo interpreten personas.
Nota: la ventana compactada generalmente contiene más que el elemento de
compactación. También puede incluir elementos conservados de la ventana anterior.
Manejo de la salida: no elimines elementos de la salida de /responses/compact. La ventana devuelta
es la siguiente ventana de contexto canónica, así que pásala a tu siguiente llamada a /responses
sin modificarla.
- Usa
/responses como de costumbre, enviando elementos de entrada que incluyan mensajes del usuario,
salidas del asistente e interacciones con herramientas.
- Cuando tu ventana de contexto alcance un tamaño considerable, llama a
/responses/compact para generar una
nueva ventana de contexto compactada. La ventana que envíes a /responses/compact
debe seguir cabiendo en la ventana de contexto de tu modelo.
- En las llamadas posteriores a
/responses, pasa la ventana compactada devuelta
(incluido el elemento de compactación) como entrada en lugar de la transcripción completa.
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)