The pattern we saw established in guardrails, where we add an extra LLM call before the main LLM call, can be used for many interesting applications.
One powerful implementation is a model router.
A model router allows us to choose which model we want to use based on the user's question. We can route requests through different LLMs depending on the complexity of the query.
Different LLMs have pricing at different orders of magnitude. If we can route simple requests to a simpler (and usually cheaper) LLM while still getting good responses, we should definitely do that.
Our setup is very similar to the previous exercise:
createUIMessageStreamconsole.time calls, we'll use generateText to call a modelconsole.time('Model Calculation Time');// TODO: Use generateText to call a model, passing in the modelMessages// and writing your own system prompt.const modelRouterResult = TODO;console.timeEnd('Model Calculation Time');
Since this routing needs to run as quickly as possible, we'll use the same technique we used in guardrails:
I recommend you use the prompt template we covered in an earlier section.
The output format section will be especially important - as will the rules, which will dictate which model to use under which circumstances.
Next, we'll need to fill in the modelSelected variable by determining which model to use from the model router result:
// TODO: Use the modelRouterResult to determine which model to use.// If we can't determine which model to use, use the basic model.const modelSelected: 'advanced' | 'basic' = TODO;
We also want to display which model was used in the frontend. To do this, we'll use message metadata.
writer.merge(streamTextResult.toUIMessageStream({// TODO: Add the model to the message metadata, so that// the frontend can display it.messageMetadata: TODO,}),);
We've already set up the MyMessage type to include a model property:
export type MyMessage = UIMessage<{model: 'advanced' | 'basic';}>;
And our Message component already has a metadata prop:
<Messagerole={message.role}parts={message.parts}metadata={message.metadata}/>
Inside the Message component, we can check for the model property and display it if it exists:
{metadata?.model && (<div className="text-sm text-gray-500 mt-1">Model: {metadata.model}</div>);}
So all you need to do is handle passing the model to the message metadata inside createUIMessageStream. The previous exercise on message metadata will be helpful.
Once your implementation is complete, you should be able to:
Try prompting your system with various different inputs to see how it chooses between the different models, and adjust your system prompt accordingly.