GEMINI LABJP
NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20
Articles/Advanced
Advanced/2026-05-05Advanced

Building a B2B Business Automation SaaS with Gemini 2.5 Pro Function Calling — Revenue Blueprint

A complete guide to building and selling B2B business automation SaaS using Gemini 2.5 Pro Function Calling. Covers API architecture, multi-tenant design, pricing strategy, and the sales process that closed first contracts within 3 weeks of demo.

Gemini75Function Calling16B2B2SaaS11monetization21automation51API12

Small and mid-sized businesses are drowning in repetitive work that off-the-shelf software doesn't fully solve. They know AI should help. They don't know how to make it work for their specific processes.

That gap is a business opportunity, and Gemini 2.5 Pro's Function Calling is the technical foundation for addressing it at scale.

This article documents the full process: understanding what Function Calling actually enables, designing a multi-tenant B2B SaaS around it, pricing it correctly, and closing the first clients.

What Function Calling Changes About Business Automation

Standard Gemini responses are text in, text out. Function Calling breaks that constraint by letting Gemini decide when to call external functions — your inventory system, your CRM, your ERP — and synthesize the results.

import google.generativeai as genai
import json
from datetime import datetime
 
genai.configure(api_key="YOUR_GEMINI_API_KEY")
 
# Define what functions Gemini can call
tools = [{
    "function_declarations": [
        {
            "name": "check_inventory",
            "description": "Get current stock level and reorder status for a product",
            "parameters": {
                "type": "object",
                "properties": {
                    "product_id": {"type": "string"},
                    "include_forecast": {"type": "boolean"}
                },
                "required": ["product_id"]
            }
        },
        {
            "name": "create_purchase_order",
            "description": "Submit a purchase order to the procurement system",
            "parameters": {
                "type": "object",
                "properties": {
                    "product_id": {"type": "string"},
                    "quantity": {"type": "integer"},
                    "supplier_id": {"type": "string"},
                    "requested_delivery": {"type": "string"}
                },
                "required": ["product_id", "quantity", "supplier_id"]
            }
        }
    ]
}]
 
def check_inventory(product_id: str, include_forecast: bool = False) -> dict:
    # In production: call your actual inventory API
    return {
        "product_id": product_id,
        "current_stock": 45,
        "reorder_point": 30,
        "daily_consumption_avg": 8.5,
        "days_remaining": 5,
        "pending_orders": 0
    }
 
def create_purchase_order(product_id: str, quantity: int, 
                          supplier_id: str, requested_delivery: str = None) -> dict:
    order_id = f"PO-{datetime.now().strftime('%Y%m%d%H%M%S')}"
    # In production: submit to your procurement system
    return {
        "order_id": order_id,
        "status": "submitted",
        "quantity": quantity,
        "estimated_delivery": requested_delivery or "2026-05-12"
    }
 
def run_procurement_automation(instruction: str) -> dict:
    """Execute multi-step procurement automation via natural language"""
    model = genai.GenerativeModel("gemini-2.5-pro-preview-05-06", tools=tools)
    chat = model.start_chat()
    response = chat.send_message(instruction)
    
    actions = []
    for _ in range(10):  # Prevent infinite loops
        part = response.candidates[0].content.parts[0]
        if not hasattr(part, 'function_call') or not part.function_call.name:
            break
        
        fc = part.function_call
        handlers = {
            "check_inventory": check_inventory,
            "create_purchase_order": create_purchase_order
        }
        
        result = handlers.get(fc.name, lambda **k: {"error": "unknown"})(**dict(fc.args))
        actions.append({"function": fc.name, "args": dict(fc.args), "result": result})
        
        response = chat.send_message(
            genai.protos.Part(
                function_response=genai.protos.FunctionResponse(
                    name=fc.name,
                    response={"result": json.dumps(result)}
                )
            )
        )
    
    return {"result": response.text, "actions": actions}
 
# A manager types a natural language instruction
result = run_procurement_automation(
    "Check SKU-00123 inventory. If we're at risk of stockout within 7 days, "
    "automatically place a replenishment order with supplier SUP-001."
)
print(result["result"])
# "SKU-00123 has 45 units with 5 days remaining at current consumption.
#  I've submitted purchase order PO-20260505143022 for 100 units from 
#  SUP-001, expected delivery May 12."
print(f"Actions taken: {len(result['actions'])}")
# "Actions taken: 2"

This is the core pattern: natural language instruction → Gemini decides which functions to call and in what order → structured results → synthesis into human-readable output.

Identifying Business Problems Worth Solving

Technical capability is not the constraint. Knowing which problems to solve is.

The most reliable method: read the operations manuals of your target industry. Dense, step-by-step manuals signal automatable processes. No manual means no standardized process, which means harder automation.

High-value automation patterns by industry:

Manufacturing & Wholesale:
- Inventory monitoring + auto-procurement (connects stock data to ordering)
- Quote generation (materials + labor + markup → PDF quote)
- Quality inspection report aggregation + anomaly detection

Real Estate:
- Showing request coordination (availability check + confirmation)
- Multi-portal listing sync (update one source, propagate everywhere)
- Rent collection follow-up (overdue detection → graduated outreach)

Professional Services (Lawyers, Accountants, HR Firms):
- Client inquiry categorization + routing to right staff member
- Invoice generation + delivery (time tracking → billing)
- Monthly report automation (data pull → analysis → formatted PDF)

The pattern that consistently leads to contracts: multi-step processes that currently require a human to bridge two or more systems. If someone copies data from System A to System B and then makes a judgment call, that's your opportunity.

The Automation Engine Architecture

Production B2B automation needs error handling, logging, and retry logic built in from day one. Demos that work once don't count.

# core/automation_engine.py
 
import google.generativeai as genai
from typing import Any, Callable
import logging
import time
from functools import wraps
 
logger = logging.getLogger(__name__)
 
def with_exponential_retry(max_retries: int = 3, base_delay: float = 1.0):
    """Retry decorator with exponential backoff for external API calls"""
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_retries - 1:
                        logger.error(f"{func.__name__} failed after {max_retries} attempts: {e}")
                        raise
                    delay = base_delay * (2 ** attempt)
                    logger.warning(f"{func.__name__} attempt {attempt+1} failed, retry in {delay}s: {e}")
                    time.sleep(delay)
        return wrapper
    return decorator
 
class AutomationEngine:
    """Production-ready Gemini Function Calling engine"""
    
    def __init__(self, api_key: str, tools: list, handlers: dict[str, Callable],
                 model: str = "gemini-2.5-pro-preview-05-06"):
        genai.configure(api_key=api_key)
        self.model = genai.GenerativeModel(model, tools=tools)
        self.handlers = handlers
        self.max_function_calls = 15  # Safety limit
    
    def execute(self, instruction: str, context: dict = None) -> dict:
        """
        Execute an automation task from natural language instruction
        
        Returns: {
            "success": bool,
            "result": str,
            "actions_taken": list,
            "error": str | None
        }
        """
        try:
            return self._execute_with_tracking(instruction, context)
        except Exception as e:
            logger.error(f"Automation failed: {e}", exc_info=True)
            return {"success": False, "result": "", "actions_taken": [], "error": str(e)}
    
    def _execute_with_tracking(self, instruction: str, context: dict = None) -> dict:
        context_addition = f"\n\nContext: {context}" if context else ""
        chat = self.model.start_chat()
        response = chat.send_message(instruction + context_addition)
        
        actions_taken = []
        call_count = 0
        
        while call_count < self.max_function_calls:
            call_count += 1
            parts = response.candidates[0].content.parts
            
            if not parts or not hasattr(parts[0], 'function_call') or not parts[0].function_call.name:
                break
            
            fc = parts[0].function_call
            handler = self.handlers.get(fc.name)
            
            if not handler:
                result = {"error": f"Handler for '{fc.name}' not registered"}
                logger.warning(result["error"])
            else:
                result = handler(**dict(fc.args))
                actions_taken.append({
                    "function": fc.name,
                    "args": dict(fc.args),
                    "result": result,
                    "timestamp": time.time()
                })
            
            import json
            response = chat.send_message(
                genai.protos.Part(
                    function_response=genai.protos.FunctionResponse(
                        name=fc.name,
                        response={"result": json.dumps(result, default=str)}
                    )
                )
            )
        
        final_text = "".join(
            p.text for p in response.candidates[0].content.parts 
            if hasattr(p, 'text')
        )
        
        return {
            "success": True,
            "result": final_text,
            "actions_taken": actions_taken,
            "error": None
        }

Multi-Tenant SaaS Design and Pricing

Serving multiple clients from the same codebase requires tenant isolation and usage tracking for billing.

# core/tenant.py
 
from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional
import uuid
 
PLANS = {
    "starter": {
        "monthly_automations": 500,
        "price_jpy": 50_000,
        "price_usd": 350,
        "max_integrations": 3
    },
    "growth": {
        "monthly_automations": 3_000,
        "price_jpy": 150_000,
        "price_usd": 1_000,
        "max_integrations": 10
    },
    "enterprise": {
        "monthly_automations": -1,   # Unlimited
        "price_jpy": 400_000,
        "price_usd": 2_700,
        "max_integrations": -1
    }
}
 
@dataclass
class Tenant:
    company_name: str
    plan: str
    tenant_id: str = field(default_factory=lambda: uuid.uuid4().hex[:8])
    enabled_integrations: list[str] = field(default_factory=list)
    created_at: datetime = field(default_factory=datetime.now)
 
class UsageTracker:
    """Tracks automation usage per tenant per billing period"""
    
    def __init__(self):
        self._usage: dict[str, int] = {}
    
    def _key(self, tenant_id: str) -> str:
        return f"{tenant_id}:{datetime.now().strftime('%Y-%m')}"
    
    def can_run(self, tenant_id: str, plan: str) -> bool:
        limit = PLANS[plan]["monthly_automations"]
        if limit == -1:
            return True  # Unlimited
        current = self._usage.get(self._key(tenant_id), 0)
        return current < limit
    
    def record_run(self, tenant_id: str) -> int:
        key = self._key(tenant_id)
        self._usage[key] = self._usage.get(key, 0) + 1
        return self._usage[key]
    
    def monthly_invoice(self, tenant: Tenant) -> dict:
        runs = self._usage.get(self._key(tenant.tenant_id), 0)
        plan = PLANS[tenant.plan]
        limit = plan["monthly_automations"]
        
        overage = max(0, runs - limit) if limit != -1 else 0
        overage_charge = overage * 15  # ¥15 per overage automation
        
        return {
            "tenant": tenant.company_name,
            "plan": tenant.plan,
            "base_price_jpy": plan["price_jpy"],
            "automations_run": runs,
            "overage_automations": overage,
            "overage_charge_jpy": overage_charge,
            "total_jpy": plan["price_jpy"] + overage_charge
        }

Three Mistakes That Kill B2B Automation Businesses

Mistake 1: No idempotency in destructive operations

A duplicate purchase order or double-sent invoice is a client relationship disaster. Every function that creates or modifies records must implement idempotency:

def create_order_idempotent(product_id: str, quantity: int, 
                             supplier_id: str, idempotency_key: str) -> dict:
    """Never create the same order twice"""
    existing = db.find_by_idempotency_key(idempotency_key)
    if existing:
        return {"status": "already_exists", "order_id": existing.id}
    
    order = db.create_order(product_id, quantity, supplier_id, idempotency_key)
    return {"status": "created", "order_id": order.id}

Mistake 2: Underestimating token costs at scale

Gemini 2.5 Pro at 3,000 complex automations per month can easily hit 30–50M tokens. Calculate your costs before setting plan prices, not after.

def estimate_monthly_token_cost(
    avg_tokens_per_automation: int,
    automations_per_month: int,
    input_price_per_m: float = 1.25,  # Gemini 2.5 Pro pricing
    output_price_per_m: float = 10.0
) -> float:
    input_tokens = avg_tokens_per_automation * 0.6 * automations_per_month
    output_tokens = avg_tokens_per_automation * 0.4 * automations_per_month
    
    cost = (input_tokens / 1_000_000 * input_price_per_m + 
            output_tokens / 1_000_000 * output_price_per_m)
    return round(cost, 2)
 
# Growth plan: 3,000 automations at ~8,000 tokens each
cost = estimate_monthly_token_cost(8000, 3000)
print(f"${cost}")  # ~$37.80 — safely covered by $1,000/month plan

Mistake 3: Selling the technology instead of the outcome

"AI-powered automation" closes fewer deals than "eliminate the 3 hours/day your team spends on X."

The Sales Process That Closes in 3 Weeks

Week 1: The Ops Audit Call

Frame it as: "I'm researching how [industry] businesses handle [specific process]. Would you spend 30 minutes walking me through how you currently do it?"

You're looking for: steps involving manual data transfer, judgment calls based on simple rules, and recurring processes that take more than 2 hours/week.

Week 2: The Demo

Build a working PoC for the single most painful process you identified. Show it live. Don't over-engineer — functional beats polished at this stage.

Week 3: The ROI Proposal

ROI Calculation Template:

Current State:
  Staff performing task: 2 people × 3 hours/day × 20 working days
  Monthly labor cost: 2 × 3 × 20 × [hourly rate] = ¥360,000

After Automation:
  Staff oversight: 15 minutes/day review
  Monthly labor cost: ¥12,500

Monthly savings: ¥347,500
System cost: ¥150,000/month (Growth Plan)
Net monthly benefit: ¥197,500

Payback period (including ¥300,000 setup): 1.5 months

Most decision-makers at SMBs understand this math intuitively. When the system costs ¥150K and saves ¥347K, objections about price evaporate.

The path to ¥3M MRR in 6 months requires roughly 10 Growth plan clients or 7-8 Enterprise clients. Neither is unrealistic if you focus on a single vertical and build deep expertise in their specific workflows. Pick your industry, build your first PoC this week.

Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Advanced2026-03-29
Deep Dive into Gemini's Speech-to-Speech Translation — Technology Architecture and Developer Applications
Comprehensive technical exploration of Gemini 2.5's speech-to-speech translation. Learn the end-to-end architecture, Native Audio API implementation, low-latency techniques, and production deployment patterns.
Advanced2026-03-25
Automated Monetization Infrastructure with Gemini API — 6 Revenue Engines Powered by Multimodal AI and Function Calling
A comprehensive guide to 6 automated revenue engines built on Gemini API's multimodal processing, Function Calling, and context caching. Covers SaaS, API services, content pipelines, data analysis, Workspace integration, and education platforms.
Advanced2026-03-16
Accelerate note Monetization with Aqua Voice × Gemini:
Combine voice input and AI to streamline article creation and monetization on note. Master the complete workflow from Aqua Voice to Gemini Advanced.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →