I am building a structured troubleshooting agent that ingests stack traces, error logs, and source code, then returns a ranked diagnosis and suggested fix. It helps backend engineers cut down the time spent reproducing elusive production bugs. We will wire it to Oxlo.ai so that even massive log payloads cost the same flat per-request rate.
What you'll need
- Python 3.10 or newer
pip install openai pydantic- An Oxlo.ai API key from https://portal.oxlo.ai
The Oxlo.ai client uses the standard OpenAI SDK, so no extra adapters are required.
Step 1: Define the schema
To keep the agent reproducible, I enforce a JSON schema with Pydantic before I send anything to the API. This guarantees that every diagnosis contains the same fields.
import json
from pydantic import BaseModel, Field
from typing import List
class Diagnosis(BaseModel):
summary: str = Field(description="One-line description of the bug")
root_cause: str = Field(description="Detailed explanation of why it happened")
affected_files: List[str] = Field(description="List of file names or paths involved")
suggested_fix: str = Field(description="Concrete code or configuration change")
confidence: int = Field(description="Integer 1-10, 10 being certain")
Step 2: Write the system prompt
The system prompt acts as a senior engineer who refuses to guess. It requires step-by-step reasoning and JSON output only.
SYSTEM_PROMPT = """You are a senior site-reliability engineer diagnosing production issues.
You will receive an error log, a code snippet, and a list of dependencies.
Follow these rules:
1. Reason silently about the most likely root cause before proposing a fix.
2. Consider race conditions, dependency mismatches, and environment assumptions.
3. Respond with valid JSON only, no markdown fences, no commentary outside the JSON.
4. Use this exact schema:
{
"summary": "...",
"root_cause": "...",
"affected_files": ["..."],
"suggested_fix": "...",
"confidence": 0
}
"""
Step 3: Assemble the context
Raw logs are noisy, so I strip trailing whitespace and wrap each piece in clear tags to reduce ambiguity for the model.
def build_user_message(error_log: str, code_snippet: str, dependencies: str) -> str:
return (
"<error_log>\n"
f"{error_log.strip()}\n"
"</error_log>\n\n"
"<code_snippet>\n"
f"{code_snippet.strip()}\n"
"</code_snippet>\n\n"
"<dependencies>\n"
f"{dependencies.strip()}\n"
"</dependencies>\n\n"
"Diagnose the issue and return the JSON object described in your instructions."
)
Step 4: Query Oxlo.ai
I send the assembled payload to Oxlo.ai. I use Llama 3.3 70B for reliable structured reasoning, but you can swap in DeepSeek R1 671B or Qwen 3 32B for deeper logic. Because Oxlo.ai pricing is per request rather than per token, I can include the full stack trace without worrying about length. See https://oxlo.ai/pricing for details.
from openai import OpenAI
client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")
def run_diagnosis(user_message: str) -> str:
response = client.chat.completions.create(
model="llama-3.3-70b",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_message},
],
)
return response.choices[0].message.content
Step 5: Parse and render
Parsing the JSON through Pydantic catches hallucinated fields early and gives me a clean report to paste into a ticket.
def print_diagnosis(raw_json: str) -> None:
d = Diagnosis.model_validate_json(raw_json)
print(f"Summary : {d.summary}")
print(f"Confidence : {d.confidence}/10")
print(f"Root Cause : {d.root_cause}")
print(f"Affected : {', '.join(d.affected_files)}")
print(f"Suggested Fix:\n{d.suggested_fix}")
Run it
Here is a realistic end-to-end test with a Python stack trace and a buggy function.
if __name__ == "__main__":
ERROR_LOG = """Traceback (most recent call last):
File "/app/worker.py", line 42, in process_event
user = payload["user"]["profile"]
KeyError: 'profile'"""
CODE = """import json
def process_event(raw: str):
payload = json.loads(raw)
user = payload["user"]["profile"]
return user["email"]"""
DEPS = "python 3.11, pydantic 2.5, redis 5.0"
msg = build_user_message(ERROR_LOG, CODE, DEPS)
raw = run_diagnosis(msg)
print_diagnosis(raw)
Example output:
Summary : Missing profile key in user payload causes KeyError in process_event
Confidence : 9/10
Root Cause : The code assumes the nested key "profile" always exists under "user", but the upstream event schema does not guarantee it.
Affected : worker.py
Suggested Fix:
Use .get() or validate the schema before accessing nested keys.
Example: user = payload.get("user", {}).get("profile")
Alternatively, define a Pydantic model for the payload and validate it on entry.
Next steps
Wire the run_diagnosis function into a Slack bot so on-call engineers can paste a log and get a triage thread in seconds. You can also add a second pass with DeepSeek R1 671B on Oxlo.ai to review any diagnosis that scores below confidence 7 and propose alternative hypotheses.
Top comments (0)