Serving#

Expose a QueryEngine plus a ChatStore as a FastAPI app that streams grounded answers over SSE. fastrag.serve.create_app(engine=, chat_store=, config=) is a thin adapter over a Retriever+ChatModel you already built — it owns no database engine and no ORM session, and it is the only place in the SDK a PipelineStep is piped to an HTTP POST rather than an async for.

app = create_app(
    engine=engine,
    chat_store=chat_store,
    # ServeConfig rejects a "*" wildcard (credentialed CORS cannot
    # use Access-Control-Allow-Origin: *). For local use, allow the
    # loopback origin the API is served from; a deployed instance
    # names its real origins here.
    config=ServeConfig(
        allowed_origins=["http://127.0.0.1:8000", "http://localhost:8000"],
        # The terminal client (15_asking.py) mints its session token
        # via POST /v1/sessions, which only exists when bearer tokens
        # are enabled — the old 10_serving.py example set this for
        # exactly that reason.
        bearer_tokens=True,
    ),
)

Start it with task serve (runs examples/14_serving.py on :8100), index once first with task index-equivalent (examples/05_indexing.py), then:

curl -sf http://127.0.0.1:8100/healthz
curl -sN -X POST http://127.0.0.1:8100/v1/chats \
  -H 'content-type: application/json' -d '{"content":"What is AgrospAI?"}'

The fastest way to see this running for real, with a dashboard and the chatbot widget in front of it rather than a bare curl, is the repository root’s composed stack (docker compose -f compose/docker-compose.yaml up -d from the repository root, documented in its README.md) — sdk/app/ is the same create_app call shown above, built into the backend service that stack runs.

The serving docs split into five audiences below: the wire contract ({doc}http-api), how the stream is framed (`{doc}`streaming), what GET /metrics exports ({doc}metrics), rate limiting and client IP/country resolution (`{doc}`admission), and what the app is configured with ({doc}configuration``).