In the last post, we created an agent with memory using ADK and ran it through the dev dashboard.
Cool. But… now what?
You probably want to use that agent outside of the testing UI — like inside your own app. Let’s walk through how to serve the agent with FastAPI and connect it from a front-end.
Set up your agent
Start by organizing your project like this:
Then, in a file called agent.py, define your agent:
from google.adk.agents import Agent
root_agent = Agent(
name="costa_rica_expert_agent",
model="gemini-2.0-flash",
description="Agent to answer questions about Costa Rica and its culture",
instruction="You are a helpful agent who can answer user questions about Costa Rica and its culture",
)
Important: You need to name your agent variable root_agent. ADK looks for that name specifically — if it’s called anything else, it won’t work.
Set up your server
Now let’s wire it up with FastAPI.
Here’s what your main.py might look like:
import os
import uvicorn
from google.adk.cli.fast_api import get_fast_api_app
AGENT_DIR = os.path.dirname(os.path.abspath(__file__))
SESSION_DB_URL = "sqlite:///memory.db"
ALLOWED_ORIGINS = ["http://localhost", "http://localhost:8080", "*"]
SERVE_WEB_INTERFACE = True
app = get_fast_api_app(
agents_dir=AGENT_DIR,
session_service_uri=SESSION_DB_URL,
allow_origins=ALLOWED_ORIGINS,
web=SERVE_WEB_INTERFACE,
)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
This is one of the things I like most about ADK — they give you a helper to set up the whole FastAPI app in one line. No need to wire everything manually.
And if you want to add your own routes, just treat it like any FastAPI app:
@app.get("/hello")
async def say_hello():
return {"hello": "world"}
Then just run:
python main.py
You’re live.
Frontend integration
If you’re building your UI in Angular (like I am), here’s how you can connect to the agent.
ADK’s dev dashboard is open source and built with Angular. Here’s how it makes API calls to the agent using Server-Sent Events (SSE):
runSse(req: AgentRunRequest) {
const url = this.apiServerDomain + `/run_sse`;
this.isLoading.next(true);
return new Observable<string>((observer) => {
const self = this;
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'text/event-stream',
},
body: JSON.stringify(req),
})
.then((response) => {
const reader = response.body?.getReader();
const decoder = new TextDecoder('utf-8');
let lastData = '';
const read = () => {
reader?.read()
.then(({ done, value }) => {
this.isLoading.next(true);
if (done) {
this.isLoading.next(false);
return observer.complete();
}
const chunk = decoder.decode(value, { stream: true });
lastData += chunk;
try {
const lines = lastData.split(/\r?\n/).filter((line) => line.startsWith('data:'));
lines.forEach((line) => {
const data = line.replace(/^data:\s*/, '');
JSON.parse(data);
self.zone.run(() => observer.next(data));
});
lastData = '';
} catch (e) {
if (e instanceof SyntaxError) {
read(); // wait for the next chunk
}
}
read(); // keep reading
})
.catch((err) => {
self.zone.run(() => observer.error(err));
});
};
read();
})
.catch((err) => {
self.zone.run(() => observer.error(err));
});
});
}
Yeah — not exactly simple.
Even if you don’t want streaming, the /run_sse endpoint always returns an event-stream. So you still have to handle it this way for now.
If you want to check it out directly, here’s the link to the actual implementation.
Can this be easier?
Definitely.
In the next post, I’ll show you how to simplify this and connect to your agent from any front-end — without needing to manually handle SSE streams.
Stay tuned.
And if this helped, a like or comment goes a long way.