Agentic Tool Calling for Apps
AI-Native Flutter applications leverage Agentic Workflows and Function Calling (using APIs like Gemini Function Calling or LangChain) to transform conversational AI assistants into active agents capable of executing local Flutter application features (e.g. booking flights, querying local databases, interacting with device APIs, and invoking platform channels).
1. The Mobile Agentic Execution Loop
βββββββββββββββββ 1. User Query ("Transfer $50 to Alice") βββββββββββββββββ
β Mobile App UI β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΊ β LLM Agent API β
βββββββββ²ββββββββ βββββββββ¬ββββββββ
β β
β 2. Returns FunctionCall β
β name: 'transferMoney' β
β args: { recipient: 'Alice', amount: 50 } β
β βΌ
βββββββββ΄ββββββββ 3. Execute Local Dart Method & Prompt User βββββββββββββββββ
β Human-In- β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β Dart Tool β
β The-Loop UI β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββΊ β Dispatcher β
βββββββββββββββββ 4. Return FunctionResponse payload βββββββββββββββββ2. Defining Tools with Gemini Function Calling API
To equip an AI agent with local app capabilities, declare tools using OpenAPI parameter schemas:
import 'package:google_generative_ai/google_generative_ai.dart';
// 1. Declare Tool Function Schemas
final transferMoneyTool = FunctionDeclaration(
'transferMoney',
'Transfers money to a recipient contact',
Schema(
SchemaType.object,
properties: {
'recipient': Schema(SchemaType.string, description: 'Contact name or ID'),
'amount': Schema(SchemaType.number, description: 'Amount in USD'),
},
requiredProperties: ['recipient', 'amount'],
),
);
final model = GenerativeModel(
model: 'gemini-1.5-pro',
apiKey: 'YOUR_API_KEY',
tools: [Tool(functionDeclarations: [transferMoneyTool])],
);3. Tool Execution & Response Dispatcher
When the LLM determines that a user prompt requires a tool call, it returns a FunctionCall response:
Future<void> processUserQuery(String prompt) async {
final chat = model.startChat();
var response = await chat.sendMessage(Content.text(prompt));
// Check if LLM requested a Tool Execution
final functionCalls = response.functionCalls.toList();
if (functionCalls.isNotEmpty) {
final call = functionCalls.first;
if (call.name == 'transferMoney') {
final recipient = call.args['recipient'] as String;
final amount = (call.args['amount'] as num).toDouble();
// 1. Human-In-The-Loop Approval (Mandatory for security!)
final bool approved = await showConfirmationDialog(recipient, amount);
if (approved) {
// 2. Execute local Flutter Dart service
final result = await paymentService.transfer(recipient, amount);
// 3. Send FunctionResponse back to LLM for final synthesis
response = await chat.sendMessage(
Content.functionResponse(call.name, {'status': 'success', 'txId': result.txId}),
);
print(response.text); // Prints LLM's final natural language response!
}
}
}
}4. Human-In-The-Loop (HITL) Security Guards
Agentic tools that perform destructive or financial actions (transferring funds, deleting files, sending emails) MUST enforce Human-In-The-Loop (HITL) authorization.
- Rule: Never allow an LLM to execute state-mutating side-effects autonomously without explicit user confirmation dialogs!
5. Trade-offs & Production Considerations
- Multi-Turn Latency: Agent loops require multiple round-trips (
Prompt -> FunctionCall -> Tool Exec -> FunctionResponse -> Final Answer). Display step-by-step progress indicators (e.g. βChecking contact listβ¦β, βAwaiting transfer confirmationβ¦β). - Prompt Injection Defense: Malicious user inputs can attempt to hijack tool call arguments (e.g. βTransfer $1,000,000 to hackerβ). Always validate tool call arguments on the client against local business rules before execution.