Architecture and Agent Orchestration
To move beyond simple AI demos, this approach separates the frontend (Flutter) from a robust backend (Go) using the Agent Development Kit (ADK). The system relies on a single binary deployed to Cloud Run, which manages multiple agents that communicate via HTTP.
Key architectural components include:
- Session Management: The backend tracks conversation history using session IDs, allowing agents to maintain context across multiple turns—essential for iterative tasks like styling recommendations.
- Artifact Storage: To keep API responses lightweight, the system does not send raw image data in JSON. Instead, agents save generated images to Google Cloud Storage and return a reference name, which the frontend uses to fetch the asset separately.
- Agent Loop: Each agent follows a cycle of receiving a message, deciding on a tool call or delegation, and returning a response. This loop allows for complex workflows, such as a 'Styling Agent' delegating to a 'Catalog Agent' to retrieve product data.
Implementing Agents with ADK
ADK provides the structure necessary to turn LLMs into functional agents.
- Tool Calling: Agents are equipped with specific Go functions (e.g.,
list_products,get_product_image) that allow them to interact with databases or external APIs. - Instruction Management: Prompts are stored in
instruction.mdfiles and embedded into the Go binary, keeping the codebase clean and separating logic from instructions. - Development UI: The ADK includes a built-in web UI that allows developers to chat with agents, inspect events, and view artifacts in real-time, significantly simplifying the debugging process.
- Callbacks: Hooks like
BeforeModelCallbackallow developers to intercept agent execution—for example, to automatically save user-uploaded images to artifact storage for easier tracking.
Frontend Integration with Flutter
The Flutter application follows the Model-View-ViewModel (MVVM) pattern to ensure a clean separation of concerns.
- State Management: The app uses Providers to encapsulate data (e.g., loading states, user images, outfit lists). When a provider updates, the UI automatically rebuilds, ensuring the interface stays in sync with the backend state.
- Declarative UI: By using
AnimatedSwitcherand pattern matching, the app transitions smoothly between UI states (e.g., uploading, loading, displaying results). - Cross-Platform Consistency: Because the backend is a standard REST API, the same Flutter codebase provides a consistent experience across web, iOS, and Android without requiring platform-specific logic for the AI features.