An AI agent is a model that can take actions. Instead of just generating text, it can call tools, evaluate results, and decide what to do next — in a loop until the task is complete.
Simple Agent
The simplest agent is generateText with tools and maxSteps:
import { generateText, tool } from "ai"
import { anthropic } from "@ai-sdk/anthropic"
import { z } from "zod"
const { text, steps } = await generateText({
model: anthropic("claude-sonnet-4-20250514"),
tools: {
searchWeb: tool({
description: "Search the web for information",
parameters: z.object({
query: z.string(),
}),
execute: async ({ query }) => {
// Your search implementation
return { results: ["..."] }
},
}),
getWeather: tool({
description: "Get current weather for a city",
parameters: z.object({
city: z.string(),
}),
execute: async ({ city }) => {
return { temp: 72, condition: "sunny" }
},
}),
},
maxSteps: 10,
prompt: "What's the weather in Tokyo? Also find recent news about Japan.",
})The model will:
- Decide which tool(s) to call
- Execute the tool(s)
- Read the results
- Decide if it needs more information (call more tools) or can respond
- Repeat until done or
maxStepsis reached
Agent Architecture
User Prompt
│
▼
┌─────────┐
│ Model │◄──── System prompt + tools
└─────────┘
│
├── Tool Call → Execute → Result ──┐
│ │
├── Tool Call → Execute → Result ──┤
│ │
▼ │
┌─────────┐ │
│ Model │◄──────────────────────────┘
└─────────┘
│
▼
Response
System Prompt Design
The system prompt is the most important part of an agent. It defines the agent's personality, capabilities, and constraints.
const systemPrompt = `You are a research assistant. Your job is to answer questions
by searching the web and analyzing the results.
## Rules
- Always search before answering factual questions
- Cite your sources
- If you can't find reliable information, say so
- Never make up facts
## Available Tools
- searchWeb: Search the internet for information
- readUrl: Read the full content of a URL
## Process
1. Break the question into sub-questions if needed
2. Search for each sub-question
3. Read the most relevant results
4. Synthesize an answer with citations`Streaming Agents
For user-facing agents, stream the response so users see progress:
import { streamText, tool } from "ai"
export async function POST(req: Request) {
const { messages } = await req.json()
const result = streamText({
model: anthropic("claude-sonnet-4-20250514"),
system: systemPrompt,
tools: { searchWeb, readUrl },
maxSteps: 5,
messages,
})
return result.toDataStreamResponse()
}On the client, useChat handles streaming automatically:
const { messages, input, handleSubmit } = useChat({
api: "/api/agent",
maxSteps: 5,
})Error Handling
Tools can fail. Handle errors gracefully so the agent can recover:
const searchTool = tool({
description: "Search the web",
parameters: z.object({ query: z.string() }),
execute: async ({ query }) => {
try {
const results = await searchApi(query)
return { success: true, results }
} catch (error) {
return { success: false, error: "Search failed. Try a different query." }
}
},
})Returning the error as a tool result (instead of throwing) lets the model decide how to proceed — it might retry with different parameters or use a different approach.
Related Patterns
- Agent Setup — basic agent configuration
- Routing Pattern — route to specialized agents
- Parallel Processing — run multiple agents concurrently
- Orchestrator-Worker — delegate subtasks (Pro)
- Tool Calling — tool fundamentals