Self-Contained Data Agents

· 3 min read
AI / Data
agents chdb clickhouse cloud-run architecture

I caught a talk at the ClickHouse Bangalore Meetup recently where someone described dashboards at a large US bank taking 8-9 minutes to load against about a year of data. The business SLA was 3 seconds.

They’d tried the usual things. More infrastructure, bigger databases, better caching. Nothing moved the number enough because the problem wasn’t any of those things. It was the topology.

The hub-and-spoke problem

Most AI data agents are built the same way: the agent sits in the middle and every query triggers multiple network calls. One to the vector store for context, one to memory, one to the data warehouse for the actual data. Each of those adds latency, and the latency compounds.

RAG can help you retrieve the right rows, but it doesn’t help you reason over them. If a user asks “what were our top 5 products by revenue last quarter”, you need to run SQL, not just find similar documents. And that SQL execution is going over the network to some external database, adding hundreds of milliseconds per query.

At small scale this is fine. As data grows, it adds up fast.

What they did instead

Stop going over the network. Load the data into the container when it starts up, and run all queries in-process.

The stack they used: Agno as the agent framework, chDB (embedded ClickHouse, runs in-process) as the SQL engine, and Google Cloud Run as the serverless host. On startup, the container pulls its dataset from object storage and loads it into chDB. Every subsequent query runs locally.

User query
  -> agent converts NL to ClickHouse SQL (chDB's native text_to_sql)
  -> chDB executes in-process against loaded dataset
  -> result converted back to natural language

Latency: 33-100ms. No external infrastructure during query time.

The cost question

The obvious pushback is that keeping a container loaded with data is expensive. But on Cloud Run you don’t have to keep it running. You scale to zero when idle, spin up on demand, and keep one warm container to handle the first request without a cold start. You pay per request, not for always-on infrastructure.

This is what makes the pattern actually usable rather than just a benchmark curiosity. For bounded analytical workloads (a week of data, a reporting dataset, a per-user segment) the container size is manageable and the pay-per-use model makes economic sense.

Where it breaks down: terabyte-scale datasets obviously don’t fit in a container, and if your data is changing faster than you’d tolerate a redeploy, you’d need a different approach.

Why chDB specifically

chDB is embedded ClickHouse, which means it runs in-process as a Python library with no server. It has a native text_to_sql function that converts natural language to ClickHouse SQL without needing a separate LLM call. The DataStore API gives you zero-copy interop with Pandas if you want to move between SQL results and Python-native data manipulation.

For this pattern specifically, the in-process part is the point. You’re not replacing your data warehouse with chDB. You’re using it as the query engine for data that’s already inside your container.

What I’m building with this

I’m implementing this in Aglitics, adding a proper multi-turn memory layer (also stored in chDB so memory stays co-located with the data) and building out connector coverage for loading from common sources.

If you’ve worked with chDB or Cloud Run deployments and want to compare notes, get in touch.

© 2026 Arnav Singh Chauhan
Built with Astro and the Astrofy template ⚡️
Chiku the cat
🐱 Konami unlocked! Chiku approves of you. (he approves of almost no one)