FastAPI AI Agent with LangChain
Create a Python AI API with FastAPI, LangChain, SQLModel, Pydantic, and Ruff using Better Fullstack.
Updated 2026-05-12
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 ruffWhat 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.pyThe 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.
| Need | This LangChain stack | Plain FastAPI API |
|---|---|---|
| Chat/completion endpoint | Generated starting point | Add by hand |
| Streaming responses | Included in the AI route pattern | Add when needed |
| Data model style | SQLModel combines tables and Pydantic shapes | SQLAlchemy models plus Pydantic schemas |
| Prompt/tool growth | AI client module gives a clear home | You choose the module boundary |
| Production concern | Provider keys, latency, retries, observability | Database 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 pytestuv run alembic revision --autogenerate -m "add conversation tables"
uv run alembic upgrade headAdd 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 langchainis an array-style Python ecosystem option; additional Python AI libraries can be selected in stacks that support them.--python-orm sqlmodelworks well for compact API/database examples because response schemas and table models can share base classes.- The generated
DATABASE_URLfallback is local SQLite. Use PostgreSQL by settingDATABASE_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
| Symptom | Check |
|---|---|
| AI route returns provider errors | Verify OPENAI_API_KEY or the provider-specific environment variables. |
| Streaming works locally but buffers in production | Confirm the proxy/platform supports streaming responses. |
| Tests are slow or flaky | Mock LangChain/provider clients in unit tests. |
| SQLModel tables are missing | Run Alembic migrations or initialize the database before hitting routes. |
Next steps
- Open the Stack Builder.
- Compare with Next.js AI CLI Agent Workbench.
- Read the Python ecosystem docs.