Salta al contenuto
AImpact
IT EN
AI per sviluppatori 6 min di lettura

FastAPI + Ollama: un backend AI in Python in 30 minuti

Come costruire un'API REST che interroga modelli AI locali con FastAPI e Ollama. Streaming, endpoint per chat, integrazione con Celery per task pesanti.

Pubblicato: 3 giugno 2025

FastAPI è il framework Python più veloce per costruire API REST. Ollama espone i tuoi modelli AI locali su http://localhost:11434. I due si connettono naturalmente — e in meno di mezz’ora hai un backend AI funzionante, senza cloud, senza costi per token, senza dati che escono dalla tua rete.

Setup minimo: endpoint /chat in 15 righe

Prima installa le dipendenze:

pip install fastapi uvicorn ollama

Poi crea main.py:

from fastapi import FastAPI
from ollama import Client

app = FastAPI()
ollama = Client()

@app.post("/chat")
async def chat(prompt: str):
    response = ollama.chat(
        model="qwen2.5:7b",
        messages=[{"role": "user", "content": prompt}]
    )
    return {"response": response['message']['content']}

Avvia con uvicorn main:app --reload e hai un endpoint POST su http://localhost:8000/chat. Testa subito:

curl -X POST "http://localhost:8000/chat?prompt=Spiegami+SOLID+in+3+righe"

Ollama deve girare già in background — se non ce l’hai: docker run -d -p 11434:11434 ollama/ollama.

Streaming token-by-token (Server-Sent Events)

La risposta sincrona blocca finché il modello non ha finito. Per un’esperienza tipo ChatGPT — carattere per carattere mentre arriva — usa lo streaming:

from fastapi.responses import StreamingResponse

@app.post("/chat/stream")
async def chat_stream(prompt: str):
    def generate():
        stream = ollama.chat(
            model="qwen2.5:7b",
            messages=[{"role": "user", "content": prompt}],
            stream=True
        )
        for chunk in stream:
            token = chunk['message']['content']
            yield f"data: {token}\n\n"

    return StreamingResponse(generate(), media_type="text/event-stream")

Il frontend consuma lo stream con EventSource o fetch + ReadableStream. Il vantaggio pratico: l’utente vede la risposta iniziare in ~200ms invece di aspettare 8-10 secondi per una risposta lunga.

Celery per task pesanti: non bloccare il thread HTTP

Se devi elaborare 100 PDF con l’AI, analizzare un dataset, o fare operazioni che durano decine di secondi, non farlo nel thread HTTP. L’utente aspetta, il server si blocca, i timeout arrivano.

Soluzione: Celery con Redis come broker. L’endpoint risponde subito con un task ID, il worker elabora in background.

tasks.py:

from celery import Celery

celery_app = Celery("tasks", broker="redis://localhost:6379/0",
                    backend="redis://localhost:6379/0")

@celery_app.task
def analyze_document(file_path: str, user_email: str):
    from ollama import Client
    client = Client()
    with open(file_path) as f:
        content = f.read()
    result = client.chat(
        model="qwen2.5:7b",
        messages=[{"role": "user", "content": f"Analizza: {content}"}]
    )
    # send_email(user_email, result['message']['content'])
    return result['message']['content']

In main.py aggiungi:

from tasks import analyze_document

@app.post("/analyze")
async def analyze(file_path: str, email: str):
    task = analyze_document.delay(file_path, email)
    return {"task_id": task.id, "status": "in elaborazione"}

@app.get("/status/{task_id}")
async def status(task_id: str):
    from celery.result import AsyncResult
    result = AsyncResult(task_id)
    return {"status": result.status, "result": result.result}

Avvia il worker: celery -A tasks worker --loglevel=info

Deploy con Docker Compose

docker-compose.yml con tutti e tre i servizi:

services:
  api:
    build: .
    ports:
      - "8000:8000"
    depends_on: [redis, ollama]

  worker:
    build: .
    command: celery -A tasks worker --loglevel=info
    depends_on: [redis, ollama]

  redis:
    image: redis:7-alpine

  ollama:
    image: ollama/ollama
    ports:
      - "11434:11434"
    volumes:
      - ollama_data:/root/.ollama

volumes:
  ollama_data:

Dockerfile minimo:

FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Cosa fare

  • Parti dal setup minimo: installa FastAPI + Ollama e fai girare l’endpoint /chat in locale — 10 minuti, zero infrastruttura.
  • Aggiungi lo streaming appena vuoi usarlo in un frontend: la differenza di UX è netta e l’implementazione è una manciata di righe.
  • Usa Celery solo quando hai task che durano più di 2-3 secondi — per tutto il resto, l’endpoint sincrono o lo streaming sono più che sufficienti.