콘텐츠로 이동

ADK용 BigQuery Agent Analytics 플러그인

ADK에서 지원Python v1.21.0미리보기

버전 요구사항

auto-schema-upgrade, tool provenance 추적, HITL 이벤트 추적을 포함해 이 문서의 기능을 온전히 활용하려면 ADK Python 버전 1.26.0 이상을 사용하세요.

BigQuery Agent Analytics 플러그인은 심층적인 에이전트 동작 분석을 위한 견고한 솔루션을 제공하여 Agent Development Kit(ADK)를 크게 확장합니다. ADK 플러그인 아키텍처와 BigQuery Storage Write API를 사용해 중요한 운영 이벤트를 Google BigQuery 테이블에 직접 캡처하고 기록하므로, 디버깅, 실시간 모니터링, 포괄적인 오프라인 성능 평가를 위한 고급 기능을 활용할 수 있습니다.

버전 1.26.0에서는 Auto Schema Upgrade(기존 테이블에 새 컬럼을 안전하게 추가), Tool Provenance 추적(LOCAL, MCP, SUB_AGENT, A2A, TRANSFER_AGENT), 그리고 사람-개입형 상호작용을 위한 HITL Event Tracing이 추가되었습니다. 버전 1.27.0에서는 Automatic View Creation(평탄화된 쿼리 친화적 이벤트 뷰 생성)이 추가되었습니다.

미리보기 릴리스

BigQuery Agent Analytics 플러그인은 미리보기 릴리스 상태입니다. 자세한 내용은 출시 단계 설명을 참고하세요.

BigQuery Storage Write API

이 기능은 유료 서비스인 BigQuery Storage Write API를 사용합니다. 비용 정보는 BigQuery 문서를 참고하세요.

사용 사례

  • 에이전트 워크플로 디버깅 및 분석: 다양한 플러그인 수명 주기 이벤트(LLM 호출, 도구 사용)와 에이전트가 생성한 이벤트(사용자 입력, 모델 응답)를 잘 정의된 스키마에 캡처합니다.
  • 대량 분석 및 디버깅: 로깅 작업은 Storage Write API를 사용해 비동기적으로 수행되므로, 높은 처리량과 낮은 지연 시간을 동시에 달성할 수 있습니다.
  • 멀티모달 분석: 텍스트, 이미지, 기타 modality를 기록하고 분석할 수 있습니다. 대용량 파일은 GCS로 오프로딩되어 Object Table을 통해 BigQuery ML에서 활용할 수 있습니다.
  • 분산 추적: trace_id, span_id 기반의 OpenTelemetry 스타일 추적을 기본 지원하여 에이전트 실행 흐름을 시각화할 수 있습니다.
  • Tool Provenance: 각 도구 호출이 어디서 왔는지(로컬 함수, MCP 서버, 하위 에이전트, A2A 원격 에이전트, transfer agent)를 추적합니다.
  • Human-in-the-Loop(HITL) 추적: 자격 증명 요청, 확인 프롬프트, 사용자 입력 요청을 위한 전용 이벤트 유형을 제공합니다.
  • 쿼리 가능한 이벤트 뷰(Queryable Event Views): 이벤트 유형별 평탄화 BigQuery 뷰(예: v_llm_request, v_tool_completed)를 자동 생성하여 JSON 페이로드를 펼친 다운스트림 분석을 단순화합니다.

기록되는 에이전트 이벤트 데이터는 ADK 이벤트 유형에 따라 달라집니다. 자세한 내용은 이벤트 유형 및 페이로드를 참고하세요.

전제 조건

  • BigQuery API가 활성화된 Google Cloud 프로젝트
  • BigQuery 데이터 세트: 플러그인을 사용하기 전에 로깅 테이블을 저장할 데이터 세트를 생성합니다. 테이블이 없으면 플러그인이 해당 데이터 세트 안에 필요한 이벤트 테이블을 자동으로 생성합니다.
  • Google Cloud Storage 버킷(선택 사항): 멀티모달 콘텐츠(이미지, 오디오 등)를 기록하려면 대용량 파일 오프로딩을 위해 GCS 버킷을 만들어 두는 것이 좋습니다.
  • 인증
    • 로컬: gcloud auth application-default login 실행
    • 클라우드: 서비스 계정에 필요한 권한이 있는지 확인

IAM 권한

에이전트가 정상적으로 동작하려면, 에이전트가 실행되는 주체(예: 서비스 계정, 사용자 계정)에 다음 Google Cloud 역할이 필요합니다.

  • roles/bigquery.jobUser: 프로젝트 수준에서 BigQuery 쿼리를 실행하기 위한 권한
  • roles/bigquery.dataEditor: 테이블 수준에서 로그/이벤트 데이터를 쓰기 위한 권한
  • GCS 오프로딩 사용 시: 대상 버킷에 대한 roles/storage.objectCreatorroles/storage.objectViewer

에이전트와 함께 사용

BigQuery Agent Analytics 플러그인은 ADK 에이전트의 App 객체에 구성하고 등록하여 사용합니다. 다음 예시는 GCS 오프로딩을 포함하여 이 플러그인을 사용하는 에이전트 구현 예입니다.

my_bq_agent/agent.py
# my_bq_agent/agent.py
import os
import google.auth
from google.adk.apps import App
from google.adk.plugins.bigquery_agent_analytics_plugin import BigQueryAgentAnalyticsPlugin, BigQueryLoggerConfig
from google.adk.agents import Agent
from google.adk.models.google_llm import Gemini
from google.adk.tools.bigquery import BigQueryToolset, BigQueryCredentialsConfig


# --- OpenTelemetry TracerProvider Setup (Optional) ---
# ADK includes OpenTelemetry as a core dependency.
# Configuring a TracerProvider enables full distributed tracing
# (populates trace_id, span_id with standard OTel identifiers).
# If no TracerProvider is configured, the plugin falls back to internal
# UUIDs for span correlation while still preserving the parent-child hierarchy.
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
trace.set_tracer_provider(TracerProvider())

# --- Configuration ---
PROJECT_ID = os.environ.get("GOOGLE_CLOUD_PROJECT", "your-gcp-project-id")
DATASET_ID = os.environ.get("BIG_QUERY_DATASET_ID", "your-big-query-dataset-id")
LOCATION = os.environ.get("GOOGLE_CLOUD_LOCATION", "US") # default location is US in the plugin
GCS_BUCKET = os.environ.get("GCS_BUCKET_NAME", "your-gcs-bucket-name") # Optional

if PROJECT_ID == "your-gcp-project-id":
    raise ValueError("Please set GOOGLE_CLOUD_PROJECT or update the code.")

# --- CRITICAL: Set environment variables BEFORE Gemini instantiation ---
os.environ['GOOGLE_CLOUD_PROJECT'] = PROJECT_ID
os.environ['GOOGLE_CLOUD_LOCATION'] = LOCATION
os.environ['GOOGLE_GENAI_USE_VERTEXAI'] = 'True'

# --- Initialize the Plugin with Config ---
bq_config = BigQueryLoggerConfig(
    enabled=True,
    gcs_bucket_name=GCS_BUCKET, # Enable GCS offloading for multimodal content
    log_multi_modal_content=True,
    max_content_length=500 * 1024, # 500 KB limit for inline text
    batch_size=1, # Default is 1 for low latency, increase for high throughput
    shutdown_timeout=10.0
)

bq_logging_plugin = BigQueryAgentAnalyticsPlugin(
    project_id=PROJECT_ID,
    dataset_id=DATASET_ID,
    table_id="agent_events", # default table name is agent_events
    config=bq_config,
    location=LOCATION
)

# --- Initialize Tools and Model ---
credentials, _ = google.auth.default(scopes=["https://www.googleapis.com/auth/cloud-platform"])
bigquery_toolset = BigQueryToolset(
    credentials_config=BigQueryCredentialsConfig(credentials=credentials)
)

llm = Gemini(model="gemini-2.5-flash")

root_agent = Agent(
    model=llm,
    name='my_bq_agent',
    instruction="You are a helpful assistant with access to BigQuery tools.",
    tools=[bigquery_toolset]
)

# --- Create the App ---
app = App(
    name="my_bq_agent",
    root_agent=root_agent,
    plugins=[bq_logging_plugin],
)

에이전트 실행 및 테스트

채팅 인터페이스를 통해 에이전트를 실행하고 "tell me what you can do" 또는 "List datasets in my cloud project <your-gcp-project-id> " 같은 요청을 몇 번 보내 플러그인을 테스트해 보세요. 이러한 동작은 Google Cloud 프로젝트의 BigQuery 인스턴스에 이벤트를 생성합니다. 이벤트가 처리된 뒤에는 BigQuery Console에서 다음 쿼리를 사용해 데이터를 확인할 수 있습니다.

SELECT timestamp, event_type, content
FROM `your-gcp-project-id.your-big-query-dataset-id.agent_events`
ORDER BY timestamp DESC
LIMIT 20;

추적 및 관측 가능성

이 플러그인은 분산 추적을 위한 OpenTelemetry를 지원합니다. OpenTelemetry는 ADK의 핵심 의존성에 포함되어 있으므로 항상 사용할 수 있습니다.

  • 자동 Span 관리: 플러그인이 에이전트 실행, LLM 호출, 도구 실행에 대한 span을 자동으로 생성합니다.
  • OpenTelemetry 통합: 예시처럼 TracerProvider가 구성되어 있으면, 플러그인은 유효한 OTel span을 사용하여 trace_id, span_id, parent_span_id를 표준 OTel 식별자로 채웁니다. 이를 통해 분산 시스템의 다른 서비스와 에이전트 로그를 상관 분석할 수 있습니다.
  • Fallback 메커니즘: TracerProvider가 구성되지 않은 경우(즉, 기본 no-op provider만 활성화된 경우), 플러그인은 내부 UUID 기반 span 생성으로 자동 폴백하고 invocation_id를 trace ID로 사용합니다. 따라서 OTel TracerProvider를 구성하지 않아도 BigQuery 로그에서 부모-자식 계층(Agent -> Span -> Tool/LLM)은 항상 유지됩니다.

구성 옵션

BigQueryLoggerConfig를 사용해 플러그인을 사용자 지정할 수 있습니다.

  • enabled (bool, 기본값: True): 플러그인의 BigQuery 테이블 로깅을 비활성화하려면 False로 설정합니다.
  • table_id (str, 기본값: "agent_events"): 데이터 세트 내의 BigQuery 테이블 ID입니다. BigQueryAgentAnalyticsPlugin 생성자의 table_id 인수로도 덮어쓸 수 있으며, 이 값이 우선합니다.
  • clustering_fields (List[str], 기본값: ["event_type", "agent", "user_id"]): 테이블을 자동 생성할 때 클러스터링에 사용하는 필드입니다.
  • gcs_bucket_name (Optional[str], 기본값: None): 대용량 콘텐츠(이미지, blob, 긴 텍스트)를 오프로딩할 GCS 버킷 이름입니다. 지정하지 않으면 큰 콘텐츠는 잘리거나 placeholder로 대체될 수 있습니다.
  • connection_id (Optional[str], 기본값: None): ObjectRef 컬럼의 authorizer로 사용할 BigQuery connection ID(예: us.my-connection)입니다. BigQuery ML에서 ObjectRef를 사용하려면 필요합니다.
  • max_content_length (int, 기본값: 500 * 1024): BigQuery에 inline으로 저장할 텍스트 콘텐츠의 최대 길이(문자 수)입니다. 이를 넘기면(GCS가 구성된 경우) GCS로 오프로딩되거나, 그렇지 않으면 잘립니다. 기본값은 500KB입니다.
  • batch_size (int, 기본값: 1): BigQuery에 쓰기 전에 묶는 이벤트 수입니다.
  • batch_flush_interval (float, 기본값: 1.0): 부분 배치를 flush하기 전까지 기다리는 최대 시간(초)입니다.
  • shutdown_timeout (float, 기본값: 10.0): 종료 시 로그가 flush될 때까지 기다리는 시간(초)입니다.
  • event_allowlist (Optional[List[str]], 기본값: None): 기록할 이벤트 유형 목록입니다. None이면 event_denylist에 포함된 이벤트를 제외한 모든 이벤트를 기록합니다. 지원되는 이벤트 유형 전체 목록은 이벤트 유형 및 페이로드 섹션을 참고하세요.
  • event_denylist (Optional[List[str]], 기본값: None): 기록에서 제외할 이벤트 유형 목록입니다. 지원되는 이벤트 유형 전체 목록은 이벤트 유형 및 페이로드 섹션을 참고하세요.
  • content_formatter (Optional[Callable[[Any, str], Any]], 기본값: None): 로깅 전에 이벤트 콘텐츠를 포맷하는 선택적 함수입니다. 이 함수는 원시 콘텐츠와 이벤트 유형 문자열(예: "LLM_REQUEST") 두 인수를 받습니다.
  • log_multi_modal_content (bool, 기본값: True): 상세 콘텐츠 파트(GCS_REFERENCE 포함)를 기록할지 여부입니다.
  • queue_max_size (int, 기본값: 10000): 메모리 내 큐에 보관할 수 있는 최대 이벤트 수입니다. 이를 초과하면 새 이벤트가 삭제됩니다.
  • retry_config (RetryConfig, 기본값: RetryConfig()): 실패한 BigQuery 쓰기를 재시도하기 위한 설정입니다(max_retries, initial_delay, multiplier, max_delay 포함).
  • log_session_metadata (bool, 기본값: True): True이면 session_id, app_name, user_id, 그리고 세션 state 딕셔너리(예: gchat thread-id, customer_id 같은 커스텀 상태)를 포함한 세션 정보를 attributes 컬럼에 기록합니다.
  • custom_tags (Dict[str, Any], 기본값: {}): 모든 이벤트의 attributes 컬럼에 포함할 정적 태그 딕셔너리입니다(예: {"env": "prod", "version": "1.0"}).
  • auto_schema_upgrade (bool, 기본값: True): 활성화하면 플러그인 스키마가 진화할 때 기존 테이블에 새 컬럼을 자동으로 추가합니다. 컬럼 삭제나 변경 없이 additive change만 수행합니다. 테이블의 버전 레이블(adk_schema_version) 덕분에 스키마 버전당 한 번만 diff가 수행됩니다. 기본적으로 켜 둬도 안전합니다.
  • create_views (bool, 기본값: True): 1.27.0에서 추가되었습니다. 활성화하면 contentattributes 같은 구조화된 JSON 데이터를 평탄한 타입 컬럼으로 펼치는 이벤트 유형별 BigQuery 뷰를 자동 생성하여 SQL 쿼리를 크게 단순화합니다.

다음 코드는 BigQuery Agent Analytics 플러그인용 구성을 정의하는 예시입니다.

import json
import re

from google.adk.plugins.bigquery_agent_analytics_plugin import BigQueryLoggerConfig

def redact_dollar_amounts(event_content: Any, event_type: str) -> str:
    """
    Custom formatter to redact dollar amounts (e.g., $600, $12.50)
    and ensure JSON output if the input is a dict.

    Args:
        event_content: The raw content of the event.
        event_type: The event type string (e.g., "LLM_REQUEST", "LLM_RESPONSE").
    """
    text_content = ""
    if isinstance(event_content, dict):
        text_content = json.dumps(event_content)
    else:
        text_content = str(event_content)

    # Regex to find dollar amounts: $ followed by digits, optionally with commas or decimals.
    # Examples: $600, $1,200.50, $0.99
    redacted_content = re.sub(r'\$\d+(?:,\d{3})*(?:\.\d+)?', 'xxx', text_content)

    return redacted_content

config = BigQueryLoggerConfig(
    enabled=True,
    event_allowlist=["LLM_REQUEST", "LLM_RESPONSE"], # Only log these events
    # event_denylist=["TOOL_STARTING"], # Skip these events
    shutdown_timeout=10.0, # Wait up to 10s for logs to flush on exit
    max_content_length=500, # Truncate content to 500 chars
    content_formatter=redact_dollar_amounts, # Redact the dollar amounts in the logging content
    queue_max_size=10000, # Max events to hold in memory
    auto_schema_upgrade=True, # Automatically add new columns to existing tables
    create_views=True, # Automatically create per-event-type views
    # retry_config=RetryConfig(max_retries=3), # Optional: Configure retries
)

plugin = BigQueryAgentAnalyticsPlugin(..., config=config)

스키마 및 프로덕션 설정

스키마 참조

이벤트 테이블(agent_events)은 유연한 스키마를 사용합니다. 아래 표는 예시 값을 포함한 포괄적인 참조입니다.

필드명 유형 모드 설명 예시 값
timestamp TIMESTAMP REQUIRED 이벤트 생성 시점의 UTC 타임스탬프입니다. 기본 정렬 키이자 일별 파티셔닝 키 역할을 합니다. 마이크로초 정밀도를 가집니다. 2026-02-03 20:52:17 UTC
event_type STRING NULLABLE 정규화된 이벤트 범주입니다. 표준 값에는 LLM_REQUEST, LLM_RESPONSE, LLM_ERROR, TOOL_STARTING, TOOL_COMPLETED, TOOL_ERROR, AGENT_STARTING, AGENT_COMPLETED, STATE_DELTA, INVOCATION_STARTING, INVOCATION_COMPLETED, USER_MESSAGE_RECEIVED, 그리고 HITL 이벤트(HITL events 참조)가 포함됩니다. 상위 수준 필터링에 사용됩니다. LLM_REQUEST
agent STRING NULLABLE 이 이벤트를 발생시킨 에이전트 이름입니다. 에이전트 초기화 시 또는 root_agent_name 컨텍스트를 통해 정의됩니다. my_bq_agent
session_id STRING NULLABLE 전체 대화 스레드를 식별하는 영속적인 식별자입니다. 여러 turn과 하위 에이전트 호출을 거쳐도 동일하게 유지됩니다. 04275a01-1649-4a30-b6a7-5b443c69a7bc
invocation_id STRING NULLABLE 단일 실행 turn 또는 요청 사이클의 고유 식별자입니다. 많은 맥락에서 trace_id와 대응됩니다. e-b55b2000-68c6-4e8b-b3b3-ffb454a92e40
user_id STRING NULLABLE 세션을 시작한 사용자(사람 또는 시스템)의 식별자입니다. User 객체나 메타데이터에서 추출됩니다. test_user
trace_id STRING NULLABLE OpenTelemetry Trace ID(32자 16진수)입니다. 하나의 분산 요청 수명 주기 내 모든 작업을 연결합니다. e-b55b2000-68c6-4e8b-b3b3-ffb454a92e40
span_id STRING NULLABLE OpenTelemetry Span ID(16자 16진수)입니다. 이 특정 원자적 작업을 고유하게 식별합니다. 69867a836cd94798be2759d8e0d70215
parent_span_id STRING NULLABLE 직전 호출자의 Span ID입니다. 부모-자식 실행 트리(DAG)를 재구성하는 데 사용됩니다. ef5843fe40764b4b8afec44e78044205
content JSON NULLABLE 기본 이벤트 페이로드입니다. 구조는 event_type에 따라 달라집니다. {"system_prompt": "You are...", "prompt": [{"role": "user", "content": "hello"}], "response": "Hi", "usage": {"total": 15}}
attributes JSON NULLABLE 메타데이터/보강 정보(사용량 통계, 모델 정보, tool provenance, custom tags)입니다. {"model": "gemini-2.5-flash", "usage_metadata": {"total_token_count": 15}, "session_metadata": {"session_id": "...", "app_name": "...", "user_id": "...", "state": {}}, "custom_tags": {"env": "prod"}}
latency_ms JSON NULLABLE 성능 메트릭입니다. 표준 키는 total_ms(총 경과 시간)와 time_to_first_token_ms(스트리밍 지연 시간)입니다. {"total_ms": 1250, "time_to_first_token_ms": 450}
status STRING NULLABLE 상위 수준 결과입니다. 값은 OK(성공) 또는 ERROR(실패)입니다. OK
error_message STRING NULLABLE 사람이 읽을 수 있는 예외 메시지 또는 스택 트레이스 일부입니다. statusERROR일 때만 채워집니다. Error 404: Dataset not found
is_truncated BOOLEAN NULLABLE contentattributes가 BigQuery 셀 크기 제한(기본 10MB)을 초과해 일부 드롭되었으면 true입니다. false
content_parts RECORD REPEATED 멀티모달 세그먼트(Text, Image, Blob) 배열입니다. 콘텐츠를 단순 JSON으로 직렬화할 수 없을 때(예: 큰 바이너리나 GCS 참조) 사용됩니다. [{"mime_type": "text/plain", "text": "hello"}]

플러그인은 테이블이 없으면 자동으로 생성합니다. 하지만 프로덕션에서는 유연성을 위한 JSON 타입과 멀티모달 콘텐츠를 위한 REPEATED RECORD를 활용하는 다음 DDL로 테이블을 수동 생성하는 것을 권장합니다.

권장 DDL:

CREATE TABLE `your-gcp-project-id.adk_agent_logs.agent_events`
(
  timestamp TIMESTAMP NOT NULL OPTIONS(description="The UTC time at which the event was logged."),
  event_type STRING OPTIONS(description="Indicates the type of event being logged (e.g., 'LLM_REQUEST', 'TOOL_COMPLETED')."),
  agent STRING OPTIONS(description="The name of the ADK agent or author associated with the event."),
  session_id STRING OPTIONS(description="A unique identifier to group events within a single conversation or user session."),
  invocation_id STRING OPTIONS(description="A unique identifier for each individual agent execution or turn within a session."),
  user_id STRING OPTIONS(description="The identifier of the user associated with the current session."),
  trace_id STRING OPTIONS(description="OpenTelemetry trace ID for distributed tracing."),
  span_id STRING OPTIONS(description="OpenTelemetry span ID for this specific operation."),
  parent_span_id STRING OPTIONS(description="OpenTelemetry parent span ID to reconstruct hierarchy."),
  content JSON OPTIONS(description="The event-specific data (payload) stored as JSON."),
  content_parts ARRAY<STRUCT<
    mime_type STRING,
    uri STRING,
    object_ref STRUCT<
      uri STRING,
      version STRING,
      authorizer STRING,
      details JSON
    >,
    text STRING,
    part_index INT64,
    part_attributes STRING,
    storage_mode STRING
  >> OPTIONS(description="Detailed content parts for multi-modal data."),
  attributes JSON OPTIONS(description="Arbitrary key-value pairs for additional metadata (e.g., 'root_agent_name', 'model_version', 'usage_metadata', 'session_metadata', 'custom_tags')."),
  latency_ms JSON OPTIONS(description="Latency measurements (e.g., total_ms)."),
  status STRING OPTIONS(description="The outcome of the event, typically 'OK' or 'ERROR'."),
  error_message STRING OPTIONS(description="Populated if an error occurs."),
  is_truncated BOOLEAN OPTIONS(description="Flag indicates if content was truncated.")
)
PARTITION BY DATE(timestamp)
CLUSTER BY event_type, agent, user_id;

자동 생성 뷰 (1.27.0+)

create_views=True(1.27.0 이상에서 기본값)이면 플러그인이 각 이벤트 유형에 대해, 공통 JSON 구조를 평탄한 타입 컬럼으로 펼친 뷰를 자동 생성합니다. 따라서 복잡한 JSON_VALUE 또는 JSON_QUERY 함수를 직접 작성하지 않고도 SQL을 훨씬 단순하게 작성할 수 있습니다.

예를 들어 v_llm_request 뷰는 다음 스키마를 포함합니다.

필드명 유형 설명
(공통 컬럼) VARIES timestamp, event_type, agent, session_id, invocation_id, user_id, trace_id, span_id, parent_span_id, status, error_message, is_truncated 같은 표준 메타데이터를 포함합니다.
model STRING 요청에 사용된 LLM 모델 이름입니다.
request_content JSON 원시 LLM 요청 페이로드입니다.
llm_config JSON LLM에 전달된 구성 매개변수(temperature, top_p 등)입니다.
tools JSON 요청 시 사용 가능했던 도구 배열입니다.

이벤트 유형 및 페이로드

이제 content 컬럼은 event_typeJSON 객체를 담습니다. content_parts 컬럼은 콘텐츠를 구조화해 보여주며, 특히 이미지나 오프로딩된 데이터에 유용합니다.

콘텐츠 잘림

  • 가변 콘텐츠 필드는 max_content_length까지 잘립니다(BigQueryLoggerConfig에서 구성, 기본 500KB).
  • gcs_bucket_name이 구성되어 있으면, 큰 콘텐츠는 잘리는 대신 GCS로 오프로딩되고 참조가 content_parts.object_ref에 저장됩니다.

LLM 상호작용(플러그인 수명 주기)

이 이벤트들은 LLM에 전송된 원시 요청과 LLM으로부터 받은 응답을 추적합니다.

1. LLM_REQUEST

대화 이력과 시스템 지침을 포함하여 모델에 전송된 프롬프트를 캡처합니다.

{
  "event_type": "LLM_REQUEST",
  "content": {
    "system_prompt": "You are a helpful assistant...",
    "prompt": [
      {
        "role": "user",
        "content": "hello how are you today"
      }
    ]
  },
  "attributes": {
    "root_agent_name": "my_bq_agent",
    "model": "gemini-2.5-flash",
    "tools": ["list_dataset_ids", "execute_sql"],
    "llm_config": {
      "temperature": 0.5,
      "top_p": 0.9
    }
  }
}

2. LLM_RESPONSE

모델 출력과 토큰 사용 통계를 캡처합니다.

{
  "event_type": "LLM_RESPONSE",
  "content": {
    "response": "text: 'Hello! I'm doing well...'",
    "usage": {
      "completion": 19,
      "prompt": 10129,
      "total": 10148
    }
  },
  "attributes": {
    "root_agent_name": "my_bq_agent",
    "model_version": "gemini-2.5-flash-001",
    "usage_metadata": {
      "prompt_token_count": 10129,
      "candidates_token_count": 19,
      "total_token_count": 10148
    }
  },
  "latency_ms": {
    "time_to_first_token_ms": 2579,
    "total_ms": 2579
  }
}

3. LLM_ERROR

LLM 호출이 예외로 실패했을 때 기록됩니다. 오류 메시지가 캡처되고 span이 종료됩니다.

{
  "event_type": "LLM_ERROR",
  "content": null,
  "attributes": {
    "root_agent_name": "my_bq_agent"
  },
  "error_message": "Error 429: Resource exhausted",
  "latency_ms": {
    "total_ms": 350
  }
}

도구 사용(플러그인 수명 주기)

이 이벤트들은 에이전트의 도구 실행을 추적합니다. 각 도구 이벤트에는 도구 출처를 분류하는 tool_origin 필드가 포함됩니다.

도구 출처 설명
LOCAL FunctionTool 인스턴스(로컬 Python 함수)
MCP Model Context Protocol 도구(McpTool 인스턴스)
SUB_AGENT AgentTool 인스턴스(하위 에이전트)
A2A 원격 Agent-to-Agent 인스턴스(RemoteA2aAgent)
TRANSFER_AGENT TransferToAgentTool 인스턴스
UNKNOWN 분류되지 않은 도구

4. TOOL_STARTING

에이전트가 도구 실행을 시작할 때 기록됩니다.

{
  "event_type": "TOOL_STARTING",
  "content": {
    "tool": "list_dataset_ids",
    "args": {
      "project_id": "bigquery-public-data"
    },
    "tool_origin": "LOCAL"
  }
}

5. TOOL_COMPLETED

도구 실행이 끝났을 때 기록됩니다.

{
  "event_type": "TOOL_COMPLETED",
  "content": {
    "tool": "list_dataset_ids",
    "result": [
      "austin_311",
      "austin_bikeshare"
    ],
    "tool_origin": "LOCAL"
  },
  "latency_ms": {
    "total_ms": 467
  }
}

6. TOOL_ERROR

도구 실행이 예외로 실패했을 때 기록됩니다. 도구 이름, 인수, tool origin, 오류 메시지를 함께 캡처합니다.

{
  "event_type": "TOOL_ERROR",
  "content": {
    "tool": "list_dataset_ids",
    "args": {
      "project_id": "nonexistent-project"
    },
    "tool_origin": "LOCAL"
  },
  "error_message": "Error 404: Dataset not found",
  "latency_ms": {
    "total_ms": 150
  }
}

상태 관리

이 이벤트들은 일반적으로 도구에 의해 발생하는 에이전트 상태 변경을 추적합니다.

7. STATE_DELTA

에이전트 내부 상태의 변경(예: 토큰 캐시 업데이트)을 추적합니다.

{
  "event_type": "STATE_DELTA",
  "attributes": {
    "state_delta": {
      "bigquery_token_cache": "{\"token\": \"ya29...\", \"expiry\": \"...\"}"
    }
  }
}

에이전트 수명 주기 및 일반 이벤트

이벤트 유형 콘텐츠(JSON) 구조

INVOCATION_STARTING

{}

INVOCATION_COMPLETED

{}

AGENT_STARTING

"You are a helpful agent..."

AGENT_COMPLETED

{}

USER_MESSAGE_RECEIVED

{"text_summary": "Help me book a flight."}

Human-in-the-Loop (HITL) 이벤트

이 플러그인은 ADK의 synthetic HITL 도구 호출을 자동 감지하고 전용 이벤트 유형을 발행합니다. 이러한 이벤트는 일반 TOOL_STARTING / TOOL_COMPLETED 이벤트에 추가로 기록됩니다.

다음 HITL 도구 이름이 인식됩니다.

  • adk_request_credential — 사용자 자격 증명 요청(예: OAuth 토큰)
  • adk_request_confirmation — 진행 전 사용자 확인 요청
  • adk_request_input — 자유 형식 사용자 입력 요청
이벤트 유형 트리거 콘텐츠(JSON) 구조

HITL_CREDENTIAL_REQUEST

에이전트가 adk_request_credential를 호출함

{"tool": "adk_request_credential", "args": {...}}

HITL_CREDENTIAL_REQUEST_COMPLETED

사용자가 자격 증명 응답을 제공함

{"tool": "adk_request_credential", "result": {...}}

HITL_CONFIRMATION_REQUEST

에이전트가 adk_request_confirmation를 호출함

{"tool": "adk_request_confirmation", "args": {...}}

HITL_CONFIRMATION_REQUEST_COMPLETED

사용자가 확인 응답을 제공함

{"tool": "adk_request_confirmation", "result": {...}}

HITL_INPUT_REQUEST

에이전트가 adk_request_input를 호출함

{"tool": "adk_request_input", "args": {...}}

HITL_INPUT_REQUEST_COMPLETED

사용자가 입력 응답을 제공함

{"tool": "adk_request_input", "result": {...}}

HITL 요청 이벤트는 on_event_callbackfunction_call 파트에서 감지됩니다. HITL 완료 이벤트는 on_event_callbackon_user_message_callbackfunction_response 파트에서 감지됩니다.

GCS 오프로딩 예시(멀티모달 및 대용량 텍스트)

gcs_bucket_name이 구성되어 있으면, 대용량 텍스트와 멀티모달 콘텐츠(이미지, 오디오 등)는 자동으로 GCS로 오프로딩됩니다. content 컬럼에는 요약 또는 placeholder가 저장되고, content_parts에는 GCS URI를 가리키는 object_ref가 저장됩니다.

오프로딩된 텍스트 예시

{
  "event_type": "LLM_REQUEST",
  "content_parts": [
    {
      "part_index": 1,
      "mime_type": "text/plain",
      "storage_mode": "GCS_REFERENCE",
      "text": "AAAA... [OFFLOADED]",
      "object_ref": {
        "uri": "gs://haiyuan-adk-debug-verification-1765319132/2025-12-10/e-f9545d6d/ae5235e6_p1.txt",
        "authorizer": "us.bqml_connection",
        "details": {"gcs_metadata": {"content_type": "text/plain"}}
      }
    }
  ]
}

오프로딩된 이미지 예시

{
  "event_type": "LLM_REQUEST",
  "content_parts": [
    {
      "part_index": 2,
      "mime_type": "image/png",
      "storage_mode": "GCS_REFERENCE",
      "text": "[MEDIA OFFLOADED]",
      "object_ref": {
        "uri": "gs://haiyuan-adk-debug-verification-1765319132/2025-12-10/e-f9545d6d/ae5235e6_p2.png",
        "authorizer": "us.bqml_connection",
        "details": {"gcs_metadata": {"content_type": "image/png"}}
      }
    }
  ]
}

오프로딩 콘텐츠 조회(서명 URL 얻기)

SELECT
  timestamp,
  event_type,
  part.mime_type,
  part.storage_mode,
  part.object_ref.uri AS gcs_uri,
  -- Generate a signed URL to read the content directly (requires connection_id configuration)
  STRING(OBJ.GET_ACCESS_URL(part.object_ref, 'r').access_urls.read_url) AS signed_url
FROM `your-gcp-project-id.your-dataset-id.agent_events`,
UNNEST(content_parts) AS part
WHERE part.storage_mode = 'GCS_REFERENCE'
ORDER BY timestamp DESC
LIMIT 10;

고급 분석 쿼리

trace_id로 특정 대화 턴 추적

SELECT timestamp, event_type, agent, JSON_VALUE(content, '$.response') as summary
FROM `your-gcp-project-id.your-dataset-id.agent_events`
WHERE trace_id = 'your-trace-id'
ORDER BY timestamp ASC;

토큰 사용량 분석(JSON 필드 접근)

SELECT
  AVG(CAST(JSON_VALUE(content, '$.usage.total') AS INT64)) as avg_tokens
FROM `your-gcp-project-id.your-dataset-id.agent_events`
WHERE event_type = 'LLM_RESPONSE';

멀티모달 콘텐츠 조회(content_partsObjectRef 사용)

SELECT
  timestamp,
  part.mime_type,
  part.object_ref.uri as gcs_uri
FROM `your-gcp-project-id.your-dataset-id.agent_events`,
UNNEST(content_parts) as part
WHERE part.mime_type LIKE 'image/%'
ORDER BY timestamp DESC;

BigQuery 원격 모델(Gemini)로 멀티모달 콘텐츠 분석

SELECT
  logs.session_id,
  -- Get a signed URL for the image
  STRING(OBJ.GET_ACCESS_URL(parts.object_ref, "r").access_urls.read_url) as signed_url,
  -- Analyze the image using a remote model (e.g., gemini-pro-vision)
  AI.GENERATE(
    ('Describe this image briefly. What company logo?', parts.object_ref)
  ) AS generated_result
FROM
  `your-gcp-project-id.your-dataset-id.agent_events` logs,
  UNNEST(logs.content_parts) AS parts
WHERE
  parts.mime_type LIKE 'image/%'
ORDER BY logs.timestamp DESC
LIMIT 1;

지연 시간 분석(LLM 및 도구)

SELECT
  event_type,
  AVG(CAST(JSON_VALUE(latency_ms, '$.total_ms') AS INT64)) as avg_latency_ms
FROM `your-gcp-project-id.your-dataset-id.agent_events`
WHERE event_type IN ('LLM_RESPONSE', 'TOOL_COMPLETED')
GROUP BY event_type;

Span 계층 및 지속 시간 분석

SELECT
  span_id,
  parent_span_id,
  event_type,
  timestamp,
  -- Extract duration from latency_ms for completed operations
  CAST(JSON_VALUE(latency_ms, '$.total_ms') AS INT64) as duration_ms,
  -- Identify the specific tool or operation
  COALESCE(
    JSON_VALUE(content, '$.tool'),
    'LLM_CALL'
  ) as operation
FROM `your-gcp-project-id.your-dataset-id.agent_events`
WHERE trace_id = 'your-trace-id'
  AND event_type IN ('LLM_RESPONSE', 'TOOL_COMPLETED')
ORDER BY timestamp ASC;

오류 분석(LLM 및 도구 오류)

SELECT
  timestamp,
  event_type,
  agent,
  error_message,
  JSON_VALUE(content, '$.tool') as tool_name,
  CAST(JSON_VALUE(latency_ms, '$.total_ms') AS INT64) as latency_ms
FROM `your-gcp-project-id.your-dataset-id.agent_events`
WHERE event_type IN ('LLM_ERROR', 'TOOL_ERROR')
ORDER BY timestamp DESC
LIMIT 20;

Tool Provenance 분석

SELECT
  JSON_VALUE(content, '$.tool_origin') as tool_origin,
  JSON_VALUE(content, '$.tool') as tool_name,
  COUNT(*) as call_count,
  AVG(CAST(JSON_VALUE(latency_ms, '$.total_ms') AS INT64)) as avg_latency_ms
FROM `your-gcp-project-id.your-dataset-id.agent_events`
WHERE event_type = 'TOOL_COMPLETED'
GROUP BY tool_origin, tool_name
ORDER BY call_count DESC;

HITL 상호작용 분석

SELECT
  timestamp,
  event_type,
  session_id,
  JSON_VALUE(content, '$.tool') as hitl_tool,
  content
FROM `your-gcp-project-id.your-dataset-id.agent_events`
WHERE event_type LIKE 'HITL_%'
ORDER BY timestamp DESC
LIMIT 20;

7. AI 기반 근본 원인 분석 (Agent Ops)

BigQuery ML과 Gemini를 사용해 실패한 세션을 자동 분석하고 오류의 근본 원인을 파악합니다.

DECLARE failed_session_id STRING;
-- Find a recent failed session
SET failed_session_id = (
    SELECT session_id
    FROM `your-gcp-project-id.your-dataset-id.agent_events`
    WHERE error_message IS NOT NULL
    ORDER BY timestamp DESC
    LIMIT 1
);

-- Reconstruct the full conversation context
WITH SessionContext AS (
    SELECT
        session_id,
        STRING_AGG(CONCAT(event_type, ': ', COALESCE(TO_JSON_STRING(content), '')), '\n' ORDER BY timestamp) as full_history
    FROM `your-gcp-project-id.your-dataset-id.agent_events`
    WHERE session_id = failed_session_id
    GROUP BY session_id
)
-- Ask Gemini to diagnose the issue
SELECT
    session_id,
    AI.GENERATE(
        ('Analyze this conversation log and explain the root cause of the failure. Log: ', full_history),
        endpoint => 'gemini-2.5-flash'
    ).result AS root_cause_explanation
FROM SessionContext;

BigQuery의 대화형 분석

BigQuery Conversational Analytics를 사용하면 자연어로 에이전트 로그를 분석할 수 있습니다. 이 도구를 사용해 다음과 같은 질문에 답할 수 있습니다.

  • "Show me the error rate over time"
  • "What are the most common tool calls?"
  • "Identify sessions with high token usage"

Looker Studio 대시보드

미리 준비된 Looker Studio Dashboard template을 사용해 에이전트 성능을 시각화할 수 있습니다.

이 대시보드를 자신의 BigQuery 테이블에 연결하려면, 아래 링크 형식에서 프로젝트, 데이터 세트, 테이블 ID placeholder를 실제 값으로 바꿔 사용하세요.

https://lookerstudio.google.com/reporting/create?c.reportId=f1c5b513-3095-44f8-90a2-54953d41b125&ds.ds3.connector=bigQuery&ds.ds3.type=TABLE&ds.ds3.projectId=<your-project-id>&ds.ds3.datasetId=<your-dataset-id>&ds.ds3.tableId=<your-table-id>

피드백

BigQuery Agent Analytics에 대한 피드백을 환영합니다. 질문, 제안, 또는 문제를 발견했다면 bqaa-feedback@google.com 으로 연락해 주세요.

추가 리소스