Files
agent_framework_llm_as_a_judge/README.md
2026-09-09 16:50:00 -03:00

33 KiB

Agent Framework OCI Evaluator — LLM-as-a-Judge

Idioma: Português | English

1. Visão geral

O Agent Framework OCI Evaluator é o componente batch responsável por avaliar, de forma assíncrona, a qualidade das conversas produzidas pelos agentes construídos sobre o Agent Framework OCI.

O serviço lê sessões e traces do Langfuse v3, seleciona uma amostra determinística de sessões, calcula métricas de qualidade com um LLM-as-a-Judge, persiste resultados em Oracle Autonomous Database, gera o arquivo oficial .TXT.GZ, publica esse arquivo em Google Cloud Storage (GCS) e registra a execução do próprio job no Langfuse.

Ele foi desenhado para execução D+1, como um Kubernetes CronJob, sem endpoint HTTP/gRPC de runtime.

Modelo de implantação recomendado: uma instância do evaluator por agente/squad. O código é genérico e suporta múltiplos agentes na configuração, mas em produção a recomendação é cada deployment carregar apenas o agente de sua responsabilidade. Isso mantém credenciais, ownership, scheduling e troubleshooting isolados.


2. Por que este componente existe

Avaliar respostas generativas em tempo real dentro do fluxo síncrono do agente aumenta latência, custo e acoplamento. O evaluator separa essa responsabilidade do atendimento online.

O desenho é:

Atendimento online
        |
        v
Agent Framework
        |
        +--------------------> Langfuse v3
                                  |
                                  | traces / sessions
                                  v
                         Evaluator D+1 (CronJob)
                                  |
               +------------------+------------------+
               |                  |                  |
               v                  v                  v
          OCI GenAI             ADB                GCS
        LLM-as-a-Judge     estado/resultados    .TXT.GZ oficial
               |
               +-----------------------> Langfuse
                                      auditoria / scores opcionais

Essa separação traz alguns benefícios:

  • não adiciona latência ao atendimento;
  • permite reprocessamento e auditoria;
  • permite amostragem configurável por agente;
  • isola falhas de avaliação do agente online;
  • permite utilizar modelos dedicados do OCI GenAI;
  • mantém um artefato oficial para a camada analítica da TIM;
  • evita acoplamento do código a nomes específicos de agentes, buckets ou credenciais.

3. Conceitos principais

3.1. Trace

Um trace representa uma interação avaliada individualmente. Para cada trace são calculadas métricas trace-level:

  • judgeScore — qualidade global da resposta;
  • accuracyScore — aderência/factualidade em relação ao contexto;
  • alucinationScore — grau de afirmações não suportadas pelo contexto;
  • promptLength — tamanho bruto, em caracteres, do trace.input.

3.2. Session

Uma session representa a conversa completa. Uma sessão normalmente possui vários traces.

As métricas session-level são calculadas uma vez e replicadas nas linhas dos traces daquela sessão:

  • inferredCsiScore;
  • resolution;
  • conversationPrecision;
  • loop.

3.3. Amostragem por sessão

A amostragem é feita sobre sessions, nunca sobre traces isolados.

A seed é determinística:

agentId:reference_date

Exemplo:

billing:2026-08-13

Com isso, duas execuções para o mesmo agente, data e percentual selecionam as mesmas sessões.

Depois que uma sessão é selecionada, todos os traces daquela sessão são mantidos.

3.4. Janela BRT

run-agents calcula a data de referência com base em:

D - daysBack

usando explicitamente:

America/Sao_Paulo

Com daysBack: 1, uma execução em 14/08 avalia o dia 13/08 completo, de 00:00:00 até 23:59:59.999999 BRT.

3.5. CONTEXT_TURN_LIMIT

CONTEXT_TURN_LIMIT controla quantos turnos anteriores são enviados ao judge trace-level.

Default:

CONTEXT_TURN_LIMIT=6

Ele existe porque uma resposta não deve ser julgada fora do contexto da conversa. Aumentar o valor fornece mais contexto, mas também aumenta tokens, custo e latência do judge.

3.6. Loop

A métrica loop não mede repetição textual simples. Ela representa o maior streak consecutivo de metadata.intent dentro da sessão.

Exemplo:

billing
billing
billing
payment
payment

Resultado:

loop = 3

4. Fluxo completo de execução

O fluxo produtivo é executado pelo comando:

python -m evaluator.cli run-agents

ou pelo entrypoint instalado:

af-evaluator run-agents

Etapas:

1. Carrega agents.yaml
2. Calcula D-daysBack em BRT
3. Resolve credenciais Langfuse do agente
4. Busca TODAS as sessions nativas do período, com paginação
5. Busca TODOS os traces do período, com paginação
6. Busca observations em bulk/paginado
7. Recupera session_id real via metadata quando o trace legado não possui sessionId nativo
8. Filtra traces do agente/aliases
9. Faz sampling determinístico das sessions lógicas
10. Mantém todos os traces das sessions selecionadas
11. Persiste itens no ADB
12. Executa judge trace-level
13. Executa judge session-level
14. Calcula loop local
15. Gera .TXT.GZ
16. Faz upload para GCS
17. Remove o arquivo local após sucesso
18. Atualiza auditoria judge-job-{agentId} no Langfuse

4.1. Por que a coleta não usa N+1

A implementação evita o padrão antigo:

1 trace
  -> GET trace detail
  -> GET observations

repetido para cada trace.

Agora a coleta é paginada em lote:

/api/public/sessions       page 1..N
/api/public/traces         page 1..N
/api/public/observations   page 1..N

Assim, 10.000 traces não produzem ~20.000 chamadas adicionais. O número de requests cresce com o número de páginas da API.

O PAGE_SIZE atual é 100.

4.2. Compatibilidade com traces sem sessionId nativo

Algumas instrumentações históricas registram a sessão no metadata do trace/observation, mas não promovem o valor para o campo nativo trace.sessionId do Langfuse. O evaluator recupera a sessão real com a seguinte precedência:

trace.sessionId / trace.session_id
  -> trace.metadata.session_id / sessionId / conversation_key
  -> observation.metadata.session_id / sessionId / conversation_key
  -> business_context.session_key (último fallback de metadata)

O trace.id nunca é usado como session_id. Assim, o evaluator preserva sampling e métricas de session mesmo para traces históricos, sem transformar cada trace em uma sessão artificial. As estatísticas de coleta expõem native_sessions_read, metadata_sessions_recovered e traces_without_session.


5. Arquitetura de componentes

agent_framework_oci_evaluator/
├── evaluator/
│   ├── analytics/
│   │   └── vloop.py
│   ├── collectors/
│   │   ├── langfuse.py
│   │   ├── langfuse_credentials.py
│   │   ├── agent_framework.py
│   │   └── mock.py
│   ├── config/
│   │   ├── agents.py
│   │   └── settings.py
│   ├── core/
│   │   └── models.py
│   ├── identity/
│   │   └── resolver.py
│   ├── judges/
│   │   └── llm_judge.py
│   ├── llm/
│   │   ├── client.py
│   │   └── profile_resolver.py
│   ├── output/
│   │   └── legacy_exporter.py
│   ├── persistence/
│   │   ├── oracle_store.py
│   │   └── repository.py
│   ├── prompts/
│   │   └── loader.py
│   ├── publishers/
│   │   ├── gcs_export.py
│   │   ├── langfuse_job_audit.py
│   │   └── langfuse_scores.py
│   ├── cli.py
│   ├── engine.py
│   └── time_utils.py
├── configs/
│   ├── identity.yaml
│   ├── judge/
│   │   ├── agents.yaml
│   │   ├── storage.yaml
│   │   ├── trace_metrics.yaml
│   │   └── session_metrics.yaml
│   ├── langfuse/
│   │   └── langfuse_credentials.example.yaml
│   └── llm_profiles/
│       └── llm_profiles.yaml
├── deploy/
├── tests/
├── .env.example
├── Dockerfile
└── pyproject.toml

5.1. Collectors

Transformam fontes externas em ConversationRecord.

Fontes disponíveis:

langfuse
agent_framework
mock

langfuse é a fonte produtiva padrão.

5.2. EvaluationEngine

evaluator/engine.py coordena o pipeline:

  • criação do run;
  • coleta;
  • amostragem;
  • persistência;
  • judge;
  • export;
  • upload;
  • auditoria.

5.3. Persistence

Os estados e resultados são persistidos em Oracle Database. O schema é criado automaticamente pelo comando init-db.

As principais tabelas são:

EVALUATION_RUN
EVALUATION_PROGRESS_EVENT
EVALUATION_ITEM
EVALUATION_RESULT
EVALUATION_METRIC
EVALUATION_FINDING

O prefixo é configurável por:

ADB_TABLE_PREFIX=AGENTFW

5.4. Publishers

  • gcs_export.py — upload do artefato oficial;
  • langfuse_job_audit.py — auditoria judge-job-{agentId};
  • langfuse_scores.py — publicação opcional de scores de trace.

Nota: a auditoria produtiva do job usa as credenciais dinâmicas do agente. A publicação opcional de scores (PUBLISH_LANGFUSE_SCORES=true) ainda utiliza as credenciais globais LANGFUSE_HOST/PUBLIC_KEY/SECRET_KEY; deixe-a desabilitada quando não houver um projeto global apropriado.


6. Configuração de agentes

Arquivo padrão:

configs/judge/agents.yaml

Exemplo:

agents:
  - agentId: billing
    enabled: true
    daysBack: 1
    percentage: 1.0
    langfuse_agent_aliases:
      - telecom_contas
    gcs_prefix: agnt_ai_contas

Campos:

Campo Descrição
agentId identidade lógica oficial do agente
enabled habilita/desabilita o agente naquele deployment
daysBack quantos dias voltar a partir do dia atual BRT
percentage percentual de sessions avaliadas, de 0.0 a 1.0
langfuse_agent_aliases nomes técnicos aceitos para o agente nos traces; quando preenchido, funciona como filtro explícito independentemente da origem das credenciais Langfuse
gcs_prefix prefixo do agente dentro do bucket

Também são aceitos agent_id e days_back por compatibilidade, mas o formato recomendado é agentId / daysBack.

Semântica de langfuse_agent_aliases: quando a lista possui valores, somente traces cujo identificador de agente corresponda a um dos aliases são elegíveis para sampling e avaliação. Quando a lista está vazia, o evaluator não aplica filtro por identidade de agente e considera o projeto/endpoint Langfuse configurado exclusivo para aquela entrada.

6.1. Um evaluator por agente

Para o modelo recomendado de uma instância por agente, mantenha apenas uma entrada habilitada naquele deployment:

agents:
  - agentId: billing
    enabled: true
    daysBack: 1
    percentage: 1.0
    langfuse_agent_aliases:
      - telecom_contas
      - billing_agent
    gcs_prefix: agnt_ai_contas

O mesmo código pode ser usado em outro repositório/deployment apenas trocando os arquivos de configuração.


7. Credenciais Langfuse dinâmicas

Não existem variáveis hardcoded do tipo:

LANGFUSE_BILLING_*
LANGFUSE_SALES_*

O evaluator lê uma definição declarativa:

LANGFUSE_CREDENTIALS_CONFIG_PATH=configs/langfuse/langfuse_credentials.yaml

Crie o arquivo a partir do exemplo:

cp configs/langfuse/langfuse_credentials.example.yaml \
   configs/langfuse/langfuse_credentials.yaml

Exemplo:

langfuse:
  agents:
    - agentId: billing
      host: https://langfuse.example.internal
      publicKey: pk-...
      secretKey: sk-...

    - agentId: outro-agente
      host: https://outro-langfuse.internal
      publicKey: pk-...
      secretKey: sk-...

O resolver percorre todas as entradas. Adicionar um agente não exige alteração Python.

7.1. Referências a env ou arquivos

Para não manter secrets no Git:

langfuse:
  agents:
    - agentId: billing
      hostEnv: BILLING_LF_HOST
      publicKeyEnv: BILLING_LF_PUBLIC
      secretKeyFile: /var/secrets/langfuse/billing-secret-key

Campos suportados:

host / hostEnv / hostFile
publicKey / publicKeyEnv / publicKeyFile
secretKey / secretKeyEnv / secretKeyFile

Ordem de resolução de cada campo:

valor direto -> variável de ambiente declarada -> arquivo declarado

7.2. Credenciais globais

Estas variáveis continuam disponíveis apenas para o comando manual genérico run:

LANGFUSE_HOST=http://localhost:3005
LANGFUSE_PUBLIC_KEY=...
LANGFUSE_SECRET_KEY=...

O fluxo produtivo run-agents resolve credenciais pelo arquivo declarativo por agente.


8. Configuração do LLM

Providers aceitos:

mock
oci_openai
oci_sdk
openai_compatible

A recomendação para os modelos OCI dedicados é:

LLM_PROVIDER=oci_sdk

8.1. OCI SDK

Exemplo local com ~/.oci/config:

LLM_PROVIDER=oci_sdk
OCI_AUTH_MODE=config_file
OCI_CONFIG_FILE=~/.oci/config
OCI_PROFILE=DEFAULT
OCI_REGION=sa-saopaulo-1
OCI_COMPARTMENT_ID=ocid1.compartment...
OCI_GENAI_BASE_URL=https://inference.generativeai.sa-saopaulo-1.oci.oraclecloud.com
OCI_GENAI_MODEL=meta.llama-3.3-70b-instruct

Modos de autenticação suportados pelo código:

config_file
instance_principal
resource_principal
oke_workload_identity
workload_identity

8.2. Dedicated endpoint

Para endpoint dedicado:

OCI_GENAI_BASE_URL=https://<private-endpoint>.inference.generativeai.<region>.oci.oraclecloud.com
OCI_GENAI_ENDPOINT_ID=ocid1.generativeaiendpoint...

Também é aceito o OCID do dedicated endpoint em OCI_GENAI_MODEL.

O provider seleciona DedicatedServingMode quando há endpoint OCID; caso contrário usa OnDemandServingMode.

8.3. Perfis do judge

Arquivo:

configs/llm_profiles/llm_profiles.yaml

Exemplo:

profiles:
  judge:
    temperature: 0
    max_tokens: 900

Selecionado por:

LLM_PROFILE=judge

9. Prompts e métricas

9.1. Trace metrics

Arquivo:

configs/judge/trace_metrics.yaml

O judge deve retornar JSON com:

{
  "judgeScore": 0.0,
  "accuracyScore": 0.0,
  "alucinationScore": 0.0,
  "rationale": "..."
}

Se o parse falhar:

1ª tentativa
   -> parse falha
2ª tentativa com retry-hint
   -> parse falha novamente
métricas trace-level = None
   -> exportadas como "0.00"

9.2. Session metrics

Arquivo:

configs/judge/session_metrics.yaml

Resultado esperado:

{
  "inferredCsiScore": 0.5,
  "resolution": 1,
  "conversationPrecision": 1,
  "rationale": "..."
}

Os valores session-level são replicados no arquivo para todos os traces da mesma session.


10. Identity normalization

Arquivo:

configs/identity.yaml

A camada de identidade converte identificadores específicos de canais/domínios para chaves canônicas como:

customer_key
contract_key
interaction_key
account_key
resource_key
session_key

Isso evita espalhar lógica como cpf, msisdn, invoice_id, order_id, ura_call_id etc. pelo código do evaluator.

A ordem das fontes funciona como fallback.

Exemplo:

session_key:
  sources:
    - business_context.session_key
    - session_key
    - conversation_key
    - session_id

11. Configuração de GCS

Buckets ficam fora do código em:

configs/judge/storage.yaml

Exemplo:

storage:
  buckets:
    dev: tim-bigdata-dev-ca1f-raw-standard-agnt-ai-atendimento
    fqa: tim-bigdata-fqa-60ce-raw-standard-agnt-ai-atendimento
    prd: tim-bigdata-prod-e305-raw-standard-agnt-ai-atendimento

Seleção:

APP_ENV=dev
STORAGE_CONFIG_PATH=configs/judge/storage.yaml

Override de emergência/operação:

JUDGE_GCS_BUCKET=meu-bucket

Para habilitar o fluxo produtivo:

ENABLE_GCS_UPLOAD=true
GOOGLE_APPLICATION_CREDENTIALS=/path/GCP_ACCESS_KEY.json

run-agents considera GCS obrigatório. Se ENABLE_GCS_UPLOAD=false ou o upload falhar, o run do agente termina como FAILED.


12. Arquivo de saída

Padrão:

AGENTE_{agentId}_LLM_JUDGE_{YYYYMMDD}_{HHMMSS}.TXT.GZ

Exemplo:

AGENTE_billing_LLM_JUDGE_20260814_020015.TXT.GZ

Cabeçalho:

"judgeScore"|;"accuracyScore"|;"alucinationScore"|;"promptLength"|;"loop"|;"inferredCsiScore"|;"resolution"|;"conversationPrecision"|;"uraCallId"|;"channelId"|;"sessionId"|;"messageId"

Linha final:

"TOTAL"|;"<n_traces>"

Após upload bem-sucedido para GCS, o arquivo local é apagado.


13. Instalação local

13.1. Pré-requisitos

  • Python 3.11+;
  • acesso ao Oracle Database/Autonomous Database;
  • Oracle Wallet quando aplicável;
  • acesso ao Langfuse v3;
  • acesso ao OCI Generative AI para execução real do judge;
  • credencial GCP para upload produtivo.

13.2. Criar venv

Linux/WSL/macOS:

python -m venv .venv
source .venv/bin/activate

Windows PowerShell:

python -m venv .venv
.\.venv\Scripts\Activate.ps1

13.3. Instalar

Modo recomendado durante desenvolvimento:

python -m pip install --upgrade pip setuptools wheel
pip install -e .

Validar:

pip check
python -c "import oci, httpx, oracledb; import google.cloud.storage; print('Dependencias OK')"

14. Configuração local passo a passo

Passo 1 — .env

cp .env.example .env

Edite os valores reais.

Configuração mínima típica:

APP_ENV=dev

ADB_USER=admin
ADB_PASSWORD=...
ADB_DSN=...
ADB_WALLET_LOCATION=/path/to/wallet
ADB_WALLET_PASSWORD=...
ADB_TABLE_PREFIX=AGENTFW

ENABLE_LANGFUSE=true
LANGFUSE_CREDENTIALS_CONFIG_PATH=configs/langfuse/langfuse_credentials.yaml

LLM_PROVIDER=oci_sdk
LLM_PROFILE=judge
OCI_AUTH_MODE=config_file
OCI_CONFIG_FILE=~/.oci/config
OCI_PROFILE=DEFAULT
OCI_REGION=sa-saopaulo-1
OCI_COMPARTMENT_ID=...
OCI_GENAI_BASE_URL=https://...
OCI_GENAI_ENDPOINT_ID=ocid1.generativeaiendpoint...

CONTEXT_TURN_LIMIT=6
BATCH_SIZE=50
MAX_ATTEMPTS=3

ENABLE_GCS_UPLOAD=true
STORAGE_CONFIG_PATH=configs/judge/storage.yaml
GOOGLE_APPLICATION_CREDENTIALS=/path/GCP_ACCESS_KEY.json

Passo 2 — Langfuse

cp configs/langfuse/langfuse_credentials.example.yaml \
   configs/langfuse/langfuse_credentials.yaml

Declare o agente que será executado.

Passo 3 — agents.yaml

Ajuste:

configs/judge/agents.yaml

Para uma instância dedicada, deixe somente o agente daquela squad habilitado.

Passo 4 — validar configuração

python -m evaluator.cli show-config

Passo 5 — inicializar banco

python -m evaluator.cli init-db

reset-db apaga e recria o schema do evaluator. Use apenas em ambiente controlado.


15. CLI

A ajuda real da versão atual é:

python -m evaluator.cli --help

Comandos disponíveis:

init-db
reset-db
show-config
run
run-agents
progress
runs

15.1. run — execução manual/diagnóstica

Sintaxe:

python -m evaluator.cli run PERIOD_START PERIOD_END [OPTIONS]

Exemplo:

python -m evaluator.cli run \
  2026-08-12T00:00:00 \
  2026-08-12T23:59:59 \
  --source langfuse \
  --limit 10

Opções:

--source TEXT                default: langfuse
--limit INTEGER
--show-progress / --no-show-progress

Importante: run é um caminho manual genérico. Ele coleta, avalia e persiste resultados, mas não executa o contrato produtivo completo por agente (sampling configurado, export GCS e auditoria de job). Para homologação/produção use run-agents.

15.2. run-agents — fluxo produtivo

python -m evaluator.cli run-agents

Um agente:

python -m evaluator.cli run-agents \
  --agent-id billing \
  --source langfuse

Teste limitado:

python -m evaluator.cli run-agents \
  --agent-id billing \
  --limit 10

Opções:

--source TEXT       default: langfuse
--agent-id TEXT
--limit INTEGER

run-agents usa daysBack, percentage, credenciais e gcs_prefix do agente.

15.3. Listar runs

python -m evaluator.cli runs

ou:

python -m evaluator.cli runs --limit 50

15.4. Progresso de um run

python -m evaluator.cli progress <RUN_ID>

Com mais eventos:

python -m evaluator.cli progress <RUN_ID> --events 100

Eventos típicos do fluxo produtivo:

LANGFUSE_JOB_AUDIT
RUN_CREATED
COLLECTING
COLLECTED
SAMPLED
ITEMS_INSERTED
BATCH_STARTED
ITEM_COMPLETED
SESSION_JUDGE_COMPLETED
COMPLETED
EXPORTED
GCS_UPLOADED
LOCAL_FILE_DELETED
LANGFUSE_JOB_AUDIT

16. Testes

Instale pytest caso necessário:

pip install pytest

16.1. Todos os testes

python -m pytest -v

16.2. Conformidade TIM

python -m pytest tests/test_tim_spec.py -v

16.3. Conformidade ampliada

python -m pytest tests/test_full_tim_compliance.py -v

16.4. Regressão de hardcodes

python -m pytest tests/test_no_product_hardcodes.py -v

16.5. Suite recomendada antes de um release

python -m pytest \
  tests/test_tim_spec.py \
  tests/test_full_tim_compliance.py \
  tests/test_no_product_hardcodes.py \
  -v

Validar sintaxe/imports:

python -m compileall evaluator

17. Teste funcional local recomendado

17.1. Smoke test com mock

Configure:

LLM_PROVIDER=mock

E rode um período pequeno com source mock quando desejado:

python -m evaluator.cli run \
  2026-08-12T00:00:00 \
  2026-08-12T23:59:59 \
  --source mock

17.2. Teste Langfuse sem volume grande

python -m evaluator.cli run-agents \
  --agent-id billing \
  --limit 5

Depois:

python -m evaluator.cli runs --limit 5
python -m evaluator.cli progress <RUN_ID> --events 100

Confirme:

  • COLLECTED > 0;
  • SAMPLED mostra sessions selecionadas;
  • itens concluem sem ITEM_FAILED;
  • EXPORTED aparece;
  • GCS_UPLOADED contém URI gs://...;
  • LOCAL_FILE_DELETED aparece;
  • auditoria completed foi confirmada.

18. Docker

Build local:

docker build -t agent-framework-evaluator:local .

O runtime produtivo é batch. O container não precisa expor porta HTTP.

Para Kubernetes, o CronJob chama:

python -m evaluator.cli run-agents --source langfuse

19. Kubernetes / OKE

O evaluator propriamente dito continua CronJob-only, conforme a especificação: ele não abre porta HTTP/gRPC e o processamento continua sendo executado exclusivamente pelo evaluator-batch.

A interface web foi reintroduzida como um componente separado e somente leitura, evaluator-monitor. Ela não executa avaliação, não altera runs e não muda o contrato batch do evaluator. O monitor apenas consulta as tabelas de execução/progresso no Autonomous Database.

Evaluator batch (evaluator-batch CronJob)
        │
        ├── cria/atualiza EVALUATION_RUN
        ├── grava EVALUATION_PROGRESS_EVENT
        └── grava EVALUATION_RESULT
                    │
                    ▼
             Autonomous Database
                    ▲
                    │ somente leitura
        Evaluator Monitor (Deployment HTTP)
                    │
                    └── /ui + APIs de acompanhamento

Recursos Kustomize:

Namespace
ServiceAccount
ConfigMap
CronJob evaluator-batch
Deployment evaluator-monitor
Service evaluator-monitor (ClusterIP)

Não existe Ingress por default. Assim, a interface não é exposta para fora do cluster automaticamente.

CronJob atual:

schedule: "0 2 * * *"
timeZone: "America/Sao_Paulo"
suspend: false
concurrencyPolicy: Forbid

19.1. Preparar arquivos de deploy

cp deploy/env/evaluator.env.example deploy/env/evaluator.env
cp deploy/langfuse/langfuse_credentials.example.yaml \
   deploy/langfuse/langfuse_credentials.yaml

Coloque o wallet em:

deploy/wallet/

Credencial GCP:

deploy/gcp/GCP_ACCESS_KEY.json

19.2. Criar secrets

DEV:

./deploy/scripts/create-secrets.sh dev

HML:

./deploy/scripts/create-secrets.sh hml

PROD:

./deploy/scripts/create-secrets.sh prod

São criados/atualizados:

evaluator-secrets
evaluator-wallet
evaluator-langfuse
evaluator-gcp        (quando o arquivo GCP existir)

19.3. Build e push

export REGISTRY=tim.azurecr.io
export IMAGE_TAG=<version>
./deploy/scripts/build-push.sh prod

19.4. Deploy

export REGISTRY=tim.azurecr.io
export IMAGE_TAG=<version>
./deploy/scripts/deploy.sh prod

Por default o script também executa o job de inicialização do banco.

Para não executar:

export RUN_INIT_DB=false

19.5. Status

./deploy/scripts/status.sh prod

ou diretamente:

kubectl -n agent-evaluator-prod get cronjob,jobs,pods

19.6. Execução imediata fora do horário

./deploy/scripts/run-now.sh prod

O script cria um Job baseado no CronJob.

Acompanhar:

kubectl -n agent-evaluator-prod get jobs,pods
kubectl -n agent-evaluator-prod logs -f job/<nome-do-job>

19.7. Interface web de acompanhamento

A UI é servida pelo componente independente evaluator-monitor:

GET /ui
GET /health
GET /api/runs
GET /api/runs/{run_id}
GET /api/runs/{run_id}/results

Para acessar localmente um monitor implantado no Kubernetes sem criar Ingress:

kubectl -n agent-evaluator-prod port-forward svc/evaluator-monitor 8080:8080

Depois abra:

http://localhost:8080/ui

A tela mostra runs recentes, RUN_ID, agente, status, progresso, eventos e resultados. O browser faz auto-refresh a cada 5 segundos.

Para executar o monitor localmente:

python -m uvicorn evaluator_monitor.app:app --host 0.0.0.0 --port 8080

O monitor utiliza as mesmas configurações ADB_*/wallet do evaluator. Ele é read-only do ponto de vista funcional: não há endpoint para iniciar, cancelar, apagar ou alterar runs.

Recomendação de segurança: mantenha o Service como ClusterIP. Se futuramente houver necessidade de exposição externa, coloque autenticação/autorização no Ingress/API Gateway corporativo; não exponha o monitor diretamente à Internet.


20. Como subir uma nova versão

Fluxo recomendado:

1. Atualizar código/configuração

Não coloque credenciais reais no Git.

2. Rodar testes

python -m pytest -v
python -m compileall evaluator

3. Testar localmente com limite

python -m evaluator.cli run-agents \
  --agent-id <agentId> \
  --limit 5

4. Validar o run

python -m evaluator.cli runs --limit 10
python -m evaluator.cli progress <RUN_ID> --events 100

5. Confirmar GCS

O evento deve conter:

GCS_UPLOADED

com uma URI como:

gs://<bucket>/<prefix>/AGENTE_<agent>_LLM_JUDGE_<timestamp>.TXT.GZ

6. Atualizar secrets/configuração do ambiente

./deploy/scripts/create-secrets.sh <dev|hml|prod>

7. Build/push com uma tag nova

export REGISTRY=<registry>
export IMAGE_TAG=<nova-versao>
./deploy/scripts/build-push.sh <ambiente>

8. Deploy

./deploy/scripts/deploy.sh <ambiente>

9. Rodar manualmente para homologação

./deploy/scripts/run-now.sh <ambiente>

10. Verificar logs e artefatos

kubectl -n agent-evaluator-<ambiente> logs -f job/<job>

Confirme também o objeto no bucket GCS e a auditoria judge-job-{agentId} no Langfuse.


21. Troubleshooting

Collected 0 traces

Verifique nesta ordem:

  1. data processada (daysBack usa BRT);
  2. credencial Langfuse do agentId correto;
  3. host do projeto Langfuse;
  4. langfuse_agent_aliases;
  5. existência de sessions/traces naquele período;
  6. se o agentId lógico é diferente do metadata.agent_id dos traces.

Exemplo:

- agentId: billing
  langfuse_agent_aliases:
    - telecom_contas
    - billing_agent

No Langfuse credentials configured for agent ...

O agente existe em agents.yaml, mas não no arquivo apontado por:

LANGFUSE_CREDENTIALS_CONFIG_PATH

Adicione uma entrada com o mesmo agentId.

Langfuse credentials definition file not found

Crie/mapeie o arquivo:

configs/langfuse/langfuse_credentials.yaml

ou configure outro path.

TIM specification requires GCS upload...

run-agents foi executado com:

ENABLE_GCS_UPLOAD=false

Altere para true e configure a credencial GCP.

GCS falha

Verifique:

echo "$GOOGLE_APPLICATION_CREDENTIALS"
ls -l "$GOOGLE_APPLICATION_CREDENTIALS"

E valide o bucket resolvido por APP_ENV/storage.yaml.

OCI SDK falha em dedicated endpoint

Confira:

LLM_PROVIDER=oci_sdk
OCI_GENAI_BASE_URL=https://<endpoint-nativo-sem-openai-v1>
OCI_GENAI_ENDPOINT_ID=ocid1.generativeaiendpoint...
OCI_COMPARTMENT_ID=...

Para oci_sdk, não use /openai/v1 no endpoint.

Banco não inicializado

python -m evaluator.cli init-db

Ver progresso pela CLI

O run-agents agora imprime o RUN_ID assim que a execução é criada:

[telecom_contas] RUN_ID=8d9a2d1e-...
  progress: python -m evaluator.cli progress 8d9a2d1e-... --events 100

Também é possível listar runs e consultar qualquer execução:

python -m evaluator.cli runs
python -m evaluator.cli progress <RUN_ID> --events 100

Ver progresso pela interface web

python -m uvicorn evaluator_monitor.app:app --host 0.0.0.0 --port 8080

Abra http://localhost:8080/ui. Em Kubernetes, prefira kubectl port-forward svc/evaluator-monitor 8080:8080.


22. Variáveis de ambiente principais

Variável Uso
APP_ENV ambiente usado para resolver storage
ADB_* conexão e wallet Oracle
ENABLE_LANGFUSE habilita coleta Langfuse
LANGFUSE_CREDENTIALS_CONFIG_PATH YAML declarativo por agente
LANGFUSE_* fallback global apenas para run manual
PUBLISH_LANGFUSE_SCORES publica scores de trace de volta no Langfuse
LLM_PROVIDER mock, oci_openai, oci_sdk, openai_compatible
LLM_PROFILE perfil de judge
OCI_AUTH_MODE autenticação OCI SDK
OCI_GENAI_BASE_URL endpoint OCI GenAI
OCI_GENAI_MODEL model ID/nome ou compatibilidade com endpoint OCID
OCI_GENAI_ENDPOINT_ID dedicated endpoint OCID
OCI_COMPARTMENT_ID compartment OCI
AGENTS_CONFIG_PATH arquivo de agentes
TRACE_PROMPT_PATH prompt trace-level
SESSION_PROMPT_PATH prompt session-level
BATCH_SIZE quantidade processada por lote interno
MAX_ATTEMPTS limite configurável de tentativas
CONTEXT_TURN_LIMIT últimos N turnos enviados ao judge trace
ENABLE_GCS_UPLOAD exige upload no fluxo produtivo
STORAGE_CONFIG_PATH mapping de buckets por ambiente
JUDGE_GCS_BUCKET override de bucket
GOOGLE_APPLICATION_CREDENTIALS credencial GCP
OUTPUT_DIR diretório temporário de export

23. Segurança e operação

  • não versionar .env real;
  • não versionar langfuse_credentials.yaml real;
  • não versionar GCP service account JSON;
  • não versionar wallet Oracle;
  • em OKE prefira oke_workload_identity quando aplicável;
  • monte credenciais como Kubernetes Secrets;
  • use readOnlyRootFilesystem no CronJob;
  • mantenha concurrencyPolicy: Forbid para evitar dois D+1 concorrentes do mesmo deployment;
  • nunca use reset-db em produção sem plano explícito de restauração.

24. Checklist de homologação

Antes de promover uma versão:

  • pip check sem erro;
  • python -m pytest -v passando;
  • python -m compileall evaluator sem erro;
  • show-config aponta para ADB/OCI/configs corretos;
  • agents.yaml contém apenas os agentes esperados para aquele deployment;
  • credencial Langfuse existe para cada agentId habilitado;
  • run-agents --limit 5 encontra traces;
  • sampling seleciona sessions, não traces individuais;
  • judge trace/session conclui;
  • arquivo possui cabeçalho de 12 colunas;
  • nome segue AGENTE_{agentId}_LLM_JUDGE_{YYYYMMDD}_{HHMMSS}.TXT.GZ;
  • evento GCS_UPLOADED confirmado;
  • arquivo local removido depois do upload;
  • auditoria Langfuse created/completed confirmada;
  • CronJob está suspend: false;
  • timezone do CronJob é America/Sao_Paulo;
  • nenhuma credencial real está no repositório.

25. Resumo para quem está chegando no projeto

Se você precisa entender o projeto em poucos minutos, pense assim:

Langfuse guarda as conversas
        ↓
Evaluator escolhe sessions D+1
        ↓
OCI GenAI julga traces e sessions
        ↓
ADB guarda execução e resultados
        ↓
GCS recebe o arquivo oficial
        ↓
Langfuse registra a auditoria do batch

Os pontos de extensão ficam em configuração:

Qual agente?          -> configs/judge/agents.yaml
Qual projeto Langfuse?-> langfuse_credentials.yaml
Qual bucket?          -> configs/judge/storage.yaml
Qual prompt?          -> trace_metrics.yaml / session_metrics.yaml
Qual modelo?          -> .env + llm_profiles.yaml
Qual identidade?      -> configs/identity.yaml

A regra arquitetural mais importante é: o código do evaluator deve permanecer genérico; detalhes de agentes, ambientes, credenciais e storage pertencem à configuração.