Skip to main content

Retool Agentic Workflow with Agent

The following lab demonstrates how to build an agentic workflow that at its heart uses an Agent to examine a support ticket and extract information relevant to the customer experience and issue that needs to be resolved.

Requirements

  • Retool Agents (Public Beta)
  • Retool Workflows + Multi-step function

Steps

In this example we will leverage an agent to extracting relevant content from support tickets to that a workflow can perform appropriate routing. This includes the issue type (lost bag | missed flight | change flight), traveler type (frequent flyer | standard traveler), and sentiment (positive | negative). The agent results are formatted and returned to the workflow for appropriate routing.

Architecturally, the following diagram shows the Retool Workflows integrating with Retool Agent and LLM provider.

Retool Workflows with Retool Agent
Retool Workflows with Retool Agent

In the image above we start with:

  1. A Parent Workflow that receives the traveler support issue. It initiates an Agent Workflow, providing the ticket details.
  2. The Agent Workflow takes the support issue, uses a multi-step function and code block to initiate the New England Air Agent. This agent executes asynchronously and the Agent Workflow polls to see when the agent is complete and extracts the Agent results.
  3. The New England Air Agent uses a reasoning model (e.g. OpenAI, Anthropic) to interact and extract traveler issue, traveler type, and sentiment.
  4. The Agent Workflow receives information that the Agent is complete and collects the response.
  5. The Parent Workflow receives the Agent Workflow response and uses this information to perform intelligent routing.

To begin this lab we are going to work our way from the Agent. We will then develop the Agent Workflow and finish off with the Parent Workflow.

Create Agent

In the first step we develop an Agent that is able to take ticket samples and extract the issue type, traveler type, and sentiment.

  • Select Retool Home > Agents(Beta) > New Agent > Start from scratch.
  • Enter a name New England Airlines Agent, specify the airplane icon, and a color blue.
Agent setup
Agent setup
  • Next we want to use the Configuration Assistant to prompt what the agent will perform and prescriptively create Tools.
I need you to examine a support ticket's content for routing the ticket appropriately. 
Tickets may or may not include information such as traveler type (frequent flyer | standard traveler)
and issue type (lost baggage | missed flight | change flight). In addition we would like to determine
the sentiment of the support ticket (positive | negative). Please return the results of this analysis in JSON format only, with no explanation for example:
{"traveler_type":"frequent_flyer", "issue_type":"lost_baggage","sentiment":"negative"}
Agent configuration and tool
Agent configuration and tool
  • The above prompt will identify a singular tool that will be used to perform the analysis and return a result.
  • Select Finish Up to create the tool.
  • In Function Generator provide the following prompt:
Create a tool that can process the ticket_content and extract content from the ticket such as traveler type (frequent flyer | standard traveler), issue type (lost baggage | missed flight | change flight), and sentiment of the support ticket (positive | negative). Please return the results of this analysis in JSON format, for example:  
{"traveler_type":"frequent_flyer", "issue_type":"lost_baggage","sentiment":"negative"}
  • Function generator will recommend the following for the tool:
Function generator
Function generator
  • Selecting Accept and Overwrite will create a completed tool as shown in the following image.
Completed tool
Completed tool
  • You can provide various ticket_content examples and Test Function to see if results categorize the traveler, issue and sentiment. The following is a sample ticket:
"I have missed my flight and need someone to help me! Your plane was late due to mechanical failure and I am an exclusive frequent flyer on Air New England! This shouldn't be happening. Maybe I should switch to Nantucket Air!"
  • Selecting Test Function, will run the Tool and you can examine the result against different tickets. The following image shows the example provided:
Test function
Test function
  • Once satisified, select Done to save the Function logic.
  • Select Save to capture the final tool.
Save tool
Save tool

Create Agent Workflow

With the agent completed, we develop a workflow that invokes the agent, polls for the results, and results a JSON payload. The following image shows the completed workflow that we will build:

Agent workflow
Agent workflow

Be aware that Agents when invoked can take 10-20+ seconds to complete. Due to this, when using Workflows, increasing the timeout settings when invoking an Agent or Workflow may be required. The samples below used 30s timeout settings.

Multi-step function to get Agent logs

We will first create a multi-step function in Workflows to get the Agent logs by passing in the agentRunId.

  • Select Functions > +
  • Rename function to getAgentLogs.
  • Select + Add parameter and create agentRunId and agentId.
  • Select Type set to Multi-step.
Multi-step function to get agent logs
Multi-step function to get agent logs
  • For the function steps, a param block with agentRunId and agentId is setup by default.
  • Next we add a Retool Agents block. Set the Agent to New England Airlines agent created in the previous section.
    • Set Input Mode to JSON.
    • Specify in the Agent Inputs text area:
    {
    "action" : "getLogs",
    "agentRunId" : {{ params.agentRunId }}
    }
  • Finally we have a Response block. The Return body is set to:
requestAgentLogs.data

The following image shows the completed multi-step function.

Multi-step function setup
Multi-step function setup

Agent Workflow

Now we will move to finishing off the Agent Workflow by adding an Invoke Agent block and connecting it to the startTrigger.

  • Rename the block to invokeAirlineAgent.
  • Agent set to New England Airlines agent.
  • Input mode kept at JSON.
  • Agent inputs is set to:
{
"action": "invoke",
"messages": [
{
"role": "user",
"content": {{ startTrigger.data.ticket }}
}
]
}
  • Next select the circle on the upper right of the invokeAirlineAgent block and create a Code block, named pollForAgentLogs.

This code block will use the multi-step function created previously and polling to pull in the agent response. Within the code block enter the following sample.

// Defines the polling interval (500ms), the max number of attempts (30), and the statuses that indicate the agent is still running (PENDING, IN_PROGRESS).
const SLEEP_DURATION_IN_MS = 500;
const MAX_ITERATIONS = 30;
const AGENT_PENDING_STATUSES = ["PENDING", "IN_PROGRESS"];

// A utility function that returns a promise which resolves after 500ms (used for pausing between polls).
const sleep = () => new Promise(resolve => setTimeout(resolve, SLEEP_DURATION_IN_MS));

// Extracts the agentId and agentRunId from the invokeAgent block. Initializes latestAgentStatus as "PENDING". latestAgentLogs will store the last retrieved logs, and iterations tracks the number of attempts.
const { agentId, agentRunId } = invokeAirlineAgent.data;
let latestAgentStatus = "PENDING"; // Initial assumption
let latestAgentLogs;
let iterations = 1;

// Keeps polling as long as the agent is in a pending state and hasn’t exceeded the maximum attempts.
while (AGENT_PENDING_STATUSES.includes(latestAgentStatus) && iterations <= MAX_ITERATIONS) {
console.log(`Beginning iteration ${iterations}/${MAX_ITERATIONS}`);

try {
// Call the multi-step function
const agentLogs = await getAgentLogs(agentRunId, agentId);
console.log({ agentLogs });
latestAgentStatus = agentLogs.data.status;
latestAgentLogs = agentLogs;
} catch (err) {
throw new Error(`Failed to fetch agent logs on iteration ${iterations}: ${err.message}`);
}

// If still pending, wait before the next iteration. If not, exit the loop early.
if (AGENT_PENDING_STATUSES.includes(latestAgentStatus)) {
await sleep();
} else {
break;
}
iterations += 1;
}

// If the status is still not complete after 30 tries, throw an error.
if (AGENT_PENDING_STATUSES.includes(latestAgentStatus)) {
throw new Error(`Agent status is still ${latestAgentStatus} after 30 polling ${MAX_ITERATIONS} attempts.`);
}

// Return the agent response.
return latestAgentLogs;
  • Finally we have a Response block that returns the status, resultText, and fullLogsResponse.
{
status: pollForAgentLogs.data?.data?.status,
resultText: pollForAgentLogs.data?.data?.resultText,
fullLogsResponse: pollForAgentLogs.data
}

This should result in the following workflow:

Agent Workflow
Agent Workflow

Create Parent Routing Workflow

In this step, we create the parent workflow that will initiate the Agent workflow and take the results to then intelligently route to either an escalated path or standard path. Below is an image of the completed workflow we will build:

Parent Workflow
Parent Workflow

Invoke Agent Workflow

To invoke the Agent workflow, we use a Workflow block.

  • Create a workflow block by selecting startTrigger circle, specify Workflow block.
  • Within the Workflow block, rename it to invokeAgentWorkflowWithAgent.
  • Update the block to the following settings:
    • Select Workflow: Frequent Flyer Agent Workflow with Agent
    • Run until Finished
    • Parameters set to Raw
    {{startTrigger.data}}

Extract JSON from Agent Workflow response

Next we want to take the Agent workflow result and format into JSON

  • Add a Code block to the right of the invokeAgentWorkflowWithAgent and name it extractJSON.
  • Paste the following JavaScript code:
let agentResponse = invokeAgentWorkflowWithAgent.data.resultText;
console.log(agentResponse);
const jsonPayload = JSON.parse(agentResponse.replace(/'/g, '"'));
return jsonPayload;

Route support ticket using Agent workflow response

Once the results are returned to the parent workflow, we have a JSON object that we can branch on through defining different conditional statements.

  • Add a Branch block to the right of extractJSON.
  • For the If path, enter the following JavaScript code, note the use of toLowerCase() to resolve issues with inputs that come in different cases from LLM.
extractJSON.data.traveler_type.toLowerCase() == "frequent_flyer" && extractJSON.data.sentiment.toLowerCase() == "negative"

Below is the completed workflow:

Parent workflow
Parent workflow

NOTE: If you run into routing issues, confirm what is being returned by the Agent JSON response. The attributes (e.g., traveler_type, sentiment) that you are performing a conditional check on must equal the names of the these attributes along with the corresponding values (e.g., frequent_flyer, negative).

Next we want to print for the escalatedPath and standardPath.

  • Add a Code block to the right of the routeSupportRequest and rename to escalatedPath.
  • Enter the following code:
let response = "Escalating this request to make sure your frequent flyer experience is positive. We will contact you regarding " + extractJSON.data.issue_type + ".";
return response;
  • Add a Code block to the right of the routeSupportRequest and rename to standardPath.
  • Enter the following code:
let response = "That you for informing us about " + extractJSON.data.issue_type + ". We will be contacting you as soon as our agent is available";
return response;

Here is a closer view of the workflow blocks:

Branch block and Code blocks for elevated and standard paths
Branch block and Code blocks for elevated and standard paths

Completed Examples

You can import the following examples and compare with what you have built.

Summary

This lab demonstrates the use of a Retool Agent / LLM reasoning being used to route support tickets within Retool Workflows.