Ground and stream
The final step is the simplest one by design. You have retrieved chunks. You have a user question. You stitch them into a grounded prompt, call streamText with Gemini, and the UI already knows how to render the stream. The pipeline is complete.
export function createPromptTemplate(
userInput: string,
mergedRelatedDocs: string,
remoteUrl: string,
): string {
return `Based on this question asked by the user: \"${'$'}{userInput}\" and the current context: \"${'$'}{mergedRelatedDocs}\" retrieved from the webpage: \"${'$'}{remoteUrl}\",
I want you to answer the user's question.
If you don't know the answer, just say that you couldn't find any information related in the provided context.
Don't try to make enough information to answer, don't try to make up an answer.
Keep the answer as concise as possible.`;
}
export const systemPrompt = 'You are a helpful assistant. Answer the question asked by the user using as context the provided text retrieved from a web page';The template bakes in the refusal contract and the grounding context. Notice how system prompt and user prompt split responsibilities: persona in the system prompt, content in the user prompt.
import { streamText } from 'ai';
import { google } from '@ai-sdk/google';
import { createPromptTemplate, systemPrompt } from '@/lib/utils';
const template = createPromptTemplate(userInput, mergedRelatedDocs, remoteUrl);
const result = streamText({
model: google('gemini-2.5-flash'),
prompt: template,
system: systemPrompt,
});
return result.toUIMessageStreamResponse();Same streamText, same toUIMessageStreamResponse, same client. Only the prompt has changed. That is the whole promise of the Vercel AI SDK.
You can, but you lose signal. Gemini and most modern models treat the system prompt as persistent instruction and the user prompt as the turn. Splitting them lets the model weigh the persona differently from the immediate task. Concatenating often works, but splitting reliably leads to cleaner, more consistent behavior.
Quiz: Quiz
Loading practice…
AI prompt: Try it: redesign the grounded template
Loading practice…
Checkpoint: Custom pipeline checkpoint
Loading practice…