Designing Routing Workflows
Introduction & Context
Welcome back! In the previous lesson, you learned how to use prompt chaining to connect multiple GPT-5 API calls in a linear sequence, breaking down complex tasks into manageable steps. This approach works well when you know exactly what sequence of operations is needed.
However, real-world applications often face unpredictable requests that require different types of expertise. Instead of building separate chains for every possible request, routing workflows use GPT-5 to analyze incoming requests and intelligently direct them to the right specialist — such as a math expert, a writing expert, or a code expert.
This lesson will show you how to build a flexible routing system that maintains high-quality responses by leveraging specialized developer prompts for each domain.
Workflow Design at a Glance
The routing workflow follows a clean two-step pattern that is more dynamic than the linear chains you have used before. When a user submits a request, your system first sends it to a router — a GPT-5 instance configured with a specialized developer prompt designed to classify the request type. The router analyzes the content and returns a decision about which specialist should handle it.
Once you have the routing decision, you send the original user request to a second GPT-5 instance configured with the appropriate specialist developer prompt. This specialist focuses entirely on providing the best possible response within their domain of expertise, whether that is solving equations, crafting stories, or debugging code.
The key insight here is that you are using the same OpenAI::Client and the same GPT-5 model for both calls, but with completely different developer messages that give each instance a distinct role and expertise. The router acts as a classifier, while the specialist acts as a domain expert. This separation of concerns makes your system both more reliable and easier to extend with new specialist types.
Crafting the Router Prompt
The router prompt is the critical component that determines how accurately your system classifies incoming requests. Unlike the open-ended prompts you might use for creative tasks, router prompts need to be strict and constrained to ensure reliable, parseable output.
In Ruby, you define the router prompt using a heredoc with <<~PROMPT, which produces a clean multi-line string without leading indentation issues:
The phrase Respond with ONLY is crucial because it prevents GPT-5 from adding explanatory text or reasoning that would complicate parsing the response. You want exactly one of three possible strings, and nothing more. The explicit list of specialist names (math_specialist, writing_specialist, or code_specialist) with their descriptions helps GPT-5 understand the boundaries between categories and reduces ambiguous classifications.
Notice how each specialist description focuses on clear, distinct domains. Mathematical problems are clearly different from creative writing, which is clearly different from programming tasks. This separation reduces edge cases where the router might struggle to choose between specialists.
This prompt string is passed to the API as a developer message inside the input array using the text_message helper — not through a separate parameter. It becomes the first element of input, followed by the user's message, which is the same role-based messaging pattern introduced in earlier lessons:
The developer role is how you configure the model's behavior and expertise in the Responses API.
Defining Specialist Developer Prompts
Each specialist needs a focused developer prompt that establishes their expertise and approach. Unlike general-purpose prompts, specialist developer prompts should be concise and role-specific to maximize performance within their domain.
In Ruby, you assign these as plain string variables. Each one will later be passed as a developer message in the input array when making the specialist API call. Your math_specialist_prompt emphasizes precision and clarity in mathematical communication:
The writing_specialist_prompt focuses on creativity and engaging communication:
The code_specialist_prompt emphasizes technical accuracy and practical implementation:
These prompts are intentionally brief because they need to work with a wide variety of requests within their domain. A math specialist might handle anything from basic arithmetic to complex calculus, so the prompt focuses on the general approach rather than specific techniques. This specialization improves both quality and consistency compared to using a generic "helpful assistant" prompt for all request types.
The beauty of this approach is reusability. Once you have crafted effective specialist developer prompts, you can use them across different projects and routing systems. They become reliable building blocks for more complex AI workflows.
Preparing and Sending the Router Request
To begin the routing workflow, you initialize the client, define the model and user_request, then send everything to the router in a single client.responses.create call:
The input array holds two messages: a developer message containing the router_prompt, and a user message containing the actual request to classify. Both are built with the text_message helper, which wraps each string in a typed content block (type: "input_text"). There is no separate parameter for instructions — the developer prompt and user message both go through input.
The reasoning: { effort: "minimal" } option is appropriate here because classification is a straightforward task that does not require deep logical analysis. Setting store: false prevents the conversation from being persisted for later retrieval; context is managed locally in your Ruby code.
Extracting and Handling the Router's Response
After the router call returns, you extract the specialist decision from output_text and strip any surrounding whitespace to ensure clean string matching in the next step:
The output_text method returns the plain text content from GPT-5's response, and .strip removes any leading or trailing whitespace. The puts call is useful for debugging and verifying that the router is making the correct classification. For the example request "Write me a very short story about robots", you should see:
This confirms that the router correctly identified the request as a creative writing task.
Mapping the Router Decision to a Specialist Prompt
Once you have the router's decision, you need to map it to the appropriate specialist developer prompt. In Ruby, this is cleanly expressed with a case...when...else expression. Because case is an expression in Ruby, you can assign its return value directly to specialist_prompt, keeping the code concise and readable:
Each when branch checks for an exact string match with the expected specialist names from your router_prompt and returns the corresponding developer prompt string. This approach is straightforward and easy to debug when routing decisions do not match expectations.
The else clause provides a crucial fallback mechanism. If the router returns an unexpected response — perhaps due to a prompt engineering issue or an edge case you did not anticipate — the system defaults to a generic helpful assistant prompt rather than crashing. This graceful degradation keeps your system functional even when routing does not work perfectly.
Sending the User Request to the Specialist
With the specialist_prompt selected, you send the original user_request to the chosen specialist in a second client.responses.create call. The structure mirrors the router call exactly, but now the developer message carries the specialist's focused expertise instead of the routing instructions:
Notice that you pass the original user_request to the specialist, not the router's response. The router's job was purely classification; the specialist needs to see the actual user question to provide a helpful answer. The developer message is now specialist_prompt — the string selected in the mapping step — which configures GPT-5 with the appropriate domain expertise through the same text_message typed content block structure used throughout the workflow.
Extracting and Displaying the Specialist's Response
Finally, extract the specialist's response from output_text and display it using puts. This is the answer that will be returned to the user:
The output_text method returns the complete response generated by the specialist. When you run this code with the robot story request, you should see output like:
This demonstrates that the writing specialist correctly understood the creative writing request and produced an engaging story rather than attempting to solve it as a math problem or write code.
Summary and Prep for Practice
You have successfully learned to implement intelligent task routing that uses GPT-5 to classify requests and direct them to specialized developer prompts optimized for specific domains. Your routing workflow follows a clean two-step pattern: send the request to a router configured with a developer message to get a classification decision, then send the original request to the appropriate specialist — also configured through a developer message — for the final response.
The key components of this workflow are the router developer prompt that constrains GPT-5 to return only specialist names, the specialist developer prompts that configure domain expertise, and the two-call pattern — which separates classification from response generation. By placing different developer messages as the first element of the input array in each client.responses.create call, you give the same model distinct roles and capabilities using the Ruby Responses API's role-based typed content block structure.
The routing patterns you have learned here form the foundation for much more sophisticated AI workflows. As you continue through this course, you will see how these routing concepts extend to dynamic workflows and complex agent behaviors that can handle real-world business problems with multiple types of expertise working together.
