---
title: Build an AI Chat Agent with Weather API Tool Calling
description: Build an intelligent conversational agent that fetches real-time weather data using the AI SDK, tool calling, and a backend weather API powered by Express, FastAPI or Nitro
url: /kb/guide/build-ai-agent-weather-api
canonical_url: "https://vercel.com/kb/guide/build-ai-agent-weather-api"
last_updated: 2026-06-15
authors: Ismael Rumzan
related:
  - /docs/ai-gateway
  - /docs/ai-gateway/authentication
  - /docs/vercel-firewall/vercel-waf/rate-limiting-sdk
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

In this tutorial, you will build and deploy an AI chat agent using Next.js and the AI SDK that:

- Engages in natural conversations with users about the weather
  
- Automatically calls a weather API tool when users ask about weather conditions
  
- Streams responses in real-time for a smooth user experience
  
- Integrates with a backend weather service built with Express, FastAPI, or Nitro
  

## Prerequisites

- Node.js and pnpm installed locally
  
- A Vercel account and project with [AI Gateway access](https://vercel.com/docs/ai-gateway)
  
- AI Gateway authentication with an [OIDC token](https://vercel.com/docs/ai-gateway/authentication#setting-up-oidc-authentication) configured with your Vercel project or an [AI Gateway API key](https://vercel.com/docs/ai-gateway/authentication#creating-an-api-key)
  
- One of the backend weather APIs running (Express, FastAPI, or Nitro)
  
- Basic understanding of Next.js and React
  

## Build the Chat Agent

### 1\. Create your Next.js project

Initialize a new Next.js project with the App Router:

`pnpm create next-app@latest nextjs-agent`

When prompted, select the following options:

- TypeScript: Yes
  
- ESLint: Yes
  
- Tailwind CSS: Yes
  
- App Router: Yes
  
- Use `src/` directory: No
  
- Import alias: No
  

Navigate to your project directory with `cd nextjs-agent`

### 2\. Install dependencies

Install the AI SDK and required packages:

`pnpm i ai @ai-sdk/react zod react-markdown`

These packages provide:

- `ai`: Core AI SDK with agent and tool calling capabilities (version 5 required)
  
- `@ai-sdk/react`: React hooks for streaming chat interfaces (version 2 required)
  
- `zod`: Schema validation for tool inputs
  
- `react-markdown`: Render formatted responses in the chat UI
  

### 3\. Configure AI Gateway authentication

Option 1: Use your [Vercel project's OIDC token](https://vercel.com/docs/ai-gateway/authentication#oidc-token)

Link your code to a Vercel project and pull the environment variables

`vercel link vercel env pull`

Option 2: Create an AI Gateway API key

Go to your [Vercel team's AI Gateway API keys dashboard](https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%2Fapi-keys&title=Go+to+AI+Gateway+API+keys) and create an API key. Create a `.env.local` file in your project root with your AI Gateway key:

`AI_GATEWAY_KEY=your_ai_gateway_key_here`

### 4\. Create the agent with weather tool

Create `lib/agent.ts` and add the agent configuration with a weather tool:

``import { Experimental_Agent as Agent, Experimental_InferAgentUIMessage as InferAgentUIMessage, stepCountIs, tool, } from 'ai'; import { z } from 'zod'; export const weatherAgent = new Agent({ model: 'openai/gpt-5', system: 'You are a helpful weather assistant. Use the getWeather tool to fetch current weather information for cities.', tools: { getWeather: tool({ description: 'Get the current weather for a city', inputSchema: z.object({ city: z.string().describe('The city name to get weather for'), }), execute: async ({ city }) => { try { const response = await fetch( `http://localhost:3001/api/weather/${encodeURIComponent(city)}` ); if (!response.ok) { throw new Error(`Failed to fetch weather: ${response.statusText}`); } const data = await response.json(); return data; } catch (error) { return { error: `Unable to fetch weather data for ${city}. Make sure the weather API is running on port 3001.`, }; } }, }), }, stopWhen: stepCountIs(10), }); export type WeatherAgentUIMessage = InferAgentUIMessage<typeof weatherAgent>;``

This agent is configured as follows:

- Uses `GPT-5` as the underlying model
  
- Defines a `getWeather` tool that calls your backend weather API
  
- Uses `Zod` schema validation for type-safe tool inputs
  
- Includes error handling for API failures
  
- Limits the agent to 10 reasoning steps to prevent infinite loops
  

### 5\. Create the API route

Create `app/api/chat/route.ts` to handle agent requests:

`import { weatherAgent } from '@/lib/agent'; export async function POST(request: Request) { const body = await request.json(); // Chat interface using agent.respond() return weatherAgent.respond({ messages: body.messages, }); }`

The `respond()` method handles the complete agent workflow:

- Processes conversation history
  
- Determines when to call tools
  
- Streams responses back to the client
  
- Manages multi-turn conversations
  

### 6\. Build the chat UI

Update `app/page.tsx` to create an interactive chat interface:

``'use client'; import { useChat } from '@ai-sdk/react'; import { DefaultChatTransport } from 'ai'; import { useState } from 'react'; import ReactMarkdown from 'react-markdown'; export default function Page() { const { messages, sendMessage, status } = useChat({ transport: new DefaultChatTransport({ api: '/api/chat', }), }); const [input, setInput] = useState(''); return ( <div style={{ display: 'flex', flexDirection: 'column', height: '100vh', backgroundColor: '#ffffff', color: '#000000', fontFamily: 'system-ui, sans-serif', }} > <div style={{ padding: '16px', borderBottom: '1px solid #e5e5e5', display: 'flex', alignItems: 'center', gap: '12px', }} > <h1 style={{ margin: 0, fontSize: '18px', fontWeight: '600' }}> Weather Agent </h1> </div> <div style={{ flex: 1, overflowY: 'auto', padding: '16px', display: 'flex', flexDirection: 'column', gap: '12px', }} > {messages.map(message => ( <div key={message.id} style={{ display: 'flex', justifyContent: message.role === 'user' ? 'flex-end' : 'flex-start', }} > <div style={{ maxWidth: '80%', padding: '12px 16px', borderRadius: '16px', backgroundColor: message.role === 'user' ? '#f0f0f0' : 'transparent', }} > {message.parts.map((part, index) => part.type === 'text' ? ( <div key={index}> <ReactMarkdown components={{ p: ({ children }: any) => ( <p style={{ margin: '0 0 8px 0' }}>{children}</p> ), ul: ({ children }: any) => ( <ul style={{ margin: '0 0 8px 0', paddingLeft: '20px' }}> {children} </ul> ), li: ({ children }: any) => ( <li style={{ marginBottom: '4px' }}>{children}</li> ), strong: ({ children }: any) => ( <strong style={{ fontWeight: '600' }}>{children}</strong> ), }} > {part.text} </ReactMarkdown> </div> ) : null, )} </div> </div> ))} {status === 'streaming' && ( <div style={{ display: 'flex', justifyContent: 'flex-start', }} > <div style={{ padding: '12px 16px', borderRadius: '16px', }} > <div style={{ display: 'flex', gap: '4px', alignItems: 'center', }} > <div style={{ width: '6px', height: '6px', borderRadius: '50%', backgroundColor: '#999', animation: 'pulse 1.4s ease-in-out infinite', }} /> <div style={{ width: '6px', height: '6px', borderRadius: '50%', backgroundColor: '#999', animation: 'pulse 1.4s ease-in-out 0.2s infinite', }} /> <div style={{ width: '6px', height: '6px', borderRadius: '50%', backgroundColor: '#999', animation: 'pulse 1.4s ease-in-out 0.4s infinite', }} /> </div> </div> </div> )} </div> <style>{` @keyframes pulse { 0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); } 40% { opacity: 1; transform: scale(1); } } `}</style> <form onSubmit={e => { e.preventDefault(); if (input.trim()) { sendMessage({ text: input }); setInput(''); } }} style={{ padding: '16px', borderTop: '1px solid #e5e5e5', display: 'flex', gap: '8px', }} > <input value={input} onChange={e => setInput(e.target.value)} disabled={status !== 'ready'} placeholder="Send a message..." style={{ flex: 1, padding: '12px 16px', borderRadius: '24px', border: '1px solid #e5e5e5', backgroundColor: '#ffffff', color: '#000000', fontSize: '14px', outline: 'none', }} /> <button type="submit" disabled={status !== 'ready'} style={{ width: '40px', height: '40px', borderRadius: '50%', border: 'none', backgroundColor: status !== 'ready' ? '#e5e5e5' : '#000000', color: '#ffffff', cursor: status !== 'ready' ? 'not-allowed' : 'pointer', fontSize: '18px', display: 'flex', alignItems: 'center', justifyContent: 'center', }} > ↑ </button> </form> </div> ); }`` This chat UI provides: - Real-time streaming with loading indicators    - Markdown rendering for formatted responses    ### 7\. Set up your backend weather API Before testing, you need a weather API backend running. Use one of the following guides to set up a weather API using the backend of your choice: - [How to Build a Weather API with Express and Vercel](https://vercel.com/guides/weather-api-with-express)
  
- [How to Build a Weather API with FastAPI and Vercel](https://vercel.com/guides/weather-api-with-fastapi)
  
- [How to Build a Weather API with Nitro and Vercel](https://vercel.com/guides/weather-api-with-nitro)
  

### 8\. Test the chat agent locally

Return to your `Next.js` project and start the development server:

`cd ../nextjs-agent pnpm dev`

Start your weather API backend from a new terminal using `vercel dev` and make sure that it runs in `http://localhost:3001.`

Open [http://localhost:3000](http://localhost:3000) in your browser. Try these example conversations:

- "What's the weather in London?"
  
- "Tell me about the weather in San Francisco"
  
- "How's the temperature in Tokyo today?"
  
- "Is it hot in Dubai right now?"
  

The agent will:

1. Understand your weather request
   
2. Extract the city name
   
3. Call the \`getWeather\` tool automatically
   
4. Format and present the weather data in a conversational way
   

### 9\. Deploy to Vercel

- If you chose the AI Gateway API key to authenticate, add it to your [Vercel's project environment variables dashboard](https://vercel.com/d?to=%2F%5Bteam%5D%2F%5Bproject%5D%2Fsettings%2Fenvironment-variables&title=Go+to+Environment+Variables). Otherwise, the OIDC token is already configured.
  
- Push the changes to your remote repository or run the `vercel` cli command
  
- Vercel will create a new preview deployment for you to test
  
- Merge to `main` branch or run `vercel --prod` to deploy to Production
  

Visit your production deployment link to chat with your AI weather agent.

## Understanding agent tool calling

The [AI SDK's agent system](https://ai-sdk.dev/docs/agents/overview) provides intelligent tool calling that:

- Automatically determines when to use tools based on user messages and available defined tools
  
- Include type-safe `zod` schemas that check that tools receive valid inputs
  
- Allow multi-step reasoning to allow for multiple tools to be called
  

Review [How to build AI Agents with Vercel and the AI SDK](https://vercel.com/guides/how-to-build-ai-agents-with-vercel-and-the-ai-sdk) to understand the fundamentals of building agents.

## Production considerations

### Error handling

Consider adding the following:

- Retry logic for failed API calls
  
- Fallback responses when tools fail
  
- Detailed error logging for debugging
  

### Rate limiting

Protect your API endpoint by limiting call frequency to the LLM and to your tool endpoints by using a tool such as the [Vercel firewall rate limiting SDK](https://vercel.com/docs/vercel-firewall/vercel-waf/rate-limiting-sdk).

## Summary

In this tutorial, you've built an AI chat agent that intelligently calls weather APIs based on natural language conversations.

You learned to:

- Configure the AI SDK with agent capabilities
  
- Define type-safe tools with `zod` schemas
  
- Build a streaming chat UI
  
- Integrate with backend APIs for real-time data
  
- Handle tool calling and error scenarios
  

## Next steps

### Hands-on challenges

Extend your knowledge by:

- Adding more tools (currency conversion, news, stock prices)
  
- Implementing conversation history persistence
  
- Adding authentication and user sessions
  
- Building a mobile app with React Native and the same agent
  

Explore references

- [AI SDK Agent documentation](https://ai-sdk.dev/docs/agents/overview)
  
- [How to build AI Agents with Vercel and the AI SDK](https://vercel.com/guides/how-to-build-ai-agents-with-vercel-and-the-ai-sdk)
  
- [AI SDK documentation](https://ai-sdk.dev/docs)
  
- [AI Gateway documentation](https://vercel.com/docs/ai-gateway)