Skip to content

日志

Supported in ADKPython v0.1.0Go v0.1.0Kotlin v0.1.0

智能体开发套件(ADK)提供灵活且强大的日志记录功能,可有效监控智能体行为并进行调试。

日志记录理念

ADK 的日志记录方法是在默认情况下不过于冗长的前提下提供详细的诊断信息。它由应用程序开发者配置,让你能够根据特定需求(无论是在开发环境还是生产环境)定制日志输出。

  • 标准库集成: ADK 使用宿主语言的标准日志记录工具(如 Python 的 logging 模块、Go 的 log 包)。
  • 结构化 GenAI 日志记录: ADK 使用 OpenTelemetry 记录 GenAI 请求和响应的结构化事件,支持在云环境中进行高级监控和调试。
  • 用户配置: 虽然 ADK 提供了默认设置并与 CLI 工具集成,但最终配置日志以适合特定环境的责任在于应用程序开发者。

日志记录方案

ADK 使用标准库工具发出日志,并通过 OpenTelemetry 发出结构化 GenAI 事件。

结构化 GenAI 日志

通过 OpenTelemetry 发出的结构化 GenAI 日志遵循 GenAI 语义约定。

默认情况下,出于安全考虑,提示内容在日志中被省略。你可以使用环境变量或编程方式配置来启用提示内容记录。有关 adk web 的设置,请参阅在 ADK Web 中捕获提示内容;有关在代码中的设置,请参阅以编程方式捕获提示内容。

日志级别(Python)

下表描述了在使用标准日志记录器时 Python 中不同级别记录的内容:

级别 描述 记录的信息类型
DEBUG 对调试至关重要。 最详细的级别,用于细粒度的诊断信息。
  • 完整 LLM 提示: 发送给语言模型的完整请求,包括系统指令、历史记录和工具。
  • 来自服务的详细 API 响应。
  • 内部状态转换和变量值。
INFO 关于智能体生命周期的一般信息。
  • 智能体初始化和启动。
  • 会话创建和删除事件。
  • 工具的执行,包括其名称和参数。
WARNING 指示潜在问题或已弃用功能的使用。智能体继续运行,但可能需要关注。
  • 使用了已弃用的方法或参数。
  • 系统已恢复的非严重错误。
ERROR 阻止操作完成的严重错误。
  • 对外部服务(如 LLM、会话服务)的 API 调用失败。
  • 智能体执行期间未处理的异常。
  • 配置错误。

Note

建议在生产环境中使用 INFO 或 WARNING。 仅在主动排查问题时启用 DEBUG,因为 DEBUG 日志可能非常冗长且包含敏感信息。

在 ADK Web 中记录日志

使用 ADK 的 adk web、adk api_server、adk deploy cloud_run 和 adk deploy gke 命令运行智能体时,你可以控制日志的详细程度或目标位置。

在 ADK Web 中的日志级别

要以 DEBUG 级别日志启动 Web 服务器,请运行:

adk web --log_level DEBUG path/to/your/agents_dir

--log_level 选项可用的日志级别为:DEBUG、INFO(默认)、WARNING、ERROR、CRITICAL。

在 ADK Web 中捕获提示内容

默认情况下,出于安全考虑,提示内容在日志中被省略。你可以使用环境变量启用提示日志记录:

export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true

该变量可用的值为:NO_CONTENT、EVENT_ONLY、SPAN_ONLY 和 SPAN_AND_EVENT。布尔值 true 或 1 表示 EVENT_ONLY,即在发出的日志事件中记录内容;这四个值以外的任何值会回退到 NO_CONTENT。要在推理 span 上记录内容,SPAN_ONLY 和 SPAN_AND_EVENT 还需要设置 OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental。

Warning

OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT 设置会记录用户提示和智能体响应的完整内容。这对于调试很有用,但可能会捕获敏感数据或 PII。在生产环境中,请将其设置为 false,或确保你有适当的数据处理策略。

在 ADK Web 中导出 OTLP

要将日志导出到 OTLP 兼容的后端,请设置标准的 OTel 环境变量:

export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT="http://your-collector:4318/v1/logs"
adk web path/to/your/agents_dir

Note

如果你希望将指标和追踪也发送到同一端点,还可以设置通用的 OTEL_EXPORTER_OTLP_ENDPOINT 环境变量。

在 ADK Web 中设置 GCP 导出

你可以使用 --otel_to_cloud 标志启用 GCP 导出:

adk web --otel_to_cloud path/to/your/agents_dir

编程方式设置

编程方式设置会从你自己的代码中配置底层日志框架和 OpenTelemetry 导出器,用于系统级诊断和生产环境可观测性。ADK 使用以下日志记录工具:

  • Python: ADK 使用标准的 logging 模块和 OpenTelemetry 来记录结构化 GenAI 日志。
  • Go: ADK 使用 google.golang.org/adk/v2/telemetry 包进行 OpenTelemetry 配置,并使用标准的 log 包记录一般事件,默认写入 stderr。
  • Kotlin: ADK 使用标准的 JVM 日志记录工具(默认为 Flogger),并使用 OpenTelemetry 记录结构化 GenAI 日志。

日志级别

你可以使用标准的日志控制方式为你的 ADK 智能体设置日志级别,如下所示:

要启用详细日志记录(包括 DEBUG 级别消息),请在脚本开头添加以下内容:

import logging

logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(name)s - %(message)s'
)

一般事件(如服务器启动或 HTTP 请求)使用标准的 Go log 包记录,默认写入 stderr。

ADK 使用标准的 JVM 日志记录工具(默认为 Flogger)。配置你的 JVM 日志记录器后端(如 java.util.logging 或 SLF4J)可以调整日志的详细程度。

捕获提示内容

你可以通过设置环境变量以编程方式启用完整的提示内容记录:

import os

os.environ["OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT"] = "true"

要将内容捕获限定到单次运行而不是整个进程,请设置 RunConfig.telemetry 而不是环境变量:

from google.adk.agents.run_config import RunConfig
from google.adk.telemetry import ContentCapturingMode, TelemetryConfig

run_config = RunConfig(
    telemetry=TelemetryConfig(
        capture_message_content=ContentCapturingMode.SPAN_AND_EVENT,
    ),
)

你可以在初始化遥测时通过导出 OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true 来启用完整的提示内容记录:

package main

import (
    "context"
    "os"

    "google.golang.org/adk/v2/telemetry"
)

func main() {
    ctx := context.Background()

    // 通过 OpenTelemetry 环境变量启用 GenAI 消息内容捕获
    os.Setenv("OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT", "true")

    tp, err := telemetry.New(ctx)
    if err != nil {
        // 处理错误
    }
    defer tp.Shutdown(ctx)
    tp.SetGlobalOtelProviders()
}

你可以通过配置全局 TelemetryConfig 来启用完整的提示内容记录:

// Enable full prompt and response logging
TelemetryConfig.captureMessageContent = true

OTLP 导出

要以编程方式将日志导出到 OpenTelemetry Collector(或 OTLP 兼容的后端):

from google.adk.telemetry.setup import maybe_set_otel_providers
import os

os.environ["OTEL_EXPORTER_OTLP_LOGS_ENDPOINT"] = "http://your-collector:4318/v1/logs"
os.environ["OTEL_SERVICE_NAME"] = "your-adk-agent"
os.environ["OTEL_RESOURCE_ATTRIBUTES"] = "key1=value1,key2=value2"
maybe_set_otel_providers()

要将日志导出到 OTLP 兼容的后端,请配置标准的 OpenTelemetry 环境变量,例如 OTEL_EXPORTER_OTLP_ENDPOINT 或 OTEL_EXPORTER_OTLP_LOGS_ENDPOINT。ADK 遥测包在初始化时会自动使用这些设置。

ADK Kotlin 的 OpenTelemetry 集成仅发出追踪——它不注册 LoggerProvider,因此没有 OTLP 日志导出。应用日志会写入你的 JVM 日志记录后端。要配置追踪导出,请参阅追踪文档。

GCP 导出设置

要以编程方式将日志导出到 Google Cloud Logging,请使用 OpenTelemetry 的 Google Cloud 导出器。以下是 Python 中的示例:

from google.adk.telemetry.google_cloud import get_gcp_exporters
from google.adk.telemetry.setup import maybe_set_otel_providers
import os

gcp_exporters = get_gcp_exporters(
  enable_cloud_logging = True,
)
os.environ["OTEL_SERVICE_NAME"] = "your-adk-agent"
os.environ["OTEL_RESOURCE_ATTRIBUTES"] = "key1=value1,key2=value2"
maybe_set_otel_providers([gcp_exporters])

要将日志导出到 Google Cloud Logging,请使用 WithOtelToCloud 选项:

package main

import (
    "context"
    "google.golang.org/adk/v2/telemetry"
)

func main() {
    ctx := context.Background()
    tp, err := telemetry.New(ctx,
        telemetry.WithOtelToCloud(true),
    )
    if err != nil {
        // 处理错误
    }
    defer tp.Shutdown(ctx)
    tp.SetGlobalOtelProviders()
}

如果使用 Go 启动器,你也可以通过 CLI 标志启用 GCP 导出:

go run main.go web -otel_to_cloud

ADK Kotlin 不发出 OpenTelemetry 日志记录,因此 Cloud Logging 没有可接收的内容;应用日志会写入你的 JVM 日志记录后端。可以通过将标准 OTLP 导出器指向 telemetry.googleapis.com 将 ADK Kotlin 的追踪发送到 Google Cloud——有关所需的凭据、配额项目和 roles/telemetry.writer 授权,请参阅 OTLP with Google Cloud。

使用插件记录活动日志

ADK 提供了内置插件来捕获智能体活动,包括用户消息、模型请求和响应、工具调用,以及(通过 DebugLoggingPlugin)会话状态。这些插件无需更改你的智能体逻辑。

使用 LoggingPlugin 记录控制台日志

要在执行期间将结构化的活动日志打印到控制台,请将 LoggingPlugin 附加到你的 App:

from google.adk.apps import App
from google.adk.plugins import LoggingPlugin

app = App(
    name="my_app",
    root_agent=root_agent,
    plugins=[LoggingPlugin()],
)
package main

import (
    "context"
    "log"
    "os"

    "google.golang.org/adk/v2/agent"
    "google.golang.org/adk/v2/cmd/launcher"
    "google.golang.org/adk/v2/cmd/launcher/full"
    "google.golang.org/adk/v2/plugin"
    "google.golang.org/adk/v2/plugin/loggingplugin"
    "google.golang.org/adk/v2/runner"
)

func main() {
    ctx := context.Background()
    logPlugin := loggingplugin.MustNew("logging_plugin")

    config := &launcher.Config{
        AgentLoader: agent.NewSingleLoader(rootAgent),
        PluginConfig: runner.PluginConfig{
            Plugins: []*plugin.Plugin{logPlugin},
        },
    }

    l := full.NewLauncher()
    if err := l.Execute(ctx, config, os.Args[1:]); err != nil {
        log.Fatalf("run failed: %v", err)
    }
}
// Use the LoggingPlugin for structured activity logging to the console
val runner =
    InMemoryRunner(
        App(appName = agent.name, rootAgent = agent, plugins = listOf(LoggingPlugin())),
    )

使用 DebugLoggingPlugin 将完整调试数据捕获到文件

Supported in ADKPython v1.23.0Kotlin v0.6.0

要将完整的交互数据以人类可读的 YAML 格式追加记录到 adk_debug.yaml(而不是输出被截断的控制台内容),请使用 DebugLoggingPlugin:

from google.adk.apps import App
from google.adk.plugins import DebugLoggingPlugin

app = App(
    name="my_app",
    root_agent=root_agent,
    plugins=[
        DebugLoggingPlugin(
            output_path="adk_debug.yaml",
            include_session_state=True,
            include_system_instruction=True,
        ),
    ],
)
// includeSystemInstruction = false logs has_system_instruction, not the instruction text
val debugPlugin = DebugLoggingPlugin(includeSystemInstruction = false)
val debugRunner =
    InMemoryRunner(
        App(appName = agent.name, rootAgent = agent, plugins = listOf(debugPlugin)),
    )

Warning

输出文件包含原始提示词、工具参数和会话状态。 尽管在 Python 中 ADK 会自动脱敏凭据和 temp: 作用域的状态键,但仍应将输出文件视为敏感数据。

理解日志输出

Python 日志条目示例

2025-07-08 11:22:33,456 - DEBUG - google_adk.google.adk.models.google_llm - LLM Request: contents { ... }
日志段 格式说明符 含义
2025-07-08 11:22:33,456 %(asctime)s 时间戳
DEBUG %(levelname)s 严重级别
google_adk.google.adk.models.google_llm %(name)s 日志记录器名称(产生日志的模块)
LLM Request: contents { ... } %(message)s 实际的日志消息

通过阅读日志记录器名称,你可以立即确定日志的来源,并理解其在智能体架构中的上下文。 ADK 日志记录器的命名格式为 google_adk. 后跟模块的完全限定名称,因此每个 ADK 日志记录器都是 google_adk 日志记录器的子级。可以使用 logging.getLogger("google_adk") 对它们进行分组配置。

调试示例

启用 DEBUG 日志(参见上面的日志级别)后,运行你的智能体并查找来自 google_adk.google.adk.models.google_llm 日志记录器的消息。 输出将显示完整的 LLM 请求和响应:

2025-07-10 15:26:13,778 - DEBUG - google_adk.google.adk.models.google_llm -
LLM Request:
-----------------------------------------------------------
System Instruction:
      You roll dice and answer questions about the outcome of the dice rolls.
      ...
-----------------------------------------------------------
Contents:
{"parts":[{"text":"Roll a 6 sided dice"}],"role":"user"}
{"parts":[{"function_call":{"args":{"sides":6},"name":"roll_die"}}],"role":"model"}
{"parts":[{"function_response":{"name":"roll_die","response":{"result":2}}}],"role":"user"}
-----------------------------------------------------------
Functions:
roll_die: {'sides': {'type': <Type.INTEGER: 'INTEGER'>}}
check_prime: {'nums': {'items': {'type': <Type.INTEGER: 'INTEGER'>}, 'type': <Type.ARRAY: 'ARRAY'>}}
-----------------------------------------------------------
2025-07-10 15:26:14,309 - INFO - google_adk.google.adk.models.google_llm -
LLM Response:
-----------------------------------------------------------
Text:
I have rolled a 6 sided die, and the result is 2.
...

从该输出中,你可以验证:

  • 系统指令是否正确?
  • 对话历史(user 和 model 轮次)是否准确?
  • 是否向模型提供了正确的工具?
  • 工具是否被模型正确调用?
  • 模型响应需要多长时间?