Ajustes conforme relatorio de testes 2026-08-27
This commit is contained in:
@@ -14,45 +14,38 @@ CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
|
||||
# LLM - OCI Generative AI como provider principal
|
||||
###############################################################################
|
||||
# Opções: mock, oci_openai, oci_sdk, openai_compatible
|
||||
LLM_PROVIDER=oci_sdk
|
||||
LLM_PROVIDER=oci_openai
|
||||
LLM_TEMPERATURE=0.2
|
||||
LLM_MAX_TOKENS=2048
|
||||
LLM_TIMEOUT_SECONDS=120
|
||||
|
||||
# OCI OpenAI-compatible endpoint
|
||||
OCI_GENAI_BASE_URL=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com
|
||||
OCI_GENAI_BASE_URL=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/openai/v1
|
||||
OCI_GENAI_MODEL=openai.gpt-4.1
|
||||
OCI_GENAI_API_KEY=sk-ph3FgX6iP3fxAQCXb9IpPIDTadkeeYAWntUWhzcWysIM6zsS
|
||||
OCI_GENAI_API_KEY=sk-ph3FgX6ph3FgX6ph3FgX6ph3FgX6ph3FgX6ph3FgX6
|
||||
OCI_GENAI_PROJECT_OCID=
|
||||
|
||||
#OCI_GENAI_BASE_URL=https://pegruagntaiatenddev.pe.inference.generativeai.sa-saopaulo-1.oci.oraclecloud.com
|
||||
#OCI_GENAI_MODEL=openai.gpt-4.1
|
||||
#OCI_GENAI_API_KEY=
|
||||
#OCI_GENAI_PROJECT_OCID=
|
||||
|
||||
|
||||
# OCI_AUTH_MODE=config_file|instance_principal|resource_principal
|
||||
OCI_AUTH_MODE=config_file
|
||||
# OCI SDK / signer / profiles
|
||||
OCI_CONFIG_FILE=~/.oci/config
|
||||
OCI_PROFILE=LATINOAMERICA-Chicago
|
||||
OCI_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaaaaaexpiw4a7dio64mkfv2t273s2hgdl6mgfvvyv7tycalnjlvpvfl3q
|
||||
OCI_PROFILE=DEFAULT
|
||||
OCI_COMPARTMENT_ID=ocid1.compartment.oc1..aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
OCI_REGION=us-chicago-1
|
||||
|
||||
###############################################################################
|
||||
# Persistência
|
||||
###############################################################################
|
||||
# Opções: memory, autonomous, mongodb
|
||||
SESSION_REPOSITORY_PROVIDER=autonomous
|
||||
MEMORY_REPOSITORY_PROVIDER=autonomous
|
||||
CHECKPOINT_REPOSITORY_PROVIDER=autonomous
|
||||
SESSION_REPOSITORY_PROVIDER=sqlite
|
||||
MEMORY_REPOSITORY_PROVIDER=sqlite
|
||||
CHECKPOINT_REPOSITORY_PROVIDER=sqlite
|
||||
SQLITE_DB_PATH=./data/agent_framework.db
|
||||
|
||||
# Autonomous Database
|
||||
ADB_USER=admin
|
||||
ADB_PASSWORD=Moniquinha19721972
|
||||
ADB_DSN=oradb23ai_high
|
||||
ADB_WALLET_LOCATION=/mnt/d/Dropbox/ORACLE/LatinoAmerica/Wallet_ORADB23ai
|
||||
ADB_WALLET_PASSWORD=Moniquinha1972
|
||||
ADB_PASSWORD=fjhsdf04954hf
|
||||
ADB_DSN=oradb23aidev_high
|
||||
ADB_WALLET_LOCATION=/ORACLE/DEFAULT/Wallet_ORADB23aiDev
|
||||
ADB_WALLET_PASSWORD=fjhsdf04954hf
|
||||
ADB_TABLE_PREFIX=AGENTFW
|
||||
|
||||
# MongoDB - também pode representar Autonomous usando API compatível com Mongo, se habilitada no ambiente
|
||||
@@ -66,10 +59,10 @@ ENABLE_REDIS_CACHE=false
|
||||
###############################################################################
|
||||
# RAG / Vector / Graph
|
||||
###############################################################################
|
||||
VECTOR_STORE_PROVIDER=autonomous
|
||||
GRAPH_STORE_PROVIDER=autonomous
|
||||
VECTOR_STORE_PROVIDER=sqlite
|
||||
GRAPH_STORE_PROVIDER=sqlite
|
||||
RAG_TOP_K=5
|
||||
EMBEDDING_PROVIDER=oci
|
||||
EMBEDDING_PROVIDER=mock
|
||||
OCI_EMBEDDING_MODEL=cohere.embed-multilingual-v3.0
|
||||
RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
||||
|
||||
@@ -77,21 +70,14 @@ RAG_FILE_GLOBS=*.md,*.txt,*.yaml,*.yml,*.json
|
||||
# Observabilidade
|
||||
###############################################################################
|
||||
ENABLE_LANGFUSE=true
|
||||
# Opcional: verbose, compact
|
||||
LANGFUSE_TRACE_MODE=compact
|
||||
# Nome customizado do trace pai, ex.: backoffice.checklist.workflow ou backoffice.emulador.workflow
|
||||
LANGFUSE_COMPACT_VISIBLE_EVENT_PREFIXES=AGA.,NOC., IC.
|
||||
LANGFUSE_COMPACT_SUPPRESSED_PREFIXES=llm.chat_completion
|
||||
LANGFUSE_IGNORE_HEALTHCHECKS=true
|
||||
LANGFUSE_IGNORED_PATHS=/health,/ready,/metrics
|
||||
LANGFUSE_PUBLIC_KEY=pk-lf-4a1e3921-5158-4fd3-a16d-7a77549fb312
|
||||
LANGFUSE_SECRET_KEY=sk-lf-efc6fd59-c5ec-4858-b6ec-4aa129734915
|
||||
LANGFUSE_TRACE_MODE=compact # Opcional: verbose, compact
|
||||
LANGFUSE_PUBLIC_KEY=pk-lf-2f9da109-5b0f-4c78-b61d-9598ed787eba
|
||||
LANGFUSE_SECRET_KEY=sk-lf-a4cb0cdd-f2ea-4468-9911-cebeb91ba944
|
||||
LANGFUSE_HOST=http://localhost:3005
|
||||
ENABLE_OTEL=false
|
||||
OTEL_EXPORTER_OTLP_ENDPOINT=
|
||||
OTEL_SERVICE_NAME=ai-agent-template
|
||||
ENABLE_LANGFUSE_OPENAI_AUTO_INSTRUMENTATION=true
|
||||
ENABLE_LANGFUSE_ANALYTICS_PUBLISHER=false
|
||||
|
||||
###############################################################################
|
||||
# Analytics / Observer corporativo
|
||||
@@ -99,7 +85,7 @@ ENABLE_LANGFUSE_ANALYTICS_PUBLISHER=false
|
||||
# Quando true, AgentObserver publica eventos IC.*, NOC.* e GRL.* nos providers abaixo.
|
||||
ENABLE_ANALYTICS=false
|
||||
# Providers aceitos: oci_streaming,pubsub,noop
|
||||
ANALYTICS_PROVIDERS=oci_streaming
|
||||
ANALYTICS_PROVIDERS=pubsub
|
||||
# Compatibilidade FIRST/TIM: pode informar AGENT_PUBSUB_TOPIC diretamente.
|
||||
AGENT_PUBSUB_TOPIC=
|
||||
GCP_PUBSUB_TOPIC_PATH=
|
||||
@@ -162,6 +148,7 @@ ROUTE_STICKINESS_HISTORY_TURNS=2
|
||||
ROUTE_STICKINESS_MAX_TOKENS=80
|
||||
HUMAN_HANDOFF_MESSAGE=Vou encaminhar seu atendimento para uma pessoa.
|
||||
END_SESSION_MESSAGE=Atendimento encerrado. Obrigado pelo contato.
|
||||
SESSION_ALREADY_ENDED_MESSAGE=Este atendimento já foi encerrado. Inicie uma nova sessão para continuar.
|
||||
|
||||
###############################################################################
|
||||
# MCP / Tools
|
||||
@@ -169,13 +156,14 @@ END_SESSION_MESSAGE=Atendimento encerrado. Obrigado pelo contato.
|
||||
ENABLE_MCP_TOOLS=true
|
||||
MCP_SERVERS_CONFIG_PATH=./config/mcp_servers.yaml
|
||||
TOOLS_CONFIG_PATH=./config/tools.yaml
|
||||
TOOL_POLICIES_PATH=./config/tool_policies.yaml
|
||||
MCP_TOOL_TIMEOUT_SECONDS=30
|
||||
|
||||
# router = EnterpriseRouter seleciona um agente; supervisor = pode acionar múltiplos agentes
|
||||
ROUTING_MODE=router
|
||||
|
||||
# Usage/cost accounting
|
||||
USAGE_REPOSITORY_PROVIDER=autonomous
|
||||
USAGE_REPOSITORY_PROVIDER=sqlite
|
||||
IDENTITY_CONFIG_PATH=./config/identity.yaml
|
||||
MCP_PARAMETER_MAPPING_PATH=./config/mcp_parameter_mapping.yaml
|
||||
|
||||
@@ -192,6 +180,18 @@ MEMORY_SUMMARY_USE_LLM=true
|
||||
MEMORY_INJECT_RECENT_MESSAGES=true
|
||||
MEMORY_INJECT_SUMMARY=true
|
||||
|
||||
###############################################################################
|
||||
# MCP Gateway
|
||||
###############################################################################
|
||||
# true = framework routes tool calls to the dedicated MCP Gateway.
|
||||
# false = framework calls MCP servers directly from mcp_servers.yaml.
|
||||
MCP_GATEWAY_ENABLED=true
|
||||
MCP_GATEWAY_URL=http://localhost:8300
|
||||
MCP_GATEWAY_TIMEOUT_SECONDS=60
|
||||
# MCP_GATEWAY_TOKEN=
|
||||
MCP_GATEWAY_AGENT_ID=telecom_contas
|
||||
MCP_GATEWAY_TENANT_ID=default
|
||||
|
||||
###############################################################################
|
||||
# LONG-TERM MEMORY
|
||||
###############################################################################
|
||||
Binary file not shown.
@@ -160,7 +160,7 @@ class AgentWorkflow:
|
||||
builder.add_conditional_edges(
|
||||
"input_guardrails",
|
||||
self._after_input_guardrails,
|
||||
{"blocked": "persist", "continue": "load_long_term_memory"},
|
||||
{"blocked": "output_guardrails", "continue": "load_long_term_memory"},
|
||||
)
|
||||
builder.add_edge("load_long_term_memory", "routing_decision")
|
||||
builder.add_conditional_edges(
|
||||
@@ -197,6 +197,31 @@ class AgentWorkflow:
|
||||
def _after_input_guardrails(self, state):
|
||||
return "blocked" if state.get("blocked") else "continue"
|
||||
|
||||
@staticmethod
|
||||
def _input_guardrail_user_message(decisions, state, sanitized_text):
|
||||
# Keep the technical guardrail reason in telemetry, but expose only a
|
||||
# safe, actionable message to the end user. The message is intentionally
|
||||
# routed through output_guardrails before persistence/delivery.
|
||||
blocked = [d for d in decisions if not getattr(d, "allowed", True)]
|
||||
first = blocked[0] if blocked else None
|
||||
code = str(getattr(first, "code", "") or "").upper()
|
||||
if code == "COER":
|
||||
return (
|
||||
"Não consegui entender sua última mensagem porque ela parece "
|
||||
"incompleta ou ambígua. Pode reformular ou completar o que você quis dizer?"
|
||||
)
|
||||
if code == "INPUT_SIZE":
|
||||
return "Sua mensagem ficou muito longa para eu processar de uma vez. Pode resumir ou dividir em partes?"
|
||||
if code == "DLEX_IN":
|
||||
return "Não posso usar essa informação da forma solicitada. Reformule o pedido sem incluir dados ou conteúdo restrito."
|
||||
if code == "PINJ":
|
||||
return "Não posso seguir instruções que tentem alterar as regras do atendimento. Posso continuar ajudando com a sua solicitação."
|
||||
if code == "TOX":
|
||||
return "Não consegui prosseguir com essa mensagem. Pode reformular o pedido para continuarmos o atendimento?"
|
||||
if code == "CMP":
|
||||
return "Não posso prosseguir com essa solicitação dessa forma. Posso ajudar com uma alternativa permitida."
|
||||
return "Não consegui processar essa mensagem. Pode reformular para eu continuar o atendimento?"
|
||||
|
||||
async def input_guardrails(self, state):
|
||||
if state.get("session_ended") is True:
|
||||
answer = str(getattr(
|
||||
@@ -281,12 +306,33 @@ class AgentWorkflow:
|
||||
component="workflow.input_guardrails.final",
|
||||
)
|
||||
if any(not d.allowed for d in decisions):
|
||||
# A blocking input guardrail stops the turn before routing/tools.
|
||||
# Clear turn-local routing/tool state so stale data from a prior
|
||||
# turn cannot appear as if it was executed after the block.
|
||||
user_message = self._input_guardrail_user_message(decisions, state, sanitized)
|
||||
return {
|
||||
"sanitized_input": sanitized,
|
||||
"answer": "Não consegui seguir com essa mensagem por regra de segurança.",
|
||||
"final_answer": "Não consegui seguir com essa mensagem por regra de segurança.",
|
||||
"answer": user_message,
|
||||
"final_answer": None,
|
||||
"guardrail_decisions": [d.model_dump() for d in decisions],
|
||||
"route": "blocked",
|
||||
"intent": "input_guardrail_blocked",
|
||||
"route_decision": {
|
||||
"route": "blocked",
|
||||
"agent": None,
|
||||
"intent": "input_guardrail_blocked",
|
||||
"confidence": 1.0,
|
||||
"reason": "Entrada interrompida por guardrail antes do roteamento.",
|
||||
"method": "guardrail",
|
||||
"next_state": state.get("next_state"),
|
||||
"handoff": False,
|
||||
"metadata": {},
|
||||
"domain": state.get("domain"),
|
||||
"mcp_tools": [],
|
||||
},
|
||||
"mcp_tools": [],
|
||||
"mcp_results": [],
|
||||
"judge_results": [],
|
||||
"blocked": True,
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -7,6 +7,35 @@ router:
|
||||
confidence_threshold: 0.65
|
||||
allow_handoff: true
|
||||
|
||||
transaction_confirmation:
|
||||
# Explicit yes/no stays deterministic. Only inconclusive replies use this LLM fallback.
|
||||
semantic_fallback:
|
||||
enabled: true
|
||||
allowed_values: [SIM, NAO, CONTINUAR]
|
||||
confirm_values: [SIM]
|
||||
reject_values: [NAO]
|
||||
continue_values: [CONTINUAR]
|
||||
include_relevant_context: true
|
||||
profile_name: router
|
||||
prompt: |
|
||||
Você classifica a resposta do cliente a uma confirmação transacional pendente.
|
||||
Considere a pergunta pendente, somente o histórico recente relacionado ao mesmo tema e a fala atual.
|
||||
Não execute a ação e não invente fatos.
|
||||
|
||||
Classes permitidas: {{ allowed_values }}
|
||||
- SIM: confirmação/aceite inequívoco, inclusive equivalentes como "isso mesmo", "pode confirmar", "é isso" quando o contexto tornar o aceite claro.
|
||||
- NAO: recusa/cancelamento inequívoco da ação pendente.
|
||||
- CONTINUAR: qualquer resposta que não confirme nem rejeite inequivocamente, incluindo pergunta adicional, correção, novo dado, ambiguidade ou possível mudança de assunto.
|
||||
|
||||
Pergunta pendente:
|
||||
{{ pending_prompt }}
|
||||
|
||||
Histórico relevante:
|
||||
{{ relevant_conversation_context }}
|
||||
|
||||
Resposta atual do cliente:
|
||||
{{ user_input }}
|
||||
|
||||
state_policies:
|
||||
- state: WAITING_BILLING_CONFIRMATION
|
||||
agent: billing_agent
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Confirmação Transacional Semântica
|
||||
|
||||
Este template suporta confirmação transacional em duas camadas: primeiro um parser determinístico para `sim`/`não` e equivalentes explícitos; somente quando ele não consegue decidir, o framework usa um classificador semântico configurado em `config/routing.yaml`.
|
||||
|
||||
A configuração `router.transaction_confirmation.semantic_fallback` usa três classes: `SIM`, `NAO` e `CONTINUAR`. O prompt pode usar `{{ pending_prompt }}`, `{{ relevant_conversation_context }}`, `{{ user_input }}` e `{{ allowed_values }}`. O histórico injetado é apenas contexto de interpretação; não substitui validação de negócio ou evidência MCP.
|
||||
|
||||
Exemplo: após `Você confirma o cancelamento do serviço Tamboro Mensal?`, a frase `isso mesmo, pode confirmar` pode ser classificada como `SIM`. Já `mas qual é o valor?` deve ser `CONTINUAR`, portanto não executa a ação por confirmação.
|
||||
|
||||
Entradas explícitas já suportadas continuam no caminho determinístico e não geram custo adicional de LLM. Em observabilidade, o fallback usa `transaction.confirmation.semantic_classifier` e o `route_decision.metadata` informa `transaction_confirmation_source: semantic`.
|
||||
|
||||
Consulte `docs/developer/pt/03_transaction_workflows_and_state.md` do framework para o contrato completo e exemplos.
|
||||
Reference in New Issue
Block a user