Careeroza
FastAPI Backend for an LLM
Design
- Keep the API key on the server. The browser talks only to your backend.
- Use the async client (
AsyncAnthropic) so one worker can serve many waiting requests. - Validate input size, and return clear HTTP errors when the LLM provider fails.
The App
# main.py
import anthropic
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
app = FastAPI(title="ShopEase Assistant")
client = anthropic.AsyncAnthropic() # reads ANTHROPIC_API_KEY from the environment
SYSTEM = "You are the ShopEase support assistant. Answer in under 80 words."
class ChatIn(BaseModel):
message: str = Field(min_length=1, max_length=2000)
history: list[dict] = Field(default_factory=list, max_length=20)
class ChatOut(BaseModel):
reply: str
input_tokens: int
output_tokens: int
@app.post("/chat", response_model=ChatOut)
async def chat(body: ChatIn):
try:
resp = await client.messages.create(
model="claude-sonnet-5-5",
max_tokens=1000,
system=SYSTEM,
messages=body.history + [{"role": "user", "content": body.message}],
)
except anthropic.RateLimitError:
raise HTTPException(503, "Assistant is busy, please retry in a few seconds")
except anthropic.APIStatusError as e:
raise HTTPException(502, f"Upstream error {e.status_code}")
text = next((b.text for b in resp.content if b.type == "text"), "")
return ChatOut(reply=text, input_tokens=resp.usage.input_tokens, output_tokens=resp.usage.output_tokens)
@app.get("/health")
async def health():
return {"status": "ok"}Call it
curl -s -X POST http://localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{"message": "What is the return window for shoes?"}'Example output
{"reply":"Shoes can be returned within 10 days of delivery, as long as the tags are attached. Start a return from My Orders and we will schedule a pickup.","input_tokens":38,"output_tokens":41}