Create a Multi-Step Customer Support Automation Workflow with Function Calling

Create a Multi-Step Customer Support Automation Workflow with Function Calling
10 min read 2,226 words
⏱ 8 min read

Aug 23, 2026

By Theo Grant

Share:
𝕏
P
f

Disclosure: AIinActionHub may earn a commission from qualifying purchases through affiliate links in this article. This helps support our work at no additional cost to you. Learn more.

This article contains affiliate links. We may earn a commission at no extra cost to you. Full disclosure.




⚠ Duplicate check: This draft looks similar to an existing post (semantic match, 80% similarity) — Build a Customer Email Automation Workflow in 30 Minutes. Decide to merge, rewrite angle, or publish as follow-up before going live.

Most customer support teams still manually sort tickets like it’s 1995. A support request arrives, a human reads it, decides if it needs escalation, searches for relevant docs, and either solves it or bumps it up the chain. This process kills two things that matter: speed (average first-response time sits at 28 hours in most industries) and accuracy (40% of escalations could’ve been handled by the first agent with the right information). Function calling in large language models solves this. Instead of asking an AI a yes-or-no question, you give it access to actual functions—retrieve knowledge base articles, check ticket priority rules, look up customer history, trigger escalations—and it orchestrates the workflow. The AI doesn’t just talk about what should happen; it does it. This article walks you through building a production-ready support automation system that triages tickets, pulls relevant knowledge base content, makes escalation decisions, and logs everything. We’ll use actual API calls, real pricing, and code you can deploy today.

Why Function Calling Matters for Customer Support

Traditional chatbots give you binary output: a canned response or a pass to a human. Function calling is different. It lets the AI decide what actions to take based on the ticket content—and then actually execute them. When a customer reports a billing error, the system doesn’t just generate a response; it simultaneously calls a function to pull their account history, another to check refund policies, and another to create a priority escalation if needed. This happens in parallel, reducing total resolution time from hours to minutes.

The business impact is measurable. Companies using function-calling automation report a 35-40% reduction in first-response time and a 25-30% decrease in manual escalations by catching solvable issues early. Zendesk reports that 60% of support tickets can be resolved without human intervention if the AI has access to the right information sources. Function calling is the bridge: it lets the AI know where to look and what to do with what it finds. Without it, you’re asking the AI to imagine what the answer might be. With it, you’re telling it to fetch the real data and act on it.

The Architecture: Three Layers of Intelligence

Stay in the loop

Get the latest insights delivered straight to your inbox.

A production support workflow needs three distinct layers. The triage layer classifies incoming tickets by urgency, category, and complexity. The resolution layer attempts to solve the ticket using knowledge bases, customer history, and documented procedures. The escalation layer decides whether a ticket needs human attention and routes it correctly. Function calling powers all three.

⭐ NordVPN

Top-rated VPN for online privacy and security. Lightning-fast servers.


Check NordVPN →

Affiliate link

Zapier

Top-rated Zapier — check latest deals.


Check Zapier →

Affiliate link

Here’s how it works in practice: a ticket arrives as JSON. The first function-calling loop classifies it (triage layer). If classification returns “self-service solvable,” the system moves to the resolution layer and calls functions to fetch relevant docs and customer context. If those functions return enough confidence (typically 80%+), a response is drafted. If confidence is lower or the ticket is flagged as urgent from the start, the escalation layer activates, calling functions to assign priority, notify the right team, and log the decision. This is fundamentally different from sequential if-then-else routing; the AI evaluates the ticket holistically and decides which functions matter most.

Setting Up Your Function Definitions

Function calling starts with explicit schema. You define what functions the AI can access, what parameters they require, and what they return. For a support system, you typically need 4-6 core functions: search_knowledge_base, get_customer_history, check_escalation_rules, create_support_ticket, and log_decision. Each needs a precise JSON schema.

Here’s a real example using the OpenAI API (the syntax is similar across Claude, Llama, and other models that support function calling):

{
  "type": "function",
  "function": {
    "name": "search_knowledge_base",
    "description": "Search the support knowledge base for articles matching a query. Returns top 5 results with relevance scores.",
    "parameters": {
      "type": "object",
      "properties": {
        "query": {
          "type": "string",
          "description": "Search query (e.g., 'billing refund policy', 'API rate limits')"
        },
        "category": {
          "type": "string",
          "enum": ["billing", "technical", "account", "product", "general"],
          "description": "Limit search to specific category (optional)"
        },
        "max_results": {
          "type": "integer",
          "description": "Number of results to return (default 5, max 10)"
        }
      },
      "required": ["query"]
    }
  }
},
{
  "type": "function",
  "function": {
    "name": "get_customer_history",
    "description": "Retrieve customer history including purchase history, previous tickets, and account status.",
    "parameters": {
      "type": "object",
      "properties": {
        "customer_id": {
          "type": "string",
          "description": "Unique customer ID or email address"
        },
        "include_tickets": {
          "type": "boolean",
          "description": "Include previous support tickets (default true)"
        },
        "days_back": {
          "type": "integer",
          "description": "How many days of history to retrieve (default 90)"
        }
      },
      "required": ["customer_id"]
    }
  }
},
{
  "type": "function",
  "function": {
    "name": "check_escalation_rules",
    "description": "Check if a ticket matches any escalation rules based on urgency, category, and customer tier.",
    "parameters": {
      "type": "object",
      "properties": {
        "ticket_category": {
          "type": "string",
          "description": "Category of the ticket"
        },
        "urgency_level": {
          "type": "string",
          "enum": ["low", "medium", "high", "critical"],
          "description": "Assessed urgency"
        },
        "customer_tier": {
          "type": "string",
          "enum": ["free", "standard", "pro", "enterprise"],
          "description": "Customer subscription level"
        }
      },
      "required": ["ticket_category", "urgency_level"]
    }
  }
}

These schemas tell the AI what it can do. When you make an API call to GPT-4o or Claude Sonnet with these functions defined, the model can decide to call search_knowledge_base with a specific query, or get_customer_history for a customer ID, based on the ticket content. The model doesn’t execute the function—your backend does—but the model determines which functions to call and with what parameters.

Implementing the Triage Layer

Triage is where tickets get sorted. A simple example: a ticket arrives from a free-tier customer reporting a feature request. That’s low urgency and likely doesn’t need escalation. An enterprise customer reporting a critical outage needs immediate routing. The triage layer uses function calling to gather context and make this decision systematically.

Here’s a practical implementation using Python and the OpenAI SDK:

import openai
import json

client = openai.OpenAI(api_key="your-api-key")

# Define triage functions
functions = [
    {
        "name": "search_knowledge_base",
        "description": "Search KB for relevant articles",
        "parameters": {
            "type": "object",
            "properties": {
                "query": {"type": "string"},
                "category": {"type": "string"}
            },
            "required": ["query"]
        }
    },
    {
        "name": "get_customer_history",
        "description": "Retrieve customer data",
        "parameters": {
            "type": "object",
            "properties": {
                "customer_id": {"type": "string"},
                "days_back": {"type": "integer", "default": 90}
            },
            "required": ["customer_id"]
        }
    }
]

# Example support ticket
ticket = {
    "id": "TKT-4521",
    "subject": "Can't access my account after password reset",
    "body": "I reset my password but keep getting 'invalid credentials' error",
    "customer_email": "alice@company.com",
    "customer_tier": "pro"
}

# First call: ask AI to triage and decide what functions to call
messages = [
    {
        "role": "user",
        "content": f"""Analyze this support ticket and determine what information you need:
        
Ticket ID: {ticket['id']}
Subject: {ticket['subject']}
Message: {ticket['body']}
Customer Tier: {ticket['customer_tier']}

Gather the information you need to properly triage this ticket. Call the appropriate functions."""
    }
]

response = client.chat.completions.create(
    model="gpt-4o",
    messages=messages,
    functions=functions,
    function_call="auto"
)

print(f"Initial response: {response.choices[0].message.function_call}")

This code sends the ticket to GPT-4o with function definitions. The model will respond with function_call objects telling you what to execute. For the password reset ticket, it might call search_knowledge_base for “account access recovery” and get_customer_history for the customer. Your backend executes these, then sends the results back to the AI for the next layer of analysis.

Building the Resolution Layer with Knowledge Base Integration

Once triage assigns a priority and category, the resolution layer takes over. This is where function calling really shines. The AI searches your knowledge base, retrieves relevant articles, and drafts a response—all in one coordinated flow. The key is that the AI can see what the search returned and decide if more information is needed.

Assume your knowledge base is in Elasticsearch, a Pinecone vector database, or even a simple REST API. Here’s how to integrate it:

def search_kb(query, category=None, max_results=5):
    """
    Simulated KB search—replace with your actual endpoint.
    In production, this calls your Elasticsearch cluster or Pinecone API.
    """
    # Real implementation would hit: 
    # POST https://your-es-cluster.com/kb_articles/_search
    # or call pinecone.Index("support-kb").query(vector, top_k=5)
    
    mock_results = [
        {
            "article_id": "KB-1204",
            "title": "How to recover a locked account",
            "content": "If you cannot access your account after a password reset...",
            "relevance_score": 0.94,
            "category": "account"
        },
        {
            "article_id": "KB-856",
            "title": "Password reset troubleshooting",
            "content": "Password resets typically process within 2 minutes...",
            "relevance_score": 0.87,
            "category": "account"
        }
    ]
    return mock_results

def get_customer_history(customer_id, include_tickets=True, days_back=90):
    """Retrieve customer data from your CRM/database"""
    # Real implementation queries your database
    return {
        "customer_id": customer_id,
        "account_created": "2021-03-15",
        "subscription_tier": "pro",
        "previous_tickets": 3,
        "last_ticket": "2024-01-10",
        "account_status": "active"
    }

# Extended messages for the resolution layer
resolution_messages = [
    {
        "role": "user",
        "content": f"""A customer with ID {ticket['customer_email']} submitted this support ticket:

Subject: {ticket['subject']}
Message: {ticket['body']}

Using the available functions:
1. Search the knowledge base for relevant articles
2. Retrieve customer history to check for patterns
3. Based on the information gathered, draft a response

If the KB articles and customer history provide sufficient information, draft a response. 
If not, indicate what additional information is needed."""
    }
]

# Call GPT-4o again, this time to use the search results
response = client.chat.completions.create(
    model="gpt-4o",
    messages=resolution_messages,
    functions=functions,
    function_call="auto",
    temperature=0.3  # Lower temperature for consistency in support responses
)

# Process function calls
while response.choices[0].finish_reason == "function_call":
    function_name = response.choices[0].message.function_call.name
    function_args = json.loads(response.choices[0].message.function_call.arguments)
    
    # Execute the function
    if function_name == "search_knowledge_base":
        result = search_kb(**function_args)
    elif function_name == "get_customer_history":
        result = get_customer_history(**function_args)
    
    # Add function result to conversation
    resolution_messages.append({"role": "assistant", "content": response.choices[0].message.content})
    resolution_messages.append({
        "role": "function",
        "name": function_name,
        "content": json.dumps(result)
    })
    
    # Get next response
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=resolution_messages,
        functions=functions,
        function_call="auto"
    )

# Final response after all function calls
print("AI Response:")
print(response.choices[0].message.content)

This code demonstrates a key pattern: the AI makes a function call, your backend executes it, you return the result, and the AI decides what to do next. For the password reset ticket, GPT-4o would call search_knowledge_base first, see that KB articles exist, retrieve them, then draft a response. If the KB articles mention that password resets take 2 minutes, but the customer history shows they submitted this 30 minutes ago, the AI might draft a different response or flag for escalation.

Escalation Rules and Smart Routing

Not every ticket can be resolved by an AI. Escalation logic determines when a human needs to take over. Function calling makes this precise. Instead of guessing, the AI queries actual business rules: “Is this customer on a contract with 4-hour response SLA?” “Has this customer filed 5+ tickets about the same issue?” “Is this category restricted to senior agents?” The system uses these answers to route correctly.

Implement escalation as another function the AI can call:

def check_escalation_rules(ticket_category, urgency_level, customer_tier):
"""
Check if ticket meets any escalation criteria.
Returns escalation decision and target team.
"""
escalation_matrix = {
("billing", "critical", "enterprise"): {
"escalate": True,
"target_team": "billing_specialist",
"sla_minutes": 60
},
("technical", "high", "pro"): {
"escalate": True,
"target_team": "technical_lead",
"sla_minutes": 120
},
("technical", "medium", "standard"): {
"escalate": False,
"target_team": "general_support",
"sla_minutes": 480
},
("account", "critical", None): {
"escalate": True,
"target_team": "security_team",
"sla_minutes": 30
}
}

key = (ticket_category, urgency_level, customer_tier)
return escalation_matrix.get(key, {
"escalate": False,
"target_team": "general_support",
"sla_minutes": 1440
})

# Add to functions list
escalation_function = {
"name": "check_escalation_rules",
"description": "Check if ticket should be escalated based on rules",
"parameters": {
"type": "object",
"properties": {
"ticket_category": {
"type": "string",

Get the AI Edge, Weekly

The tools, tutorials, and trends that actually pay — no hype.

Enjoyed this article?

Join AIinActionHub for exclusive content and updates.

Subscribe Free
Theo Grant
Written byTheo Grant

Theo Grant explores real-world AI applications, automation workflows, and hands-on tutorials at AI In Action Hub. Theo breaks down complex AI concepts into practical guides that help professionals and creators leverage AI in their daily work.

Featured on
Listed on DevTool.io Listed on SaaSHub

Enjoyed this article?

Join thousands of readers who get our best insights delivered weekly. Free, no spam, unsubscribe anytime.

Subscribe Free →
Scroll to Top