Skip to content

AI & Semantic Memory Usage Guide

Overview

This guide provides practical recipes for leveraging the athomic.ai module. It covers common scenarios such as generating text with LLMs, extracting structured data, building RAG (Retrieval-Augmented Generation) pipelines using Semantic Memory, and enforcing governance policies.


Recipe 1: Chat & Text Generation

This recipe demonstrates the standard way to invoke an LLM (like OpenAI GPT-4 or Google Gemini) for text generation.

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

async def generate_marketing_copy(product_name: str):
    # 1. Load configuration
    # Assumes 'default' is configured in settings.toml
    settings = get_settings().ai.llm.connections["default"]

    # 2. Create the provider instance via Factory
    # This automatically handles authentication and connection setup
    llm = LLMFactory.create(settings)

    # 3. Generate content
    # The 'system_message' sets the behavior of the model
    response = await llm.generate_content(
        prompt=f"Write a catchy tagline for {product_name}",
        system_message="You are a creative marketing expert.",
        temperature=0.9 # Higher creativity
    )

    return response

Key Concepts

  • LLMFactory: Decouples your code from the specific provider class (OpenAI vs Vertex).
  • generate_content: The unified method for unstructured text, automatically traced and measured.

Recipe 2: Structured Data Extraction

Extracting reliable JSON from an LLM is a common requirement. Athomic standardizes this using Pydantic models.

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

# 1. Define the desired output schema
class SupportTicketAnalysis(BaseModel):
    sentiment: str = Field(..., description="Customer sentiment: positive, neutral, negative")
    urgency: int = Field(..., description="Urgency level from 1 to 5")
    category: str = Field(..., description="Category: billing, technical, feature_request")

async def analyze_ticket(ticket_body: str):
    settings = get_settings().ai.llm.connections["default"]
    llm = LLMFactory.create(settings)

    # 2. Call generate_structured
    # This guarantees the return type is SupportTicketAnalysis or raises StructuredOutputError
    analysis = await llm.generate_structured(
        prompt=f"Analyze this ticket:n{ticket_body}",
        response_model=SupportTicketAnalysis,
        max_retries=2
    )

    if analysis.urgency >= 4:
        print(f"High urgency ticket detected! Category: {analysis.category}")

Recipe 3: Implementing Semantic Memory (RAG)

The SemanticMemoryService orchestrates the entire RAG flow: embedding text, storing it in the vector DB, and retrieving relevant context.

Storing Information (Indexing)

from nala.athomic.ai.memory.factory import SemanticMemoryFactory

async def learn_user_preferences(user_id: str, notes: list[str]):
    # 1. Initialize the service
    # 'user_context' is the logical collection name in the Vector DB
    memory_service = SemanticMemoryFactory.create(collection_name="user_context")

    # 2. Add memories in batch for efficiency
    # The service automatically handles embedding generation (Document Mode)
    await memory_service.add_batch(
        contents=notes,
        metadatas=[{"user_id": user_id, "source": "onboarding"}] * len(notes)
    )
    print("Preferences stored.")

Recalling Information (Retrieval)

async def chat_with_context(user_id: str, user_question: str):
    memory_service = SemanticMemoryFactory.create(collection_name="user_context")
    llm = LLMFactory.create(get_settings().ai.llm.connections["default"])

    # 1. Recall relevant memories
    # The service automatically embeds the query (Query Mode) and searches the DB
    results = await memory_service.recall(
        query=user_question,
        limit=3,
        filters={"user_id": user_id} # Tenancy isolation
    )

    # 2. Construct the context block
    context_str = "n".join([f"- {res.memory.content}" for res in results])

    # 3. Generate answer using context
    prompt = f"""
    Context information is below:
    {context_str}
    ---------------------
    Given the context, answer the question: {user_question}
    """

    return await llm.generate_content(prompt)

Recipe 4: Enforcing AI Governance (Rate Limits)

To prevent cost overruns or abuse, you can attach governance guards to your LLM provider.

from nala.athomic.ai.llm.factory import LLMFactory
from nala.athomic.ai.governance.guards import RateLimitGuard
from nala.athomic.config import get_settings

async def protected_generation(user_id: str, prompt: str):
    settings = get_settings().ai.llm.connections["default"]

    # 1. Define the guard
    # 'ai_standard_user' must be a policy defined in your RateLimiter configuration
    rate_limiter = RateLimitGuard(policy_name="ai_standard_user")

    # 2. Initialize LLM with the guard
    llm = LLMFactory.create(settings)
    llm.guards.append(rate_limiter)

    try:
        # 3. The check is executed automatically before generation
        # Pass 'user_id' in kwargs so the guard knows the scope
        return await llm.generate_content(prompt, user_id=user_id)

    except Exception as e:
        # Captures QuotaExceededError if limit is hit
        print(f"Request blocked by governance: {e}")

Best Practices

1. Asymmetric Embeddings

When working with embeddings directly (via EmbeddingFactory), always distinguish between documents and queries. * Use embed_documents() for text you are storing. * Use embed_query() for the search term. * This distinction is critical for providers like Vertex AI (text-embedding-gecko) to produce high-quality vectors.

2. Error Handling

Always wrap AI calls in try/except blocks to handle standard Athomic exceptions: * ContextWindowExceededError: Use a fallback strategy (e.g., summarize context). * StructuredOutputError: The model failed to produce JSON. You might want to retry or return a default value.

3. Tracing

The AI module is fully instrumented with OpenTelemetry. Use the trace_id from your application logs to visualize the full chain: Request -> Controller -> Memory Recall -> Vector Search -> LLM Generation.