> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrating Agent With BigQuery

> Explains integrating a conversational agent with BigQuery using parameterized SQL, a narrow get_customer tool, credentials, schema and guidance to assess customer churn from real feature tables.

Welcome back. It's Wednesday afternoon and the third email brings good news: Claire sent another message with the subject line "Access Granted."

Let's walk through what changed and how to move from a toy demo to using the real warehouse table, `analytics.customer_features`, as the agent's data source.

That demo made my week. I talked to the product analytics team: you now have read access to `analytics.customer_features` in [BigQuery](https://cloud.google.com/bigquery). Every row is one customer — you can point your agent at the real thing.

P.S. Marcus from the platform asked what exactly your agent gets to see. I said I would ask you. We'll come back to that next week.

Yesterday the agent answered a question using a dictionary with two fake rows. Today it will query a real feature table containing thousands of customers. The agent itself barely changes: same model, same runner, same session, same question. The instruction is updated so the model understands the real columns. The one real code change is inside one function: `get_customer`. Previously it did a dictionary lookup; now it runs a parameterized SQL query. That is the essence of a tool.

![A dark-themed flowchart titled "The Real Thing" showing an "Instruction" flowing into a "Churn Agent" which calls a "get\_customer" function. The get\_customer node branches to "A Dictionary" and "BigQuery (analytics.customer\_features)" and a sidebar lists "Same model, Same runner, Same session, Same question."](https://mintcdn.com/kodekloud-c4ac6d9a/YiW0Xl5gQ25uff6L/images/AI-Agents-For-Data-Analytics/Building-Agent-With-BigQuery/Integrating-Agent-With-BigQuery/real-thing-churn-agent-get-customer.jpg?fit=max\&auto=format\&n=YiW0Xl5gQ25uff6L\&q=85\&s=8594f19dd6136732417184dd0ef78d91)

The model asks for a customer; it doesn't care whether the answer comes from a dictionary, a REST API, or a 5,000-row feature table. Design your tool to present a consistent interface (`customer_id` in → `dict` out) and keep the tool responsible for data access.

## Credentials: one for the model, one for BigQuery

This lesson is a short version and omits some deployment mechanics. You will use two credentials that serve different purposes:

| Credential | Purpose | Notes / Example |
| - | - | - |
| Model API key | Model access (inference) | Set in `.env` as `ANTHROPIC_API_KEY=sk-ant-xxxx` |
| Application Default Credentials | BigQuery read access | Use `gcloud auth application-default login` and `GOOGLE_CLOUD_PROJECT` in `.env` |

![A diagram titled "Two Credentials" showing two columns: on the left a "Model API Key" feeding a model (brain icon), and on the right "Default Credentials" feeding BigQuery (BigQuery icon). Each column is represented by a key icon leading to its respective service.](https://mintcdn.com/kodekloud-c4ac6d9a/YiW0Xl5gQ25uff6L/images/AI-Agents-For-Data-Analytics/Building-Agent-With-BigQuery/Integrating-Agent-With-BigQuery/two-credentials-model-api-bigquery.jpg?fit=max\&auto=format\&n=YiW0Xl5gQ25uff6L\&q=85\&s=f80cdea87b82e5b9927c62c47aafd8f7)

In short: one credential for thinking (the model), one for reading (BigQuery). The install adds one package and the login is one `gcloud` command. Your `.env` file gains exactly one new line for the Google Cloud project ID:

```bash theme={null}
# the model
ANTHROPIC_API_KEY=sk-ant-xxxx

GOOGLE_CLOUD_PROJECT=ch
```

## The schema: what the agent reads

Everything the agent decides will be drawn from these columns. Each row is one customer and carries an ID, a region, and several features. Represent these columns explicitly to the model so it can reason over them consistently.

| Column | Meaning | Notes |
| - | - | - |
| `customer_id` | Unique customer identifier | Example: `cust-0003115` |
| `region` | Geographical region | Example: `west` |
| `usage_last_30_days` | Recent usage magnitude | Low values indicate disengagement |
| `usage_delta_30_days` | Change vs prior month (%) | Large negative = steep drop |
| `support_tickets_90_days` | Count of support tickets (90 days) | Higher counts indicate friction |
| `tenure_months` | Months since signup | Lower tenure is usually riskier |
| `plan_tier` | Subscription tier | e.g., `basic`, `pro` |
| `upgrade_eligible` | Boolean | Whether an upgrade path exists |

Example row from `analytics.customer_features`:

```text theme={null}
analytics.customer_features

customer_id                cust-0003115
region                     west
usage_last_30_days         0.11
usage_delta_30_days       -26.86
support_tickets_90_days    5
tenure_months              3
plan_tier                  pro
upgrade_eligible           true
```

Note: `support_tickets_90_days` is a plain count (e.g., `5` tickets). Additional context (ticket severity, time to resolution) would change the agent's reasoning — consider adding those if you need finer signals.

## Implementing get\_customer (parameterized SQL)

What doesn't change is the tool contract: keep the function name `get_customer`, the signature (`customer_id: str`) and the one-line docstring explaining churn signals. The body changes to run a parameterized SELECT against `analytics.customer_features` and return a Python `dict`.

Using a parameterized query (`@cid`) is critical: it tells BigQuery to treat the value as data (not SQL), which protects against prompt injection and SQL injection-like attacks.

Here is the adjusted function:

```python theme={null}
def get_customer(customer_id: str) -> dict:
    """Churn signals for one customer, e.g. "cust-0003115"."""

    sql = """SELECT region, plan_tier, tenure_months,
        usage_last_30_days, usage_delta_30_days,
        support_tickets_90_days
    FROM analytics.customer_features
    WHERE customer_id = @cid"""

    p = ScalarQueryParameter("cid", "STRING", customer_id)
    return run_query(sql, [p])
```

BigQuery will treat the bound `cid` parameter as a scalar value, not part of the SQL text.

## How to instruct the agent with real columns

Update the agent's instruction so the model understands how to interpret these columns. The same heuristics from the toy demo apply, but now tie them to exact column names:

* Low `usage_last_30_days` → disengagement.
* Sharply negative `usage_delta_30_days` → steep decline in usage.
* High `support_tickets_90_days` → friction and unresolved issues.
* Low `tenure_months` → increased churn risk.
* Consider `plan_tier` and `upgrade_eligible` when suggesting remediation (e.g., targeted offers).

Ask the agent to produce three outputs (same as before):

1. A concise risk level (e.g., LOW / MEDIUM / HIGH).
2. The signal(s) that drove the decision (list the relevant columns and values).
3. One concrete retention action (e.g., a customer success call within 48 hours).

At-a-glance checklist of signals to surface:

```text theme={null}
usage_last_30_days ↓
usage_delta_30_days ↓
support_tickets_90_days ↑
tenure_months ↓
```

## Run the agent on a real customer

Now run the agent and ask about a real customer:

You: "Is customer cust-0003115 at risk?"

The model decides to call `get_customer`. The tool fires the parameterized query at BigQuery, one real row comes back, the model reads it, and returns a verdict with supporting signals.

Example interaction and output:

```text theme={null}
Agent ready. Ask a question:
You: Is customer cust-0003115 at risk?

Risk level: HIGH
usage_last_30_days      0.11
usage_delta_30_days    -26.86
support_tickets_90_days 5
tenure_months           3
plan_tier               pro
upgrade_eligible        true
```

Interpretation: this is a high-risk customer — very low usage that dropped sharply, multiple support tickets, and short tenure. The agent should explain these signals and recommend one concrete action, for example: schedule a customer success call within 48 hours to discuss friction points and propose a tailored plan.

## Tool scope and limitations

Before you close the file, consider what this tool can and cannot do. `get_customer` answers exactly one kind of question: "tell me about this one customer." One ID goes in, and one row comes out. This is a deliberate design:

* Narrow tools make model-to-tool handoffs predictable.
* Parameterized queries protect your database from injected SQL.
* If you need to answer other question patterns (for example, "Which customers should I call urgently this week?"), write a new function and SQL that returns multiple rows or aggregates. Each distinct question pattern usually becomes a distinct tool.

Example conceptual mapping:

```text theme={null}
Input: customer_id "cust-0003115"
Tool: get_customer
Table: analytics.customer_features
Output: one row with region, plan_tier, tenure_months, usage_* and support_tickets_90_days
```

If you want broader queries (lists, aggregates, cohorts), add new tools with parameterized SQL that explicitly declares their input parameters.

Design tools narrowly and use parameterized queries. Narrow tools make model-tool handoffs predictable and parameterization protects your database from injected SQL.

## Links and References

* [BigQuery documentation](https://cloud.google.com/bigquery)
* [Application Default Credentials](https://cloud.google.com/docs/authentication/production)
* [gcloud SDK](https://cloud.google.com/sdk/gcloud)

> **[Watch Video](https://learn.kodekloud.com/user/courses/ai-agents-for-data-analytics/module/4e6bc78e-00a8-405d-97ce-830c7892b1b1/lesson/0e2cf8a2-c06d-4abb-beba-4a6b905a8ca0)**

> **[Practice Lab](https://learn.kodekloud.com/user/courses/ai-agents-for-data-analytics/module/4e6bc78e-00a8-405d-97ce-830c7892b1b1/lesson/83b2e13e-6175-46ff-9403-bfcb01ac9f24)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.