DEV Community

shashank ms
shashank ms

Posted on

Building a Code Analysis Tool with LLM: A Step-by-Step Guide

We are going to build a lightweight static analysis assistant that reads a local codebase, flags potential bugs, and suggests refactors. It is useful for teams who want to automate first-pass code review on legacy projects or large pull requests.

What you'll need

Step 1: Initialize the Oxlo.ai client

Create a new file named analyzer.py and set up the OpenAI-compatible client pointing to Oxlo.ai. I keep my key in an environment variable so it does not end up in git.

import os
from openai import OpenAI

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

if not client.api_key:
    raise ValueError("Set the OXLO_API_KEY environment variable.")

Step 2: Collect source files

We need a small scanner that walks a target directory and returns the text content of code files. I filter by common extensions and skip hidden directories like .git and node_modules.

import pathlib

TARGET_EXTENSIONS = {".py", ".js", ".ts", ".go", ".rs", ".java"}

def collect_files(root: str):
    files = {}
    for path in pathlib.Path(root).rglob("*"):
        if any(part.startswith(".") for part in path.parts):
            continue
        if path.suffix in TARGET_EXTENSIONS and path.is_file():
            try:
                files[str(path)] = path.read_text(encoding="utf-8")
            except UnicodeDecodeError:
                continue
    return files

Step 3: Define the system prompt

The system prompt tells the model how to behave. I want structured output so I can parse it later. I ask for a JSON object with a list of findings, each containing a line number, severity, and suggestion.

SYSTEM_PROMPT = """You are a senior staff engineer performing a static code review.
Analyze the provided code file carefully.
Return ONLY a valid JSON object with no markdown formatting.
Use this exact schema:
{
  "findings": [
    {
      "line": integer or null,
      "severity": "critical" | "warning" | "info",
      "category": "security" | "performance" | "correctness" | "style",
      "message": "concise explanation of the issue",
      "suggestion": "concrete fix or refactored code snippet"
    }
  ]
}
If the file has no issues, return {"findings": []}.
"""

Step 4: Send files to Oxlo.ai for analysis

I wrap the API call in a function that passes the file content as a user message. I use deepseek-v3.2 because it is strong at coding and reasoning, and I enable JSON mode so the response is machine readable. Because Oxlo.ai uses request-based pricing, analyzing a 500-line module costs the same as a 50-line module, which keeps long-file audits predictable.

import json

def analyze_file(file_path: str, content: str):
    user_message = f"File: {file_path}\n\n

```\n{content}\n```

"

    response = client.chat.completions.create(
        model="deepseek-v3.2",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
        response_format={"type": "json_object"},
        temperature=0.2,
    )

    raw = response.choices[0].message.content
    return json.loads(raw)

Step 5: Run the analyzer over an entire project

Now I wire the scanner and the analyzer together. I iterate over every file, print a short status line, and collect the results. I also add a small delay and basic error handling so one malformed file does not kill the whole run.

import time

def run_analysis(project_dir: str):
    files = collect_files(project_dir)
    report = []

    for path, content in files.items():
        print(f"Analyzing {path} ...")
        try:
            result = analyze_file(path, content)
            for finding in result.get("findings", []):
                finding["file"] = path
                report.append(finding)
        except Exception as e:
            print(f"  Failed: {e}")
        time.sleep(0.5)

    return report

if __name__ == "__main__":
    findings = run_analysis("./src")
    with open("report.json", "w") as f:
        json.dump(findings, f, indent=2)
    print(f"\nDone. {len(findings)} findings written to report.json.")

Run it

Export your key and point the script at a codebase folder. Here is an example against a small Python utility:

export OXLO_API_KEY="sk-..."
python analyzer.py

Example output:

Analyzing ./src/auth.py ...
Analyzing ./src/db.py ...
Analyzing ./src/main.py ...

Done. 4 findings written to report.json.

The generated report.json looks like this:

[
  {
    "line": 42,
    "severity": "critical",
    "category": "security",
    "message": "SQL query constructed via string concatenation",
    "suggestion": "Use parameterized queries: cursor.execute('SELECT * FROM users WHERE id = ?', (user_id,))",
    "file": "./src/db.py"
  },
  {
    "line": 15,
    "severity": "warning",
    "category": "correctness",
    "message": "Exception handler catches bare Exception and silently passes",
    "suggestion": "Log the error or re-raise a domain-specific exception after handling.",
    "file": "./src/main.py"
  }
]

Next steps

Wire this script into a CI pipeline so every pull request gets an automatic review comment. You can also swap deepseek-v3.2 for qwen-3-32b or kimi-k2.6 if you need stronger multilingual or agentic reasoning support. For details on flat, per-request pricing, see https://oxlo.ai/pricing.

Top comments (0)