Documentação

Padrões de arquitetura e casos de uso em produção

Laya é um motor de decisão no dispositivo e não autorregressivo, construído sobre uma arquitetura transformer de passada direta única (ModernBERT-large e mmBERT-base). Em vez de gerar tokens sequencialmente como um LLM (o que acarreta custos variáveis de geração de tokens, sobrecarga do loop de decodificação e esquemas de saída imprevisíveis), Laya calcula distribuições de probabilidade calibradas sobre perguntas discretas em uma única passada.

Este documento serve como planta de arquitetura para arquitetos de sistemas e engenheiros de backend que integram o Laya em ambientes de produção.


Motor de decisão vs. LLM vs. recuperação por embeddings

Escolher a primitiva certa depende das restrições de latência, da topologia de hospedagem e de se a tarefa exige geração livre ou classificação discreta:

Dimensão Recuperação por embeddings Motor de decisão Laya LLM autorregressivo
Modelo de computação Distância de cosseno entre vetores Passada direta única (cabeça mascarada não autorregressiva) Geração sequencial token a token
Perfil de execução Busca em índice de vizinhos mais próximos Passada direta única fixa (sem loop de decodificação) Loop de decodificação iterativo que escala com o comprimento da saída
Hospedagem e topologia Em processo ou banco de dados vetorial Em processo (CPU/GPU local) ou daemon HTTP auto-hospedado API remota hospedada ou serviço GPU de modelos grandes
Atenção de contexto Representação vetorial agrupada Atenção cruzada bidirecional profunda sobre toda a entrada Atenção sequencial causal
Saída estruturada Trechos recuperados não estruturados Distribuições nativas alinhadas ao esquema (choice, score, noul) Texto livre que exige reparo de JSON ou amostragem de esquema
Carga de trabalho principal Recuperação ampla de candidatos Classificação discreta, gating de políticas e roteamento Síntese aberta, tradução e geração

1. Gateway de entrada inteligente

Em arquiteturas em camadas, uma grande fração das requisições de entrada não exige as capacidades generativas de um LLM autorregressivo. Consultas como FAQs padrão, perguntas determinísticas sobre estado ou decisões categóricas de roteamento podem ser avaliadas localmente.

O Laya funciona como um gateway de entrada inteligente: ele classifica a intenção e a complexidade da consulta em uma única passada direta local. Requisições determinísticas são resolvidas localmente via endpoints internos ou respostas em cache, enquanto tarefas generativas complexas são encaminhadas para LLMs a montante.

Arquitetura

graph TD
    A[User Request] --> B["<b>Laya Gateway Router</b><br/>• query_complexity: simple | moderate | complex<br/>• intent: faq | account_lookup | creative_synthesis"]
    B -->|Simple & High Confidence| C["<b>Local In-Process Resolution</b><br/>Deterministic FAQ / Internal API"]
    B -->|Complex or Low Confidence| D["<b>Upstream Generative LLM</b><br/>Open-ended synthesis & reasoning"]

Implementação

import laya

agent = laya.load("convaiinnovations/laya")

GATEWAY_QUESTIONS = {
    "complexity": {
        "type": "choice",
        "instructions": "How complex is the user's request?",
        "criteria": {
            "canned": "A greeting, standard FAQ, or simple status request.",
            "structured": "A deterministic data query that can be answered by an API.",
            "complex": "Requires creative generation, multi-step code, or complex analysis.",
        },
    },
    "requires_reasoning": {
        "type": "noul",
        "instructions": "Does this query require frontier model reasoning?",
    },
}

def route_request(user_prompt: str):
    res = agent.system_one(user_prompt, GATEWAY_QUESTIONS, min_confidence=0.85)
    answers = res["answers"]

    complexity = answers["complexity"]["choice"]
    low_confidence = answers["complexity"].get("low_confidence", False)

    # Abstain or escalate if complex or unconfident
    if low_confidence or complexity == "complex" or answers["requires_reasoning"]["noul"] > 0.5:
        return call_frontier_llm(user_prompt)

    if complexity == "canned":
        return lookup_faq_response(user_prompt)
    return execute_internal_api(user_prompt)

2. Roteador de troca de turnos e interrupção de voz de baixa latência

Agentes de voz conversacionais (WebRTC, telefonia) operam sob restrições rigorosas de troca de turnos: atrasos ao detectar quando um usuário fala ou interrompe criam silêncios antinaturais na conversa. Esperar que um modelo generativo completo produza seu primeiro token introduz uma defasagem evitável quando quem liga apenas confirma ou interrompe.

O Laya pode ser colocado diretamente após a transcrição de fala para texto (STT) para classificar o fluxo da conversa e a intenção do usuário em uma única passada direta: disparar áudio de preenchimento rápido ou interromper a reprodução de áudio imediatamente quando uma interrupção é detectada, ao mesmo tempo em que delega consultas complexas ao pipeline de síntese completo.

Arquitetura

graph TD
    A[User Voice Audio] --> B["<b>Speech-to-Text</b><br/>Streaming Audio Transcription"]
    B --> C["<b>Laya Voice Router</b><br/>• intent: ack | reject | interrupt | inquiry<br/>• is_interruption: noul probability"]
    C -->|Interruption: score &gt; 0.6| D["<b>Halt Audio Playback</b><br/>Immediate playback cutoff"]
    C -->|Quick Intent: ack / reject| E["<b>Immediate Audio Filler</b><br/>Conversational confirmation"]
    C -->|Complex Inquiry| F["<b>Upstream Pipeline</b><br/>Full response synthesis"]

Implementação

from laya import Agent

agent = Agent("convaiinnovations/laya")

VOICE_QUESTIONS = {
    "intent": {
        "type": "choice",
        "instructions": "Caller conversational intention",
        "criteria": {
            "ack": "Caller said yes, ok, sure, or agreed.",
            "reject": "Caller said no, cancel, or disagreed.",
            "interrupt": "Caller said hold on, wait, or wants to stop.",
            "inquiry": "Caller is asking a detailed question.",
        },
    },
    "is_interruption": {
        "type": "noul",
        "instructions": "Is the caller interrupting the current speech playback?",
    },
}

def on_voice_chunk(transcript: str, is_speaking: bool):
    decision = agent.system_one(transcript, VOICE_QUESTIONS)
    answers = decision["answers"]

    # Halt playback immediately if caller interrupts
    if answers["is_interruption"]["noul"] > 0.6:
        stop_audio_playback()

    intent = answers["intent"]["choice"]
    if intent in ("ack", "reject"):
        play_immediate_filler_audio(intent)
    else:
        dispatch_to_background_pipeline(transcript)

3. Segurança pré-LLM e firewall de prompts

Proteger sistemas contra injeções de prompt adversariais, jailbreaks e vazamento de dados sensíveis deve acontecer antes de o prompt chegar à janela de contexto do LLM. Executar um modelo generativo separado apenas para julgar se um prompt é seguro adiciona latência redundante e sobrecarga operacional.

O Laya atua como um firewall de segurança inline e não autorregressivo, avaliando injeções de prompt, escalonamentos de privilégio e tarefas fora de escopo em uma única passada direta antes do processamento posterior.

Arquitetura

graph TD
    A[User Input] --> B["<b>Inline Security Hook</b><br/>• prompt_injection (noul)<br/>• system_prompt_extraction (noul)<br/>• pii_present (noul)"]
    B -->|Policy Violation: score &ge; 0.5| C["<b>Abort &amp; Reject</b><br/>Raise policy exception &amp; audit event"]
    B -->|Clean: score &lt; 0.5| D["<b>Dispatch to Main Workflow</b><br/>Safe to execute"]

Implementação

Os hooks no Laya são duck-typed: qualquer objeto que implemente os métodos de ciclo de vida de Hook (ou que herde de BaseHook em laya.hooks) pode ser anexado a um Agent ou Router.

Sob a semântica padrão de lançamento de hooks do Laya (hooks_raise=True):

  • Lançar uma exceção dentro de on_predict_start aborta a execução imediatamente antes que ocorram a tokenização ou a inferência do modelo.
  • A exceção se propaga diretamente para fora de system_one() / predict() até quem chamou.
  • As limpezas de ciclo de vida (on_error e on_predict_end) ainda são executadas, com ctx.error definido como a exceção lançada, garantindo que os logs de auditoria e a telemetria registrem a requisição bloqueada.
import laya
from laya import Router
from laya.hooks import BaseHook, PredictContext

SECURITY_SCHEMA = {
    "is_jailbreak": {
        "type": "noul",
        "instructions": "Is the user attempting a prompt injection, exploit, or jailbreak?",
    },
    "extracts_system_prompt": {
        "type": "noul",
        "instructions": "Is the user asking to reveal instructions, system prompts, or hidden rules?",
    },
    "pii_leak": {
        "type": "noul",
        "instructions": "Does the input contain passwords, API keys, or credentials?",
    },
}

class SecurityFirewallHook(BaseHook):
    """Inspect inputs before inference; raises on policy violation.

    With hooks_raise=True (the default), raising from on_predict_start aborts
    inference immediately and propagates the exception to the caller, while
    allowing any downstream on_error or audit logging hooks to record the event.
    """
    def __init__(self, guard_agent):
        self.guard = guard_agent

    def on_predict_start(self, ctx: PredictContext):
        for state in ctx.states:
            check = self.guard.system_one(state, SECURITY_SCHEMA)
            ans = check["answers"]
            if ans["is_jailbreak"]["noul"] > 0.5 or ans["extracts_system_prompt"]["noul"] > 0.5:
                raise PermissionError("Request blocked by security firewall: adversarial prompt detected.")

# Attach to Router or Agent; hooks_raise=True ensures policy exceptions propagate
guard_agent = laya.load("convaiinnovations/laya")
router = Router(hooks=[SecurityFirewallHook(guard_agent)], hooks_raise=True)

[!TIP] Para workflows do CrewAI, o Laya também fornece LayaTaskGuard pronto para uso em laya.integrations.crewai para exatamente esse padrão de porta de segurança pré-execução.


4. Roteador RAG de borda em rede isolada

Em ambientes corporativos seguros (defesa, saúde, conformidade financeira, dispositivos de borda), APIs externas estão indisponíveis ou são proibidas. As coleções de documentos costumam ser segregadas em domínios distintos (por exemplo, ensaios clínicos, prontuários de pacientes, relatórios financeiros, especificações técnicas).

Em vez de consultar um único índice vetorial monolítico com embeddings não relacionados, o Laya atua como um roteador de borda local que direciona as consultas do usuário ao índice vetorial local específico ou ao banco de dados SQLite antes da recuperação.

Arquitetura

graph TD
    A["<b>User Query</b><br/>Local / Edge Workstation"] --> B["<b>Laya Edge Router</b><br/>• target_domain: clinical | billing | compliance<br/><i>In-process local routing</i>"]
    B -->|Clinical Domain| C[("<b>Clinical Vector Store</b><br/>Medical trials, dosages & EHR")]
    B -->|Billing Domain| D[("<b>Billing Vector Store</b><br/>Invoices, claims & ICD-10 codes")]
    B -->|Compliance Domain| E[("<b>Compliance Vector Store</b><br/>HIPAA policies & audit guidelines")]

Implementação

from laya import Router

# Automatically routes between local English and Multilingual models
router = Router()

INDEX_QUESTIONS = {
    "target_domain": {
        "type": "choice",
        "instructions": "Which domain index contains the source truth for this query?",
        "criteria": {
            "clinical": "Medical conditions, medications, dosages, and clinical trials.",
            "billing": "Invoices, payment claims, ICD-10 billing codes, and insurance.",
            "compliance": "HIPAA compliance rules, privacy policies, and data audits.",
        },
    }
}

def query_airgapped_rag(user_query: str):
    decision = router.predict(user_query, INDEX_QUESTIONS)
    domain = decision["answers"]["target_domain"]["choice"]

    # Load and search only the relevant isolated local index
    local_index = get_isolated_vector_store(domain)
    return local_index.similarity_search(user_query, k=4)

5. Delegação hierárquica de tarefas entre múltiplos agentes

Frameworks multiagente frequentemente empregam um nó «gerente» ou «supervisor» baseado em LLM para decidir qual agente especializado deve executar o próximo passo.

Como os nós gerentes generativos geram tokens sequencialmente, a delegação pelo supervisor pode introduzir sobrecarga de orquestração substancial por salto. Substituir o supervisor generativo por um modelo de decisão não autorregressivo realiza a delegação em uma única passada direta, proporcionando roteamento determinístico entre os agentes.

O Laya oferece integrações próprias para frameworks de orquestração populares:

  • CrewAI: Use LayaCrewRouter para roteamento hierárquico de tarefas entre múltiplos agentes e guardrails.
  • LlamaIndex: Use LayaSingleSelector para mecanismos de consulta de roteador de passada direta única.
  • LangChain / LangGraph: Use laya.integrations.langchain para despacho de arestas condicionais.

Arquitetura

graph TD
    A["<b>Task Input / Workflow State</b>"] --> B["<b>Laya Orchestrator</b><br/>• assignee: researcher | coder | writer<br/>• priority: score (1–5 urgency)"]
    B -->|Research Assignment| C["<b>Researcher Agent</b><br/>Literature search & fact-checking"]
    B -->|Code Assignment| D["<b>Coder Agent</b><br/>Implementation, bug-fixing & tests"]
    B -->|Writing Assignment| E["<b>Copywriter Agent</b><br/>Drafting, copy editing & summary"]

Implementação (exemplo de CrewAI / LangGraph)

from laya import Router

router = Router()

DELEGATION_QUESTIONS = {
    "assignee": {
        "type": "choice",
        "instructions": "Assign this task to the most qualified specialist.",
        "criteria": {
            "researcher": "Needs literature search, fact checking, or data collection.",
            "coder": "Needs bug fixing, script writing, or unit test generation.",
            "writer": "Needs article drafting, copy editing, or summary composition.",
        },
    },
    "priority": {
        "type": "score",
        "instructions": "Urgency score from 1 (low) to 5 (critical)",
        "criteria": ["1", "2", "3", "4", "5"],
    },
}

def supervisor_node(state):
    task_description = state["task"]
    decision = router.predict(task_description, DELEGATION_QUESTIONS)
    answers = decision["answers"]

    return {
        "next_agent": answers["assignee"]["choice"],
        "urgency": answers["priority"]["score"],
    }

6. Triagem de tickets e suporte de alto throughput

Organizações de suporte ao cliente e centros de operações processam diariamente grandes volumes de tickets, e-mails e alertas. Usar APIs de LLM generativo hospedadas para triagem categórica pode introduzir:

  1. Limites de taxa de rede: Limitação durante picos repentinos de volume.
  2. Amplificação de custos: Custos variáveis de tokens apenas para classificação discreta.
  3. Deriva de esquema: Modelos generativos que retornam JSON malformado ou blocos de código markdown.

Os pipelines de processamento em lote podem avaliar fluxos de tickets em passadas diretas compartilhadas usando predict_batch ou decide_batch(), emitindo dados estritamente tipados que atendem diretamente aos esquemas da aplicação.

Arquitetura

graph TD
    A["<b>Incoming Ticket Stream</b><br/>Message Broker / Webhook"] --> B["<b>Laya Batch Worker</b><br/>decide_batch()<br/>• department: billing | tech | sales | general<br/>• severity: 1..5<br/>• escalate_to_human: true | false"]
    B -->|Department: billing| C["<b>Billing & Invoicing Queue</b>"]
    B -->|Severity &ge; 4 or Human Escalation| D["<b>Tier-3 Escalation Queue</b><br/>Human On-Call Pager"]
    B -->|Low Severity & Standard Inquiry| E["<b>Automated Resolution Pipeline</b>"]

Implementação

from laya.structured import decide_batch
from laya import Agent

agent = Agent("convaiinnovations/laya")

# Strict typed schema
TICKET_SCHEMA = {
    "type": "object",
    "properties": {
        "department": {
            "type": "string",
            "enum": ["billing", "technical_support", "sales", "general"],
            "description": "Primary support category",
        },
        "severity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5,
            "description": "Severity level from 1 (minor) to 5 (outage)",
        },
        "escalate_to_human": {
            "type": "boolean",
            "description": "True if customer is angry, threatening churn, or reporting a legal issue",
        },
    },
}

def process_ticket_batch(tickets: list[str]):
    # Returns typed dictionaries conforming exactly to TICKET_SCHEMA
    results = decide_batch(agent, tickets, TICKET_SCHEMA)
    for ticket_text, structured in zip(tickets, results):
        enqueue_ticket(
            department=structured["department"],
            severity=structured["severity"],
            human_required=structured["escalate_to_human"],
            raw_text=ticket_text,
        )

Lista de verificação para implantação em produção

Antes de lançar qualquer um dos padrões acima em produção, verifique:

  1. Dimensionamento de hardware: Garanta memória de host suficiente para os pesos residentes do modelo. Em CPU, configure os pools de threads de forma adequada (torch.set_num_threads).
  2. Limiares de confiança: Defina min_confidence (por exemplo, 0.80–0.90) nas portas críticas para que o sistema recorra a uma alternativa segura quando as consultas forem ambíguas.
  3. Roteamento multilíngue: Use Router() em vez de um Agent() estático quando o tráfego de usuários incluir entradas mistas ou não inglesas.
  4. Implantação por etapas: Siga o Guia de adoção por etapas para observar o tráfego de produção em modo sombra antes de tornar as decisões autoritativas.