An intelligent, white-label conversational agent built with Google ADK + Gemini 2.5 Flash that conducts structured customer support interviews, performs semantic knowledge-base search, and persists tickets with full lookup support.
βββββββββββββββββββββββββββββββββββββββββββ
β cli.py / adk web β
β (text mode or --voice mode) β
ββββββββββββββββββββ¬βββββββββββββββββββββββ
β
ββββββββββββββββββββΌβββββββββββββββββββββββ
β ADK Runner β
β (InMemorySessionService) β
ββββββββββββββββββββ¬βββββββββββββββββββββββ
β
ββββββββββββββββββββΌβββββββββββββββββββββββ
β LlmAgent: support_bot β
β model: gemini-2.5-flash β
β β
β ββββββββββββββββββββββββββββββββββββ β
β β InstructionProvider β β
β β (dynamic prompt from state) β β
β ββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββ ββββββββββββββββββββββ β
β β before_ β β after_agent_ β β
β β agent_ β β callback β β
β βcallback β β (phase advancement) β β
β βββββββββββ ββββββββββββββββββββββ β
ββββββββββββββββββββ¬βββββββββββββββββββββββ
β tools
βββββββββββββββββββββββββββββΌβββββββββββββββββββββββββ
β β β
ββββββββββββΌβββββββββββ ββββββββββββββΌβββββββββ ββββββββββββββΌβββββββββββ
β support_tools.py β β validation_tools.py β β rag_tools.py β
β - save_field β β - validate_order_no β β - search_knowledge_ β
β - finalize_ticket β β - validate_email β β base (KB search) β
ββββββββββββ¬βββββββββββ ββββββββββββββββββββββββ ββββββββββββββ¬βββββββββββ
β β
ββββββββββββΌβββββββββββ βββββββββββββΌβββββββββββ
β session_store.py β β knowledge_base.py β
β data/tickets/*.jsonβ β knowledge_base/*.md β
β data/sessions/*.jsonβ β ChromaDB vector storeβ
βββββββββββββββββββββββ β (Gemini embeddings) β
ββββββββββββββββββββββββ
β
ββββββββββββΌβββββββββββ
β sentiment_tools.py β
β - analyze_sentimentβ
βββββββββββββββββββββββ
GREETING
β
βΌ
COLLECT_IDENTITY ββββ customer_name, email
β
βΌ
COLLECT_ORDER ββββ order_number (validated)
β
βΌ
COLLECT_ISSUE ββββ problem_category, problem_description
β
βΌ
COLLECT_URGENCY ββββ urgency_level
β
βΌ
CONFIRM ββββ show summary, ask to confirm or amend
β
βΌ
FINALIZE ββββ finalize_ticket() β ticket # generated
β
βΌ
COMPLETED
Phase transitions are driven by the after_agent_callback which inspects session.state["fields_completed"].
| Feature | Implementation |
|---|---|
| Structured data collection | save_field tool + session state |
| Input validation | validate_order_number, validate_email tools + Pydantic |
| Ticket persistence | data/tickets/<uuid>.json via Pydantic models |
| RAG knowledge base | Semantic vector search via ChromaDB + Gemini embeddings (search_knowledge_base) |
| Ticket lookup | Look up existing tickets by confirmation number or email (lookup_ticket) |
| Sentiment analysis | Rule-based scoring in analyze_sentiment |
| Dynamic tone adaptation | Frustration detected β empathy addendum in system prompt |
| Language detection | before_agent_callback detects language on first message |
| Voice I/O | ADK run_live() + gemini-live-2.5-flash-native-audio native audio model; sounddevice for mic/speaker I/O |
| ADK Web UI | adk web for browser testing |
- Python 3.11+
- A Google AI API key (get one at aistudio.google.com)
- (Optional) Google Cloud project with Speech and TTS APIs for voice mode
cd support-bot
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"cp .env .env.local
# Edit .env.local and set GOOGLE_API_KEY=your_key_herepython cli.pyVoice mode uses the Gemini Live API (gemini-live-2.5-flash-native-audio) for
real-time bidirectional audio streaming. No Google Cloud Speech/TTS credentials needed β
the model handles STT and TTS natively.
# Default voice (Aoede)
python cli.py --voice
# Choose a different voice: Puck, Charon, Kore, Fenrir, Aoede, Leda, Orus, Zephyr
python cli.py --voice --voice-name PuckAudio requirements: a working microphone and speakers. The system uses:
- Input: 16-bit PCM, 16 kHz mono (captured via
sounddevice) - Output: 16-bit PCM, 24 kHz mono (played via
sounddevice)
Built-in VAD (Voice Activity Detection) controls turn boundaries β just speak naturally.
The Live API supports 70 languages (BCP-47 codes):
| Language | Code | Language | Code |
|---|---|---|---|
| Afrikaans | af |
Kannada | kn |
| Albanian | sq |
Kazakh | kk |
| Amharic | am |
Khmer | km |
| Arabic | ar |
Korean | ko |
| Armenian | hy |
Lao | lo |
| Assamese | as |
Latvian | lv |
| Azerbaijani | az |
Lithuanian | lt |
| Basque | eu |
Macedonian | mk |
| Belarusian | be |
Malay | ms |
| Bengali | bn |
Malayalam | ml |
| Bosnian | bs |
Marathi | mr |
| Bulgarian | bg |
Mongolian | mn |
| Catalan | ca |
Nepali | ne |
| Chinese | zh |
Norwegian | no |
| Croatian | hr |
Odia | or |
| Czech | cs |
Polish | pl |
| Danish | da |
Portuguese | pt |
| Dutch | nl |
Punjabi | pa |
| English | en |
Romanian | ro |
| Estonian | et |
Russian | ru |
| Filipino | fil |
Serbian | sr |
| Finnish | fi |
Slovak | sk |
| French | fr |
Slovenian | sl |
| Galician | gl |
Spanish | es |
| Georgian | ka |
Swahili | sw |
| German | de |
Swedish | sv |
| Greek | el |
Tamil | ta |
| Gujarati | gu |
Telugu | te |
| Hebrew | iw |
Thai | th |
| Hindi | hi |
Turkish | tr |
| Hungarian | hu |
Ukrainian | uk |
| Icelandic | is |
Urdu | ur |
| Indonesian | id |
Uzbek | uz |
| Italian | it |
Vietnamese | vi |
| Japanese | ja |
Zulu | zu |
Source: Gemini Live API documentation
adk web
# Opens browser at http://localhost:8000
# Select "support_bot" from the agent dropdown# Unit tests only (no API key required)
pytest tests/unit/ -v
# All tests including integration (requires GOOGLE_API_KEY)
pytest tests/ -vsupport-bot/
βββ support_bot/ # ADK agent package
β βββ __init__.py # exports root_agent
β βββ agent.py # LlmAgent definition
β βββ prompts.py # InstructionProvider
β βββ callbacks.py # before/after callbacks
β βββ tools/
β β βββ support_tools.py # save_field, finalize_ticket
β β βββ validation_tools.py
β β βββ rag_tools.py
β β βββ sentiment_tools.py
β βββ models/
β β βββ schemas.py # Pydantic models
β βββ storage/
β βββ session_store.py # JSON persistence
β βββ knowledge_base.py # KB loader + search
βββ knowledge_base/ # Markdown knowledge base
βββ audio/speech.py # Google Cloud STT + TTS
βββ cli.py # CLI entry point
βββ data/ # Runtime data (gitignored)
β βββ tickets/ # One JSON file per ticket
β βββ sessions/ # Session log files
β βββ chroma/ # ChromaDB vector store (auto-created on first run)
βββ tests/ # Unit + integration tests
βββ sample_conversations/ # Annotated conversation transcripts
βββ pyproject.toml
The support flow is strictly linear and stateful. Sub-agents would add complexity without benefit β the phase-based InstructionProvider dynamically focuses the single agent on exactly what's needed at each step.
ADK performs {key} substitution on static instruction strings. A dynamic provider callable avoids this, and lets the prompt evolve with session state (showing remaining fields, adapting tone based on sentiment, injecting ticket summaries at confirmation time).
For a demo/interview context, file-based JSON is zero-infrastructure, immediately inspectable, and fully portable. The TicketRecord and ConversationSession models use identical APIs to what a Vertex AI Firestore backend would use β swapping persistence is a one-file change.
A separate LLM call for sentiment adds latency and cost on every turn. A lightweight keyword-scoring heuristic is fast, deterministic, and easily testable. In production, this could be upgraded to a dedicated sentiment model.
Knowledge-base markdown files are chunked by ## heading and embedded via
gemini-embedding-001 into a persistent ChromaDB collection (data/chroma/).
The collection is auto-ingested on first run and reused on subsequent runs.
Semantic search handles paraphrased queries far better than keyword matching,
and the latency cost (one embedding call per search query) is negligible in a
support context.
- Vertex AI Session Service: Swap
InMemorySessionServiceforVertexAiSessionServicefor multi-instance deployment. - Multi-turn memory: Use
InMemoryMemoryService.add_session_to_memory()to give the agent cross-session recall (e.g., recognizing returning customers). - Streaming responses: Implement
runner.run_live()for token-by-token streaming in the CLI and web UI. - LLM-based sentiment: Replace rule-based scoring with a dedicated lightweight model call.
- Ticket webhook: On
finalize_ticket, POST to a CRM API (Zendesk, Salesforce) instead of writing JSON. - Authentication: Add OAuth2 session management so customers log in before starting a conversation.
- Multi-language STT: Configure Google Cloud STT to auto-detect language for global support.
- Admin dashboard: A FastAPI web interface to view, filter, and update tickets.
- A/B testing: Use ADK's evaluation framework to test different prompt strategies and measure resolution rates.