Skip to main content
This guide walks you through:
  • Building a minimal FastAPI app with a Upsonic agent using async endpoints and agent.do_async()
  • Containerizing with Docker
  • Running locally

Why async with FastAPI

FastAPI is async-native. Use agent.do_async() in your route handlers so the event loop is not blocked during LLM and tool calls. That keeps the server responsive under concurrent requests.

Setup

1

Create a new directory for your project

Create a new directory and navigate into it:
mkdir my-upsonic-project
cd my-upsonic-project
Resulting structure:
my-upsonic-project/
├── main.py
├── Dockerfile
├── .dockerignore
├── pyproject.toml
2

Initialize the project with uv

uv init
uv add fastapi upsonic uvicorn anthropic

Step 1: Create the FastAPI app

1

Create `main.py` with async endpoints and `agent.do_async()`

main.py
from fastapi import FastAPI
from upsonic import Agent, Task
from upsonic.tools import WebSearch

app = FastAPI()

agent = Agent(
    "anthropic/claude-sonnet-4-6",
    name="Customer Support",
    company_url="https://your-company.com",
    company_objective="To provide excellent customer service and support",
)

@app.get("/ask")
async def ask(query: str) -> dict[str, str]:
    task = Task(query, tools=[WebSearch])
    response = await agent.do_async(task)
    return {"response": response}
2

Set ANTHROPIC_API_KEY

export ANTHROPIC_API_KEY=your_api_key  # On Windows: set ANTHROPIC_API_KEY=your_api_key
3

Run the app

uv run uvicorn main:app --reload

Step 2: Docker

1

Create a `.dockerignore` file

.dockerignore
.venv
__pycache__
2

Create a `Dockerfile`

Dockerfile
FROM python:3.12-slim

WORKDIR /app

COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

COPY pyproject.toml uv.lock ./
RUN uv sync --frozen --no-dev

COPY . .

CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
3

Build and run the image

docker build -t my-upsonic-app .
docker run -p 8000:8000 -e ANTHROPIC_API_KEY=your_api_key my-upsonic-app
4

Access the app

Open http://localhost:8000. Interactive API docs: http://localhost:8000/docs.

Step 3: Structured responses (async)

Use Pydantic models and agent.do_async() with response_format for typed JSON responses.
1

Add structured response in `main.py`

main.py
from fastapi import FastAPI
from upsonic import Agent, Task
from upsonic.tools import WebSearch
from pydantic import BaseModel
from typing import List

app = FastAPI()

class TravelRecommendation(BaseModel):
    destination: str
    attractions: List[str]
    best_time_to_visit: str
    estimated_budget: str

agent = Agent(
    "anthropic/claude-sonnet-4-6",
    name="Travel Advisor",
    company_url="https://your-travel-company.com",
    company_objective="To provide personalized travel recommendations and advice",
)

@app.get("/travel-recommendation")
async def get_travel_recommendation(
    destination_type: str, budget: str, duration: str
) -> TravelRecommendation:
    task = Task(
        f"Recommend a travel destination for a {duration} trip with {destination_type} experience and {budget} budget",
        tools=[WebSearch],
        response_format=TravelRecommendation,
    )
    response = await agent.do_async(task)
    return response

@app.get("/ask")
async def ask(query: str) -> dict[str, str]:
    task = Task(query, tools=[WebSearch])
    response = await agent.do_async(task)
    return {"response": response}
2

Test the structured endpoint

curl "http://localhost:8000/travel-recommendation?destination_type=beach&budget=medium&duration=7%20days"

Key takeaways

  • Use async route handlers and await agent.do_async(task) so FastAPI’s event loop stays non-blocking.
  • Use response_format=YourPydanticModel when you need structured JSON.
  • Run in production with uv run uvicorn main:app --host 0.0.0.0 --port 8000 or via Docker as above.