# Expected Signature for a Custom SkillSpector Analyzer: Implementation Guide

> Learn the expected signature for a custom SkillSpector analyzer inheriting from LLMAnalyzerBase. Implement the __init__ method to initialize the LLM backend and token budget for efficient analysis.

- Repository: [NVIDIA Corporation/SkillSpector](https://github.com/NVIDIA/SkillSpector)
- Tags: how-to-guide
- Published: 2026-06-14

---

**A custom SkillSpector analyzer must inherit from `LLMAnalyzerBase` and implement the constructor signature `def __init__(self, base_prompt: str, model: str) -> None`, calling `super().__init__(base_prompt, model)` to initialize the LLM backend and token budget.**

The NVIDIA SkillSpector framework provides a pluggable architecture for LLM-powered code analysis. All analyzers in the system extend a common base class that standardizes how prompts are built and how model responses are parsed. Understanding the expected signature and extension points ensures your custom analyzer integrates seamlessly with SkillSpector's graph-execution engine.

## Base Class Constructor Signature

Every custom analyzer subclasses `LLMAnalyzerBase` defined in [`src/skillspector/llm_analyzer_base.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/llm_analyzer_base.py). The constructor at lines 39-42 expects exactly two parameters:

```python
def __init__(self, base_prompt: str, model: str) -> None

```

**`base_prompt`** is the static system prompt that describes analysis criteria to the LLM.  
**`model`** is the string identifier for the LLM (e.g., `"gpt-4o"`, `"claude-3-opus-20240229"`) that `skillspector.llm_utils.get_chat_model` resolves.

When invoked, the parent constructor:
- Stores both parameters as instance attributes
- Calculates the model-specific input-token budget
- Initializes the underlying LangChain chat model

Your custom analyzer must invoke `super().__init__(base_prompt, model)` to ensure these initialization steps execute.

## Optional Extension Points

Beyond the required constructor, the base class exposes three primary hooks for customization:

### Customizing Response Schemas

The class attribute `response_schema` defines the Pydantic model used to structure the LLM's output. By default, this is set to `LLMAnalysisResult` (lines 22-24). Override this attribute to enforce a different JSON structure:

```python
from pydantic import BaseModel, Field

class SecurityFinding(BaseModel):
    severity: str
    line_number: int
    description: str

class SecurityAnalyzer(LLMAnalyzerBase):
    response_schema = SecurityFinding

```

### Overriding Prompt Construction

The `build_prompt(self, batch, **kwargs)` method (documented in the class docstring at lines 6-13) assembles the final prompt sent to the LLM. Override this to customize how file chunks or metadata are injected into the `base_prompt`:

```python
def build_prompt(self, batch, **kwargs):
    # Custom logic to format batch data

    custom_context = f"Analyzing {len(batch)} files..."
    return f"{self.base_prompt}\n{custom_context}\n{batch.content}"

```

### Parsing LLM Responses

The `parse_response(self, response, batch)` method (lines 30-33) converts the structured LLM output into `Finding` objects (defined in [`src/skillspector/models.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/models.py)). Override this when using a custom `response_schema` or when you need non-standard extraction logic:

```python
def parse_response(self, response, batch):
    # response is an instance of self.response_schema

    findings = []
    for item in response.issues:
        findings.append(Finding(
            message=item.description,
            line=item.line_number
        ))
    return findings

```

## Complete Implementation Examples

### Minimal Custom Analyzer

The following skeleton demonstrates the minimal required implementation using the default schema:

```python
from skillspector.llm_analyzer_base import LLMAnalyzerBase

class SimpleStaticAnalyzer(LLMAnalyzerBase):
    def __init__(self, model: str):
        prompt = (
            "Detect any use of unsafe system calls (e.g., exec, system, popen) "
            "and report them with line numbers."
        )
        super().__init__(base_prompt=prompt, model=model)

```

### Advanced Analyzer with Custom Schema

This example implements a custom response schema and overrides the parser:

```python
from pydantic import BaseModel, Field
from skillspector.llm_analyzer_base import LLMAnalyzerBase, LLMAnalysisResult
from skillspector.models import Finding

class MyResult(BaseModel):
    issues: list[dict] = Field(default_factory=list)

class MyAdvancedAnalyzer(LLMAnalyzerBase):
    response_schema = MyResult

    def __init__(self, model: str):
        super().__init__(base_prompt="Find all TODO comments.", model=model)

    def parse_response(self, response, batch):
        findings = []
        for item in response.issues:
            findings.append(
                Finding(
                    message=item.get("text", "TODO found"),
                    file_path=batch.file_path,
                    line=item.get("line", 0)
                )
            )
        return findings

```

## Integration with the Execution Engine

Once implemented, your custom analyzer plugs directly into SkillSpector's batch processing system. The base class provides `get_batches()` to prepare file chunks and both synchronous and asynchronous execution methods:

```python

# Synchronous execution

analyzer = SimpleStaticAnalyzer(model="gpt-4o")
batches = analyzer.get_batches(
    file_paths=["src/my_module.py"],
    file_cache={"src/my_module.py": open("src/my_module.py").read()},
)
results = analyzer.run_batches(batches)

```

```python

# Asynchronous execution

import asyncio

async def run():
    analyzer = SimpleStaticAnalyzer(model="gpt-4o")
    batches = analyzer.get_batches(
        file_paths=["src/my_module.py"],
        file_cache={"src/my_module.py": open("src/my_module.py").read()},
    )
    results = await analyzer.arun_batches(batches)
    return results

asyncio.run(run())

```

## Summary

- **Custom SkillSpector analyzers** must inherit from `LLMAnalyzerBase` in [`src/skillspector/llm_analyzer_base.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/llm_analyzer_base.py) and implement the signature `__init__(self, base_prompt: str, model: str)`.
- **Initialization** requires calling `super().__init__(base_prompt, model)` to configure the LangChain backend and token budgets.
- **Customization** happens through three optional overrides: `response_schema` (class attribute), `build_prompt()`, and `parse_response()`.
- **Execution** uses inherited methods `run_batches()` or `arun_batches()` after preparing data with `get_batches()`.

## Frequently Asked Questions

### What happens if I don't call the parent `__init__` in my custom analyzer?

The analyzer will fail at runtime because it won't have the `_chat_model` attribute or the `_token_budget` calculated. According to the source code in [`src/skillspector/llm_analyzer_base.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/llm_analyzer_base.py) lines 39-42, the parent constructor initializes the LangChain model via `get_chat_model()` and determines the maximum tokens available for the prompt. Without these, `build_prompt()` and `run_batches()` will raise AttributeError exceptions.

### Can I change the constructor signature to accept additional parameters?

Yes, but you must preserve the `base_prompt` and `model` parameters and pass them to `super().__init__()`. You can add custom parameters like `temperature` or `api_key` before the `super()` call, provided you handle the storage of those values yourself. The execution engine only checks that the instance is an `LLMAnalyzerBase` subclass; it does not inspect your specific constructor signature.

### Where is the `Finding` class defined that `parse_response` should return?

The `Finding` dataclass is defined in [`src/skillspector/models.py`](https://github.com/NVIDIA/SkillSpector/blob/main/src/skillspector/models.py). This is the standard return type expected by SkillSpector's reporting nodes. When overriding `parse_response`, ensure your method returns a list of `Finding` objects (or instances of a compatible dataclass) so that downstream nodes in the analysis graph can process the results correctly.

### Does the `model` parameter accept any string, or only specific values?

The `model` string must be resolvable by `skillspector.llm_utils.get_chat_model`. This utility function maps common identifiers like `"gpt-4o"` or `"claude-3-opus"` to their respective LangChain chat model classes. If you provide an unsupported identifier, the parent constructor will raise a `ValueError` during initialization when attempting to instantiate the chat model.