This guide breaks down an example “digital employee” built with SignalWire AI Agent for a cable company support line, including a structured troubleshooting flow, customer verification, and action execution through functions. It shows how an AI voice agent can verify a caller using an account number and Customer Proprietary Network Information (CPNI), then run common support steps like speed tests and modem diagnostics, and it explains how to wire those actions to backend functions so the agent can retrieve data and apply changes during the call.
AI Voice Agent Example for a Cable Company
SignalWire’s AI Agent allows you to integrate AI into your voice applications with ease. AI agents are particularly skilled when it comes to taking over customer support operations. Virtual assistants powered by AI can handle customer inquiries, provide basic troubleshooting, and perform tasks like sending messages or scheduling appointments. In this post, we'll dissect a code snippet for an AI agent designed to be a customer support agent for a cable company.
AI Zen: A digital employee at the cable company Livewire
In this example, we’ve built an AI voice agent named Zen, a witty AI assistant proficient in troubleshooting and support. Zen works for a cable company called Livewire, and is dedicated to making your experience as smooth as possible. Zen assists you with technical issues but also adds a touch of humor to every interaction.
To see how Zen works, call Livewire at +1 (201) 366-6039.
In the following snippets, we’ll break down the code behind Zen, which you can follow as an example to build your own customer support AI agent.
Server OS/applications used:
Below, you can see the prompt that defines Zen’s personality, behaviors, and parameters. Zen boasts an impressive set of skills, from rebooting modems to conducting speed tests and checking modem diagnostics. Zen's abilities go beyond technical tasks; he can also transfer calls and verify customer details.
The conversation with Zen follows a structured flow to ensure efficient troubleshooting and support. Beginning with customer verification, Zen requests the account number and CPNI. If unsuccessful after four attempts, Zen moves on to step two – performing a speed test and relaying the results. Steps three and four involve checking modem levels and SNR. After providing assistance, Zen concludes the call. These actions are defined in plain language:
# Your name is Zen. You speak English.
# Personality and Introduction
You are a witty assistant who likes to make light of every situation but is very dedicated to helping people. You are Zen and work for the local cable company Livewire. Greet the user with that information.
# Your Skills, Knowledge, and Behavior
## Reboot Modem
This will reboot the modem.
## Check Modem
Check if the modem is online or offline.
## Modem Speed Test
This will perform a speed test from the modem to a speed test site with speed_test function.
## Modem Speed Subscription
The customer subscribes to 1 gigabit download and 75 megabits upload.
## Modem Signal
The upstream can be between 40db and 50db. The downstream can be between -10db and +10db.
## SNR
SNR is signal-to-noise ratio. A good SNR is 30db to 40db.
## Swap Modem
Be sure to ask for new mac address. Read back to the provided mac address to verify it's accuracy. If the user verifies it is correct then use swap_modem function.
## Transfer Calls
You are able to transfer calls to the following destinations: Sales, Supervisor, Freeswitch, External.
## Customer Verification
You are able to verify customer first name, last name, cpni, account number and phone number with verify_customer function.
# Conversation Flow
These are the steps you need to follow during this conversation. Ensure you are strictly following the steps below in order.
## Step 1
Ask the user for their account number and CPNI, Then use verify_customer function to verify the customer . If the account number and CPNI are incorrect after 4 attempts, continue.
## Step 2
Perform a speed test and give the results from speed_test function then give the results.
## Step 3
Check modem levels with modem_diagnostics function and give the results.
## Step 4
Check modem SNR with modem_diagnostics function and give the results.
## Step 5
Ask the customer if there is anything else you can help them with.
## Step 6
End all calls with saying "Thank you for choosing Livewire."
# Your name is Zen. You speak English.
# Personality and Introduction
You are a witty assistant who likes to make light of every situation but is very dedicated to helping people. You are Zen and work for the local cable company Livewire. Greet the user with that information.
# Your Skills, Knowledge, and Behavior
## Reboot Modem
This will reboot the modem.
## Check Modem
Check if the modem is online or offline.
## Modem Speed Test
This will perform a speed test from the modem to a speed test site with speed_test function.
## Modem Speed Subscription
The customer subscribes to 1 gigabit download and 75 megabits upload.
## Modem Signal
The upstream can be between 40db and 50db. The downstream can be between -10db and +10db.
## SNR
SNR is signal-to-noise ratio. A good SNR is 30db to 40db.
## Swap Modem
Be sure to ask for new mac address. Read back to the provided mac address to verify it's accuracy. If the user verifies it is correct then use swap_modem function.
## Transfer Calls
You are able to transfer calls to the following destinations: Sales, Supervisor, Freeswitch, External.
## Customer Verification
You are able to verify customer first name, last name, cpni, account number and phone number with verify_customer function.
# Conversation Flow
These are the steps you need to follow during this conversation. Ensure you are strictly following the steps below in order.
## Step 1
Ask the user for their account number and CPNI, Then use verify_customer function to verify the customer . If the account number and CPNI are incorrect after 4 attempts, continue.
## Step 2
Perform a speed test and give the results from speed_test function then give the results.
## Step 3
Check modem levels with modem_diagnostics function and give the results.
## Step 4
Check modem SNR with modem_diagnostics function and give the results.
## Step 5
Ask the customer if there is anything else you can help them with.
## Step 6
End all calls with saying "Thank you for choosing Livewire."
# Your name is Zen. You speak English.
# Personality and Introduction
You are a witty assistant who likes to make light of every situation but is very dedicated to helping people. You are Zen and work for the local cable company Livewire. Greet the user with that information.
# Your Skills, Knowledge, and Behavior
## Reboot Modem
This will reboot the modem.
## Check Modem
Check if the modem is online or offline.
## Modem Speed Test
This will perform a speed test from the modem to a speed test site with speed_test function.
## Modem Speed Subscription
The customer subscribes to 1 gigabit download and 75 megabits upload.
## Modem Signal
The upstream can be between 40db and 50db. The downstream can be between -10db and +10db.
## SNR
SNR is signal-to-noise ratio. A good SNR is 30db to 40db.
## Swap Modem
Be sure to ask for new mac address. Read back to the provided mac address to verify it's accuracy. If the user verifies it is correct then use swap_modem function.
## Transfer Calls
You are able to transfer calls to the following destinations: Sales, Supervisor, Freeswitch, External.
## Customer Verification
You are able to verify customer first name, last name, cpni, account number and phone number with verify_customer function.
# Conversation Flow
These are the steps you need to follow during this conversation. Ensure you are strictly following the steps below in order.
## Step 1
Ask the user for their account number and CPNI, Then use verify_customer function to verify the customer . If the account number and CPNI are incorrect after 4 attempts, continue.
## Step 2
Perform a speed test and give the results from speed_test function then give the results.
## Step 3
Check modem levels with modem_diagnostics function and give the results.
## Step 4
Check modem SNR with modem_diagnostics function and give the results.
## Step 5
Ask the customer if there is anything else you can help them with.
## Step 6
End all calls with saying "Thank you for choosing Livewire."
# Your name is Zen. You speak English.
# Personality and Introduction
You are a witty assistant who likes to make light of every situation but is very dedicated to helping people. You are Zen and work for the local cable company Livewire. Greet the user with that information.
# Your Skills, Knowledge, and Behavior
## Reboot Modem
This will reboot the modem.
## Check Modem
Check if the modem is online or offline.
## Modem Speed Test
This will perform a speed test from the modem to a speed test site with speed_test function.
## Modem Speed Subscription
The customer subscribes to 1 gigabit download and 75 megabits upload.
## Modem Signal
The upstream can be between 40db and 50db. The downstream can be between -10db and +10db.
## SNR
SNR is signal-to-noise ratio. A good SNR is 30db to 40db.
## Swap Modem
Be sure to ask for new mac address. Read back to the provided mac address to verify it's accuracy. If the user verifies it is correct then use swap_modem function.
## Transfer Calls
You are able to transfer calls to the following destinations: Sales, Supervisor, Freeswitch, External.
## Customer Verification
You are able to verify customer first name, last name, cpni, account number and phone number with verify_customer function.
# Conversation Flow
These are the steps you need to follow during this conversation. Ensure you are strictly following the steps below in order.
## Step 1
Ask the user for their account number and CPNI, Then use verify_customer function to verify the customer . If the account number and CPNI are incorrect after 4 attempts, continue.
## Step 2
Perform a speed test and give the results from speed_test function then give the results.
## Step 3
Check modem levels with modem_diagnostics function and give the results.
## Step 4
Check modem SNR with modem_diagnostics function and give the results.
## Step 5
Ask the customer if there is anything else you can help them with.
## Step 6
End all calls with saying "Thank you for choosing Livewire."
Functions
This example requires some code in order for Zen to perform functions such as speed tests and modem swaps. Functions in this example will connect to a database and pull data with a json output.
Once the function verify_customer is executed by the user verifying the account_number and cpni then the record for that customer can be used later. The prompt for this example won't allow any further steps to happen unless verify_customer is validated.
verify_customer
Name: verify_customer
Purpose: Verify customer account number, cpni first, last name and phone number
Argument: account_number|7 digit number,cpni|4 digit number
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $dbh = DBI->connect(
"dbi:Pg:dbname=$database;host=$host;port=$port",
$dbusername,
$dbpassword,
{ AutoCommit => 1, RaiseError => 1 } ) or die "Couldn't execute statement: $DBI::errstr\n";
my $sql = "SELECT * FROM customers WHERE account_number = ? AND cpni = ? LIMIT 1";
my $sth = $dbh->prepare( $sql );
$sth->bind_param(1,$data->{account_number});
$sth->bind_param(2,$data->{cpni});
$sth->execute() or die "Couldn't execute statement: $DBI::errstr";
my $agents = $sth->fetchrow_hashref;
if ($data->{account_number} eq $agents->{account_number} && $data->{cpni} eq $agents->{cpni}) {
$res->body( $swml->swaig_response_json( { response => "Account verified, proceed", action => [ { set_meta_data => { customer => $agents } } ] } ) );
} else {
$res->body( $swml->swaig_response_json( { response => "Account invalid try again" } ) ) ;
}
return $res
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $dbh = DBI->connect(
"dbi:Pg:dbname=$database;host=$host;port=$port",
$dbusername,
$dbpassword,
{ AutoCommit => 1, RaiseError => 1 } ) or die "Couldn't execute statement: $DBI::errstr\n";
my $sql = "SELECT * FROM customers WHERE account_number = ? AND cpni = ? LIMIT 1";
my $sth = $dbh->prepare( $sql );
$sth->bind_param(1,$data->{account_number});
$sth->bind_param(2,$data->{cpni});
$sth->execute() or die "Couldn't execute statement: $DBI::errstr";
my $agents = $sth->fetchrow_hashref;
if ($data->{account_number} eq $agents->{account_number} && $data->{cpni} eq $agents->{cpni}) {
$res->body( $swml->swaig_response_json( { response => "Account verified, proceed", action => [ { set_meta_data => { customer => $agents } } ] } ) );
} else {
$res->body( $swml->swaig_response_json( { response => "Account invalid try again" } ) ) ;
}
return $res
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $dbh = DBI->connect(
"dbi:Pg:dbname=$database;host=$host;port=$port",
$dbusername,
$dbpassword,
{ AutoCommit => 1, RaiseError => 1 } ) or die "Couldn't execute statement: $DBI::errstr\n";
my $sql = "SELECT * FROM customers WHERE account_number = ? AND cpni = ? LIMIT 1";
my $sth = $dbh->prepare( $sql );
$sth->bind_param(1,$data->{account_number});
$sth->bind_param(2,$data->{cpni});
$sth->execute() or die "Couldn't execute statement: $DBI::errstr";
my $agents = $sth->fetchrow_hashref;
if ($data->{account_number} eq $agents->{account_number} && $data->{cpni} eq $agents->{cpni}) {
$res->body( $swml->swaig_response_json( { response => "Account verified, proceed", action => [ { set_meta_data => { customer => $agents } } ] } ) );
} else {
$res->body( $swml->swaig_response_json( { response => "Account invalid try again" } ) ) ;
}
return $res
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $dbh = DBI->connect(
"dbi:Pg:dbname=$database;host=$host;port=$port",
$dbusername,
$dbpassword,
{ AutoCommit => 1, RaiseError => 1 } ) or die "Couldn't execute statement: $DBI::errstr\n";
my $sql = "SELECT * FROM customers WHERE account_number = ? AND cpni = ? LIMIT 1";
my $sth = $dbh->prepare( $sql );
$sth->bind_param(1,$data->{account_number});
$sth->bind_param(2,$data->{cpni});
$sth->execute() or die "Couldn't execute statement: $DBI::errstr";
my $agents = $sth->fetchrow_hashref;
if ($data->{account_number} eq $agents->{account_number} && $data->{cpni} eq $agents->{cpni}) {
$res->body( $swml->swaig_response_json( { response => "Account verified, proceed", action => [ { set_meta_data => { customer => $agents } } ] } ) );
} else {
$res->body( $swml->swaig_response_json( { response => "Account invalid try again" } ) ) ;
}
return $res
Meta data functions
meta_data functions access the output of an already executed function. In this example once the function verify_customer is executed by the user by verifying account_number and cpni, then the record for that customer is accessible via json for any meta_data functions.
modem_swap
Name: modem_swap
Purpose: Swap the users modem
Argument: mac_address|new modem MAC Address in lowercase hex 12 characters
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $customer = $post_data->{meta_data}->{customer};
sub is_valid_mac_address {
my ($mac) = @_;
my $mac_regex = qr/^([0-9A-Fa-f]{2}(:|-)?){5}[0-9A-Fa-f]{2}$/;
return $mac =~ $mac_regex;
}
my $dbh = DBI->connect(
"dbi:Pg:dbname=$database;host=$host;port=$port",
$dbusername,
$dbpassword,
{ AutoCommit => 1, RaiseError => 1 } ) or die "Couldn't execute statement: $DBI::errstr\n";
if ( is_valid_mac_address($data->{mac_address}) ) {
my $update_sql = "UPDATE customers SET mac_address = ? WHERE account_number = ?";
my $update_sth = $dbh->prepare( $update_sql );
$update_sth->bind_param(1, $data->{mac_address});
$update_sth->bind_param(2, $customer->{account_number});
$update_sth->execute() or die "Couldn't execute statement: $DBI::errstr";
$update_sth->finish;
my $select_sql = "SELECT * FROM customers WHERE account_number = ? LIMIT 1";
my $select_sth = $dbh->prepare( $select_sql );
$select_sth->bind_param(1, $customer->{account_number} );
$select_sth->execute() or die "Couldn't execute statement: $DBI::errstr";
my $agents = $select_sth->fetchrow_hashref;
$select_sth->finish;
if (lc $agents->{mac_address} eq lc $data->{mac_address} ) {
$res->body( $swml->swaig_response_json( { response => "Customers modem mac address updated, please allow 5 minutes for all systems to update and plug in your new modem.", action => [ { set_meta_data => { customer => $agents } } ] } ) );
broadcast_by_agent_id( $agent, $agents );
} else {
$res->body( $swml->swaig_response_json( { response => "Error swapping modem, mac address may be invalid, try again. #1" } ) );
}
} else {
$res->body( $swml->swaig_response_json( { response => "Error swapping modem, mac address may be invalid, try again later. #2" } ) );
}
return $res
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $customer = $post_data->{meta_data}->{customer};
sub is_valid_mac_address {
my ($mac) = @_;
my $mac_regex = qr/^([0-9A-Fa-f]{2}(:|-)?){5}[0-9A-Fa-f]{2}$/;
return $mac =~ $mac_regex;
}
my $dbh = DBI->connect(
"dbi:Pg:dbname=$database;host=$host;port=$port",
$dbusername,
$dbpassword,
{ AutoCommit => 1, RaiseError => 1 } ) or die "Couldn't execute statement: $DBI::errstr\n";
if ( is_valid_mac_address($data->{mac_address}) ) {
my $update_sql = "UPDATE customers SET mac_address = ? WHERE account_number = ?";
my $update_sth = $dbh->prepare( $update_sql );
$update_sth->bind_param(1, $data->{mac_address});
$update_sth->bind_param(2, $customer->{account_number});
$update_sth->execute() or die "Couldn't execute statement: $DBI::errstr";
$update_sth->finish;
my $select_sql = "SELECT * FROM customers WHERE account_number = ? LIMIT 1";
my $select_sth = $dbh->prepare( $select_sql );
$select_sth->bind_param(1, $customer->{account_number} );
$select_sth->execute() or die "Couldn't execute statement: $DBI::errstr";
my $agents = $select_sth->fetchrow_hashref;
$select_sth->finish;
if (lc $agents->{mac_address} eq lc $data->{mac_address} ) {
$res->body( $swml->swaig_response_json( { response => "Customers modem mac address updated, please allow 5 minutes for all systems to update and plug in your new modem.", action => [ { set_meta_data => { customer => $agents } } ] } ) );
broadcast_by_agent_id( $agent, $agents );
} else {
$res->body( $swml->swaig_response_json( { response => "Error swapping modem, mac address may be invalid, try again. #1" } ) );
}
} else {
$res->body( $swml->swaig_response_json( { response => "Error swapping modem, mac address may be invalid, try again later. #2" } ) );
}
return $res
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $customer = $post_data->{meta_data}->{customer};
sub is_valid_mac_address {
my ($mac) = @_;
my $mac_regex = qr/^([0-9A-Fa-f]{2}(:|-)?){5}[0-9A-Fa-f]{2}$/;
return $mac =~ $mac_regex;
}
my $dbh = DBI->connect(
"dbi:Pg:dbname=$database;host=$host;port=$port",
$dbusername,
$dbpassword,
{ AutoCommit => 1, RaiseError => 1 } ) or die "Couldn't execute statement: $DBI::errstr\n";
if ( is_valid_mac_address($data->{mac_address}) ) {
my $update_sql = "UPDATE customers SET mac_address = ? WHERE account_number = ?";
my $update_sth = $dbh->prepare( $update_sql );
$update_sth->bind_param(1, $data->{mac_address});
$update_sth->bind_param(2, $customer->{account_number});
$update_sth->execute() or die "Couldn't execute statement: $DBI::errstr";
$update_sth->finish;
my $select_sql = "SELECT * FROM customers WHERE account_number = ? LIMIT 1";
my $select_sth = $dbh->prepare( $select_sql );
$select_sth->bind_param(1, $customer->{account_number} );
$select_sth->execute() or die "Couldn't execute statement: $DBI::errstr";
my $agents = $select_sth->fetchrow_hashref;
$select_sth->finish;
if (lc $agents->{mac_address} eq lc $data->{mac_address} ) {
$res->body( $swml->swaig_response_json( { response => "Customers modem mac address updated, please allow 5 minutes for all systems to update and plug in your new modem.", action => [ { set_meta_data => { customer => $agents } } ] } ) );
broadcast_by_agent_id( $agent, $agents );
} else {
$res->body( $swml->swaig_response_json( { response => "Error swapping modem, mac address may be invalid, try again. #1" } ) );
}
} else {
$res->body( $swml->swaig_response_json( { response => "Error swapping modem, mac address may be invalid, try again later. #2" } ) );
}
return $res
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $customer = $post_data->{meta_data}->{customer};
sub is_valid_mac_address {
my ($mac) = @_;
my $mac_regex = qr/^([0-9A-Fa-f]{2}(:|-)?){5}[0-9A-Fa-f]{2}$/;
return $mac =~ $mac_regex;
}
my $dbh = DBI->connect(
"dbi:Pg:dbname=$database;host=$host;port=$port",
$dbusername,
$dbpassword,
{ AutoCommit => 1, RaiseError => 1 } ) or die "Couldn't execute statement: $DBI::errstr\n";
if ( is_valid_mac_address($data->{mac_address}) ) {
my $update_sql = "UPDATE customers SET mac_address = ? WHERE account_number = ?";
my $update_sth = $dbh->prepare( $update_sql );
$update_sth->bind_param(1, $data->{mac_address});
$update_sth->bind_param(2, $customer->{account_number});
$update_sth->execute() or die "Couldn't execute statement: $DBI::errstr";
$update_sth->finish;
my $select_sql = "SELECT * FROM customers WHERE account_number = ? LIMIT 1";
my $select_sth = $dbh->prepare( $select_sql );
$select_sth->bind_param(1, $customer->{account_number} );
$select_sth->execute() or die "Couldn't execute statement: $DBI::errstr";
my $agents = $select_sth->fetchrow_hashref;
$select_sth->finish;
if (lc $agents->{mac_address} eq lc $data->{mac_address} ) {
$res->body( $swml->swaig_response_json( { response => "Customers modem mac address updated, please allow 5 minutes for all systems to update and plug in your new modem.", action => [ { set_meta_data => { customer => $agents } } ] } ) );
broadcast_by_agent_id( $agent, $agents );
} else {
$res->body( $swml->swaig_response_json( { response => "Error swapping modem, mac address may be invalid, try again. #1" } ) );
}
} else {
$res->body( $swml->swaig_response_json( { response => "Error swapping modem, mac address may be invalid, try again later. #2" } ) );
}
return $res
speed_test
Name: speed_test
Purpose: Test upload and download speed from the modem
Argument: account_number|7 digit number,cpni|4 digit number
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $customer = $post_data->{meta_data}->{customer};
if ($customer->{modem_speed_upload} && $customer->{modem_speed_download}) {
$res->body( $swml->swaig_response_json( { response => "Tell the user here are the test results. Download speed: $customer->{modem_speed_download}, Upload speed: $customer->{modem_speed_upload}" } ) );
} else {
$res->body( $swml->swaig_response_json( { response => "Invalid try again speed_test" } ) );
}
return $res
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $customer = $post_data->{meta_data}->{customer};
if ($customer->{modem_speed_upload} && $customer->{modem_speed_download}) {
$res->body( $swml->swaig_response_json( { response => "Tell the user here are the test results. Download speed: $customer->{modem_speed_download}, Upload speed: $customer->{modem_speed_upload}" } ) );
} else {
$res->body( $swml->swaig_response_json( { response => "Invalid try again speed_test" } ) );
}
return $res
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $customer = $post_data->{meta_data}->{customer};
if ($customer->{modem_speed_upload} && $customer->{modem_speed_download}) {
$res->body( $swml->swaig_response_json( { response => "Tell the user here are the test results. Download speed: $customer->{modem_speed_download}, Upload speed: $customer->{modem_speed_upload}" } ) );
} else {
$res->body( $swml->swaig_response_json( { response => "Invalid try again speed_test" } ) );
}
return $res
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $customer = $post_data->{meta_data}->{customer};
if ($customer->{modem_speed_upload} && $customer->{modem_speed_download}) {
$res->body( $swml->swaig_response_json( { response => "Tell the user here are the test results. Download speed: $customer->{modem_speed_download}, Upload speed: $customer->{modem_speed_upload}" } ) );
} else {
$res->body( $swml->swaig_response_json( { response => "Invalid try again speed_test" } ) );
}
return $res
modem_diagnostics
Name: modem_diagnostics
Purpose: customer modem upstream downstream and snr levels
Argument: account_number|7 digit number,cpni|4 digit number
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $customer = $post_data->{meta_data}->{customer};
if ($customer) {
$res->body( $swml->swaig_response_json( { response => "Tell the user here are the test results. Downstream level: $customer->{modem_downstream_level}, Upstream level: $customer->{modem_upstream_level}, Modem SNR: $customer->{modem_snr}" } ) );
} else {
$res->body( $swml->swaig_response_json( { response => "Invalid try again. Use modem-diagnostics-function" } ) );
}
return $res
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $customer = $post_data->{meta_data}->{customer};
if ($customer) {
$res->body( $swml->swaig_response_json( { response => "Tell the user here are the test results. Downstream level: $customer->{modem_downstream_level}, Upstream level: $customer->{modem_upstream_level}, Modem SNR: $customer->{modem_snr}" } ) );
} else {
$res->body( $swml->swaig_response_json( { response => "Invalid try again. Use modem-diagnostics-function" } ) );
}
return $res
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $customer = $post_data->{meta_data}->{customer};
if ($customer) {
$res->body( $swml->swaig_response_json( { response => "Tell the user here are the test results. Downstream level: $customer->{modem_downstream_level}, Upstream level: $customer->{modem_upstream_level}, Modem SNR: $customer->{modem_snr}" } ) );
} else {
$res->body( $swml->swaig_response_json( { response => "Invalid try again. Use modem-diagnostics-function" } ) );
}
return $res
my $env = shift;
my $req = Plack::Request->new( $env );
my $swml = SignalWire::ML->new;
my $post_data = decode_json( $req->raw_body );
my $data = $post_data->{argument}->{parsed}->[0];
my $res = Plack::Response->new( 200 );
my $agent = $req->param( 'agent_id' );
my $customer = $post_data->{meta_data}->{customer};
if ($customer) {
$res->body( $swml->swaig_response_json( { response => "Tell the user here are the test results. Downstream level: $customer->{modem_downstream_level}, Upstream level: $customer->{modem_upstream_level}, Modem SNR: $customer->{modem_snr}" } ) );
} else {
$res->body( $swml->swaig_response_json( { response => "Invalid try again. Use modem-diagnostics-function" } ) );
}
return $res
Have any questions as you’re building an AI agent? Bring them to our community Discord!
Frequently asked questions
What is a “digital employee” for customer support?
A digital employee is an AI voice agent that answers support calls, gathers the information needed to diagnose an issue, and completes routine tasks like running checks, guiding troubleshooting steps, and routing calls to a human when escalation is needed.
What problems are AI voice agents best at solving in customer support?
AI voice agents are strongest at high-volume, repeatable workflows, including basic troubleshooting, status checks, appointment scheduling, capturing case details, and routing calls, especially when the agent can also take actions like sending messages or triggering backend functions.
How do you verify a caller before performing account-level actions?
Use a verification step before any sensitive troubleshooting or changes. In this example, verification uses an account number and Customer Proprietary Network Information (CPNI), and the flow blocks later steps unless verification succeeds.
What backend actions should an AI support agent be allowed to run?
Start with safe, reversible actions like running a speed test, checking modem diagnostics, and collecting line statistics, then expand cautiously to state-changing actions such as a modem swap, only after verification passes and guardrails are in place.
How do you connect an AI Agent to real support systems and data?
With SignalWire, define functions that query or update your systems, return structured JavaScript Object Notation (JSON), and constrain when those functions can run. This example uses functions for customer verification, speed tests, modem diagnostics, and modem swaps.
How do you keep an AI support flow predictable instead of free-form?
Use a staged troubleshooting flow, gate progression on verification, constrain the agent to specific steps, and limit the function set to approved actions so the agent cannot improvise unsafe behavior.