Skip to content

Large Language Models (LLM)

Overview

The athomic.ai.llm module provides a unified, provider-agnostic interface for interacting with Large Language Models (LLMs) such as OpenAI (GPT-4) and Google Vertex AI (Gemini). It is designed to solve common challenges in production AI applications:

  • Vendor Lock-in: Switch providers via configuration without changing code.
  • Real-Time Streaming: Native support for asynchronous token streaming with standardized chunks.
  • Structured Data: Reliably extract Pydantic models from LLM outputs using a standardized API (generate_structured).
  • Observability: Automatic tracing (OpenTelemetry) and metrics (Prometheus) for every call (unary or streaming).
  • Embedded Governance: Enforce rate limits and safety checks directly within the provider pipeline.
  • Resilient Routing: Dynamically route requests across fallback chains using transparent wrappers, ensuring high availability without changing business logic.

Core Concepts

LLMProviderProtocol

The contract that all LLM providers must implement. It defines three primary operations:

  • generate_content(prompt, ...): Generates unstructured text (blocking).
  • stream_content(prompt, ...): Generates unstructured text incrementally (async iterator).
  • generate_structured(prompt, response_model, ...): Generates a structured object adhering to a specific Pydantic schema.

BaseLLM & Governance

The abstract base class now handles AI Governance automatically: 1. Input Guards: Executed before the request is sent to the provider. These are blocking (e.g., Rate Limiting, Prompt Injection check). 2. Output Guards: Executed after the response is received. For streaming, these currently act in audit mode.


Usage Example

Basic Text Generation (Blocking)

from nala.athomic.ai.llm.factory import LLMFactory
from nala.athomic.config import get_settings

async def chat_with_ai(user_input: str):
    # 1. Create the provider from global settings
    settings = get_settings().ai.llms.connections["default"]
    llm = LLMFactory.create(settings)

    # 2. Generate content (waits for full completion)
    response = await llm.generate_content(
        prompt=user_input,
        system_message="You are a helpful assistant."
    )
    return response.content

Real-Time Streaming

import sys
from nala.athomic.ai.llm.factory import LLMFactory

async def stream_chat(user_input: str):
    llm = LLMFactory.create_default()

    # stream_content yields LLMResponseChunk objects
    async for chunk in llm.stream_content(prompt=user_input):

        # 1. Process incremental text (Token Delta)
        if chunk.content_delta:
            sys.stdout.write(chunk.content_delta)
            sys.stdout.flush()

        # 2. Handle metadata on finish (Usage, Stop Reason)
        if chunk.is_final:
            print(f"\n[Meta] Finished. Tokens: {chunk.usage.total_tokens}")

Structured Output (JSON Extraction)

from pydantic import BaseModel, Field
from nala.athomic.ai.llm.factory import LLMFactory

class UserIntent(BaseModel):
    intent: str = Field(..., description="The user's intention (buy, sell, support)")
    confidence: float

async def analyze_intent(text: str):
    llm = LLMFactory.create_default()

    # Guaranteed to return a UserIntent instance or raise StructuredOutputError
    intent: UserIntent = await llm.generate_structured(
        prompt=f"Analyze this text: {text}",
        response_model=UserIntent
    )

    return intent

Configuration

LLM connections are configured in settings.toml under the [ai.llms] section. You can define resilient routing by attaching wrappers to a connection.

[default.ai.llms]
# The default connection to use
default_connection_name = "gpt4_main"

  # 1. Primary Connection (with Router Wrapper)
  [default.ai.llms.connections.gpt4_main]
  enabled = true
  backend = "openai"
  default_model = "gpt-4-turbo"
  timeout = 10.0

    [default.ai.llms.connections.gpt4_main.provider]
    # OpenAI specific settings
    api_key = { path = "ai/openai", key = "api_key" }
    organization_id = "org-123"

    # Transparent fallback to a local or secondary model on failure
    [[default.ai.llms.connections.gpt4_main.wrappers]]
    name = "router"
    enabled = true
    fallback_chain = ["local_fallback"]
    strategy = "tier"

  # 2. Fallback Connection (e.g., Local Ollama)
  [default.ai.llms.connections.local_fallback]
  enabled = true
  backend = "openai"
  default_model = "llama3.2:1b"
  timeout = 30.0

    [default.ai.llms.connections.local_fallback.provider]
    base_url = "http://localhost:11434/v1"
    api_key = "ollama" # pragma: allowlist secret

API Reference

nala.athomic.ai.llm.protocol.LLMProviderProtocol

Bases: Protocol

Protocol defining the contract for Large Language Model (LLM) interactions. Focused on text generation and structured data extraction.

generate_content(prompt=None, system_message=None, **kwargs) async

Generates unstructured text content based on a given prompt.

generate_structured(prompt, response_model, system_message=None, max_retries=3, **kwargs) async

Generates structured data conforming to a specific Pydantic schema.

stream_content(prompt=None, system_message=None, **kwargs) async

Generates unstructured text content incrementally as an asynchronous stream.

This method is critical for low-latency user experiences (UX).

Parameters:

Name Type Description Default
prompt Optional[str]

The user input text.

None
system_message Optional[str]

Optional system instruction.

None
**kwargs Any

Additional generation parameters.

{}

Returns:

Type Description
AsyncIterator[LLMResponseChunk]

An asynchronous iterator yielding LLMResponseChunk objects.

nala.athomic.ai.llm.base.BaseLLM

Bases: BaseService, LLMProviderProtocol, Generic[S], ABC

Abstract base class for all LLM providers (Vertex, OpenAI, etc.).

This class implements the Template Method pattern to enforce: 1. Lifecycle Management (Startup/Shutdown via BaseService). 2. Unified Observability (Tracing, Metrics, Logging). 3. Error Handling boundaries.

Note: Governance (Guards) is handled by the LLMManager/GuardPipeline before calling this provider.

generate(prompt=None, system_message=None, tools=None, **kwargs) async

Public method for generation (Text or Tool Calls) with observability.

generate_structured(prompt, response_model, system_message=None, max_retries=3, **kwargs) async

Public method for structured generation with observability.

get_output_max_tokens()

Helper to get max output tokens from generation settings.

record_token_usage(prompt_tokens, completion_tokens)

Helper method to record token usage metrics to Prometheus.

stream_content(prompt=None, system_message=None, tools=None, **kwargs) async

Executes an asynchronous streaming generation request and applies output governance. Validates the input prompt against configured guards before initiating the stream. Intercepts each generated chunk to enforce output guards, such as PII sanitization, by wrapping the delta in a standard response schema before yielding to the client.

nala.athomic.ai.schemas.llms.LLMResponseChunk

Bases: BaseModel

Represents a single, incremental chunk of the response during streaming.

nala.athomic.ai.llm.factory.LLMFactory

Bases: FactoryProtocol[LLMProviderProtocol, LLMConnectionSettings]

Factory responsible for constructing LLM providers and transparently applying configured decorator wrappers.

Adheres to the Open/Closed Principle by utilizing registries to resolve both base providers and decorator layers dynamically. It delegates the iteration of configured wrappers to a dedicated internal method, maintaining high cohesion and decoupling from specific routing logic.

create(settings, **kwargs) classmethod

Builds the base LLM client and delegates the application of enabled wrappers.

Parameters:

Name Type Description Default
settings LLMConnectionSettings

The configuration object for the connection.

required
**kwargs Any

Additional unbound dependencies (such as managers or routers) to be passively injected into the custom wrapper creators.

{}

Returns:

Name Type Description
LLMProviderProtocol LLMProviderProtocol

The fully composed LLM client instance.

Raises:

Type Description
ValueError

If the required base provider is not registered.