Build an AI Code Generation Agent
Deploy a LangGraph ReAct agent that generates full project scaffolds from prompts.
Introduction
30 Second Summary
Every developer has faced the tedium of scaffolding a new project from scratch. You write the same boilerplate, set up the same folder structures, and install the same dependencies over and over.
In this project, you will build and deploy an AI agent that generates complete project scaffolds from plain English prompts. You'll wire up a reasoning loop powered by LangGraph that plans, writes code, and resolves dependencies automatically.
What You'll Build
You'll send a request like "build me a Flask todo app with SQLite" to your live API and get back a fully structured project with all the files, a dependency list, and setup instructions.
By the end of this project, you'll have:
- A deployed AI agent with a public URL that takes natural language prompts and returns complete, multi-file project scaffolds.
- A ReAct reasoning loop where the agent plans the project structure, generates each file, and resolves dependencies step by step.
- An LLM-agnostic architecture where swapping from Gemini to OpenAI or Claude requires changing a single file.
- Secret Mission: Add a self-correcting code review tool that critiques and improves generated code before returning it.
Are there any prerequisites?
You'll need basic Python knowledge (functions, imports, dictionaries) and familiarity with how APIs work (sending requests, receiving JSON responses). No prior experience with AI agents or LangGraph is required.
Before We Start
Before We Start...
Before we dive in, let's lock in what you're about to build and why it matters.
Set Up Your Environment
To build an AI agent, you need a working local environment with the right Python packages and an API key to power the LLM behind it.
In this step, you will create a project folder, install the core libraries (LangGraph, LangChain, FastAPI), get a free Gemini API key, and set up your project file structure.
In this step, get ready to:
- Install Python dependencies for LangGraph and FastAPI.
- Get a free Gemini API key and store it in a .env file.
- Create the project file structure.
Create your project folder and install dependencies
This project requires Python 3.12 or higher. Let's confirm your version first.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type Terminal and press Enter to open it.
- Check your Python version by running this command:
macOS
python3 --version
Windows
python --version
✔️ I see version 3.12 or higher
Your Python version is compatible. Move on to the next instruction below.
ⓧ I see an older version
You need Python 3.12+ for this project. On macOS, the system Python is often outdated.
- Visit python.org/downloads and download the latest Python 3.12+ installer.
- Run the installer and follow the prompts.
- On macOS, after installing, use python3.12 instead of python3 in all commands below, since the system python3 may still point to the old version.
- Confirm the new version by running python3.12 --version in a fresh terminal window.
ⓧ Command not found
Python is not installed or not on your PATH.
- Visit python.org/downloads and download the latest Python 3.12+ installer for your operating system.
- Run the installer. On Windows, check the box that says Add Python to PATH before clicking Install Now.
- Close your terminal and open a fresh one, then re-run the version check.
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir ai-code-agent
cd ai-code-agent
- Create a virtual environment and activate it by running these commands:
macOS
python3 -m venv venv
source venv/bin/activate
Windows
python -m venv venv
venv\Scripts\activate
You should see (venv) appear at the beginning of your terminal prompt. This means your virtual environment is active.
What is a virtual environment?
A virtual environment is an isolated Python installation just for this project. Packages you install here won't affect other Python projects on your machine. Think of it as a sealed sandbox for your dependencies.
- Install all the project dependencies by running:
pip install langgraph langchain-google-genai fastapi uvicorn python-dotenv
What are these packages?
- langgraph is the agent orchestration framework that manages the ReAct loop.
- langchain-google-genai connects LangGraph to Google's Gemini models.
- fastapi is the web framework that turns your agent into an API.
- uvicorn is the server that runs your FastAPI app locally.
- python-dotenv loads environment variables from a .env file so you don't hardcode secrets.
You should see output ending with Successfully installed followed by a list of packages.
Seeing a 'pip not found' error?
- Make sure your virtual environment is active. You should see (venv) in your prompt.
- If it's not active, re-run the activation command from the platform tab above.
- On some macOS systems, try pip3 instead of pip.
Still stuck? Help me fix my pip install error.
Get a free Gemini API key
Your agent needs an LLM to power its reasoning. You will use Google's Gemini API, which offers free-tier access with no billing setup required.
- Open your browser and navigate to aistudio.google.com/app/apikey.
- Sign in with your Google account. If you are a new user, Google AI Studio automatically creates a project and API key for you after you accept the Terms of Service.
- If you do not see a key listed, click Create API key to generate one.
- Copy your API key. You will paste it into a file in the next step.
Why is this free?
The Gemini API free tier provides input and output tokens at no charge. No billing setup or credit card is required. The free tier has rate limits, but they are sufficient for this project.
Having trouble creating a key?
- Try clearing your browser cache and signing in again.
- Disable any VPN or proxy you may be using, then retry.
- If Google AI Studio cannot create a project for you, you can create a key directly in the Google Cloud Console under APIs & Services then Credentials.
Still stuck? Help me get a Gemini API key.
- Back in your terminal, create a .env file to store your key by running:
echo "GOOGLE_API_KEY=your-api-key-here" > .env
- Open the .env file in your editor and replace your-api-key-here with the actual API key you copied from Google AI Studio.
- Save the file.
- Create a .env.example file so collaborators know what environment variables are needed, without exposing your real key:
echo "GOOGLE_API_KEY=your-api-key-here" > .env.example
- Test that your API key works by running this quick connection check:
python -c "from langchain_google_genai import ChatGoogleGenerativeAI; from dotenv import load_dotenv; import os; load_dotenv(); llm = ChatGoogleGenerativeAI(model='gemini-2.5-flash', google_api_key=os.getenv('GOOGLE_API_KEY')); print(llm.invoke('Say hello in one word').content)"
You should see a short response from Gemini printed in your terminal (something like "Hello"). This confirms your API key is valid and the connection works.
Seeing an authentication or rate limit error?
- Double-check that your .env file has no extra spaces around the = sign or surrounding the key value.
- Make sure you copied the entire key from Google AI Studio.
- If you see a rate limit error, wait a minute and try again. The free tier has per-minute limits.
Still stuck? Help me debug my Gemini API connection.
Create the project file structure
Your agent code will live in an app/ package with four modules, each handling a distinct responsibility.
- Create the app directory and its files by running these commands:
macOS
mkdir app
touch app/__init__.py app/config.py app/tools.py app/agent.py app/main.py
Windows
mkdir app
New-Item app/__init__.py, app/config.py, app/tools.py, app/agent.py, app/main.py
What are these files for?
- config.py holds your LLM setup. Changing providers later means editing only this file.
- tools.py defines the tools your agent can call (planner, code generator, dependency resolver).
- agent.py wires the LLM and tools into a ReAct agent.
- main.py is the FastAPI app that exposes your agent as an API endpoint.
- Confirm the files were created by running:
ls app/
You should see __init__.py, agent.py, config.py, main.py, and tools.py listed in the output.
Before you run the final verification, what do you think will happen when you try to import create_react_agent from LangGraph?
- Verify that LangGraph installed correctly by running:
python -c "from langgraph.prebuilt import create_react_agent; print('LangGraph ready')"
You should see LangGraph ready printed in your terminal. This proves all core dependencies are installed and importable.
Seeing an ImportError?
- Confirm your virtual environment is active ((venv) in your prompt).
- Re-run pip install langgraph and check the output for errors.
- Make sure you are using the Python from your virtual environment, not the system Python.
Still stuck? Help me fix my LangGraph import error.
Your environment is ready and wired up to the Gemini API. Next up, you will build a minimal agent that generates code with a single tool.
Build a Minimal Agent That Generates Code
Your environment is ready and your Gemini API key is verified. Now it's time to prove the core integration actually works.
Before adding multiple tools or a web framework, you need to see the fundamental loop running: prompt goes in, LLM reasons about what tool to call, tool executes, result comes back. A minimal agent with one tool proves the LangGraph + Gemini integration works end-to-end.
In this step, get ready to:
- Configure the LLM connection in config.py.
- Define a code generation tool in tools.py.
- Wire the agent together in agent.py and test it with a real prompt.
Create the LLM configuration
The config.py file holds a single function that returns your LLM instance. This is the one file you swap out later to change providers.
- Open app/config.py in VS Code and add the following code:
import os
from dotenv import load_dotenv
from langchain_google_genai import ChatGoogleGenerativeAI
load_dotenv()
def get_llm():
"""Get the LLM instance. Change this one function to swap providers."""
return ChatGoogleGenerativeAI(
model="gemini-2.5-flash",
google_api_key=os.getenv("GOOGLE_API_KEY"),
temperature=0.2,
)
What does this code do?
This module creates a reusable LLM factory function.
- load_dotenv() reads your .env file so the API key is available as an environment variable.
- get_llm() returns a configured ChatGoogleGenerativeAI instance pointing at the gemini-2.5-flash model.
- temperature=0.2 keeps output deterministic, which is important for code generation.
- Save app/config.py.
- Verify the module loads correctly by running this command in your terminal:
python -c "from app.config import get_llm; print(type(get_llm()))"
You should see something like <class 'langchain_google_genai.chat_models.ChatGoogleGenerativeAI'> printed.
Seeing a ModuleNotFoundError?
- Make sure your virtual environment is activated. You should see (venv) or similar at the start of your terminal prompt.
- Confirm you're running the command from the project root folder (the one containing the app/ directory).
- Check that python-dotenv is installed. Run pip install python-dotenv if needed.
Why is my config.py import failing?
Define the code generation tool
Tools give the agent actions it can take. The @tool decorator from LangChain turns a regular Python function into something the LLM can discover and call during its reasoning loop.
- Open app/tools.py and add the following code:
from langchain_core.tools import tool
@tool
def generate_code(filename: str, purpose: str, project_context: str) -> str:
"""Generate the code content for a single file in the project.
Args:
filename: The name of the file to generate (e.g. app.py)
purpose: What this file should do
project_context: Description of the overall project for context
"""
return f"""Generate production-ready Python code for the file '{filename}'.
Purpose: {purpose}
Project context: {project_context}
Return ONLY the code, no markdown fences, no explanation."""
What does this tool do?
This tool doesn't generate code itself. It returns a prompt string that the LLM uses as context for its next reasoning step.
This is the standard ReAct pattern: the LLM calls a tool, reads the tool's output, then uses that output to inform what it does next. The docstring is critical because the LLM reads it to decide when and how to call the tool.
- Save app/tools.py.
- Verify the tool registers correctly by running:
python -c "from app.tools import generate_code; print(generate_code.name)"
You should see generate_code printed. This confirms the @tool decorator registered the function correctly.
Seeing a syntax error in tools.py?
- Check that the triple-quoted f-string uses matching triple quotes (""") at both the opening and closing.
- Make sure the @tool decorator sits directly above the function definition with no blank line between them.
Help me fix my tools.py syntax error.
✔️ Awesome, I've got everything!
Great. Double check you've saved both app/config.py and app/tools.py.
ⓧ I'd like to double check the full code
Here is app/config.py in full:
import os
from dotenv import load_dotenv
from langchain_google_genai import ChatGoogleGenerativeAI
load_dotenv()
def get_llm():
"""Get the LLM instance. Change this one function to swap providers."""
return ChatGoogleGenerativeAI(
model="gemini-2.5-flash",
google_api_key=os.getenv("GOOGLE_API_KEY"),
temperature=0.2,
)
Here is app/tools.py in full:
from langchain_core.tools import tool
@tool
def generate_code(filename: str, purpose: str, project_context: str) -> str:
"""Generate the code content for a single file in the project.
Args:
filename: The name of the file to generate (e.g. app.py)
purpose: What this file should do
project_context: Description of the overall project for context
"""
return f"""Generate production-ready Python code for the file '{filename}'.
Purpose: {purpose}
Project context: {project_context}
Return ONLY the code, no markdown fences, no explanation."""
Wire the agent together and test it
Now you'll connect the LLM and the tool into a working agent using create_react_agent. This prebuilt function from LangGraph handles the reasoning loop automatically: the LLM decides which tool to call, calls it, reads the result, and repeats until it has a final answer.
- Open app/agent.py and add the imports, system prompt, and tools list:
from langchain_core.messages import HumanMessage
from langgraph.prebuilt import create_react_agent
from app.config import get_llm
from app.tools import generate_code
SYSTEM_PROMPT = """You are a senior software engineer AI agent that generates complete project scaffolds.
When given a project request, you MUST follow this workflow:
1. PLAN: Use the plan_project_structure tool to determine what files are needed
2. GENERATE: Use the generate_code tool for EACH file in the plan
3. RESOLVE: Use the resolve_dependencies tool to create requirements.txt
Always complete all three steps. Be thorough and generate production-ready code with error handling, type hints, and docstrings."""
tools = [generate_code]
What does the system prompt do?
The system prompt tells the agent its identity and workflow. It references tools that don't exist yet (plan_project_structure, resolve_dependencies). That's intentional.
The agent will only call tools that are actually available. Right now it only has generate_code, so it will use that. When you add more tools in the next step, the prompt is already set up for them.
- Below the code you just added, add the two agent functions:
def create_agent():
"""Create and return the code generation agent."""
llm = get_llm()
agent = create_react_agent(
llm,
tools=tools,
prompt=SYSTEM_PROMPT,
)
return agent
def run_agent(prompt: str) -> dict:
"""Run the agent with a user prompt and return structured output."""
agent = create_agent()
result = agent.invoke(
{"messages": [HumanMessage(content=prompt)]}
)
last_message = result["messages"][-1]
return {
"response": last_message.content,
"steps_taken": len(result["messages"]),
}
What do these functions do?
- create_agent() builds the agent by combining your LLM, tools, and system prompt into a single executable graph.
- run_agent() is the public interface. It creates a fresh agent, sends in the user's message as a HumanMessage, and extracts the final response from the message history.
- steps_taken tells you how many reasoning steps the agent used, including tool calls and intermediate thoughts.
- Save app/agent.py.
Before you run this, what do you think will happen? The agent has one tool (generate_code) and the system prompt tells it to plan, generate, and resolve. Will it try to call tools that don't exist, or will it adapt?
- Test the agent by running:
python -c "from app.agent import run_agent; result = run_agent('Create a simple hello world Python script'); print(result['response'][:500]); print('\nSteps:', result['steps_taken'])"
After a few seconds, you'll see generated Python code printed to your terminal along with the number of steps the agent took. The agent adapts to the tools available and uses generate_code to produce output.
What should I see?
The output will contain Python code for a hello world script. The exact content varies because the LLM generates it fresh each time. The important thing is that you see actual code (not an error) and a step count of 3 or more, which means the agent called the tool and reasoned about the result.
Seeing a 429 or RESOURCE_EXHAUSTED error?
The Gemini free tier has rate limits. If you hit a limit, wait 60 seconds and try again. The free tier is sufficient for this project, but you may need short pauses between test runs.
Help me debug my agent's API error.
Seeing an import error from agent.py?
- Confirm you're running the command from the project root (the folder that contains the app/ directory), not from inside app/ itself.
- Check that app/config.py and app/tools.py are both saved with the code from the previous substeps.
Why is my agent.py import failing?
✔️ Awesome, I've got everything!
Great. Confirm you saved app/agent.py and saw generated code in your terminal output.
ⓧ I'd like to double check the full code
The full app/agent.py file combines the two chunks you added above. Scroll up and confirm you have both sections in order:
- The imports, SYSTEM_PROMPT, and tools list at the top.
- The create_agent() and run_agent() functions below them.
Make sure there are no duplicate imports and that run_agent is the last function in the file.
Your minimal agent is alive. It takes a prompt, reasons about it, calls a tool, and returns generated code. Next up, you'll add the full tool suite so the agent can plan project structures and resolve dependencies across multiple files.
Add the Full Tool Suite
In the previous step, your agent generated a single file from a prompt. That proves the LangGraph + Gemini integration works.
A single file is not a usable project. A real code generation agent needs to plan a project structure, generate multiple files, and figure out which packages the project depends on. In this step, you'll add two new tools to give your agent that full workflow.
In this step, get ready to:
- Add a project planning tool that decides which files to create.
- Add a dependency resolver tool that produces a requirements.txt from generated code.
- Wire all three tools into the agent and test the full loop.
Add the project planning tool
The planner is the first tool the agent calls. It takes a project description and returns a JSON list of files the project needs, so the agent knows what to generate next.
- In app/tools.py, find the existing @tool decorator above generate_code.
- Add the following function above it, leaving a blank line between the new function and generate_code:
@tool
def plan_project_structure(project_description: str) -> str:
"""Plan the file structure for a coding project. Takes a project description and returns a JSON list of files needed with their purposes.
Args:
project_description: A description of the project to plan
"""
return f"""Based on the project description, plan the files needed.
Project: {project_description}
Return a JSON array where each item has: filename, purpose, and key_imports.
Only return the JSON, no explanation."""
What does this tool do?
This tool does not execute code or hit an API directly. It returns a prompt string that the LLM uses as context for its next reasoning step.
When the agent calls plan_project_structure, the LLM sees the returned prompt and generates a JSON file list in its response. This is the standard ReAct pattern: tools shape what the LLM reasons about next.
- Save app/tools.py.
- Verify the new tool loads without errors by running:
python -c "from app.tools import plan_project_structure; print('plan_project_structure loaded')"
You should see plan_project_structure loaded printed with no import errors.
Seeing an ImportError?
Make sure the new function is above generate_code and has the @tool decorator on the line immediately before def. Also check that the triple-quoted f-string has matching """ at the start and end.
help me fix an ImportError when loading plan_project_structure from app.tools
Add the dependency resolver tool
After the agent generates all the files, it needs to figure out which third-party packages the project requires. The dependency resolver analyzes the imports and produces a valid requirements.txt.
- In app/tools.py, scroll to the end of the generate_code function.
- Add the following function below it, leaving a blank line between generate_code and the new function:
@tool
def resolve_dependencies(file_contents: str) -> str:
"""Analyze all generated code and produce a requirements.txt with pinned versions.
Args:
file_contents: A summary of all imports used across the project files
"""
return f"""Based on these imports and usages: {file_contents}
Generate a valid requirements.txt with appropriate version pins.
Only include third-party packages, not standard library modules.
Return ONLY the requirements.txt content, one package per line."""
What does this tool do?
Like the planner, this tool returns a prompt string. The LLM reads it, analyzes the imports from all generated files, and produces a requirements.txt in its response.
This completes the three-tool workflow: plan the structure, generate each file, resolve the dependencies.
- Save app/tools.py.
- Verify all three tools load correctly by running:
python -c "from app.tools import plan_project_structure, generate_code, resolve_dependencies; print('All 3 tools loaded')"
You should see All 3 tools loaded printed.
Only seeing 2 tools load?
Check that resolve_dependencies is defined after the closing """ of generate_code's return statement. If you accidentally placed it inside generate_code, Python will raise an indentation or syntax error.
help me debug why resolve_dependencies isn't loading from my tools.py
✔️ Awesome, I've got everything!
Great. Double check you've saved app/tools.py and move on to connecting these tools to the agent.
ⓧ I'd like to double check the full code
Your app/tools.py should have these three functions in this order:
- The from langchain_core.tools import tool import at the top.
- plan_project_structure (takes project_description).
- generate_code (takes filename, purpose, project_context).
- resolve_dependencies (takes file_contents).
Each function has a @tool decorator and returns an f-string prompt. Scroll up and confirm each one matches the code blocks above.
Connect all tools to the agent
The tools exist in tools.py but the agent still only knows about generate_code. You need to import the new tools and add them to the agent's tool list.
- In app/agent.py, find this import line near the top:
from app.tools import generate_code
- Replace it with this line to import all three tools:
from app.tools import generate_code, plan_project_structure, resolve_dependencies
- Now find the tools list further down:
tools = [generate_code]
- Replace it with all three tools in the correct workflow order:
tools = [plan_project_structure, generate_code, resolve_dependencies]
Why does the system prompt already mention all three tools?
In the previous step, the system prompt was written to describe the full plan-generate-resolve workflow. The agent tried to follow it but only had generate_code available.
Now that you've added the missing tools to the list, the agent can actually execute the full workflow the prompt describes.
- Save app/agent.py.
Before you run the agent, think about what you expect to happen. With three tools available and a system prompt telling it to plan first, generate each file, then resolve dependencies, how many tool calls do you think it will make for a simple Flask app?
- Test the full tool suite by running:
python -c "from app.agent import run_agent; result = run_agent('build me a Flask hello world app'); print(result['response'][:1000]); print(f'\nSteps taken: {result[\"steps_taken\"]]}')"
You should see the agent return a multi-file project with at least an app.py and a requirements.txt. The steps_taken count will be higher than before because the agent now calls multiple tools in sequence.
What should I see?
The agent follows the plan-generate-resolve loop. It first calls plan_project_structure to decide which files are needed. Then it calls generate_code once for each file in the plan. Finally it calls resolve_dependencies to produce the requirements.txt.
The final response contains all the generated code assembled together. The steps_taken count reflects the total number of messages (your prompt + each tool call/response pair + the final answer).
Getting a rate limit error?
The Gemini free tier has limited requests per minute. If you see a 429 or RESOURCE_EXHAUSTED error, wait 60 seconds and try again. The agent makes multiple LLM calls per invocation, which can hit the rate limit quickly.
help me handle Gemini rate limit errors when running my LangGraph agent
✔️ Awesome, I've got everything!
Great. Double check you've saved app/agent.py and confirm your agent returns a multi-file project.
ⓧ I'd like to double check the full code
Your app/agent.py should have these elements in order:
- Imports: HumanMessage, create_react_agent, get_llm, and all three tools (generate_code, plan_project_structure, resolve_dependencies).
- SYSTEM_PROMPT describing the plan-generate-resolve workflow (unchanged from Step 2).
- tools = [plan_project_structure, generate_code, resolve_dependencies] (all three tools).
- create_agent() and run_agent() functions (unchanged from Step 2).
Scroll up and confirm the import line and tools list match the code blocks above.
Your agent now runs a complete plan-generate-resolve loop. Next up, you'll wrap it in a FastAPI endpoint so anyone can hit it over HTTP.
Wrap It in a FastAPI Endpoint
Your agent generates multi-file projects from a script, but nobody can reach it except you. Recruiters and collaborators need a real API they can hit from a browser or tool like Postman.
FastAPI gives you automatic interactive docs, request validation, and the exact structure Vercel expects for deployment. In this step, you will wrap the agent in an HTTP endpoint that accepts a prompt and returns a structured project.
In this step, get ready to:
- Create a FastAPI app with Pydantic request and response models.
- Connect the agent to a POST endpoint that returns generated code.
- Add error handling for rate limits and LLM failures.
Create the FastAPI app and define your data models
Every API needs a clear contract: what the caller sends and what they get back. Pydantic models define that contract, and FastAPI uses them to validate requests automatically.
- Open app/main.py in VS Code and add the following code:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from app.agent import run_agent
# Create the FastAPI app with metadata
app = FastAPI(
title="AI Code Generation Agent",
description="Generate complete project scaffolds from natural language prompts",
version="1.0.0",
)
# Define what the caller sends
class GenerateRequest(BaseModel):
prompt: str
# Define what the caller gets back
class GenerateResponse(BaseModel):
response: str
steps_taken: int
# Simple health check at the root URL
@app.get("/")
def health_check():
"""Health check endpoint."""
return {"status": "healthy", "agent": "code-generation-v1"}
What does this code do?
You import FastAPI for the web framework and HTTPException for returning proper error responses. BaseModel from Pydantic lets you define typed schemas that FastAPI validates for you.
GenerateRequest ensures callers provide a prompt string. GenerateResponse shapes the output into response (the generated project) and steps_taken (how many reasoning steps the agent used).
The health_check endpoint at / gives you a quick way to confirm the server is alive.
- Save app/main.py.
- Start the development server by running this command:
uvicorn app.main:app --reload
- Open http://localhost:8000/docs in your browser.
You should see the Swagger UI with your app title "AI Code Generation Agent" and two endpoints listed: a GET / and a POST /generate.
What is this docs page?
FastAPI auto-generates interactive API documentation at /docs. You can send test requests directly from this page without needing a separate tool.
Server won't start?
Make sure your virtual environment is active and that you ran the command from your project's root folder (the one containing the app/ directory).
If you see ModuleNotFoundError, confirm you installed all dependencies in Step 1. Help me debug why uvicorn can't find my app module.
Add the /generate endpoint with error handling
The /generate endpoint is where the real work happens. It takes the user's prompt, runs the agent, and returns the structured output.
The Gemini free tier has rate limits, so the endpoint needs to catch those errors and return helpful messages instead of crashing.
- In app/main.py, add the following code below the health_check function:
@app.post("/generate", response_model=GenerateResponse)
def generate_project(request: GenerateRequest):
"""Generate a complete project from a natural language prompt."""
# Reject empty prompts before calling the LLM
if not request.prompt.strip():
raise HTTPException(status_code=400, detail="Prompt cannot be empty")
try:
# Run the agent and return structured output
result = run_agent(request.prompt)
return GenerateResponse(**result)
except Exception as e:
error_msg = str(e)
# Handle Gemini rate limit errors specifically
if "429" in error_msg or "RESOURCE_EXHAUSTED" in error_msg:
raise HTTPException(
status_code=429,
detail="Rate limit reached. Gemini free tier allows limited requests per minute. Please wait and retry.",
)
raise HTTPException(status_code=500, detail=f"Agent error: {error_msg}")
What does this code do?
- The @app.post decorator creates a POST endpoint at /generate that expects a GenerateRequest body.
- The empty-prompt check returns a 400 error immediately, saving you a wasted LLM call.
- The try/except block catches Gemini rate limit errors (status 429 or the string RESOURCE_EXHAUSTED) and returns a user-friendly 429 response.
- Any other failure becomes a 500 error with the actual error message, so you can debug it.
- Save app/main.py.
Your terminal should show uvicorn reloading automatically (thanks to --reload).
Server crashed on save?
Check that the generate_project function is indented at the top level of the file, not nested inside health_check. Also verify that your try/except block has matching indentation.
Help me fix a syntax error in my FastAPI main.py file.
Test the endpoint from the Swagger UI
Before you send a test request, think about what you expect to happen. The agent will plan a project, generate files, and resolve dependencies.
- Return to http://localhost:8000/docs in your browser (refresh if needed).
- Click the POST /generate endpoint to expand it.
- Click Try it out.
- Replace the request body with this JSON:
{
"prompt": "build me a simple Python hello world script"
}
- Before you click Execute, predict: will you get back a JSON response with generated code, or an error?
- Click Execute.
After a few seconds, the Swagger UI shows a 200 response with a JSON body containing response (the generated project output) and steps_taken (the number of messages the agent exchanged).
Why does it take a few seconds?
The agent is calling Gemini multiple times in a loop: once to plan, once per file to generate, and once to resolve dependencies. Each call takes 1-3 seconds, so a multi-file project adds up.
Getting a 429 or 500 error?
A 429 means you hit the Gemini free tier rate limit. Wait 60 seconds and try again with a simpler prompt like "build me a hello world script".
A 500 error with a message about GOOGLE_API_KEY means your .env file is missing or the key is invalid. Help me debug my /generate endpoint error.
✔️ Awesome, I've got everything!
Great. Double check you have saved app/main.py and your server is still running.
ⓧ I'd like to double check the full code
Here is the complete app/main.py file. Compare it against yours:
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from app.agent import run_agent
app = FastAPI(
title="AI Code Generation Agent",
description="Generate complete project scaffolds from natural language prompts",
version="1.0.0",
)
class GenerateRequest(BaseModel):
prompt: str
class GenerateResponse(BaseModel):
response: str
steps_taken: int
@app.get("/")
def health_check():
"""Health check endpoint."""
return {"status": "healthy", "agent": "code-generation-v1"}
@app.post("/generate", response_model=GenerateResponse)
def generate_project(request: GenerateRequest):
"""Generate a complete project from a natural language prompt."""
if not request.prompt.strip():
raise HTTPException(status_code=400, detail="Prompt cannot be empty")
try:
result = run_agent(request.prompt)
return GenerateResponse(**result)
except Exception as e:
error_msg = str(e)
if "429" in error_msg or "RESOURCE_EXHAUSTED" in error_msg:
raise HTTPException(
status_code=429,
detail="Rate limit reached. Gemini free tier allows limited requests per minute. Please wait and retry.",
)
raise HTTPException(status_code=500, detail=f"Agent error: {error_msg}")
Your agent now has a proper API interface with validation, error handling, and interactive docs. Next up, you will deploy it to Vercel so anyone with the URL can generate projects from your live agent.
Deploy to Vercel
Your agent works locally, but a project running on localhost is invisible to anyone else.
Deploying to Vercel gives you a live, public URL with automatic HTTPS. It proves you can ship production software, and it gives recruiters something they can click.
In this step, get ready to:
- Create Vercel configuration files that tell the platform how to run your FastAPI app.
- Push your project to GitHub and connect it to Vercel.
- Deploy and verify the live endpoint returns a generated project.
Create the Vercel configuration
Vercel needs two files to know how to build and serve your Python app. The first tells Vercel how long your function is allowed to run. The second declares your dependencies and entry point.
- Create a new file called vercel.json in the root of your ai-code-agent folder (at the same level as your app/ directory) and paste the following:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"functions": {
"app/main.py": {
"maxDuration": 60
}
}
}
What does this file do?
The functions object tells Vercel which file contains your serverless function. maxDuration: 60 gives the function up to 60 seconds to respond. AI agents need more time than a typical web request because the LLM may call multiple tools in sequence.
- Save vercel.json.
- You should see vercel.json listed in the VS Code Explorer sidebar, at the same level as your app/ folder.
- Create another new file called pyproject.toml in the same root directory and paste the following:
[project]
name = "ai-code-agent"
version = "1.0.0"
requires-python = ">=3.12"
dependencies = [
"langgraph>=1.2.10",
"langchain-google-genai>=4.3.2",
"fastapi>=0.141.1",
"uvicorn>=0.34.0",
"python-dotenv>=1.1.0",
]
[tool.vercel]
entrypoint = "app.main:app"
What does this file do?
Vercel reads pyproject.toml to install your Python dependencies during the build. The [tool.vercel] section tells Vercel exactly where your FastAPI app instance lives.
This is the same app variable you defined in app/main.py. Vercel uses app.main:app (module path, colon, variable name) to find it.
- Save pyproject.toml.
- Confirm both files exist by running:
ls
You should see vercel.json and pyproject.toml alongside your app/ folder and .env file in the output.
Don't see both files?
Make sure you created them in the project root (the same folder that contains app/), not inside the app/ directory itself. If they ended up in the wrong place, move them up one level.
help me fix my project file structure
Push to GitHub and connect to Vercel
Vercel deploys directly from a GitHub repository. Every push to your main branch triggers a new deployment automatically.
- Create a .gitignore file in your project root to keep secrets and generated files out of version control:
# Ignore environment secrets and Python artifacts
.env
__pycache__/
venv/
- Save .gitignore.
- Initialize a git repository and make your first commit by running these commands:
git init
git add .
git commit -m "Initial commit: AI code generation agent"
- Open GitHub in your browser and create a new repository.
- Name it ai-code-agent and leave it empty (no README, no .gitignore, no license).
- Push your local code to GitHub by running:
git remote add origin [[REPO_URL="https://github.com/your-username/ai-code-agent.git"]]
git branch -M main
git push -u origin main
You should see your files appear on the GitHub repository page after refreshing it.
Push rejected or authentication error?
If git asks for credentials, you may need to set up a GitHub personal access token or SSH key. Check your GitHub authentication settings.
help me push my code to GitHub
- Go to vercel.com and sign up for a free Hobby account using your GitHub login.
- Click the Add New... button and select Project.
- Under Import Git Repository, find your ai-code-agent repo and click Import.
Don't see your repository?
If your repo is missing from the list, click Configure GitHub App on the import screen. Make sure the Vercel GitHub App has access to the repository you just created, then return to the import screen.
- On the configuration page, expand the Environment Variables section.
- Enter GOOGLE_API_KEY as the Name.
- Paste your Gemini API key (the same value from your local .env file) as the Value.
- Click Deploy.
Vercel begins building your project. This takes about 30-60 seconds.
Build failed?
Check the build logs in the Vercel dashboard. Common issues include a missing dependency in pyproject.toml or a typo in the entrypoint value. Make sure your [tool.vercel] section says entrypoint = "app.main:app" exactly.
help me debug my Vercel deployment
Test the live endpoint
Once the build succeeds, Vercel gives you a public URL. Time to prove the agent works in production.
- Copy your deployment URL from the Vercel dashboard. It looks like https://your-project.vercel.app.
- Open the Swagger docs by visiting your deployment URL with /docs appended:
[[VERCEL_URL="https://your-project.vercel.app"]]/docs
Before you test, think about what you expect to happen. Do you think the agent will successfully generate a project through the live URL, or will something fail?
- In the Swagger UI, expand the POST /generate endpoint.
- Click Try it out.
- Replace the request body with:
{
"prompt": "build me a simple Python hello world script"
}
- Click Execute.
You should see a 200 response with a response field containing generated code and a steps_taken field showing how many messages the agent exchanged. Your AI agent is now live on the internet.
Getting a timeout or 500 error?
If you see a 500 error, check that your GOOGLE_API_KEY environment variable is set correctly in the Vercel dashboard. Select your project, click Environment Variables in the sidebar, and verify the key is there.
If you see a timeout, your request may have exceeded 60 seconds. Try a simpler prompt like the one above. The Gemini free tier rate limit can also cause 429 errors if you made many requests locally before deploying.
help me fix my deployed Vercel agent
✔️ Awesome, I've got everything!
Great. Double check you have saved both vercel.json and pyproject.toml in your project root.
ⓧ I'd like to double check the full code
Here is vercel.json:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"functions": {
"app/main.py": {
"maxDuration": 60
}
}
}
Here is pyproject.toml:
[project]
name = "ai-code-agent"
version = "1.0.0"
requires-python = ">=3.12"
dependencies = [
"langgraph>=1.2.10",
"langchain-google-genai>=4.3.2",
"fastapi>=0.141.1",
"uvicorn>=0.34.0",
"python-dotenv>=1.1.0",
]
[tool.vercel]
entrypoint = "app.main:app"
You now have a live, publicly accessible AI agent. Anyone with the URL can send it a prompt and get a complete project scaffold back. Next up, a secret mission to make the agent even smarter.
Secret mission
Add a Code Review Tool
Your agent generates code, but it never checks its own work. Production agents use self-correcting loops to catch missing error handling, security issues, and anti-patterns before returning output. Can you add a review tool that critiques generated code and triggers regeneration when it finds critical problems?
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely on free tiers (Gemini API free tier and Vercel Hobby plan), so there are no ongoing costs.
Resources you used:
- Local project folder (ai-code-agent) with Python virtual environment.
- Vercel project hosting your deployed API.
- GitHub repository connected to Vercel.
- Google AI Studio API key stored in your Vercel environment variables.
Keep everything running
No action needed. Choose this if you're still actively building or want to keep your live demo URL available.
- Your Vercel deployment stays live at no cost on the Hobby plan.
- Your Gemini API key remains active on the free tier with no charges.
- Your local project folder stays on your Desktop.
Pause - I'll come back to this later
Shut down running processes to free up memory. Your deployed API on Vercel stays live at no cost, so no action is needed there.
- If your local dev server is still running, press Ctrl+C in the terminal to stop it.
- Deactivate your virtual environment by running:
deactivate
- When you come back, navigate to your project folder and reactivate with source .venv/bin/activate (macOS/Linux) or .venv\Scripts\activate (Windows).
Delete - I don't want to use this again
Remove all project resources and start fresh. Follow each step below to fully clean up.
Delete your local project folder:
- On macOS/Linux, run:
cd ~/Desktop
rm -rf ai-code-agent
- On Windows, run:
cd ~\Desktop
rmdir /s /q ai-code-agent
Delete your Vercel project:
- Go to your project on vercel.com and open the Settings tab.
- Scroll to the bottom of the General page.
- Click Delete Project and confirm by typing your project name.
Delete your GitHub repository:
- Open your repository on github.com and go to Settings.
- Scroll to the bottom of the General page and find the Danger Zone section.
- Click Delete this repository and follow the confirmation prompts.
Delete your Google AI Studio API key:
- Go to aistudio.google.com and open the API keys section.
- Find the key you created for this project and delete it.
Nice Work!
Nice Work!
Nice work! You just built and deployed a production-grade AI code generation agent powered by LangGraph and Gemini.
You've learned how to:
- Build a LangGraph ReAct agent that orchestrates multiple tools in a reasoning loop, deciding what to do next based on each tool's output.
- Create custom tools for project planning, code generation, and dependency resolution that an LLM calls autonomously during its plan-execute-validate workflow.
- Deploy the agent as a live FastAPI endpoint on Vercel with proper error handling, rate limit awareness, and a public URL anyone can hit.
- Secret Mission: Added a self-correcting code review loop that critiques generated code and regenerates files with critical issues, producing higher quality output.
Ready to quiz yourself?