Files
agent_platform_oci/specs/SPEC-002-Agent-Runtime.md

27 KiB

SPEC-002 — Agent Runtime

1. Visão geral

O Agent Runtime coordena a execução conversacional dos agentes da plataforma OCI. O runtime combina grafos LangGraph, estado por conversa, roteamento de intenções, agentes de domínio, guardrails, judges, memória de longo prazo e persistência. A biblioteca reutilizável do framework fornece serviços e contratos consumidos pelos backends; o backend de referência agent_template_backend compõe esses serviços em um workflow executável.

2. Organização da implementação

Elemento Localização Função
Runtime compartilhado libs/agent_framework/src/agent_framework/runtime/ Capacidades reutilizáveis para execução dos agentes.
Workflow de referência templates/agent_template_backend/app/workflows/agent_graph.py Construção do grafo e implementação dos nós do workflow.
Estado do workflow templates/agent_template_backend/app/state.py Definição tipada dos dados transportados entre nós.
Configuração dos agentes templates/agent_template_backend/config/agents.yaml Cadastro de agentes e caminhos de políticas/configurações.
Configuração de roteamento templates/agent_template_backend/config/routing.yaml Modo do roteador, fallback, limiar e catálogo de intenções.
Configuração das ferramentas templates/agent_template_backend/config/tools.yaml Definições de ferramentas utilizadas pelos agentes.

3. Estado de execução

O workflow utiliza o AgentState abaixo. A declaração TypedDict(total=False) permite que os nós adicionem os campos pertinentes a cada etapa sem exigir a presença de todos os campos em cada estado.

from typing import Any, TypedDict

class AgentState(TypedDict, total=False):
    tenant_id: str
    agent_id: str
    session_id: str
    conversation_key: str
    workflow_id: str
    agent_profile: dict[str, Any]
    user_text: str
    sanitized_input: str
    route: str
    intent: str
    route_decision: dict[str, Any]
    answer: str
    final_answer: str
    history: list[dict[str, Any]]
    context: dict[str, Any]
    guardrail_decisions: list[dict[str, Any]]
    judge_results: list[dict[str, Any]]
    next_state: str
    domain: str
    mcp_tools: list[str]
    mcp_results: list[dict[str, Any]]
    rag_results: list[dict[str, Any]]
    available_mcp_tools: list[str]
    selected_tool_call: dict[str, Any]
    pending_tool_call: dict[str, Any]
    active_transaction: dict[str, Any]
    last_transaction: dict[str, Any]
    transaction_status: str
    transaction_pre_validation: dict[str, Any]
    transaction_evidence: list[dict[str, Any]]
    last_transaction_evidence: dict[str, Any]
    relevant_transaction_evidence: list[dict[str, Any]]
    confirmation_required: bool
    confirmation_received: bool
    tool_policy_result: dict[str, Any]
    missing_parameters: list[str]
    supervisor_plan: dict[str, Any]
    supervisor_results: list[dict[str, Any]]
    agent_responses: list[dict[str, Any]]
    pending_topics: list[dict[str, Any]]
    handled_topics: list[dict[str, Any]]
    operation_results: dict[str, dict[str, Any]]
    multi_intent_plan: dict[str, Any]
    active_agent: str
    route_bypassed: bool
    continuity_signal: dict[str, Any]
    session_control: str
    session_ended: bool
    human_handoff_requested: bool
    blocked: bool
    supervisor_action: str
    supervisor_guidance: str
    supervisor_attempt: int
    supervisor_handover_reason: str
    output_supervisor_results: list[dict[str, Any]]
    output_guardrails_already_applied: bool
    long_term_memories: list[dict[str, Any]]
    long_term_memory_context: str
    long_term_memory_write_result: dict[str, Any]
    long_term_memory_subject_key: str
    long_term_memory_load_error: str

4. Fluxo de execução

O workflow é compilado com FrameworkStateGraph(AgentState) e utiliza um checkpointer criado por create_langgraph_checkpointer(self.settings).

flowchart TD
  START([START]) --> input_guardrails
  input_guardrails -->|continue| load_long_term_memory
  input_guardrails -->|blocked| output_guardrails
  load_long_term_memory --> routing_decision
  routing_decision --> billing_agent
  routing_decision --> product_agent
  routing_decision --> orders_agent
  routing_decision --> support_agent
  routing_decision --> handoff
  routing_decision --> human_handoff
  routing_decision --> end_session
  routing_decision --> supervisor_agent
  billing_agent --> output_supervisor
  product_agent --> output_supervisor
  orders_agent --> output_supervisor
  support_agent --> output_supervisor
  handoff --> output_supervisor
  human_handoff --> output_supervisor
  end_session --> output_supervisor
  supervisor_agent --> output_supervisor
  output_supervisor --> output_guardrails
  output_guardrails -->|continue| judge
  output_guardrails -->|blocked| persist
  judge --> supervisor_review
  supervisor_review --> persist_long_term_memory
  persist_long_term_memory --> persist
  persist --> END([END])

O roteamento após input_guardrails depende de state['blocked']. Após routing_decision, a rota em state['route'] seleciona um dos nós registrados, com valor padrão billing_agent quando a chave não está presente. O roteamento após output_guardrails também consulta state['blocked'].

5. Nós do workflow

Nó Responsabilidade
input_guardrails Avalia e processa a entrada antes do roteamento.
load_long_term_memory Carrega contexto de memória de longo prazo.
routing_decision Determina o destino de execução da conversa.
billing_agent Executa o agente de faturamento.
product_agent Executa o agente de produtos e serviços.
orders_agent Executa o agente de pedidos.
support_agent Executa o agente de suporte.
handoff Processa o fluxo de transferência previsto pelo workflow.
human_handoff Processa a solicitação de transferência para atendimento humano.
end_session Processa o encerramento de sessão.
supervisor_agent Executa o fluxo associado ao supervisor.
output_supervisor Processa a etapa de supervisão da resposta.
output_guardrails Aplica as políticas de saída.
judge Realiza a avaliação da resposta.
supervisor_review Processa a revisão após o judge.
persist_long_term_memory Executa a etapa de escrita de memória de longo prazo.
persist Executa a etapa final de persistência do workflow.

Os nós são encapsulados pelo método _node, que os executa no contexto self.langgraph_telemetry.node(name, state).

6. Roteamento

O arquivo config/routing.yaml define as opções principais sob a chave router:

# Roteamento enterprise configurável com MCP-aware intents.
router:
  # mode também pode ser definido por variável de ambiente ROUTING_MODE.
  # Valores: router | supervisor
  mode: router
  fallback_agent: billing_agent
  confidence_threshold: 0.65
  allow_handoff: true

A configuração contém também state_policies para manter determinadas etapas de confirmação ou coleta vinculadas ao agente correspondente, além do catálogo intents com atributos como name, domain, agent, priority, mcp_tools, keywords e examples.

O catálogo de agentes em config/agents.yaml declara os agentes telecom_contas e retail_orders. Cada registro aponta para arquivos de política de prompts, roteamento, guardrails, judges, servidores MCP e ferramentas, além de metadados do domínio.

7. Execução dos agentes e ferramentas

Os nós de domínio encaminham a solicitação para as instâncias dos agentes de faturamento, produtos, pedidos e suporte. A integração com ferramentas MCP é disponibilizada aos agentes por meio da configuração de ferramentas e dos componentes de roteamento de tools. Os resultados de ferramentas podem ser transportados no estado pelo campo mcp_results; os nomes selecionados ficam em mcp_tools.

O estado também comporta selected_tool_call, pending_tool_call, tool_policy_result, missing_parameters e os campos de evidências transacionais. Esses elementos permitem que etapas de preparação, validação, confirmação e execução compartilhem informações ao longo da conversa.

8. Estado transacional

O AgentState mantém em active_transaction os dados da transação em andamento e em last_transaction o registro da última transação encerrada. Os campos transaction_status, transaction_pre_validation, transaction_evidence, last_transaction_evidence, relevant_transaction_evidence, confirmation_required e confirmation_received transportam as informações necessárias ao processamento transacional.

A configuração de roteamento inclui políticas de estado para as etapas WAITING_BILLING_CONFIRMATION, WAITING_PRODUCT_CONFIRMATION, WAITING_ORDER_CONFIRMATION, WAITING_SUPPORT_CONFIRMATION, COLLECTING_BILLING_PARAMETERS, COLLECTING_PRODUCT_PARAMETERS, COLLECTING_ORDER_PARAMETERS e COLLECTING_SUPPORT_PARAMETERS.

A documentação de referência dos fluxos transacionais encontra-se em docs/TRANSACTION_STATE_DEVELOPER_GUIDE.md.

9. Memória e checkpoints

O workflow integra duas etapas explícitas de memória de longo prazo: load_long_term_memory, anterior ao roteamento, e persist_long_term_memory, anterior à persistência final. Os campos long_term_memories, long_term_memory_context, long_term_memory_write_result, long_term_memory_subject_key e long_term_memory_load_error compõem a interface de estado dessa capacidade.

A construção do grafo fornece o resultado de create_langgraph_checkpointer(self.settings) ao método compile. O armazenamento e a recuperação dos checkpoints são executados pelo checkpointer configurado, preservando a continuidade do estado entre interações conforme o backend selecionado.

10. Guardrails, supervisão e judges

A entrada é submetida a input_guardrails antes da carga de memória e do roteamento. Quando a entrada é bloqueada, o fluxo segue diretamente para output_guardrails.

As respostas dos agentes passam por output_supervisor e output_guardrails. Uma resposta não bloqueada segue para judge e supervisor_review; uma resposta bloqueada segue para persist. Os resultados são transportados nos campos guardrail_decisions, output_supervisor_results, judge_results, supervisor_action, supervisor_guidance e campos correlatos do estado.

11. Observabilidade

O workflow envolve cada nó com a instrumentação langgraph_telemetry.node. Essa instrumentação associa a execução à identificação do nó e ao estado da conversa. A rastreabilidade das decisões e etapas de execução é tratada pelos mecanismos de telemetria e observabilidade do framework.

12. Tratamento de erros e recuperação por componente

12.1. Princípios de propagação de falhas

O runtime distingue falhas absorvidas pela própria etapa, resultados negativos de políticas/ferramentas e exceções que impedem a execução do grafo. O contrato de cada componente determina se o processamento continua, se a resposta é alterada ou se a exceção é devolvida ao chamador. O campo blocked indica uma decisão de política no estado, e não equivale genericamente a uma exceção Python.

Área Representação utilizada Efeito na execução
Guardrails Decisões com allowed, code e reason; decisões da supervisão com action Pode interromper roteamento, substituir/sanitizar a resposta ou continuar.
MCP Resultado de ferramenta com ok, error, tool_name e informações de execução conforme a origem O agente utiliza o resultado para controlar a continuação da operação.
Memória de longo prazo Campos long_term_memory_load_error e long_term_memory_write_result Uma falha de leitura ou escrita capturada no nó não encerra o grafo.
RAG Resultado de recuperação ou objeto de erro técnico A falha pode ser incorporada ao contexto de execução do agente.
Checkpoints Exceções do repositório, verificação de integridade e recuperação de versões A leitura pode selecionar checkpoint válido anterior ou iniciar estado limpo; falhas de armazenamento esgotadas são propagadas.
Workflow Exceções emitidas pelos nós ou por graph.ainvoke A execução é marcada como falha na telemetria; a exceção é relançada.

12.2. Entrada, sessão e guardrails de entrada

O nó input_guardrails verifica primeiro session_ended. Caso a sessão já esteja encerrada, define blocked=True, session_control="END_SESSION", session_ended=True e next_state="SESSION_ENDED", compõe a mensagem configurada em SESSION_ALREADY_ENDED_MESSAGE e registra session.message.rejected_after_end. Essa condição impede que a mensagem prossiga para roteamento e agentes.

Para mensagens de sessões ativas, o pipeline avalia os guardrails e guarda as decisões em guardrail_decisions. Se alguma decisão possuir allowed=False, o nó produz uma resposta segura, estabelece route="blocked", intent="input_guardrail_blocked", limpa as listas de ferramentas e resultados MCP daquele turno e segue pelo ramo de saída. A função _input_guardrail_user_message contém respostas específicas para COER, INPUT_SIZE, DLEX_IN, PINJ, TOX e CMP, além de uma resposta padrão para os demais códigos. O motivo detalhado permanece nas decisões e na telemetria; a mensagem ao usuário é controlada pelo runtime.

A avaliação registra guardrails.input.completed, decisões individuais na telemetria de guardrails e eventos GRL por meio do observer. No bloqueio de entrada, não são executados o nó de memória anterior ao roteamento, o roteador nem ferramentas do agente. O ramo segue para output_guardrails e, conforme as condições do grafo, termina em persist.

Referência: templates/agent_template_backend/app/workflows/agent_graph.py (input_guardrails, _input_guardrail_user_message, _after_input_guardrails).

12.3. Roteamento, classificação e continuidade

A configuração do roteamento é carregada por routing/config_loader.py; a ausência do arquivo resulta em FileNotFoundError. O EnterpriseRouter contém tratamento localizado para erros de chamadas de classificação e de interpretação das saídas do modelo. No classificador semântico de entradas esperadas, uma falha de llm.ainvoke é registrada com logger.warning e a função retorna (None, None), permitindo o uso dos caminhos subsequentes do roteamento em vez de transformar essa falha em uma classificação válida.

O fluxo utiliza as configurações fallback_agent e confidence_threshold, assim como políticas de estado em routing.yaml. A seleção de fallback é uma decisão de roteamento; não constitui, por si só, um código de erro. As estruturas route_decision, continuity_signal, pending_topics e multi_intent_plan preservam informações para retomada e roteamento de turnos correlatos.

A recuperação de falhas deve ser interpretada conforme o método efetivamente invocado: nem todo erro interno de roteamento é absorvido pelo mesmo except; exceções que escapem do nó alcançam o tratamento de falha do workflow em ainvoke.

Referências: libs/agent_framework/src/agent_framework/routing/config_loader.py, routing/enterprise_router.py, routing/continuity.py; templates/agent_template_backend/app/workflows/agent_graph.py (routing_decision, ainvoke).

12.4. Execução de agentes, argumentos e ferramentas MCP

A preparação das ferramentas é realizada pelo runtime reutilizável em runtime/agent_runtime.py. O método _prepare_mcp_call consulta o roteador MCP e devolve o erro de preparação como resultado estruturado quando prepare_call o retorna. Se o roteador de ferramentas não estiver disponível, o runtime produz um resultado negativo com ok=False, tool_name e a descrição MCP Tool Router indisponível.

No mapeamento de parâmetros, erros de expressão regular (re.error, IndexError, ValueError) são capturados e registrados como mcp.parameter.regex_extract_failed. Na extração por LLM, indisponibilidade do modelo ou da mensagem e exceções de inferência são registradas como mcp.parameter.llm_extract_failed. O processamento dos argumentos e o retorno da chamada continuam sujeitos à validação da ferramenta e às políticas do agente; não se assume sucesso pela simples ausência de exceção.

Resultados MCP podem expor ok=False e um campo error, inclusive para falhas de validação e execução. A implementação emite NOC.MCP_TOOL_FAILED em um dos caminhos que agregam resultados negativos de ferramentas. O tratamento de transações, confirmações, evidências e resultados parciais é realizado sobre os dados de execução, incluindo active_transaction, transaction_pre_validation, transaction_evidence e operation_results, conforme o tipo de operação.

Referência: libs/agent_framework/src/agent_framework/runtime/agent_runtime.py (_prepare_mcp_call, processamento de parâmetros, execução e agregação de resultados das ferramentas).

12.5. RAG e recuperação de conhecimento

O runtime encapsula falhas de recuperação de conhecimento em um resultado técnico que inclui technical_error=True, technical_error_in_rag=True, status="error" e a descrição em error. Essa representação permite que o agente diferencie falha de recuperação de uma busca concluída sem evidência útil.

O serviço RAG também valida pré-condições: RagService.generate_answer lança RuntimeError quando utilizado sem LLM, e o kbdb_service.py possui verificações de configuração/assinatura e impede operações de ingestão/publicação quando o provider KBDB está configurado exclusivamente para serving. Na ingestão, diretório inexistente pode produzir FileNotFoundError e chunk_overlap >= chunk_size produz ValueError. Esses erros de inicialização e administração não devem ser confundidos com um resultado de busca vazio em atendimento.

Referências: libs/agent_framework/src/agent_framework/runtime/agent_runtime.py (tratamento técnico RAG); rag/rag_service.py, rag/kbdb_service.py, rag/ingest.py.

12.6. Memória de longo prazo

O nó load_long_term_memory captura exceções do long_term_memory_manager.load(state). Quando a leitura falha, publica long_term_memory.load.failed, retorna long_term_memories=[], long_term_memory_context="" e registra a exceção textual em long_term_memory_load_error. A conversa continua sem o contexto de memória recuperado naquele turno.

O nó persist_long_term_memory captura exceções do long_term_memory_manager.persist_turn(state). Uma gravação concluída publica long_term_memory.persist.completed e armazena seu retorno em long_term_memory_write_result; uma falha publica long_term_memory.persist.failed e retorna {"saved": 0, "error": str(exc)} no mesmo campo. A falha de persistência de memória de longo prazo é, portanto, isolada no nó e não provoca automaticamente o encerramento excepcional do grafo.

Esses campos descrevem a memória de longo prazo do workflow e são distintos da persistência de checkpoints LangGraph.

Referência: templates/agent_template_backend/app/workflows/agent_graph.py (load_long_term_memory, persist_long_term_memory).

12.7. Checkpoints, tentativas e integridade

O grafo é compilado com o checkpointer criado por create_langgraph_checkpointer(self.settings) e utiliza conversation_key ou session_id como thread_id em ainvoke. A camada de repositório em checkpoints/checkpoint_repository.py implementa tentativas para operações protegidas por _with_retry: após uma exceção, calcula espera exponencial limitada com jitter, registra checkpoint.<operation>.retry e tenta novamente até retry_policy.max_attempts. Esgotadas as tentativas, relança a última exceção.

Na recuperação, recover_latest examina registros recentes, desconsidera registros que não satisfazem is_valid_checkpoint e ignora checkpoints com CheckpointIntegrityError, registrando checkpoint.recovery.skip_corrupt. Quando não resta checkpoint válido após falhas de integridade, a recuperação retorna None para permitir início sem estado restaurado. A compactação executada após uma gravação é isolada: uma falha registra checkpoint.compaction.failed e não desfaz a gravação já concluída.

A estratégia de recuperação de integridade não garante preservação do histórico se nenhum checkpoint válido puder ser recuperado. Falhas de comunicação com o armazenamento que excedam a política de retry seguem o caminho de exceção do componente que invocou a operação.

Referências: libs/agent_framework/src/agent_framework/checkpoints/checkpoint_repository.py, checkpoints/langgraph_saver.py; templates/agent_template_backend/app/workflows/agent_graph.py (ainvoke).

12.8. Supervisão de saída e guardrails de saída

O output_supervisor avalia a resposta e interpreta RailAction. Para ALLOW, SANITIZE e OBSERVE, utiliza decision.candidate; para HANDOVER, entrega uma mensagem de encaminhamento ao especialista; para as demais ações, utiliza decision.fallback_message. A ação, orientação e resultados são gravados em supervisor_action, supervisor_guidance e output_supervisor_results.

O nó marca output_guardrails_already_applied=True. Quando output_guardrails recebe esse sinal, retorna a resposta já preparada sem executar novamente o pipeline. Caso contrário, executa guardrails.run_output, registra as decisões, os bloqueios e a conclusão GRL, e devolve final_answer.

O executor paralelo de rails (guardrails/parallel_executor.py) converte falhas inesperadas de tarefas em RailResult: escolhe RailAction.BLOCK quando fail_closed está ativo e RailAction.OBSERVE no outro caso. Esse comportamento é uma política do executor e não implica que todo guardrail falhe fechado. O executor também administra cancelamentos e término antecipado quando uma ação terminal é produzida.

Referências: templates/agent_template_backend/app/workflows/agent_graph.py (output_supervisor, output_guardrails); libs/agent_framework/src/agent_framework/guardrails/parallel_executor.py.

12.9. Judges e revisão do supervisor

O nó judge constrói o contexto de avaliação com resultados MCP, RAG e evidências transacionais relevantes, executa a avaliação e grava os resultados em judge_results. A revisão posterior utiliza self.supervisor.review e registra supervisor.review.completed. Uma reprovação ou recomendação de um judge integra o mecanismo de avaliação e revisão; não é, por definição, uma exceção de infraestrutura.

A camada de judges contém validação de configuração e de resposta estruturada. O cliente do judge calibrado lança ValueError para tarefas não suportadas e quando a saída estruturada é inválida. A construção do LLM e a leitura de configurações de judges também podem produzir RuntimeError ou ValueError nas condições verificadas em judges/judge.py. As exceções não capturadas pelo nó propagam-se para ainvoke.

Referências: templates/agent_template_backend/app/workflows/agent_graph.py (judge, supervisor_review); libs/agent_framework/src/agent_framework/judges/judge.py, judges/calibrated/llm_client.py.

12.10. Persistência final e falha global do workflow

O nó persist produz a observabilidade de conclusão do atendimento, incluindo o evento IC AGENT_COMPLETED. A execução pública do grafo acontece em ainvoke, que cria a configuração de thread, inicia a telemetria de workflow e emite os eventos de início NOC.001 e AGENT_STARTED antes de invocar self.graph.ainvoke.

Se graph.ainvoke conclui, o workflow é marcado como concluído e seu estado final é retornado. Se uma exceção escapa do grafo, o except Exception de ainvoke chama workflow_telemetry.failed("agent_workflow", exc), emite NOC.005 com error e exception_type e relança a mesma exceção. Nesse caminho, o método não converte automaticamente o erro em uma resposta conversacional de sucesso.

Falhas absorvidas por nós como memória de longo prazo não acionam esse except global. Já erros não tratados durante roteamento, execução dos agentes, salvamento de checkpoints ou outras etapas podem alcançar esse limite e produzir a falha geral do workflow.

Referência: templates/agent_template_backend/app/workflows/agent_graph.py (persist, ainvoke).

12.11. Eventos e rastreamento operacional

A instrumentação _node envolve a execução de cada nó em self.langgraph_telemetry.node(name, state). Os mecanismos complementares usam spans de workflow, eventos semânticos e o observer para GRL, IC e NOC. Entre os registros concretos presentes no fluxo estão session.message.rejected_after_end, guardrails.input.completed, guardrails.output.completed, output_supervisor.completed, supervisor.review.completed, long_term_memory.load.failed, long_term_memory.persist.failed, long_term_memory.persist.completed e workflow_telemetry.failed na falha global.

Erros operacionais devem ser correlacionados por conversation_key ou session_id, juntamente com tenant_id e agent_id quando disponíveis. A ocorrência de um evento de falha de memória ou de ferramenta não implica necessariamente falha global do workflow; a determinação depende de o componente ter retornado um estado/resultado ou propagado uma exceção.

Referências: templates/agent_template_backend/app/workflows/agent_graph.py; libs/agent_framework/src/agent_framework/observability/.

13. Interfaces de integração

Interface Integração no runtime
LangGraph Construção, compilação e execução do grafo de estado.
Agentes de domínio Nós especializados para faturamento, produtos, pedidos e suporte.
MCP Seleção, parametrização e execução de ferramentas pelos agentes.
RAG Recuperação de informações incorporada à execução dos agentes.
Guardrails Avaliação da entrada e da saída.
Judges Avaliação posterior à geração da resposta.
Memória Leitura e escrita de informações de longo prazo.
Checkpointer Persistência do estado do grafo.
Observabilidade Telemetria por nó e rastreamento do processamento.

14. Referências de implementação