Principle:Protectai Llm guard Input Scanner Factory Pattern
| Knowledge Sources | |
|---|---|
| Domains | Factory_Pattern, Configuration |
| Last Updated | 2026-02-14 12:00 GMT |
Overview
Dynamic instantiation of scanner objects by name using the factory pattern.
Description
The factory pattern is a creational design pattern that provides an interface for creating objects without specifying their concrete classes at compile time. In the context of LLM guardrails, this principle enables configuration-driven pipeline assembly -- scanners can be selected and instantiated at runtime based on string names rather than hard-coded class references.
The input scanner factory maintains a mapping from human-readable scanner names (strings) to their corresponding class constructors. When a pipeline is being assembled from a configuration file or dictionary, the factory receives the scanner name and an optional configuration dictionary. It looks up the appropriate constructor in its mapping and invokes it, unpacking the configuration dictionary as keyword arguments to the constructor.
This decoupling of scanner selection from scanner instantiation allows for:
- Dynamic pipeline composition -- adding or removing scanners without code changes.
- Configuration-driven deployment -- different environments can run different scanner combinations.
- Extensibility -- new scanner types can be registered with the factory without modifying existing pipeline code.
Usage
Apply this principle when building configurable guardrail pipelines:
- Deployment systems that need to assemble scanner pipelines from configuration files.
- Testing frameworks that need to instantiate specific scanner combinations dynamically.
- Multi-tenant systems where different users or applications require different scanner sets.
- Any architecture that benefits from separating scanner selection logic from pipeline execution logic.
Theoretical Basis
The factory pattern for input scanners operates as follows:
1. Maintain a registry: a dictionary mapping scanner name strings to class references.
registry = { "ScannerA": ScannerAClass, "ScannerB": ScannerBClass, ... }
2. When a scanner is requested by name:
a. Look up the name in the registry to obtain the class reference.
b. If the name is not found, raise an error indicating an unknown scanner.
3. If an optional configuration dictionary is provided:
a. Unpack it as keyword arguments to the constructor:
instance = registry[name](**config)
b. Otherwise, invoke the constructor with no arguments:
instance = registry[name]()
4. Return the instantiated scanner object, ready for use in the pipeline.
5. The calling code uses the returned object through its common scanner interface
(e.g., a scan() method), without needing to know the concrete class.