All guides
OpenAI

可观测性与使用情况

Checked 09/15/2026View original

AI translation, not an official translation. Refer to the original for technical details.

On this page

完整文档索引请参见 llms.txt。在页面 URL 后附加 .md 可获取文档页面的 Markdown 版本。

追踪实时 Agent 活动、检查已完成的工作,以及查看详细的轮次追踪:

  1. 您可以在 Platform 控制台中查看会话日志。
  2. 您可以通过事件流和已保存的历史记录跟踪会话进展。
  3. 您可以检查轮次并识别已委托的命令执行。
  4. 您可以检查根 Agent 和子 Agent 轮次的已记录 Token 用量。

在控制台中查看会话

前往 platform.openai.com/logs?api=agents 并打开 Agents 标签页。

通过 ID 搜索会话,以检查其轮次、工具调用和子 Agent。

使用追踪指南在控制台中检查已记录的模型响应、工具调用和子 Agent 活动。追踪检索与外部追踪导出器不属于公测 API 的范围。

跟踪事件流并检查会话历史

每个会话都提供一个事件流,实时显示 Agent 正在执行的操作。设置 OPENAI_API_KEY 并将以下示例中的示意性会话 ID 替换为您保存的会话 ID:

跟踪实时会话事件

// 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();
}
# 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))
// 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)
}
// Replace the illustrative IDs and URLs below with your own resource values.
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.http.StreamResponse;
import com.openai.models.beta.agents.AgentSessionEvent;

OpenAIClient client = OpenAIOkHttpClient.fromEnv();
var json = new 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));
  }
}
# 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
curl -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"

事件流在空闲事件期间保持打开状态,以确保不遗漏已排队的工作。按 Ctrl+C 停止监听。

在会话运行时,您将看到如下事件:

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

如需检查已发生的工作,可检索会话的已保存条目:

检查已保存的会话条目

// 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);
# 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())
// 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)
// 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());
# 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
curl \
  -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"

检查轮次并识别已委托的命令

会话轮次可通过公开 API 获取。使用命令条目中的 turn_id,结合您保存的会话 ID。cURL 示例需要 jq

识别已委托的命令执行

// 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 turns = await client.beta.agents.sessions.turns.list(sessionId, {
  limit: 20,
  order: "desc",
});
console.log(turns.data);
const turnId = "turn_123";
const turn = await client.beta.agents.sessions.turns.retrieve(turnId, {
  session_id: sessionId,
});
console.log(turn.subagent_id);
# Replace the illustrative IDs and URLs below with your own resource values.
from openai import OpenAI

client = OpenAI()

session_id = "sess_123"
turns = client.beta.agents.sessions.turns.list(session_id, limit=20, order="desc")
print(turns.to_json())
turn_id = "turn_123"
turn = client.beta.agents.sessions.turns.retrieve(turn_id, session_id=session_id)
print(turn.subagent_id)
// 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.Turns.List(ctx,
	"sess_123",
	openai.BetaAgentSessionTurnListParams{
		Limit: openai.Int(20),
		Order: "desc",
	})
if err != nil {
	panic(err)
}
fmt.Println(result.Data)
turn, err := client.Beta.Agents.Sessions.Turns.Get(ctx,
	"sess_123",
	"turn_123")
if err != nil {
	panic(err)
}
fmt.Println(turn.SubagentID)
// 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.turns.TurnListParams;
import com.openai.models.beta.agents.sessions.turns.TurnRetrieveParams;

OpenAIClient client = OpenAIOkHttpClient.fromEnv();
var result =
    client
        .beta()
        .agents()
        .sessions()
        .turns()
        .list(
            TurnListParams.builder()
                .sessionId("sess_123")
                .limit(20L)
                .order(TurnListParams.Order.of("desc"))
                .build());
System.out.println(result.items());
var turn =
    client
        .beta()
        .agents()
        .sessions()
        .turns()
        .retrieve(
            TurnRetrieveParams.builder().turnId("turn_123").sessionId("sess_123").build());
System.out.println(turn.subagentId());
# Replace the illustrative IDs and URLs below with your own resource values.
require "openai"

client = OpenAI::Client.new
result = client.beta.agents.sessions.turns.list(
  "sess_123",
  limit: 20,
  order: "desc"
)
puts result.data
turn = client.beta.agents.sessions.turns.retrieve(
  "turn_123",
  session_id: "sess_123"
)
puts turn.subagent_id
curl "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'

has_moretrue 时,将返回的 last_id 用作下一页的 after 值。

命令条目包含 turn_id。检索该轮次并读取 subagent_id,以识别执行该命令的委托 Agent。null 子 Agent ID 标识根 Agent 的工作。命令输出截断情况不会被上报。

检查轮次追踪

使用 Platform 控制台检查已完成的轮次及其 Agent 活动。 详细的追踪检索不能通过普通项目 API 密钥获取。控制台追踪端点需要单独的访问权限,不属于受支持的客户 API。

轮次资源包含尽力而为的 usage 以及标识委托工作的 subagent_id。用量在未知时可能为 null,且可能发生变化。请参阅检查子 Agent Token 用量

若要将 Shell 命令归因,请检索由命令条目的 turn_id 标识的轮次,然后检查 turn.subagent_id。客户 API 不会指示命令输出是否被截断。

模型用量与费用

Agent 在完成任务时可能会进行多次模型调用。每次调用均遵循模型的Token 定价提示词缓存规则,与 Responses API 一致。请对完成任务所需的所有调用进行成本估算。

哪些内容会产生费用?

每次模型调用可消耗:

  • 输入 Token: Agent 指令、工具定义、对话历史、用户输入、文件或图像,以及工具结果。
  • 缓存输入 Token: 从匹配的提示词前缀中复用的输入,按模型的缓存输入费率计费。
  • 输出 Token: 生成的文本、工具调用参数和推理内容。

推理 Token 按输出 Token 计费。

子 Agent 也可以进行模型调用。在调查模型费用时,请将其记录的轮次用量与根 Agent 的工作一并检查。

在估算时,需考虑根 Agent 和子 Agent 的工作(包括重试),以及适用的工具费用、沙箱计算费用和第三方服务费用。对于有缓存写入定价的模型,将输入写入缓存也会产生费用。下方的 Agents API 用量字段未单独提供缓存写入数量,因此在适用该定价时无法确定确切的模型费用。

提示词缓存

Agent 在会话中持续传递上下文。当连续的模型调用共享相同的提示词前缀时,提示词缓存可以复用之前的处理结果。模型会生成新的响应;缓存不会重放旧的回答。维持会话并不保证缓存命中。复用取决于前缀匹配以及模型的缓存资格和生命周期规则。

在实际可行的情况下,保持初始指令和工具定义的稳定,并将新任务的详细信息放在后续消息中。使用工具搜索时,新发现的定义会被追加到对话末尾,从而为早期内容的缓存复用提供保障。有关特定模型的规则,请参阅提示词缓存

较高的缓存输入占比并不能衡量总任务成本的节省。缓存输入仍会计费,且重复调用可能处理大量历史记录。请比较以您的应用程序所需质量和延迟完成同一任务的成本。

了解 Token 用量

会话和轮次资源提供尽力而为的 usage。在未知时其值可能为 null,且随着计费数据的到达,已记录的数值可能发生变化。缺少用量数据并不意味着用量为零。这些数据不是最终账单。

已记录的用量对象包含以下 Token 类别:

{
  "input_tokens": 5000,
  "input_tokens_details": {
    "cached_tokens": 1500
  },
  "output_tokens": 900,
  "output_tokens_details": {
    "reasoning_tokens": 200
  },
  "total_tokens": 5900
}

在此示例中,Agent 处理了 5,000 个输入 Token,并生成了 900 个输出 Token。在输入 Token 中,有 1,500 个来自缓存。在输出 Token 中,有 200 个为推理 Token。

缓存 Token 已包含在 input_tokens 中,推理 Token 已包含在 output_tokens 中。

检查子 Agent Token 用量

列出或检索会话轮次,并检查每个轮次的 usagesubagent_id 用于标识子 Agent;对于根 Agent 的轮次,其值为 null。当 has_moretrue 时,以相同的 orderlast_id 作为 after 传入,以读取剩余轮次。

用量为尽力而为:在未知时可能为 null,且已记录的值可能发生变化。您也可以在追踪控制台中检查每个 Agent 的已记录用量。