General-purpose agent using Google Agent Development Kit (ADK) 2.0 with a web search tool. It uses the LiteLLM model connector to route inference through a LlamaStack server's OpenAI-compatible API endpoint.
- uv — Python package manager
- Podman or Docker — for local container builds (Option A)
- oc — for OpenShift deployment
- Helm — for deploying to Kubernetes/OpenShift
- GNU Make and a bash-compatible shell — on Windows, use WSL (recommended) or Git Bash
Here you copy .env.example file into .env
cd agents/google/adk
make initEdit .env with your configuration, then:
Now you will remove old .venv and create new. Next dependencies will be installed.
make envThis will install ollama if it is not installed already. Then pull needed models for local work.
The default model is llama3.1:8b. To use a different model, pass MODEL=:
make ollama MODEL=llama3.2:3b
make ollamaKeep this terminal open – the server needs to keep running. You should see output indicating the server started on
http://localhost:8321.
make llama-serverKeep this terminal open – the app needs to keep running. You should see output indicating the app started on
http://localhost:8000.
cd agents/google/adk
make run-app # fails if port is already in use and print steps TO-DOFor terminal-based testing without a browser:
cd agents/google/adk
make run-clicd agents/google/adk
make initEdit .env with your model endpoint and container image:
API_KEY = your-api-key-here
BASE_URL = https://your-model-endpoint.com/v1
MODEL_ID = llama-3.1-8b-instruct
CONTAINER_IMAGE = quay.io/your-username/google-adk-agent:latestNotes:
-
API_KEY- your API key or contact your cluster administrator -
BASE_URL- should end with/v1 -
MODEL_ID- model identifier available on your endpoint -
CONTAINER_IMAGE– full image path where the agent container will be pushed and pulled from. The image is built locally, pushed to this registry, and then deployed to OpenShift.Format:
<registry>/<namespace>/<image-name>:<tag>Examples:
- Quay.io:
quay.io/your-username/google-adk-agent:latest - Docker Hub:
docker.io/your-username/google-adk-agent:latest - GHCR:
ghcr.io/your-org/google-adk-agent:latest
Note: OpenShift must be able to pull the container image. Make the image public, or configure an image pull secret for private registries.
- Quay.io:
Login to OC
oc login -u "login" -p "password" https://super-link-to-cluster:111Login ex. Docker
docker login -u='login' -p='password' quay.ioRequires Podman (or Docker) and a registry account (e.g., Quay.io).
make build # builds the image locally
make push # pushes to the registry specified in CONTAINER_IMAGENo Podman, Docker, or registry account needed — just the oc CLI.
make build-openshiftAfter the build completes, set CONTAINER_IMAGE in your .env to the internal registry URL printed after the build.
make dry-run # preview rendered Helm manifests (secrets redacted)make deployAfter deploying, the application may take about a minute to become available while the pod starts up.
The route URL is printed after make deploy. You can also retrieve it manually:
oc get route google-adk-agent -o jsonpath='{.spec.host}'make undeploySee OpenShift Deployment for more details.
make testNon-streaming:
curl -X POST http://localhost:8000/chat/completions \
-H "Content-Type: application/json" \
-d '{"messages": [{"role": "user", "content": "Best server service?"}], "stream": false}'Streaming:
curl -sN -X POST http://localhost:8000/chat/completions \
-H "Content-Type: application/json" \
-d '{"messages": [{"role": "user", "content": "Search for RedHat OpenShift"}], "stream": true}'Pretty Printed Stream:
curl -sN -X POST http://localhost:8000/chat/completions \
-H "Content-Type: application/json" \
-d '{"messages": [{"role": "user", "content": "Search for RedHat OpenShift"}], "stream": true}' |
jq -R -r -j --stream 'scan("^data:(.*)")[] | fromjson.choices[0].delta.content // empty'curl http://localhost:8000/healthThis agent combines three key components:
- Google ADK 2.0 LlmAgent: Manages the agent loop (reason, call tools, observe, answer)
- LiteLLM Model Connector: Routes LLM calls to any OpenAI-compatible API (LlamaStack)
- InMemoryRunner: Handles session management and agent execution
User Input -> ADK LlmAgent -> LiteLLM -> LlamaStack (OpenAI API)
| |
v v
Tool Calls LLM Inference
| |
v v
Tool Results Model Response
| |
+------ Agent Loop ---------+
|
v
Final Response
Environment Variables:
| Variable | Description | Example |
|---|---|---|
BASE_URL |
LLM API endpoint | http://localhost:8321/v1 |
MODEL_ID |
Model identifier | ollama/llama3.1:8b |
API_KEY |
API authentication | not-needed-for-local-development (local) or API key |
CONTAINER_IMAGE |
Container registry | quay.io/user/google-adk-agent:latest |
Customization:
Edit src/adk_agent/tools.py to add new tools:
def my_custom_tool(query: str) -> dict:
"""Description of what this tool does.
Args:
query: The input for the tool.
Returns:
A dict with status and result.
"""
return {"status": "success", "result": "Tool output here"}Then register it in src/adk_agent/__init__.py:
from .tools import dummy_web_search, my_custom_tool
TOOLS = [dummy_web_search, my_custom_tool]Error: "OPENAI_API_BASE not set"
- Solution: Ensure
BASE_URLis set in your.envfile
Tool calls returned as plain text instead of function calls
- This can happen with smaller models (e.g.,
llama3.2:3b). Try a larger model or ensure the model supports function calling through LlamaStack.
LiteLLM debug mode
-
To see the actual API requests being made, add to your code:
import litellm litellm._turn_on_debug()
- Google ADK 2.0 Documentation: https://google.github.io/adk-docs/2.0/
- LiteLLM Documentation: https://docs.litellm.ai/
- Llama Stack Documentation: https://llama-stack.readthedocs.io/
- Ollama Documentation: https://ollama.com/docs
MIT License
