Guides/ Python

FastAPI AI Agent with LangChain

Create a Python AI API with FastAPI, LangChain, SQLModel, Pydantic, and Ruff using Better Fullstack.

Updated 2026-05-12

fastapilangchainaisqlmodel

Use this stack when you want a Python API prepared for AI application code.

npm create better-fullstack@latest my-python-ai-api -- \
  --ecosystem python \
  --python-web-framework fastapi \
  --python-orm sqlmodel \
  --python-validation pydantic \
  --python-ai langchain \
  --python-quality ruff

What this creates

  • A FastAPI project.
  • LangChain as the Python AI library option.
  • SQLModel and Pydantic.
  • Ruff for code quality.

Generated shape

This scaffold starts with an HTTP API, SQLModel persistence, and LangChain helper modules. The route layer handles validation and streaming responses, while the AI client module owns model calls. That separation matters once prompts, retrieval, tools, and persistence start changing at different speeds.

my-python-ai-api/
├── pyproject.toml
├── alembic.ini
├── src/app/
│   ├── main.py
│   ├── database.py
│   ├── models.py
│   ├── crud.py
│   ├── langchain_client.py
│   ├── langchain_schemas.py
│   └── settings.py
└── tests/
    ├── test_main.py
    └── test_database.py

The generated dependencies include langchain and langchain-openai. Set provider credentials through environment variables before calling the AI endpoints.

OPENAI_API_KEY="sk-..."
DATABASE_URL="postgresql+psycopg://postgres:postgres@localhost:5432/my_python_ai_api"

When to choose it

Choose this for AI APIs, retrieval workflows, agent backends, and Python services that need a web boundary around model or tool orchestration.

Choose this over a plain FastAPI database API when the first-class workflow is model orchestration. Choose the SQLAlchemy guide when persistence is the center of the service and AI may be added later.

NeedThis LangChain stackPlain FastAPI API
Chat/completion endpointGenerated starting pointAdd by hand
Streaming responsesIncluded in the AI route patternAdd when needed
Data model styleSQLModel combines tables and Pydantic shapesSQLAlchemy models plus Pydantic schemas
Prompt/tool growthAI client module gives a clear homeYou choose the module boundary
Production concernProvider keys, latency, retries, observabilityDatabase and HTTP behavior first

Representative snippets

SQLModel keeps persistence and validation close together for small services.

from datetime import datetime

from pydantic import EmailStr
from sqlmodel import Field, SQLModel


class UserBase(SQLModel):
    email: EmailStr = Field(index=True, unique=True)
    name: str | None = Field(default=None, max_length=255)


class User(UserBase, table=True):
    __tablename__ = "users"

    id: int | None = Field(default=None, primary_key=True)
    created_at: datetime = Field(default_factory=datetime.utcnow)
    updated_at: datetime = Field(default_factory=datetime.utcnow)

Keep the route thin and let langchain_client.py own model details.

from fastapi.responses import StreamingResponse

from app.langchain_client import chat, chat_stream
from app.langchain_schemas import ChatRequest, ChatResponse


@app.post("/ai/chat", response_model=ChatResponse)
async def langchain_chat(request: ChatRequest):
    response = await chat(request.message, history=request.history)
    return ChatResponse(response=response)


@app.post("/ai/chat/stream")
async def langchain_chat_stream(request: ChatRequest):
    return StreamingResponse(
        chat_stream(request.message, history=request.history),
        media_type="text/event-stream",
    )

As the agent grows, introduce explicit tool functions rather than letting routes assemble prompt strings.

from langchain_core.tools import tool


@tool
def lookup_customer(customer_id: str) -> str:
    """Return customer context for support workflows."""
    return customer_repository.summary(customer_id)

Migrations and tests

The generated SQLModel path includes Alembic configuration. Use it to make database changes repeatable, especially if you store conversations, tool calls, evaluation traces, or document chunks.

uv run ruff check .
uv run pytest
uv run alembic revision --autogenerate -m "add conversation tables"
uv run alembic upgrade head

Add tests at two levels: route tests for request validation and streaming behavior, and client tests around prompt/tool orchestration with the model provider mocked. Avoid calling paid model APIs in the normal unit test lane.

Compatibility notes

Python AI options are selected through --python-ai. This is separate from the TypeScript --ai flag used by web app AI SDK choices.

  • --python-ai langchain is an array-style Python ecosystem option; additional Python AI libraries can be selected in stacks that support them.
  • --python-orm sqlmodel works well for compact API/database examples because response schemas and table models can share base classes.
  • The generated DATABASE_URL fallback is local SQLite. Use PostgreSQL by setting DATABASE_URL.
  • FastAPI streaming responses require the deployment target to support long-running HTTP responses.

Deployment notes

Deploy this like a FastAPI service, but budget for AI-specific concerns: provider credentials, request timeouts, retries, rate limits, and response streaming. Run migrations before release and keep model/provider settings outside the image.

uv run alembic upgrade head
uv run uvicorn app.main:app --host 0.0.0.0 --port "${PORT:-8000}"

For production agent workflows, add request IDs and structured logs around each model call. If you introduce retrieval, keep embeddings, vector indexes, and source documents versioned separately from the application deploy.

Troubleshooting

SymptomCheck
AI route returns provider errorsVerify OPENAI_API_KEY or the provider-specific environment variables.
Streaming works locally but buffers in productionConfirm the proxy/platform supports streaming responses.
Tests are slow or flakyMock LangChain/provider clients in unit tests.
SQLModel tables are missingRun Alembic migrations or initialize the database before hitting routes.

Next steps