"On-Device AI Agent in Flutter with Gemma: Explained"

"An on-device AI agent in Flutter with Gemma turns a chatbot into software that perceives, decides, and acts — fully offline. Here is how the agent loop works, how to build one with tool calling, and when on-device beats cloud."

Most Flutter apps with "AI" are lying to you. They are one-shot prompt boxes: you type, the model answers, the conversation ends. Ask it to do something real — check your calendar, rename a file, act on a photo — and it shrugs. Turn off the Wi-Fi and the whole feature dies, sometimes after silently phoning home with your API key. The missing piece is not a smarter model. It is the loop . An on-device AI agent in Flutter with Gemma is a chatbot that grew hands: it perceives, decides, acts on the world, sees the result, and decides again — all without the internet. Here is how that loop works, how to build one in Dart, and when on-device beats the cloud. What you'll build By the end of this guide you will understand: The exact difference between a chatbot and an agent (it is one mechanism) The perceive → decide → act loop, implemented as a hand-rolled Dart class Function calling in Flutter: how a model invokes your Dart code The 2026 on-device stack: flutter_edge_ai + Gemma 4, skills, and model setup When to run on-device vs cloud — with a decision table Five mistakes that make agents loop forever, leak context, or ship dead package names Agent vs chatbot: the one difference that matters A chatbot is a single function: prompt in, text out. An agent is a loop : the model's output can include a request to run a tool, your app runs it, the result goes back into the model, and it answers again with the new information. That is the entire architectural difference. Everything else — memory, planning, skills — is machinery around that loop. User: "What meetings clash with my dentist appointment?" │ ▼ ┌──────────────┐ perceive ┌───────────┐ │ Flutter app │ ───────────► │ Model │ └──────────────┘ └─────┬─────┘ ▲ decide │ tool call: read_calendar() │ ▼ │…

Explore