Skip to main content

CLI tool to create new AI agent projects based on LangGraph and FastAPI

Project description

FastAPI Base Project

A modular FastAPI project template with JWT authentication, SQLAlchemy ORM, Alembic migrations, and LangGraph AI agents.

Purpose

This project serves as a production-ready template for building AI agents with LangGraph and exposing them through FastAPI endpoints. It eliminates the need to configure authentication, database management, API routing, and agent infrastructure from scratch.

Key Goals:

  • Rapid Agent Development: Start building LangGraph agents immediately without boilerplate setup
  • Production-Ready API: Pre-configured FastAPI with JWT authentication, CORS, and comprehensive error handling
  • State Persistence: Built-in PostgreSQL checkpointing for maintaining conversation history
  • Developer Experience: Hot-reloading with langgraph dev, interactive API docs, and comprehensive testing tools
  • Scalability: Modular architecture that scales from simple chatbots to complex multi-agent systems

Whether you're prototyping a conversational AI, building a production agent system, or learning LangGraph, this template provides everything you need to get started quickly.

Features

  • FastAPI - Modern, fast web framework for building APIs
  • SQLAlchemy ORM - Powerful database ORM with support for multiple databases
  • JWT Authentication - Secure authentication using JSON Web Tokens
  • Alembic - Database migration management
  • LangGraph Agents - AI agents with state persistence using LangGraph
  • Modular Architecture - Clean separation of concerns with routers, services, and models
  • Pydantic Schemas - Request/response validation and serialization
  • CORS Support - Cross-Origin Resource Sharing enabled
  • Base Models - Pre-built User and Profile models with relationships

Project Structure

agent-base-project/
├── src/
│   ├── main.py              # Application entry point
│   ├── core/                # Core configuration and security
│   │   ├── config.py        # Settings and environment variables
│   │   ├── security.py      # JWT and password hashing utilities
│   │   └── constants.py     # Application constants
│   ├── db/                  # Database configuration
│   │   ├── database.py      # SQLAlchemy engine setup
│   │   ├── session.py       # Database session management
│   │   └── checkpoint.py    # LangGraph checkpoint configuration
│   ├── models/              # SQLAlchemy ORM models
│   │   ├── base.py          # Declarative base
│   │   ├── user.py          # User model
│   │   └── profile.py       # Profile model
│   ├── schemas/             # Pydantic schemas
│   │   ├── user.py          # User schemas (Create, Update, Read)
│   │   ├── profile.py       # Profile schemas
│   │   ├── token.py         # Authentication token schemas
│   │   └── common.py        # Common/shared schemas
│   ├── services/            # Business logic layer
│   │   ├── auth_service.py  # Authentication logic
│   │   ├── user_service.py  # User management logic
│   │   └── profile_service.py # Profile management logic
│   ├── routers/             # API endpoints
│   │   ├── auth.py          # Authentication routes
│   │   ├── chatbot.py       # Chatbot/Agent routes
│   │   ├── users.py         # User management routes
│   │   └── profiles.py      # Profile routes
│   └── dependencies.py      # Shared dependencies (auth, etc.)
├── agents/                  # LangGraph agents
│   └── basic/               # Basic chatbot agent
│       ├── agent.py         # Agent graph definition
│       ├── state.py         # Agent state schema
│       └── nodes/           # Agent nodes
│           └── chatbot/     # Chatbot node
│               ├── node.py  # Node implementation
│               └── prompt.py # System prompt
├── alembic/                 # Database migrations
├── tests/                   # Test suite
├── .env.example             # Environment variables template
├── langgraph.json           # LangGraph configuration
├── requirements.txt         # Python dependencies
└── README.md               # This file

Setup Instructions

Follow these steps to set up and run the project:

Step 1: Create Virtual Environment

# Create virtual environment
python -m venv venv

Step 2: Activate Virtual Environment

On Windows:

venv\Scripts\activate

On Linux/Mac:

source venv/bin/activate

Step 3: Install Dependencies

pip install -r requirements.txt

Step 4: Configure Environment Variables

On Windows:

copy .env.example .env

On Linux/Mac:

cp .env.example .env

Then edit the .env file with your configuration:

# Database Configuration
DATABASE_URL=sqlite:///./app.db

# JWT Configuration
SECRET_KEY=your-super-secret-key-here-change-in-production
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30

# OpenAI Configuration (Required for LangGraph Agent)
OPENAI_API_KEY=sk-your-openai-api-key-here

# LangSmith Configuration (Optional - for tracing and monitoring)
LANGSMITH_TRACING=true
LANGSMITH_API_KEY=lsv2_xxx

Generate a secure SECRET_KEY:

# Using openssl
openssl rand -hex 32

# Or using Python
python -c "import secrets; print(secrets.token_hex(32))"

Important: You need to set your OpenAI API key to use the chatbot agent. Get your API key from OpenAI Platform.

Step 5: Initialize Database

Create the initial database migration:

alembic revision --autogenerate -m "initial migration"

Apply the migration to create tables:

alembic upgrade head

Note: The application also has Base.metadata.create_all(bind=engine) in src/main.py which will create tables automatically if they don't exist. However, using Alembic migrations is recommended for production and better database version control.

Step 6: Run the Application

Option 1: Using the run script

python run.py

Option 2: Using uvicorn directly

# Development mode with auto-reload
uvicorn src.main:app --reload

# Production mode
uvicorn src.main:app --host 0.0.0.0 --port 8000

The API will be available at:


Alternative Setup Methods

Using Docker Compose

If you prefer using Docker:

docker-compose up

This will start both the application and a PostgreSQL database.

API Endpoints

Root

  • GET / - Root endpoint, returns API information

    • No authentication required
    • Returns project name, status, and docs link
  • GET /health - Health check endpoint

    • No authentication required
    • Returns health status

Authentication (/auth)

  • POST /auth/register - Register a new user

    • Body: { "username", "email", "password", "first_name"?, "last_name"? }
    • Returns: User object (without password)
    • Status: 201 Created
    • Automatically creates a Profile for the user
    • Validates email format and password strength (min 8 chars)
    • Returns 400 if email or username already exists
  • POST /auth/token - Login and get JWT access token

    • Body: Form data with username (email) and password
    • Returns: { "access_token", "token_type": "bearer" }
    • Status: 200 OK
    • Returns 401 if credentials are invalid
    • Updates user's last_login timestamp
    • Token expires according to ACCESS_TOKEN_EXPIRE_MINUTES setting

Users (/users)

🔒 All user endpoints require authentication (Bearer token)

  • GET /users/me - Get current authenticated user information

    • Returns: Complete user object with all fields
    • Status: 200 OK
  • GET /users/{id} - Get user by ID

    • Returns: User object
    • Status: 200 OK
    • Permissions: Users can only view their own profile unless they are staff/superuser
    • Returns 403 if insufficient permissions
    • Returns 404 if user not found
  • PATCH /users/{id} - Update user information

    • Body: Any of { "username", "email", "password", "first_name", "last_name", "is_active" }
    • Returns: Updated user object
    • Status: 200 OK
    • Permissions: Users can only update their own profile unless they are superuser
    • Regular users cannot modify is_active field
    • Password will be automatically hashed if provided
    • Returns 403 if insufficient permissions
    • Returns 404 if user not found

Profiles (/profiles)

🔒 All profile endpoints require authentication (Bearer token)

  • GET /profiles/me - Get current user's profile

    • Returns: Profile object with time_zone, language, preferences, timestamps
    • Status: 200 OK
    • Returns 404 if profile not found (shouldn't happen if created with user)
  • PATCH /profiles/me - Update current user's profile

    • Body: Any of { "time_zone", "language", "preferences", "is_active" }
    • Returns: Updated profile object
    • Status: 200 OK
    • preferences field can store JSON string for custom settings
    • Returns 404 if profile not found

Chatbot (/chatbot)

🔒 All chatbot endpoints require authentication (Bearer token)

  • POST /chatbot - Send a message to the chatbot agent

    • Body: { "message": "your message here" }
    • Returns: String with the agent's response
    • Status: 200 OK
    • Uses LangGraph agent with state persistence (thread_id: "1")
    • Maintains conversation history across requests
  • POST /chatbot/stream - Send a message and receive streaming response

    • Body: { "message": "your message here" }
    • Returns: Server-Sent Events (SSE) stream with agent's response chunks
    • Status: 200 OK
    • Content-Type: text/event-stream
    • Uses LangGraph agent with state persistence (thread_id: "2")
    • Streams response in real-time as it's generated

Usage Examples

1. Register a New User

curl -X POST "http://localhost:8000/auth/register" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "john_doe",
    "email": "john@example.com",
    "password": "securepass123",
    "first_name": "John",
    "last_name": "Doe"
  }'

Response (201 Created):

{
  "id": 1,
  "username": "john_doe",
  "email": "john@example.com",
  "first_name": "John",
  "last_name": "Doe",
  "is_active": true,
  "is_staff": false,
  "is_superuser": false,
  "date_joined": "2024-01-15T10:30:00Z",
  "last_login": null
}

2. Login and Get Token

curl -X POST "http://localhost:8000/auth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=john@example.com&password=securepass123"

Response (200 OK):

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer"
}

3. Get Current User Info (Authenticated)

curl -X GET "http://localhost:8000/users/me" \
  -H "Authorization: Bearer YOUR_TOKEN_HERE"

4. Update User Profile

curl -X PATCH "http://localhost:8000/users/1" \
  -H "Authorization: Bearer YOUR_TOKEN_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Jane",
    "last_name": "Smith"
  }'

5. Get Current User's Profile

curl -X GET "http://localhost:8000/profiles/me" \
  -H "Authorization: Bearer YOUR_TOKEN_HERE"

6. Update Profile Settings

curl -X PATCH "http://localhost:8000/profiles/me" \
  -H "Authorization: Bearer YOUR_TOKEN_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "time_zone": "America/New_York",
    "language": "es",
    "preferences": "{\"theme\": \"dark\", \"notifications\": true}"
  }'

7. Chat with the Agent (Non-Streaming)

curl -X POST "http://localhost:8000/chatbot" \
  -H "Authorization: Bearer YOUR_TOKEN_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Hello! What can you help me with?"
  }'

Response:

"Hello! I'm here to help you with a variety of tasks..."

8. Chat with the Agent (Streaming)

curl -X POST "http://localhost:8000/chatbot/stream" \
  -H "Authorization: Bearer YOUR_TOKEN_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Tell me a short story"
  }'

Response (Server-Sent Events):

data: Once
data:  upon
data:  a
data:  time
data: ...

Database Migrations

# Create a new migration
alembic revision --autogenerate -m "description of changes"

# Apply migrations
alembic upgrade head

# Rollback one migration
alembic downgrade -1

# View migration history
alembic history

# View current version
alembic current

Running Tests

# Run all tests
pytest

# Run with coverage
pytest --cov=src --cov-report=html

# Run specific test file
pytest tests/test_auth.py

# Run with verbose output
pytest -v

# Run and stop on first failure
pytest -x

LangGraph Agent Testing

The project includes a basic chatbot agent built with LangGraph. You can test it in multiple ways:

Option 1: Testing with LangGraph Studio (LangSmith)

LangGraph Studio provides a visual interface for testing and debugging your agents with full tracing capabilities.

Prerequisites

  1. Install LangGraph CLI (if not already installed):

    pip install langgraph-cli
    
  2. Configure LangSmith (optional but recommended for tracing):

    Get your API key from LangSmith and add to .env:

    LANGSMITH_TRACING=true
    LANGSMITH_API_KEY=lsv2_your_api_key_here
    
  3. Set OpenAI API Key in .env:

    OPENAI_API_KEY=sk-your-openai-api-key-here
    

Start LangGraph Dev Server

Run the following command in your project root:

langgraph dev

This will:

  • Start the LangGraph development server
  • Open LangGraph Studio in your browser (typically at http://localhost:8123)
  • Enable hot-reloading for agent changes
  • Provide visual debugging and tracing

Using LangGraph Studio

  1. Select the Agent: Choose the chatbot graph from the dropdown
  2. Configure Thread: Set a thread ID for conversation persistence
  3. Send Messages: Type messages in the input box and see responses
  4. View State: Inspect the agent's state at each step
  5. Trace Execution: See detailed traces of LLM calls and node executions

LangGraph Configuration

The agent is configured in langgraph.json:

{
  "dependencies": ["."],
  "graphs": {
    "chatbot": "agents/basic/agent.py:make_graph"
  },
  "env": ".env"
}

Option 2: Testing via FastAPI Endpoints

You can test the agent through the FastAPI endpoints after starting the application.

Start the FastAPI Server

# Using the run script
python run.py

# Or using uvicorn directly
uvicorn src.main:app --reload

Test Non-Streaming Endpoint

Using curl:

# First, get an authentication token
TOKEN=$(curl -s -X POST "http://localhost:8000/auth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=your_email@example.com&password=your_password" \
  | jq -r '.access_token')

# Then chat with the agent
curl -X POST "http://localhost:8000/chatbot" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Hello! Can you help me?"
  }'

Using Python:

import requests

# Login
response = requests.post(
    "http://localhost:8000/auth/token",
    data={"username": "your_email@example.com", "password": "your_password"}
)
token = response.json()["access_token"]

# Chat with agent
response = requests.post(
    "http://localhost:8000/chatbot",
    headers={"Authorization": f"Bearer {token}"},
    json={"message": "Hello! Can you help me?"}
)
print(response.text)

Using the provided api.http file:

Open api.http in VS Code with the REST Client extension:

  1. First, execute the login request to get a token
  2. Copy the access_token from the response
  3. Update the @token variable at the top of the file
  4. Execute the chatbot requests
### Chat (Non-Streaming)
POST {{baseUrl}}/chatbot HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{token}}

{
  "message": "Hello! What can you help me with?"
}

### Chat (Streaming)
POST {{baseUrl}}/chatbot/stream HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{token}}

{
  "message": "Tell me a short story"
}

Test Streaming Endpoint

Using curl:

curl -N -X POST "http://localhost:8000/chatbot/stream" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Tell me a story"
  }'

Using Python with SSE:

import requests
import json

# Login first (same as above)
response = requests.post(
    "http://localhost:8000/auth/token",
    data={"username": "your_email@example.com", "password": "your_password"}
)
token = response.json()["access_token"]

# Stream chat response
response = requests.post(
    "http://localhost:8000/chatbot/stream",
    headers={"Authorization": f"Bearer {token}"},
    json={"message": "Tell me a story"},
    stream=True
)

for line in response.iter_lines():
    if line:
        decoded_line = line.decode('utf-8')
        if decoded_line.startswith('data: '):
            content = decoded_line[6:]  # Remove 'data: ' prefix
            print(content, end='', flush=True)

Option 3: Testing via Swagger UI

  1. Start the FastAPI server: python run.py
  2. Open http://localhost:8000/docs
  3. Authenticate:
    • Click "Authorize" button
    • Login via /auth/token endpoint
    • Copy the access token
    • Enter Bearer <token> in the authorization dialog
  4. Test the chatbot endpoints:
    • Expand /chatbot POST endpoint
    • Click "Try it out"
    • Enter your message in the request body
    • Click "Execute"

Agent Architecture

The basic chatbot agent consists of:

  • State: Defined in agents/basic/state.py - Manages conversation messages
  • Graph: Defined in agents/basic/agent.py - Orchestrates the conversation flow
  • Nodes:
    • chatbot node in agents/basic/nodes/chatbot/node.py - Handles LLM interaction
  • Checkpoint: PostgreSQL-based state persistence for conversation history
  • LLM: Uses OpenAI's GPT-4o-mini model

Conversation Persistence

The agent uses PostgreSQL checkpointing to maintain conversation history:

  • Thread ID: Each conversation has a unique thread ID
  • State Persistence: Messages are stored and retrieved across requests
  • Multiple Conversations: Different thread IDs maintain separate conversations

Example with different threads:

# Conversation 1 (thread_id: "1" - used by /chatbot endpoint)
curl -X POST "http://localhost:8000/chatbot" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message": "My name is Alice"}'

curl -X POST "http://localhost:8000/chatbot" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message": "What is my name?"}'
# Response: "Your name is Alice"

# Conversation 2 (thread_id: "2" - used by /chatbot/stream endpoint)
# This will be a separate conversation with no memory of "Alice"

Customizing the Agent

To modify the agent behavior:

  1. Change the LLM model: Edit agents/basic/nodes/chatbot/node.py

    llm = init_chat_model("openai:gpt-4o", temperature=0.7)
    
  2. Modify the system prompt: Edit agents/basic/nodes/chatbot/prompt.py

  3. Add new nodes: Create new node files in agents/basic/nodes/

  4. Update the graph: Modify agents/basic/agent.py to add edges and nodes

  5. Test changes: Use langgraph dev for hot-reloading during development

Architecture Principles

This template follows these key principles:

  1. Layered Architecture: Clear separation between routers (HTTP), services (business logic), and models (data)
  2. No Business Logic in Routers: All business logic resides in service layer
  3. Dependency Injection: Database sessions and authentication via FastAPI's Depends
  4. Schema Separation: Distinct Create, Update, and Read schemas for each model
  5. Bidirectional Relationships: Models use SQLAlchemy relationships properly
  6. Security First: Passwords hashed with bcrypt, JWT for stateless auth

Extending the Template

Adding a New Model

  1. Create model in src/models/new_model.py (inherit from Base)
  2. Create schemas in src/schemas/new_model.py (Create, Update, Read)
  3. Create service in src/services/new_model_service.py
  4. Create router in src/routers/new_model.py
  5. Include router in src/main.py
  6. Generate migration: alembic revision --autogenerate -m "add new_model"
  7. Apply migration: alembic upgrade head

Database Support

The template works with:

  • SQLite (default, for development)

    DATABASE_URL=sqlite:///./app.db
    
  • PostgreSQL (recommended for production)

    DATABASE_URL=postgresql://user:password@localhost:5432/dbname
    
  • MySQL

    DATABASE_URL=mysql+pymysql://user:password@localhost:3306/dbname
    

Change DATABASE_URL in .env accordingly.

Docker Support

Using Docker Compose (Recommended)

The project includes a docker-compose.yml that sets up both the application and a PostgreSQL database.

# Start all services
docker-compose up

# Start in detached mode
docker-compose up -d

# View logs
docker-compose logs -f

# Stop services
docker-compose down

# Stop and remove volumes (⚠️ deletes database data)
docker-compose down -v

The application will be available at http://localhost:8000 with PostgreSQL running on port 5432.

Using Docker Only

# Build the image
docker build -t fastapi-base .

# Run the container
docker run -d -p 8000:8000 \
  -e DATABASE_URL="sqlite:///./app.db" \
  -e SECRET_KEY="your-secret-key" \
  fastapi-base

Environment Variables Reference

Variable Description Default Required
DATABASE_URL Database connection string sqlite:///./app.db Yes
SECRET_KEY JWT signing secret key - Yes
ALGORITHM JWT algorithm HS256 No
ACCESS_TOKEN_EXPIRE_MINUTES Token expiration time in minutes 30 No
OPENAI_API_KEY OpenAI API key for LangGraph agent - Yes (for chatbot)
LANGSMITH_TRACING Enable LangSmith tracing false No
LANGSMITH_API_KEY LangSmith API key for monitoring - No

Generate a secure SECRET_KEY:

openssl rand -hex 32
# or using Python:
python -c "import secrets; print(secrets.token_hex(32))"

Get API Keys:

Troubleshooting

"Module not found" errors

Make sure you're in the virtual environment and have installed all dependencies:

source venv/bin/activate  # or venv\Scripts\activate on Windows
pip install -r requirements.txt

Database connection errors

  • Check that DATABASE_URL is correctly set in .env
  • For SQLite, ensure the directory is writable
  • For PostgreSQL/MySQL, verify the server is running and credentials are correct

"Could not validate credentials" errors

  • Ensure you're sending the token in the Authorization: Bearer <token> header
  • Check that the token hasn't expired (default: 30 minutes)
  • Verify SECRET_KEY in .env matches the one used to generate the token

Alembic migration issues

# Reset migrations (⚠️ development only)
rm -rf alembic/versions/*.py
alembic revision --autogenerate -m "initial migration"
alembic upgrade head

LangGraph agent errors

"OpenAI API key not found"

  • Ensure OPENAI_API_KEY is set in your .env file
  • Verify the key is valid and has credits available

"Checkpointer not initialized"

  • Make sure the PostgreSQL database is running
  • Check the DB_URI in src/db/checkpoint.py is correct
  • Verify the database is accessible

"langgraph dev" command not found

  • Install LangGraph CLI: pip install langgraph-cli
  • Ensure you're in the virtual environment

Agent not responding or timing out

  • Check your OpenAI API key has sufficient credits
  • Verify internet connection for API calls
  • Check LangSmith dashboard for error traces (if enabled)

Project Status

This is a production-ready template that includes:

  • ✅ JWT authentication with secure password hashing
  • ✅ LangGraph AI agents with state persistence
  • ✅ Streaming and non-streaming chatbot endpoints
  • ✅ PostgreSQL checkpointing for conversation history
  • ✅ LangSmith integration for tracing and monitoring
  • ✅ Modular architecture following best practices
  • ✅ Complete test suite with 85%+ coverage
  • ✅ Database migrations with Alembic
  • ✅ Docker support for easy deployment
  • ✅ Comprehensive API documentation
  • ✅ CORS configuration
  • ✅ Input validation with Pydantic
  • ✅ Role-based access control (staff, superuser)

Contributing

This is a template project. Feel free to:

  • Fork and customize for your needs
  • Report issues or suggest improvements
  • Use as a starting point for your projects

License

This is a template project - use it as you wish for your own projects.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dinnovos_agent_cli-1.0.2.tar.gz (49.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dinnovos_agent_cli-1.0.2-py3-none-any.whl (40.3 kB view details)

Uploaded Python 3

File details

Details for the file dinnovos_agent_cli-1.0.2.tar.gz.

File metadata

  • Download URL: dinnovos_agent_cli-1.0.2.tar.gz
  • Upload date:
  • Size: 49.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for dinnovos_agent_cli-1.0.2.tar.gz
Algorithm Hash digest
SHA256 a11d812159d81fec8360fc6a43a84c46de7aa5508157573488939256f8a174be
MD5 2821011af6ae906c4fcdb5ed0cb22149
BLAKE2b-256 b4ce953fa61c5c7dff2cbf7010a350ce5bac534117d6de8d5e8ad281688ffffb

See more details on using hashes here.

File details

Details for the file dinnovos_agent_cli-1.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for dinnovos_agent_cli-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0cc75cbec4041970e824dcf8a70681a452bf0833aa6f3f8d6c347a68724b798d
MD5 89795703bb8680240847ba98531e6393
BLAKE2b-256 ffea52bfc4ad1bcc2efb6d665ab92e4ecb922b756d3b7b94ef0b7588d1f14cf6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page