首页 / 文章

超越控制面板:构建具备自主功能的 BigQuery 数据分析代理

基于Google ADK和Gemini的自主BigQuery数据分析师代理:为何仪表板与简单的文本转SQL在最后阶段会受阻,以及如何在CI/CD中解决这一问题。

发布者:REACTAPP.TOP阅读约 13 分钟2876 词

来源: Beyond Dashboards: Building an Autonomous BigQuery Data Analyst Agent with Google ADK for Customer 360

本指南将逐步构建从原始材料到可运行系统的完整流程,适用于《超越数据看板:使用 Google ADK 为 Customer 360 构建自主式 BigQuery 数据分析代理》这一项目。重点在于可操作的步骤、明确的检查点,以及可直接放入代码仓库的代码,无需猜测其用途。 在概览阶段,应在修改代码之前明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测其中的隐藏状态。 建议使用小型、可测试的单元而非庞大的脚本。当某个步骤失败时,故障应能指向单一责任模块,而非复杂的流程链。

1. 最后一公里的瓶颈:为何传统 BI 工具及简单的文本转 SQL 方法会失败

在处理“最后一公里瓶颈”阶段时,首先写下相关契约:所需的输入参数、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将这一阶段视为输入与验证后输出之间的契约。为相关成果命名,明确成功判定标准,杜绝无声的半完成状态。 在成本较高的步骤之后设置检查点。当操作员重新尝试后续节点时,恢复流程不应再次调用相同的大型语言模型。

传统商业智能仪表板为何会失效

在处理“为何使用传统 BI 数据看板”这一阶段时,首先需列出相关要求:所需输入、成功标志以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 在功能结果旁记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在系统从演示环境过渡到共享环境时出现意外费用。 在成本较高的步骤之后设置检查点。当操作员重新尝试后续节点时,恢复流程不应再次收取相同的 LLM 调用费用。

为何天真的“文本转 SQL”LLM 封装方案在企业环境中会失败

在处理“为何选择朴素文本转SQL大语言模型”这一阶段时,首先需明确规范:所需的输入参数、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将配置信息置于应用程序代码之外。环境文件、密钥存储以及功能开关应集中存放于一个位置,以便操作人员无需查看整个系统结构即可进行审计。 缓存稳定的系统指令和工具架构。重复发送相同的开头信息是导致资源浪费的常见原因。 在处理“为何选择朴素文本转SQL大语言模型”这一阶段时,首先需明确规范:所需的输入参数、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 相较于庞大的脚本,应优先选择小型且可测试的单元。当某个步骤出现故障时,故障原因应能指向单一责任模块,而非复杂的流程链。

2. 智能体架构:Google ADK框架

在处理“智能体架构”的第二阶段时,应将其视为可度量的工作面。在扩大范围之前,先记录一份最佳案例、一个失败案例以及回滚说明。 将这一阶段视为输入与已验证输出之间的契约。为相关成果命名,明确成功标准,杜绝默许的半完成状态。 保持图结构的状态简洁且具有类型约束。嵌套的数据块会掩盖哪个节点编写了哪个字段的信息,且在中断后会导致流程无法继续。

3. 工程支柱1:知识基础构建与Vertex AI上下文缓存

将“3个工程支柱1阶段”视为可测量的界面来处理时,其效果最佳。在扩大范围之前,先记录一份优秀的测试用例、一个故障案例以及回滚说明。在功能结果旁同时记录执行时间以及令牌或查询成本。提前了解成本情况,就能避免在从演示环境过渡到共享环境时出现意外费用。要保持图表状态简洁且类型明确,嵌套的数据块会掩盖哪个节点修改了哪个字段的信息,还会在出现中断后导致状态无法恢复。

将Markdown词典编译到系统提示中

将 Markdown 字典编译为阶段版本时,若能将其视为可度量的对象会更为有效。在扩大范围之前,先记录一份理想的运行日志、一个故障案例以及回滚说明。 配置应置于应用程序代码之外。环境文件、密钥存储和功能开关应集中存放于一处,这样操作人员无需查看整个系统结构即可进行审计。 为每轮对话和每次会话设定令牌预算。智能工具往往会过度扩展上下文,设置上限可避免演示过程变成意外的费用账单。 将 Markdown 字典编译为阶段版本时,若能将其视为可度量的对象会更为有效。在扩大范围之前,先记录一份理想的运行日志、一个故障案例以及回滚说明。 相较于庞大的脚本,宜采用小型且可测试的单元。当某个步骤出现故障时,故障应能指向单一的责任主体,而非复杂的流程链。

# c360_agent/config.py
import os
import glob

def compile_knowledge_base(knowledge_dir: str) -> str:
    """Recursively compiles markdown architecture guides into structured agent context."""
    context_chunks = []
    guide_files = glob.glob(os.path.join(knowledge_dir, "**/*.md"), recursive=True)

    for file_path in sorted(guide_files):
        with open(file_path, "r", encoding="utf-8") as f:
            rel_name = os.path.relpath(file_path, knowledge_dir)
            content = f.read()
            context_chunks.append(f"### KNOWLEDGE GUIDE: {rel_name}\n\n{content}\n")

    return "\n---\n".join(context_chunks)

KNOWLEDGE_CONTEXT = compile_knowledge_base("c360_agent/knowledge")

SYSTEM_PROMPT = f"""
You are an expert BigQuery Data Analyst Agent for an Enterprise Customer 360 (C360) Lakehouse.
Your mission is to answer business and analytical questions by generating and executing accurate, cost-effective SQL queries.

CRITICAL OPERATIONAL RULES:
1. TARGET CONFORMED MARTS FIRST: Always query `c360_curated_unified` for golden demographics or cross-system questions. Use Spoke marts (`c360_curated_*`) only for system-specific line-item grain.
2. MANDATORY DRY RUN: You MUST execute `dry_run_bq_query` on every generated SQL statement before calling `execute_bq_query`. Inspect syntax and bytes scanned.
3. CLUSTER AWARENESS: Always filter or join on clustered keys (`UnifiedCustomerDimId`, `UnifiedOrderDimId`) to minimize BigQuery slot consumption.
4. STRICT READ-ONLY: You are strictly forbidden from executing INSERT, UPDATE, DELETE, DROP, or ALTER statements.

DOMAIN ARCHITECTURE CONTEXT:
{KNOWLEDGE_CONTEXT}
"""

改变成本格局的利器:Vertex AI上下文缓存

在采用“改变成本格局的利器”Vertex阶段时,应在修改代码之前明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 应将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,设定成功检测标准,杜绝无声的半完成状态。 对于会耗费资金或修改生产数据的操作,必须经过人工审批。编译时的连接方式并不等同于业务上的完整性。

# c360_agent/agent.py
from google.adk.agents.llm_agent import Agent
from google.adk.apps import App
from google.adk.agents.context_cache_config import ContextCacheConfig
from .config import SYSTEM_PROMPT
from .tools import (
    execute_bq_query,
    dry_run_bq_query,
    get_table_schema,
    list_dataset_tables,
    get_table_preview
)

# 1. Initialize the Google ADK Agent
root_agent = Agent(
    name="c360_data_analyst",
    model="projects/enterprise-c360-prod/locations/us-central1/publishers/google/models/gemini-2.5-flash",
    description="Autonomous BigQuery Data Analyst for the Enterprise Customer 360 Lakehouse.",
    instruction=SYSTEM_PROMPT,
    tools=[
        dry_run_bq_query,
        execute_bq_query,
        get_table_schema,
        list_dataset_tables,
        get_table_preview
    ]
)

# 2. Wrap in App with Vertex AI Context Caching
app = App(
    name="c360_agent_app",
    root_agent=root_agent,
    context_cache_config=ContextCacheConfig(
        ttl_seconds=1800,   # Cache prompt for 30 minutes
        cache_intervals=10  # Reuse across up to 10 conversational turns
    )
)

4. 工程支柱2:安全且受成本控制的工具执行

在“工程支柱2”的第4阶段,修改代码之前需明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。应在功能结果旁记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在系统从演示环境过渡到共享环境时出现意外费用。

# c360_agent/tools.py
import subprocess
import re

def dry_run_bq_query(query: str) -> str:
    """Dry-runs a BigQuery SQL query to validate syntax and estimate bytes scanned."""
    clean_query = query.strip().upper()

    # Layer 1: Strict Read-Only Guard
    if not (clean_query.startswith("SELECT") or clean_query.startswith("WITH")):
        return "SECURITY ERROR: Only SELECT queries are permitted. DDL/DML is strictly forbidden."

    try:
        # Executes 'bq query --dry_run' to inspect execution planner without billing slots
        result = subprocess.run(
            ["bq", "query", "--use_legacy_sql=false", "--dry_run", query],
            capture_output=True,
            text=True,
            check=True
        )
        # bq CLI outputs estimated bytes scanned to stderr on dry run
        dry_run_output = result.stderr if result.stderr else result.stdout
        return f"DRY_RUN SUCCESS: {dry_run_output.strip()}"
    except subprocess.CalledProcessError as e:
        return f"DRY_RUN SYNTAX ERROR: {e.stderr.strip()}"


def execute_bq_query(query: str) -> str:
    """Executes a validated BigQuery SQL query and returns the formatted tabular results."""
    clean_query = query.strip().upper()

    if not (clean_query.startswith("SELECT") or clean_query.startswith("WITH")):
        return "SECURITY ERROR: Only SELECT queries are permitted."

    try:
        result = subprocess.run(
            ["bq", "query", "--use_legacy_sql=false", "--format=pretty", "--max_rows=50", query],
            capture_output=True,
            text=True,
            check=True
        )
        return result.stdout
    except subprocess.CalledProcessError as e:
        return f"EXECUTION ERROR: {e.stderr.strip()}"

5. 工程支柱3:自主自我修正循环

在5个工程支柱的第三阶段,修改代码之前需明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 配置信息应置于应用程序代码之外。环境文件、密钥存储和功能标志应集中存放于一个位置,以便操作人员无需查看整个流程即可进行审计。 对于涉及资金支出或修改生产数据的操作,必须经过人工审批。编译时的连接方式并不等同于业务功能的完整性。 在5个工程支柱的第三阶段,修改代码之前需明确输入参数、该步骤的负责人以及完成标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 相比庞大的脚本,应优先使用小型且可测试的单元。当某个步骤失败时,故障原因应能明确指向单一责任模块,而非复杂的流程链。

真实生产追踪:自我修复循环的实际应用

在处理“真实生产追踪”阶段时,首先需写下相关契约:所需的输入参数、成功信号以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 将此阶段视为输入与已验证输出之间的契约。为相关产物命名,明确成功判定标准,杜绝无声的半完成状态。 在成本较高的步骤之后设置检查点。当操作员重新尝试后续节点时,恢复流程不应再次调用相同的大型语言模型。

业务用户的问题

在处理“业务用户阶段”时,首先写下相关契约:所需的输入参数、成功标志以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 在功能结果旁记录执行时间以及令牌或查询成本。提前了解成本情况,可避免在从演示环境过渡到共享环境时出现意外账单。 在耗时较高的步骤之后设置检查点。当操作员重新尝试后续节点时,恢复流程不应再次收取相同的LLM调用费用。

步骤1:初次尝试与编译器拒绝

在完成第一步“初步尝试”阶段时,首先需明确相关规范:所需的输入参数、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 应将配置信息与应用程序代码分开存放。环境文件、密钥存储以及功能开关应集中于一个位置,以便操作人员无需查看整个系统结构即可进行审计。 在耗时较高的步骤之后设置检查点。当操作人员重新尝试后续节点时,恢复流程不应再次调用相同的大型语言模型接口。 在完成第一步“初步尝试”阶段时,首先需明确相关规范:所需的输入参数、成功标志以及部分失败时的处理方式。这样的清单能确保后续的代码修改保持一致性。 相较于庞大的脚本,宜采用小型且可测试的单元。当某个步骤失败时,故障应能指向具体的责任模块,而非整个复杂的处理流程。

-- Attempt 1: Generated by Agent (Pre-Flight Dry Run)
SELECT
    SUM(c.total_spent) AS total_vip_revenue
FROM `enterprise-c360-prod.c360_curated_shopify.dim_customer` c
JOIN `enterprise-c360-prod.c360_curated_shopify.CustomerWarranties` w
    ON c.customer_id = w.customer_id;

第2步:自主诊断与自我修正

将第2步的自主诊断阶段视为可度量的界面来处理效果最佳。在扩大范围之前,先收集一份理想的记录、一个故障案例以及回滚说明。 把这一阶段视为输入与经过验证的输出之间的契约。为相关成果命名,明确成功标准,杜绝默许的半完成状态。 保持图结构的状态简洁且类型明确。嵌套的数据块会掩盖哪个节点编写了哪个字段的信息,还会在中断后导致无法继续处理。

  SELECT SUM(c.total_spent) AS total_vip_revenue
  FROM `enterprise-c360-prod.c360_curated_shopify.dim_customer` c
  JOIN `enterprise-c360-prod.c360_curated_shopify.CustomerWarranties` w
-     ON c.customer_id = w.customer_id;
+     ON c.UnifiedCustomerDimId = w.UnifiedCustomerDimId;

第3步:飞行前成本验证

将第三阶段的“飞行前成本”环节视为可度量的指标会更为有效。在扩大范围之前,先记录一份理想的测试结果、一个故障案例以及回滚说明。在功能结果旁同时记录执行时间以及令牌或查询成本。提前了解成本情况,就能避免在从演示环境过渡到共享环境时出现意外账单。要保持图表状态简洁且类型明确,嵌套的数据块会掩盖是哪个节点修改了哪个字段,还会在中断后导致无法继续执行。

第四步:受限执行与执行结果综合

将第4步的有限执行阶段视为可度量的对象来处理,效果最佳。在扩大范围之前,需记录一份理想状态下的执行日志、一个故障案例以及回滚说明。 应将配置与应用程序代码分开。环境文件、密钥存储和功能开关应集中存放于一处,以便操作人员无需查看整个系统结构即可进行审计。 需保持系统状态的简洁性与类型化。嵌套的数据结构会掩盖具体是哪个节点修改了哪个字段,还会导致中断后无法继续执行。 将第4步的有限执行阶段视为可度量的对象来处理,效果最佳。在扩大范围之前,需记录一份理想状态下的执行日志、一个故障案例以及回滚说明。 相比庞大的脚本,更应优先使用小型且可测试的单元。当某一步骤出现故障时,故障原因应能明确指向某个具体的责任模块,而非复杂的流程链。

6. 从终端CLI到交互式Web UI

在“从终端命令行界面开始的6个阶段”中,应在修改代码之前明确输入参数、该步骤的负责人以及终止标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 将此阶段视为输入与经过验证的输出之间的契约。为相关成果命名,定义成功判定标准,杜绝默许的半完成状态。 对于涉及资金支出或修改生产数据的操作,必须经过人工审批。编译时的配置并不等同于业务上的完整性。

模式1:面向数据工程师及CI/CD的终端命令行界面

在模式1的终端命令行阶段,应在修改代码之前明确输入参数、该步骤的负责人以及退出标准。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。除了功能结果外,还需记录执行时间以及令牌或查询成本。提前了解这些成本可以避免在从演示环境过渡到共享环境时出现意外费用。对于那些会消耗资金或修改生产数据的操作,必须经过人工审批。仅靠编译时的配置并不足以确保业务的完整性。

python3 c360_agent/agent.py "Show me top 5 customers by SAP delivery volume in 2026"

模式2:交互式网页调试控制台(adk web)

在模式2的交互式网页阶段,修改代码之前需先明确输入参数、该步骤的负责人以及终止条件。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 配置信息应置于应用程序代码之外。环境文件、密钥存储以及功能开关应集中存放于一个位置,以便操作人员无需查看整个流程即可进行审计。 对于涉及资金支出或修改生产数据的操作,必须经过人工审批。编译时的连接方式并不等同于业务流程的完整性。 在模式2的交互式网页阶段,修改代码之前需先明确输入参数、该步骤的负责人以及终止条件。操作人员应能够从已知的检查点重新运行该步骤,而无需猜测隐藏状态。 相较于庞大的脚本,应优先使用小型且可测试的单元。当某个步骤失败时,故障原因应能明确指向单一责任模块,而非复杂的流程链。

。

adk web --port 8001 c360_agent --reload

总结:企业自主代理检查清单

在处理“企业自主”阶段时,首先写下相关契约:所需输入、成功信号以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 将此阶段视为输入与已验证输出之间的契约。为相关成果命名,明确成功标准,杜绝无声的半完成状态。 在成本较高的步骤之后设置检查点。当操作员重新尝试后续节点时,恢复流程不应再次调用相同的大型语言模型。

三部曲完结:现代企业数据基础

在处理“三部曲完结”阶段时,首先写下相关约定:所需输入、成功标志以及部分失败时的处理方式。这样的检查清单能确保后续的代码修改保持一致性。 在功能结果旁记录执行时间以及令牌或查询成本。提前明确成本有助于避免从演示环境过渡到共享环境时出现意外费用。 在耗时较高的步骤之后设置检查点。当操作员重新尝试后续节点时,恢复流程不应再次收取相同的LLM调用费用。

操作检查清单

将“操作检查清单”阶段视为可度量的工作面,效果最佳。在扩大范围之前,先记录一份标准操作流程、一个失败案例以及回滚说明。 同时记录正常运行路径和故障恢复路径。重试机制、人工审核流程以及死信处理都是产品的一部分,而非后续需要完善的内容。

保持图状态扁平且具有类型约束。嵌套的数据结构会隐藏是哪个节点修改了哪个字段,还会在任务中断后导致无法继续执行。

只要预算允许,就在持续集成过程中使用测试用例而非真实的付费 API 来执行关键路径的测试。

优先选择小型、易于测试的单元,而非庞大的脚本。当某个步骤失败时,故障应能明确指向某个具体的功能模块,而非整个复杂的流程。

保持图状态扁平且具有类型约束。嵌套的数据结构会隐藏是哪个节点修改了哪个字段,还会在任务中断后导致无法继续执行。