DEV Community

shashank ms
shashank ms

Posted on

Deploying LLM on a Server

I needed a private API that could accept raw server logs and return structured incident analysis without sending data to a managed chat UI. In this tutorial, we will build exactly that: a containerized FastAPI service that forwards log analysis to Oxlo.ai. Because Oxlo.ai charges per request instead of per token, dumping multi-thousand-line logs into the prompt does not explode the cost.

What you'll need

  • Python 3.10 or newer
  • An Oxlo.ai API key from https://portal.oxlo.ai
  • The OpenAI SDK installed via pip install openai
  • Docker for the containerization step

Step 1: Scaffold the project

Create a virtual environment and install the dependencies. Then store your Oxlo.ai API key in a .env file.

mkdir log-analysis-api && cd log-analysis-api
python3 -m venv venv && source venv/bin/activate
pip install openai fastapi uvicorn pydantic python-dotenv
OXLO_API_KEY=YOUR_OXLO_API_KEY

Step 2: Define the system prompt

The agent needs strict instructions to return valid JSON. I keep the prompt in its own variable so it is easy to tweak without touching the route logic.

SYSTEM_PROMPT = """You are a senior site reliability engineer. 
Analyze the provided server logs and return a structured JSON object with three fields:
- summary: a one-sentence description of the issue
- severity: one of low, medium, high, or critical
- root_cause: the most likely root cause
Be concise and factual. Do not speculate beyond what the logs show."""

Step 3: Build the FastAPI server

I wire everything together in main.py. The Oxlo.ai client uses the OpenAI-compatible base URL, and the endpoint calls llama-3.3-70b with the system prompt and log payload.

import os
import json
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from openai import OpenAI

client = OpenAI(
    base_url="https://api.oxlo.ai/v1",
    api_key=os.environ["OXLO_API_KEY"],
)

SYSTEM_PROMPT = """You are a senior site reliability engineer. 
Analyze the provided server logs and return a structured JSON object with three fields:
- summary: a one-sentence description of the issue
- severity: one of low, medium, high, or critical
- root_cause: the most likely root cause
Be concise and factual. Do not speculate beyond what the logs show."""

app = FastAPI()

class LogRequest(BaseModel):
    logs: str

class AnalysisResponse(BaseModel):
    summary: str
    severity: str
    root_cause: str

@app.post("/analyze", response_model=AnalysisResponse)
async def analyze_logs(req: LogRequest):
    if not req.logs.strip():
        raise HTTPException(status_code=400, detail="Empty log payload")
    
    try:
        response = client.chat.completions.create(
            model="llama-3.3-70b",
            messages=[
                {"role": "system", "content": SYSTEM_PROMPT},
                {"role": "user", "content": req.logs},
            ],
        )
        content = response.choices[0].message.content
        parsed = json.loads(content)
        return AnalysisResponse(**parsed)
    except json.JSONDecodeError:
        raise HTTPException(status_code=502, detail="Invalid JSON from model")
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Step 4: Containerize for deployment

I containerize the service so it can deploy to any server without managing GPUs or model weights. The Dockerfile uses a slim Python image and passes the API key at runtime.

Create requirements.txt:

openai
fastapi
uvicorn[standard]
pydantic

Create a Dockerfile:

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY main.py .

ENV PYTHONUNBUFFERED=1
EXPOSE 8000

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

Build and run:

docker build -t log-analysis-api .
docker run -p 8000:8000 -e OXLO_API_KEY=$OXLO_API_KEY log-analysis-api

Run it

With the container running, send a test payload. I trimmed real nginx error logs for the demo.

curl -X POST http://localhost:8000/analyze \
  -H "Content-Type: application/json" \
  -d '{"logs": "2024-05-20T14:32:10Z ERROR upstream timed out (110: Connection timed out)\n2024-05-20T14:32:11Z ERROR connect() failed (111: Connection refused)\n2024-05-20T14:32:15Z WARN upstream server temporarily disabled"}'

The endpoint should return structured JSON immediately.

Example output:

{
  "summary": "Upstream backend is unreachable, causing connection timeouts and nginx failovers.",
  "severity": "high",
  "root_cause": "Backend service is either down or rejecting connections on the expected port."
}

Next steps

Add an async Redis cache in front of the /analyze endpoint to avoid re-analyzing identical log batches. If your team handles multilingual logs, swap the model string to qwen-3-32b or kimi-k2.6 with no other code changes. You can review Oxlo.ai request-based pricing at https://oxlo.ai/pricing to estimate cost as you scale traffic.

Top comments (0)