DEV Community

Cover image for Building an AI Search Visibility & Brand Analyzer with Gemini, BigQuery, and Google Search Grounding
Hastimal Jangid
Hastimal Jangid Subscriber

Posted on Edited on

Building an AI Search Visibility & Brand Analyzer with Gemini, BigQuery, and Google Search Grounding

AI Search Journey Lab — Part 3 of 7

Measuring how brands appear across AI search journeys using Gemini, Google Search grounding, deterministic visibility scans, and BigQuery history.

Open source: ai-search-journey-lab

Previous: Building Grounded Local Search with Gemini and Google Maps on Google Cloud


The first two articles answered a user question. This one measures the system itself.

In Part 1, I focused on the search journey:

How does one natural-language request become a grounded decision?

In Part 2, I went deeper into the actual local-search implementation:

How do Gemini, Google Places, Search grounding, deterministic ranking, and Maps work together?

Once that worked, I started asking a different question.

Suppose I run the same kind of search repeatedly.

What happens if instead of only asking:

Which business should the user choose?

I ask:

Which brands keep appearing?
Which brands are cited?
Which competitors show up more often?
Does a brand appear in the initial answer, the fan-out journey, or only in supporting evidence?
How does that change over time?

That was the starting point for V3 — AI Visibility.

This article is about turning an AI search workflow into something measurable.


Why AI visibility needs a different data model

A single search result is transient.

If I want to measure visibility, I need history.

One run is interesting.

Fifty runs are analyzable.

Five hundred runs can start showing patterns.

So V3 introduced a new concern into the project: persistence

That is where BigQuery enters the architecture.


What I wanted to measure

For each visibility run, I wanted to capture things such as:

  • target brand
  • competitors
  • original query
  • fan-out tasks
  • mentions
  • citations
  • candidate coverage
  • source coverage
  • ranking position
  • execution timestamp
  • historical trend

The important shift was this:

V1/V2:
user query → recommendation

V3:
many queries → repeatable measurements
Enter fullscreen mode Exit fullscreen mode

That turns the project from a search demo (which we have planned) into an analytics system. :)


Architecture

Building an AI Search Visibility & Brand Analyzer with Gemini


Step 1: I made visibility scans deterministic

One important design choice was that V3 should not rely on a user manually clicking around and interpreting the results.

I wanted repeatable runs.

That means the runner should accept an explicit input scope and execute the same workflow consistently.

Conceptually:

run = VisibilityRun(
    target_brand="Example Brand",
    competitors=[
        "Competitor A",
        "Competitor B",
    ],
    queries=[
        "best local coffee shops in San Antonio",
        "quiet coffee shop for remote work",
    ],
)
Enter fullscreen mode Exit fullscreen mode

Then the runner executes the scan and records the results.

The goal is reproducibility.

If I run the same scenario tomorrow, I want to compare the resulting data rather than rely on screenshots or memory.

AI Search Visibility


Step 2: Separate mention detection from visibility scoring

A brand appearing in a response is not the same as a brand being strongly visible.

For example:

Target brand:
RankRabbit

Response:
"Other platforms include RankRabbit, Competitor A, and Competitor B."
Enter fullscreen mode Exit fullscreen mode

That is a mention.

But now compare:

1. RankRabbit — recommended first
2. Competitor A
3. Competitor B
Enter fullscreen mode Exit fullscreen mode

Those two appearances should not necessarily have the same visibility weight.

So I separate several concepts:

  • mention presence
  • position
  • citation presence
  • fan-out coverage
  • narrative prominence

That lets the application calculate visibility metrics explicitly instead of collapsing everything into one LLM judgment.


Step 3: Capture evidence before calculating visibility

The workflow should preserve what caused a brand to be counted.

Conceptually:

{
  "brand": "Example Brand",
  "mentioned": true,
  "rank": 2,
  "citation_present": true,
  "fanout_coverage": 0.67,
  "evidence_sources": [
    "source-a",
    "source-b"
  ]
}
Enter fullscreen mode Exit fullscreen mode

That data is much more valuable later than a single score such as:

visibility_score = 74
Enter fullscreen mode Exit fullscreen mode

because it lets me explain where the score came from.


Step 4: Persist visibility history in BigQuery

V3 can run in-memory for a quick demo, but historical analysis needs persistence.

I used a BigQuery dataset for that purpose:

Project:
ai-search-journey-lab

Dataset:
ai_search_journey_v3
Enter fullscreen mode Exit fullscreen mode

Let's explore how bigQuery tables look like.....

bq query \
  --use_legacy_sql=false \
  '
  SELECT
    table_name,
    table_type,
    creation_time
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.INFORMATION_SCHEMA.TABLES`
  ORDER BY
    table_name
  '
Enter fullscreen mode Exit fullscreen mode

Bigquery dataset


Step 5: Query historical visibility with SQL

Once I started persisting V3 runs in BigQuery, I no longer had to rely only on what the Streamlit dashboard displayed.

I could query the visibility history directly from the terminal.
That became one of my favorite parts of V3 because it gave me a second way to validate everything the UI was showing.

For all of the examples below, I use the BigQuery CLI:

Once scan results are persisted, SQL becomes one of the most useful tools in the project.

Big Query visibility scans

BigQuery dataset showing the persisted visibility-analysis tables.

BigQuery dataset showing the persisted visibility-analysis tables
The four tables I use most for visibility analysis are:

visibility_scans
brand_observations
fanout_observations
citations
Enter fullscreen mode Exit fullscreen mode

Each answers a different question.

visibility_scans
    └── What happened during the scan?

brand_observations
    └── How did each brand appear?

fanout_observations
    └── Where was the brand found during query fan-out?

citations
    └── Which sources supported the grounded result?
Enter fullscreen mode Exit fullscreen mode

That separation became important as V3 grew.

I did not want one oversized table containing execution metadata, brand observations, fan-out evidence, citations, and historical measurements all mixed together.

Inspect the actual schema

Before writing analytical queries, I wanted to verify the exact schema from the terminal.

bq query \
  --use_legacy_sql=false \
  --format=pretty \
  '
  SELECT
    table_name,
    ordinal_position,
    column_name,
    data_type
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.INFORMATION_SCHEMA.COLUMNS`
  WHERE
    table_name IN (
      "visibility_scans",
      "brand_observations",
      "fanout_observations",
      "citations"
    )
  ORDER BY
    table_name,
    ordinal_position
  '
Enter fullscreen mode Exit fullscreen mode

Inspecting the V3 BigQuery schema directly from the CLI

This is useful because the schema itself reflects the measurements I wanted to preserve.

For example, brand_observations contains separate fields for:

mentioned
mention_count
first_mention_position

retrieved
best_retrieval_position

recommended
recommendation_position

cited
citation_urls
citation_domains
Enter fullscreen mode Exit fullscreen mode

That was deliberate.

I wanted to store what actually happened before reducing everything to a single visibility number.

Query recent visibility scans

The first operational query I usually run is simple:

Show me the latest scans

bq query \
  --use_legacy_sql=false \
  --format=pretty \
  '
  SELECT
    scan_id,
    batch_id,
    project_id,
    brand_id,
    brand_name_snapshot,
    prompt_id,
    model_name,
    location_snapshot,
    started_at,
    completed_at,
    status,
    duration_seconds
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.visibility_scans`
  WHERE
    started_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  ORDER BY
    started_at DESC
  LIMIT 20
  '
Enter fullscreen mode Exit fullscreen mode

Recent AI visibility scans queried directly from BigQuery using the bq CLI.

Recent AI visibility scans queried directly from BigQuery using the bq CLI.

The time filter is important.

My visibility tables are partitioned by started_at, and I intentionally require partition filtering rather than allowing unrestricted scans over the complete history.

That becomes increasingly useful as the amount of historical data grows.

From this one query I can inspect:

  • which scan ran
  • which batch it belonged to
  • which brand was evaluated
  • which prompt triggered it
  • which Gemini model was used
  • which location context was applied
  • when the scan started and completed
  • whether it succeeded
  • how long it took

The dashboard gives me the visualization.

BigQuery gives me the underlying record.


Step 6: Mentioned is not the same as recommended

This became one of the most important distinctions in V3.

A brand can appear in an AI-generated result in several different ways.

It might be:

  • retrieved
  • mentioned
  • recommended
  • cited
  • ranked before or after another brand

Those are not the same thing.

Let's consider these two observations:

retrieved = true
mentioned = true
recommended = false
cited = true
Enter fullscreen mode Exit fullscreen mode

and

retrieved = true
mentioned = true
recommended = true
cited = true
Enter fullscreen mode Exit fullscreen mode

Both brands were visible.

But they were not visible in the same way.

The first brand was discovered and mentioned.

The second made it into the recommendation.

Instead of asking Gemini to generate a vague visibility score, I first persist these observable states.

I can inspect them directly:

bq query \
  --use_legacy_sql=false \
  --format=pretty \
  '
  SELECT
    scan_id,
    brand_id,
    role,
    mentioned,
    mention_count,
    first_mention_position,
    retrieved,
    best_retrieval_position,
    recommended,
    recommendation_position,
    cited,
    citation_domains
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.brand_observations`
  WHERE
    started_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  ORDER BY
    started_at DESC,
    scan_id,
    first_mention_position
  LIMIT 50
  '
Enter fullscreen mode Exit fullscreen mode

BigQuery AI visibility

I can ask:

Was the brand retrieved?

Was it mentioned?

Where did the first mention occur?

Was it actually recommended?

At what recommendation position?

Was there citation evidence associated with it?
Enter fullscreen mode Exit fullscreen mode

Those questions are much easier to reason about than:

visibility_score = 74
Enter fullscreen mode Exit fullscreen mode

without knowing why the score is 74.


Step 7: Aggregate visibility across repeated scans

Once multiple scans exist, SQL becomes even more useful.

For example, I can ask:

How often does each brand appear, get recommended, or receive citation support?

bq query \
  --use_legacy_sql=false \
  --format=pretty \
  '
  SELECT
    brand_id,
    COUNT(*) AS observations,
    COUNTIF(mentioned) AS mentioned_count,
    COUNTIF(retrieved) AS retrieved_count,
    COUNTIF(recommended) AS recommended_count,
    COUNTIF(cited) AS cited_count,
    ROUND(
      SAFE_DIVIDE(COUNTIF(mentioned), COUNT(*)) * 100,
      2
    ) AS mention_rate_pct,
    ROUND(
      SAFE_DIVIDE(COUNTIF(recommended), COUNT(*)) * 100,
      2
    ) AS recommendation_rate_pct
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.brand_observations`
  WHERE
    started_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  GROUP BY
    brand_id
  ORDER BY
    recommendation_rate_pct DESC,
    mention_rate_pct DESC
  '
Enter fullscreen mode Exit fullscreen mode

Now I am no longer asking only:

What did Gemini answer?

I can ask:

Across repeated grounded search journeys, which brands keep appearing?

That is a very different problem.

And it is where V3 started becoming an analytics system rather than only a search demo.

Aggregating brand mentions, retrievals, recommendations, and citations across repeated scans

Aggregating brand mentions, retrievals, recommendations, and citations across repeated scans

Let's be on the same page.

Position matters too
Presence alone is not enough.

A brand appearing first in an answer is different from appearing sixth.

That is why V3 also preserves:

first_mention_position
best_retrieval_position
recommendation_position
Enter fullscreen mode Exit fullscreen mode

I can analyze those separately:

bq query \
  --use_legacy_sql=false \
  --format=pretty \
  '
  SELECT
    brand_id,
    COUNTIF(mentioned) AS mentions,
    ROUND(AVG(first_mention_position), 2) AS avg_first_mention_position,
    COUNTIF(recommended) AS recommendations,
    ROUND(AVG(recommendation_position), 2) AS avg_recommendation_position,
    ROUND(AVG(best_retrieval_position), 2) AS avg_best_retrieval_position
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.brand_observations`
  WHERE
    started_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  GROUP BY
    brand_id
  ORDER BY
    recommendations DESC,
    avg_recommendation_position ASC
  '
Enter fullscreen mode Exit fullscreen mode

Aggregating brand mentions, retrievals, recommendations, and citations across repeated scans
This lets me separate several ideas that often get grouped together as AI visibility:

Presence
Position
Retrieval
Recommendation
Citation
Enter fullscreen mode Exit fullscreen mode

I find that separation much more useful.


Step 8: Look inside query fan-out

One thing I learned while building the earlier versions of this project is that the final answer hides a lot of interesting behavior.

A single user query can create several retrieval tasks.

For example:

User prompt
    │
    ├── search intent A
    ├── search intent B
    ├── search intent C
    └── search intent D
Enter fullscreen mode Exit fullscreen mode

A brand may appear in all four branches.

Or only one.

Those situations should not necessarily be treated as identical.

That is why V3 persists fanout_observations.

The table includes fields such as:

task_id
query_text
tool
brand_id
brand_found
position_in_task
Enter fullscreen mode Exit fullscreen mode

I can inspect those observations directly:

bq query \
  --use_legacy_sql=false \
  --format=pretty \
  '
  SELECT
    scan_id,
    prompt_id,
    task_id,
    query_text,
    tool,
    brand_id,
    brand_found,
    position_in_task
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.fanout_observations`
  WHERE
    started_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  ORDER BY
    started_at DESC,
    scan_id,
    task_id,
    position_in_task
  LIMIT 100
  '
Enter fullscreen mode Exit fullscreen mode

Now the intermediate journey becomes queryable:

Original prompt
      ↓
Fan-out task
      ↓
Generated query
      ↓
Retrieval tool
      ↓
Brand found?
      ↓
Position in task
Enter fullscreen mode Exit fullscreen mode

This gives me a way to investigate why one brand appears repeatedly while another does not.

Measure fan-out coverage

I can also aggregate the fan-out behavior.

bq query \
  --use_legacy_sql=false \
  --format=pretty \
  '
  SELECT
    brand_id,
    COUNT(DISTINCT task_id) AS fanout_tasks,
    COUNTIF(brand_found) AS observations_where_brand_was_found,
    ROUND(
      SAFE_DIVIDE(
        COUNTIF(brand_found),
        COUNT(*)
      ) * 100,
      2
    ) AS found_rate_pct
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.fanout_observations`
  WHERE
    started_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  GROUP BY
    brand_id
  ORDER BY
    found_rate_pct DESC
  '
Enter fullscreen mode Exit fullscreen mode

Measure fan-out coverage

I think of this as a project-specific fan-out coverage signal.

It is not intended to be a universal AI visibility metric.

It simply tells me how consistently a brand was found across the retrieval observations generated by this implementation.

Being explicit about that distinction matters.


Step 9: Make citation visibility queryable

Mentions are useful.

Recommendations are useful.

But I also wanted to understand the evidence behind the grounded answer.

So citations are persisted separately.

The citations table contains:

scan_id
project_id
prompt_id
started_at
url
domain
source_type
matched_brand_ids
Enter fullscreen mode Exit fullscreen mode

I can inspect the underlying evidence directly:

bq query \
  --use_legacy_sql=false \
  --format=pretty \
  '
  SELECT
    scan_id,
    prompt_id,
    domain,
    source_type,
    url,
    matched_brand_ids
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.citations`
  WHERE
    started_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  ORDER BY
    started_at DESC
  LIMIT 100
  '
Enter fullscreen mode Exit fullscreen mode

Evidence query

This leads to another interesting question:

Which domains repeatedly appear as supporting sources?

Analyzing which source domains repeatedly support grounded visibility results

That gives me another dimension of AI visibility.

Instead of only asking:

Was my brand mentioned?

I can also ask:

Which sources repeatedly support grounded answers?

Which domains are connected to particular brands?

Which sources appear across multiple scans?
Enter fullscreen mode Exit fullscreen mode

For me, that makes citation analysis one of the more interesting parts of V3.

Working with repeated fields in BigQuery

matched_brand_ids is stored as an ARRAY<STRING>.

BigQuery makes it straightforward to expand that repeated field using UNNEST.

bq query \
  --use_legacy_sql=false \
  --format=pretty \
  '
  SELECT
    matched_brand_id AS brand_id,
    domain,
    COUNT(*) AS citation_count
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.citations`,
    UNNEST(matched_brand_ids) AS matched_brand_id
  WHERE
    started_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  GROUP BY
    matched_brand_id,
    domain
  ORDER BY
    citation_count DESC
  LIMIT 50
  '
Enter fullscreen mode Exit fullscreen mode

matched_brand_ids based query

That connects two useful concepts:

Brand visibility
        +
Citation visibility
Enter fullscreen mode Exit fullscreen mode

A brand may appear frequently but have relatively little citation support.

Another may appear less often but repeatedly connect to a particular set of sources.

Persisting both lets me investigate that difference instead of hiding it inside one aggregate score.


Step 10: Turn visibility into a historical signal

The reason I chose BigQuery was not just to persist individual runs.

The real value appears when the same measurements accumulate over time.

For example, I can calculate daily visibility observations:

bq query \
  --use_legacy_sql=false \
  --format=pretty \
  '
  SELECT
    DATE(started_at) AS scan_date,
    brand_id,
    COUNT(*) AS observations,
    COUNTIF(mentioned) AS mentions,
    COUNTIF(recommended) AS recommendations,
    COUNTIF(cited) AS citations,
    ROUND(
      SAFE_DIVIDE(COUNTIF(mentioned), COUNT(*)) * 100,
      2
    ) AS mention_rate_pct,
    ROUND(
      SAFE_DIVIDE(COUNTIF(recommended), COUNT(*)) * 100,
      2
    ) AS recommendation_rate_pct
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.brand_observations`
  WHERE
    started_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  GROUP BY
    scan_date,
    brand_id
  ORDER BY
    scan_date DESC,
    brand_id
  '
Enter fullscreen mode Exit fullscreen mode

Now the system evolves from:

Search Journey
      ↓
One Answer
Enter fullscreen mode Exit fullscreen mode

into:

Search Journey
      ↓
Repeated Scans
      ↓
Persisted Observations
      ↓
Historical Visibility
Enter fullscreen mode Exit fullscreen mode

That historical layer is what I was missing in the first versions of the project.

A single answer can tell me what happened now.

A history can start telling me what keeps happening.


Step 11: The scan itself is also observable

Another useful part of the schema is that visibility_scans does not only record the result.

It also records operational information such as:

started_at
completed_at
status
duration_seconds
error_code
error_message
Enter fullscreen mode Exit fullscreen mode

That means I can inspect the behavior of the visibility pipeline itself.

For example:

bq query \
  --use_legacy_sql=false \
  --format=pretty \
  '
  SELECT
    status,
    COUNT(*) AS scans,
    ROUND(AVG(duration_seconds), 2) AS avg_duration_seconds,
    ROUND(MAX(duration_seconds), 2) AS max_duration_seconds
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.visibility_scans`
  WHERE
    started_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
  GROUP BY
    status
  ORDER BY
    scans DESC
  '
Enter fullscreen mode Exit fullscreen mode

And I can inspect unsuccessful runs separately:

bq query \
  --use_legacy_sql=false \
  --format=pretty \
  '
  SELECT
    scan_id,
    brand_name_snapshot,
    prompt_text_snapshot,
    model_name,
    started_at,
    status,
    error_code,
    error_message
  FROM
    `ai-search-journey-lab.ai_search_journey_v3.visibility_scans`
  WHERE
    started_at >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
    AND status != "completed"
  ORDER BY
    started_at DESC
  LIMIT 25
  '
Enter fullscreen mode Exit fullscreen mode

Journey Lab

This distinction became useful later when I added deeper observability to the project.

There are really two different things I want to observe:

What did the AI search journey produce?

and

How did the system behave while producing it?
Enter fullscreen mode Exit fullscreen mode

V3 primarily focuses on the first.

Later versions go much deeper into the second.


Step 12: Keep BigQuery as the analytical source of truth

At this point, the V3 architecture became much clearer to me.

                    AI Visibility Scan
                           │
                           ▼
                 Gemini + Search Grounding
                           │
                           ▼
                    Evidence Extraction
                           │
              ┌────────────┼────────────┐
              │            │            │
              ▼            ▼            ▼
        Brand          Fan-out       Citation
      Observation    Observation     Evidence
              │            │            │
              └────────────┼────────────┘
                           │
                           ▼
                        BigQuery
                           │
                 ┌─────────┴─────────┐
                 ▼                   ▼
          Streamlit Dashboard    SQL Analysis
                 │                   │
                 └─────────┬─────────┘
                           ▼
                Historical Visibility
Enter fullscreen mode Exit fullscreen mode

BigQuery Analytics Architecture

BigQuery gives me an independent analytical layer.

That means I can:

  • validate what the dashboard shows
  • write new analytical queries without changing the UI
  • compare historical runs
  • inspect fan-out behavior
  • study citation sources
  • later expose the same evidence to an agent

That last part becomes important in V4.

Visibility Dashboard


Step 13: Validate the implementation, not just the demo

I try not to treat a working Streamlit page as proof that the underlying application is healthy.

Before considering a milestone complete, I run the repository checks together.

./.venv/bin/ruff check . && \
./.venv/bin/mypy src && \
./.venv/bin/pytest -q
Enter fullscreen mode Exit fullscreen mode

At the time of this build, the repository validation looked like:

ruff
All checks passed!

mypy
Success: no issues found in 38 source files

pytest
382 passed
Enter fullscreen mode Exit fullscreen mode

The exact number of tests will naturally change as the project continues to grow.

What matters more to me is keeping the same habit:

Build
  ↓
Run
  ↓
Inspect
  ↓
Test
  ↓
Then extend
Enter fullscreen mode Exit fullscreen mode

That has become especially important as this project has expanded from one search workflow into multiple versions with analytics, agents, and observability.

Final repository validation for the V3 visibility milestone.


From analytics to an agent

Once V3 was working, I found myself doing something repeatedly.

I would open the dashboard.

Then I would run a BigQuery query.

Then another.

Then I would compare brands.

Then citation domains.

Then fan-out behavior.

Eventually the next question became obvious:

What if I could ask an agent questions about this visibility history instead of manually writing every query?

But I did not want an unconstrained agent with arbitrary access to the analytics store.

I wanted something much more controlled:

User question
      ↓
Gemini
      ↓
Google ADK Agent
      ↓
Approved tools
      ↓
MCP
      ↓
BigQuery visibility history
      ↓
Grounded analytical answer
Enter fullscreen mode Exit fullscreen mode

That became V4.

And it introduced a different engineering problem:

How do I give an AI agent useful access to analytics while keeping its capabilities explicit, inspectable, and constrained?

That is where I go next.


Next: Building an AI Visibility Agent with Gemini, Google ADK, MCP, and BigQuery

In Part 4, I take the visibility history created in V3 and put an agent in front of it.

The focus will be on:

  • Gemini for reasoning
  • Google ADK for agent orchestration
  • MCP for tool access
  • BigQuery as the visibility data source
  • explicit read-only analytical boundaries
  • tool-call visibility
  • handling unsupported questions
  • keeping deterministic data access separate from model reasoning

The goal is not to add a chatbot on top of a dashboard.

The goal is to build an agent that can investigate the evidence already produced by the system.

Top comments (0)