Acompanhe a atividade do agente em tempo real, inspecione o trabalho concluído e consulte os rastreamentos detalhados de cada turno.
- Consulte os logs da sessão no painel da plataforma.
- Acompanhe a sessão pelos eventos e pelo histórico salvo.
- Inspecione os turnos e identifique quais comandos tiveram sua execução delegada.
- Consulte o uso registrado de tokens nos turnos do agente raiz e dos subagentes.
Acesse platform.openai.com/logs?api=agents e abra a aba Agentes.
Busque a sessão pelo ID para inspecionar os turnos, as chamadas de ferramentas e os subagentes.
Consulte o guia de rastreamento para inspecionar no painel os registros de respostas do modelo, chamadas de ferramentas e atividade dos subagentes, ou exporte os rastreamentos da sessão em formato OTLP JSON pela API pública.
Cada sessão disponibiliza um fluxo de eventos que mostra o que o agente está fazendo em tempo real. Defina OPENAI_API_KEY e substitua o ID de sessão usado nos exemplos pelo ID da sessão que você salvou.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// Replace the illustrative IDs and URLs below with your own resource values.
import OpenAI from "openai";
const client = new OpenAI();
const events = await client.beta.agents.sessions.events.stream("sess_123");
try {
for await (const event of events) {
if (
[
"agent.session.turn.failed",
"agent.session.turn.cancelled",
"agent.session.failed",
"agent.session.environment.failed",
"error",
].includes(event.type)
) {
throw new Error(`Agent lifecycle failure: ${event.type}`);
}
console.log(JSON.stringify(event));
}
} finally {
events.controller.abort();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# Replace the illustrative IDs and URLs below with your own resource values.
from openai import OpenAI
client = OpenAI()
session_id = "sess_123"
with client.beta.agents.sessions.events.stream(session_id) as events:
for event in events:
if event.type in {
"agent.session.turn.failed",
"agent.session.turn.cancelled",
"agent.session.failed",
"agent.session.environment.failed",
"error",
}:
raise RuntimeError(f"Agent lifecycle failure: {event.type}")
print(event.to_json(indent=None))
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// Replace the illustrative IDs and URLs below with your own resource values.
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
)
ctx := context.Background()
client := openai.NewClient()
events := client.Beta.Agents.Sessions.Events.StreamStreaming(ctx, "sess_123")
defer events.Close()
if events.Err() != nil {
panic(events.Err())
}
for events.Next() {
event := events.Current()
switch event.Type {
case "agent.session.turn.failed", "agent.session.turn.cancelled", "agent.session.failed", "agent.session.environment.failed", "error":
panic(event.RawJSON())
}
fmt.Println(event.RawJSON())
}
if err := events.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// Replace the illustrative IDs and URLs below with your own resource values.
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.ObjectMappers;
import com.openai.core.http.StreamResponse;
import com.openai.models.beta.agents.AgentSessionEvent;
OpenAIClient client = OpenAIOkHttpClient.fromEnv();
var json = ObjectMappers.jsonMapper();
try (StreamResponse<AgentSessionEvent> events =
client.beta().agents().sessions().events().streamStreaming("sess_123")) {
var iterator = events.stream().iterator();
while (iterator.hasNext()) {
var event = iterator.next();
if (event.turnFailed().isPresent()
|| event.turnCancelled().isPresent()
|| event.failed().isPresent()
|| event.environmentFailed().isPresent()
|| event.error().isPresent()) {
throw new IllegalStateException("Agent failed: " + event);
}
System.out.println(json.writeValueAsString(event));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# Replace the illustrative IDs and URLs below with your own resource values.
require "openai"
require "json"
client = OpenAI::Client.new
events = client.beta.agents.sessions.events.stream_streaming("sess_123")
begin
events.each do |event|
case event.type.to_s
when "agent.session.turn.failed", "agent.session.turn.cancelled", "agent.session.failed", "agent.session.environment.failed", "error"
raise "Agent failed: #{event.to_h}"
end
puts JSON.generate(event.to_h)
end
ensure
events.close
end
1
2
3
4
5curl -N \
-H "OpenAI-Beta: agents=v1" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Accept: text/event-stream" \
"https://api.openai.com/v1/agents/sessions/sess_123/events?stream=true"
O fluxo permanece aberto mesmo após eventos de inatividade, para que você possa acompanhar o trabalho na fila. Pressione Ctrl+C para encerrar o acompanhamento.
Durante a execução da sessão, você verá eventos como estes:
agent.session.environment.connected
agent.session.turn.created
agent.session.turn.in_progress
agent.session.turn.item.added
agent.session.turn.output_text.delta
agent.session.turn.completed
agent.session.idle
Para inspecionar o trabalho já realizado, recupere os itens salvos da sessão.
1
2
3
4
5
6
7
8
9
10// Replace the illustrative IDs and URLs below with your own resource values.
import OpenAI from "openai";
const client = new OpenAI();
const sessionId = "sess_123";
const items = await client.beta.agents.sessions.items.list(sessionId, {
order: "asc",
limit: 100,
});
console.log(items.data);
1
2
3
4
5
6
7
8# Replace the illustrative IDs and URLs below with your own resource values.
from openai import OpenAI
client = OpenAI()
session_id = "sess_123"
items = client.beta.agents.sessions.items.list(session_id, order="asc", limit=100)
print(items.to_json())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// Replace the illustrative IDs and URLs below with your own resource values.
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
)
ctx := context.Background()
client := openai.NewClient()
result, err := client.Beta.Agents.Sessions.Items.List(ctx,
"sess_123",
openai.BetaAgentSessionItemListParams{
Order: "asc",
Limit: openai.Int(100),
})
if err != nil {
panic(err)
}
fmt.Println(result.Data)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// Replace the illustrative IDs and URLs below with your own resource values.
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.beta.agents.sessions.items.ItemListParams;
OpenAIClient client = OpenAIOkHttpClient.fromEnv();
var result =
client
.beta()
.agents()
.sessions()
.items()
.list(
ItemListParams.builder()
.sessionId("sess_123")
.order(ItemListParams.Order.of("asc"))
.limit(100L)
.build());
System.out.println(result.items());
1
2
3
4
5
6
7
8
9
10# Replace the illustrative IDs and URLs below with your own resource values.
require "openai"
client = OpenAI::Client.new
result = client.beta.agents.sessions.items.list(
"sess_123",
order: "asc",
limit: 100
)
puts result.data
1
2
3
4curl \
-H "OpenAI-Beta: agents=v1" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
"https://api.openai.com/v1/agents/sessions/sess_123/items?order=asc&limit=100"
Os turnos da sessão estão disponíveis pela API pública. Use o turn_id de um item de comando junto com o ID da sessão que você salvou. O exemplo em Go usa a paginação nativa do SDK para localizar o turno pelo ID entre os turnos do agente raiz e dos subagentes. Em seguida, recupera o turno do agente ao qual ele pertence. Substitua os IDs de exemplo pelos IDs da sua sessão. O exemplo em cURL requer jq.
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// Replace the illustrative session and turn IDs with values from your command item.
import OpenAI from "openai";
const client = new OpenAI();
async function findTurn(sessionId, turnId) {
for await (const turn of client.beta.agents.sessions.turns.list(sessionId, {
limit: 100,
})) {
if (turn.id === turnId) {
return client.beta.agents.sessions.turns.retrieve(turnId, {
session_id: sessionId,
});
}
}
for await (const subagent of client.beta.agents.sessions.subagents.list(
sessionId,
{ limit: 100 }
)) {
for await (const turn of client.beta.agents.sessions.subagents.turns.list(
subagent.id,
{ session_id: sessionId, limit: 100 }
)) {
if (turn.id === turnId) {
return client.beta.agents.sessions.subagents.turns.retrieve(turnId, {
session_id: sessionId,
subagent_id: subagent.id,
});
}
}
}
throw new Error(`Turn ${turnId} not found in session ${sessionId}`);
}
const turn = await findTurn("sess_123", "turn_123");
console.log(turn.subagent_id || "main agent");
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# Replace the illustrative IDs and URLs below with your own resource values.
from openai import OpenAI
def find_turn(client, session_id, turn_id):
# Native SDK pagination searches every page for the owning agent.
for turn in client.beta.agents.sessions.turns.list(session_id, limit=100):
if turn.id == turn_id:
return client.beta.agents.sessions.turns.retrieve(
turn_id, session_id=session_id
)
for subagent in client.beta.agents.sessions.subagents.list(session_id, limit=100):
turns = client.beta.agents.sessions.subagents.turns.list(
subagent.id, session_id=session_id, limit=100
)
for turn in turns:
if turn.id == turn_id:
return client.beta.agents.sessions.subagents.turns.retrieve(
turn_id, session_id=session_id, subagent_id=subagent.id
)
raise ValueError(f"Turn {turn_id} not found in session {session_id}")
turn = find_turn(OpenAI(), "sess_123", "turn_123")
print(turn.subagent_id or "main agent")
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// Replace the illustrative session and turn IDs with values from your command item.
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
)
ctx := context.Background()
client := openai.NewClient()
turn, err := findTurn(ctx, &client, "sess_123", "turn_123")
if err != nil {
panic(err)
}
if turn.SubagentID == "" {
fmt.Println("main agent")
} else {
fmt.Println(turn.SubagentID)
}
// findTurn discovers the owning agent using native SDK pagination.
func findTurn(ctx context.Context, client *openai.Client, sessionID, turnID string) (*openai.Turn, error) {
turns := client.Beta.Agents.Sessions.Turns.ListAutoPaging(ctx, sessionID,
openai.BetaAgentSessionTurnListParams{Limit: openai.Int(100)})
for turns.Next() {
if turns.Current().ID == turnID {
return client.Beta.Agents.Sessions.Turns.Get(ctx, sessionID, turnID)
}
}
if err := turns.Err(); err != nil {
return nil, err
}
subagents := client.Beta.Agents.Sessions.Subagents.ListAutoPaging(ctx, sessionID,
openai.BetaAgentSessionSubagentListParams{Limit: openai.Int(100)})
for subagents.Next() {
subagent := subagents.Current()
childTurns := client.Beta.Agents.Sessions.Subagents.Turns.ListAutoPaging(ctx, sessionID, subagent.ID,
openai.BetaAgentSessionSubagentTurnListParams{Limit: openai.Int(100)})
for childTurns.Next() {
if childTurns.Current().ID == turnID {
return client.Beta.Agents.Sessions.Subagents.Turns.Get(ctx, sessionID, subagent.ID, turnID)
}
}
if err := childTurns.Err(); err != nil {
return nil, err
}
}
if err := subagents.Err(); err != nil {
return nil, err
}
return nil, fmt.Errorf("turn %s not found in session %s", turnID, sessionID)
}
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
56// Replace the illustrative session and turn IDs with values from your command item.
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.beta.agents.sessions.subagents.SubagentListParams;
import com.openai.models.beta.agents.sessions.turns.Turn;
import com.openai.models.beta.agents.sessions.turns.TurnListParams;
import com.openai.models.beta.agents.sessions.turns.TurnRetrieveParams;
OpenAIClient client = OpenAIOkHttpClient.fromEnv();
var turn = findTurn(client, "sess_123", "turn_123");
System.out.println(turn.subagentId().orElse("main agent"));
// Discover the owning agent using native SDK pagination before retrieving the turn.
static Turn findTurn(OpenAIClient client, String sessionId, String turnId) {
var sessions = client.beta().agents().sessions();
var turns =
sessions.turns().list(TurnListParams.builder().sessionId(sessionId).limit(100L).build());
for (var turn : turns.autoPager()) {
if (turn.id().equals(turnId)) {
return sessions
.turns()
.retrieve(TurnRetrieveParams.builder().sessionId(sessionId).turnId(turnId).build());
}
}
var subagents =
sessions
.subagents()
.list(SubagentListParams.builder().sessionId(sessionId).limit(100L).build());
for (var subagent : subagents.autoPager()) {
var childTurns =
sessions
.subagents()
.turns()
.list(
com.openai.models.beta.agents.sessions.subagents.turns.TurnListParams.builder()
.sessionId(sessionId)
.subagentId(subagent.id())
.limit(100L)
.build());
for (var turn : childTurns.autoPager()) {
if (turn.id().equals(turnId)) {
return sessions
.subagents()
.turns()
.retrieve(
com.openai.models.beta.agents.sessions.subagents.turns.TurnRetrieveParams
.builder()
.sessionId(sessionId)
.subagentId(subagent.id())
.turnId(turnId)
.build());
}
}
}
throw new IllegalArgumentException("Turn " + turnId + " not found in session " + sessionId);
}
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# Replace the illustrative IDs below with values from your command item.
require "openai"
# Discover the owning agent before retrieving the turn.
def find_turn(client, session_id, turn_id)
turns = client.beta.agents.sessions.turns.list(session_id, limit: 100)
turns.auto_paging_each do |turn|
if turn.id == turn_id
return client.beta.agents.sessions.turns.retrieve(turn_id, session_id: session_id)
end
end
subagents = client.beta.agents.sessions.subagents.list(session_id, limit: 100)
subagents.auto_paging_each do |subagent|
turns = client.beta.agents.sessions.subagents.turns.list(
subagent.id, session_id: session_id, limit: 100
)
turns.auto_paging_each do |turn|
if turn.id == turn_id
return client.beta.agents.sessions.subagents.turns.retrieve(
turn_id, session_id: session_id, subagent_id: subagent.id
)
end
end
end
raise "Turn #{turn_id} not found in session #{session_id}"
end
turn = find_turn(OpenAI::Client.new, "sess_123", "turn_123")
puts(turn.subagent_id || "main agent")
1
2
3
4
5
6
7curl "https://api.openai.com/v1/agents/sessions/sess_123/turns?limit=20&order=desc" \
-H "OpenAI-Beta: agents=v1" \
-H "Authorization: Bearer $OPENAI_API_KEY"
curl "https://api.openai.com/v1/agents/sessions/sess_123/turns/turn_123" \
-H "OpenAI-Beta: agents=v1" \
-H "Authorization: Bearer $OPENAI_API_KEY" | jq '.subagent_id'
Para paginar manualmente, use o last_id retornado como valor de after na próxima página quando has_more for true. O exemplo em Go percorre essas páginas automaticamente.
Os itens de comando contêm turn_id. Recupere o turno correspondente e consulte subagent_id para identificar o subagente que executou o comando. Se o ID do subagente for null, o agente raiz executou o comando. A API não informa se a saída do comando foi truncada.
Use o painel da plataforma para inspecionar um turno concluído e a atividade do agente nesse turno.
Para recuperar os rastreamentos registrados pela API pública, use o endpoint de exportação de rastreamentos da sessão com uma chave de API do projeto. Os endpoints de rastreamento do painel são separados da API com suporte para clientes.
Os recursos de turno incluem o campo usage, preenchido com os dados disponíveis, e o campo subagent_id, que identifica o trabalho delegado. O valor de uso pode ser null quando o uso é desconhecido e pode mudar depois de registrado. Consulte Inspecione o uso de tokens dos subagentes.
Para identificar quem executou um comando de shell, recupere o turno indicado pelo
turn_id do item de comando e consulte turn.subagent_id. A API para clientes não informa
se a saída do comando foi truncada.
Consulte Erros e recuperação para inspecionar falhas,
escolher uma forma de recuperação e tentar novamente com segurança.
Um agente pode fazer várias chamadas ao modelo para concluir uma tarefa. Cada chamada segue os preços por token e as regras de cache de prompts do modelo, como na API Responses. Para estimar o custo, considere todas as chamadas necessárias para concluir a tarefa.
Cada chamada ao modelo pode consumir:
- Tokens de entrada: instruções do agente, definições de ferramentas, histórico da conversa, entrada do usuário, arquivos ou imagens e resultados das ferramentas.
- Tokens de entrada em cache: parte da entrada reutilizada quando o prefixo do prompt coincide com um prefixo em cache. A cobrança segue a tarifa de entrada em cache do modelo.
- Tokens de saída: texto gerado, argumentos de chamadas de ferramentas e raciocínio.
Os tokens de raciocínio são cobrados como tokens de saída.
Os subagentes também podem fazer chamadas ao modelo. Ao investigar os custos do modelo, consulte o uso registrado por turno dos subagentes junto com o do agente raiz.
Considere o trabalho do agente raiz e dos subagentes, inclusive as novas tentativas, além das cobranças aplicáveis pelo uso de ferramentas, recursos computacionais do sandbox e serviços de terceiros. Nos modelos que cobram por gravação em cache, gravar a entrada no cache também tem um custo. Os campos de uso da API de Agentes descritos abaixo não apresentam uma contagem separada de tokens gravados no cache. Por isso, quando essa tarifa se aplica, esses campos não permitem calcular o valor exato cobrado pelo uso do modelo.
Os agentes mantêm o contexto ao longo da sessão. Quando chamadas sucessivas ao modelo compartilham o mesmo prefixo de prompt, o cache de prompts pode aproveitar o processamento anterior desse prefixo. O modelo gera uma nova resposta a cada chamada, sem reproduzir uma resposta anterior do cache. Manter uma sessão não garante que o cache será usado. A reutilização depende da correspondência entre os prefixos e das regras do modelo sobre o que pode ser armazenado no cache e por quanto tempo.
Sempre que possível, mantenha as instruções iniciais e as definições de ferramentas estáveis e envie os novos detalhes da tarefa nas mensagens seguintes. Com a busca de ferramentas, as definições encontradas são adicionadas ao fim da conversa, o que preserva o conteúdo anterior para reutilização pelo cache. Consulte Cache de prompts para conhecer as regras de cada modelo.
Uma alta porcentagem de entrada em cache não indica quanto você economizou no custo total da tarefa. A entrada em cache também é cobrada, e chamadas repetidas podem processar um histórico extenso. Compare os custos de concluir a mesma tarefa com a qualidade e a latência de que seu aplicativo precisa.
Os recursos de sessão e de turno incluem o campo usage, preenchido com os dados disponíveis. O valor pode ser null quando o uso é desconhecido, e as contagens registradas podem mudar à medida que o uso é contabilizado. A ausência de dados de uso não significa que o consumo foi zero. Essas contagens não representam a cobrança final.
Um objeto de uso registrado contém as seguintes categorias de tokens:
1234567891011{
"input_tokens": 5000,
"input_tokens_details": {
"cached_tokens": 1500
},
"output_tokens": 900,
"output_tokens_details": {
"reasoning_tokens": 200
},
"total_tokens": 5900
}
Neste exemplo, o agente processou 5.000 tokens de entrada e gerou 900 tokens de saída. Dos tokens de entrada, 1.500 estavam em cache. Dos tokens de saída, 200 eram tokens de raciocínio.
Os tokens em cache entram na contagem de input_tokens, e os tokens de raciocínio entram na contagem de output_tokens.
Liste ou recupere os turnos da sessão e consulte usage em cada turno. O campo subagent_id identifica o subagente e tem valor null nos turnos do agente raiz. Quando has_more for true, passe last_id como valor de after e mantenha o mesmo valor de order para consultar os turnos restantes.
O uso registrado reflete os dados disponíveis. O valor pode ser null quando o uso é desconhecido, e os valores registrados podem mudar. Você também pode consultar o uso registrado de cada agente no painel de rastreamento.