# Abeesys RAG — documentação completa > Conhecimento com citação — insira texto curto e pergunte; cada resposta diz de onde veio. Contrato 1.2.0 (OpenAPI 3.1.0). A API ainda não tem endereço público. Hoje ela atende só em: `http://rag.railway.internal:8000` — rede privada do Railway; `http://localhost:8002` — stack local (make up). ## Visão geral Plataforma de conhecimento da Abeesys — spec 0025. Dois contratos de domínio: **inserir conhecimento** e **perguntar**. As demais operações são as portas de apoio que a spec exige: ler o conhecimento por id e por versão (o caminho que a origem de um trecho abre), pôr e tirar veto, e trocar a credencial de modelo do tenant. O serviço vive na **rede privada** (`rag.railway.internal`): a API ainda não tem endereço público. Toda rota exige a API key do tenant em `Authorization: Bearer `, exceto as de saúde e as quatro de documentação (`/openapi.yaml`, `/openapi.json`, `/llms.txt` e `/llms-full.txt`), que não carregam dado de tenant. O tenant vem **só** da key — nunca do corpo, da URL ou de um header escolhido pelo cliente. Conhecimento de outro tenant, ou inexistente, é o **mesmo 404**: a existência de um id não é informação que um tenant ganha. Os nomes dos campos e dos valores de enum são os da spec (em português), e são estáveis. ## Autenticação - `apiKey`: http bearer — `Authorization: Bearer `. API key do tenant, gerada pelo `cmd/admin` e guardada só como hash. - Sem API key: `GET /v1/health`, `GET /v1/health/ready`, `GET /openapi.yaml`, `GET /openapi.json`, `GET /llms.txt`, `GET /llms-full.txt`. ## Erros Todo erro sai como `application/problem+json` (RFC 9457), com `type`, `title`, `status`, `detail` e, no 422, `errors[]` com `field` e `message`. - `BadRequest`: requisição ilegível — corpo que não é JSON, parâmetro malformado — type `https://abeesys.com/errors/bad-request` - `Unauthorized`: API key ausente, inválida, ou de tenant desativado — a mesma resposta — type `https://abeesys.com/errors/unauthorized` - `NotFound`: inexistente **ou de outro tenant** — indistinguíveis de propósito — type `https://abeesys.com/errors/not-found` - `ValidationFailed`: Entrada que viola o schema ou regra de entrada: enum fora, texto vazio ou acima do limite, campo desconhecido, null onde se pede valor, credencial não cadastrada, texto acima da janela de tokens do vetorizador, ou identidade do vetorizador (repositório, arquivo, quantização, dimensão, pooling, janela) diferente da do índice. Não deixa registro. — type `https://abeesys.com/errors/validation`, `https://abeesys.com/errors/embedder-identity-mismatch`, `https://abeesys.com/errors/text-exceeds-window` ## Rotas Os caminhos abaixo — inclusive `/openapi.json` — são relativos ao endereço da API, que ainda não é público. Um site que só publica esta documentação não os atende. ### GET /v1/health O processo está de pé - operationId: `getLiveness` - autenticação: sem API key Respostas: - `200`: vivo — `application/json` Health Exemplo de resposta 200 `application/json`: ```json { "status": "ok" } ``` ### GET /v1/health/ready Pronto para receber tráfego - operationId: `getReadiness` - autenticação: sem API key 200 só com o banco alcançável, a extensão `vector` instalada em versão 0.8 ou maior (scan iterativo) e o índice HNSW presente. Sem a extensão o serviço **não entra no ar** — ADR 0005. O vetorizador **não** entra aqui: ele fora é degradação, não indisponibilidade. Respostas: - `200`: pronto — `application/json` Health - `503`: não pronto — banco fora, extensão ausente ou abaixo de 0.8, índice ausente — `application/json` Health Exemplo de resposta 200 `application/json`: ```json { "status": "ok" } ``` Exemplo de resposta 503 `application/json`: ```json { "status": "indisponivel", "motivo": "extensao-vector-ausente" } ``` ### POST /v1/conhecimento Insere ou revisa um conhecimento - operationId: `insertKnowledge` - autenticação: API key do tenant A `Idempotency-Key` é a **identidade natural** do conhecimento, única por tenant. Mesma chave com o mesmo corpo devolve o registro como está (200). Mesma chave com corpo novo é **revisão** do mesmo registro: a versão sobe e a resposta passa a usar o texto novo (200). Chave nova cria (201). Nunca 409. O vetor é pedido ao vetorizador **antes** da gravação. Vetorizador fora, lento ou ainda carregando o modelo: o registro é gravado com `indexacao: pendente`, responde só pela busca textual, e um worker interno o reprocessa quando o vetorizador volta — sem nunca mexer na publicação. O vetorizador **nunca trunca**. Texto que não cabe na janela de tokens dele é recusado com **422** `text-exceeds-window`, nomeando o limite em tokens, e **não deixa registro** — nem versão, nem pendência. O limite de caracteres de `texto` não garante caber na janela: a contagem é em tokens, e quem conta é o vetorizador. Um registro que já estava `pendente` e o vetorizador recusa por janela passa a `indexacao: recusado` e não é reprocessado; volta à indexação só com um texto novo na mesma chave (spec 0029). Marca `sugestao` segura o registro em `rascunho` até a marca ser retirada na mesma chave. Parâmetros: - `Idempotency-Key` (header, obrigatório): string, de 1 a 255 caracteres, padrão `^[\x21-\x7E]+$` — identidade natural do conhecimento; única por tenant Corpo (`application/json`): KnowledgeInput - `texto` (obrigatório): string, de 1 a 510 caracteres — O texto indexável. Acima de 510 caracteres é 422. Dentro do limite, o texto ainda precisa caber na janela de tokens do vetorizador: se não couber, 422 `text-exceeds-window` nomeando o limite em tokens — nunca vetor truncado. Só espaço, ou caractere de controle, é 422. - `tipo` (obrigatório): KnowledgeKind (enum: `equivalencia`, `apelido`, `aplicacao`, `observacao`) - `nivel` (opcional): Confidence (enum: `alta`, `media`, `baixa`) - `publicacao` (obrigatório): Publication (enum: `publicado`, `rascunho`) - `marca` (opcional): KnowledgeMark (enum: `negativo`, `sugestao`) - `referencia` (opcional): string, de 1 a 512 caracteres — id opaco de outro sistema; devolvido intacto, byte a byte, na origem Exemplo de corpo: ```json { "texto": "A remarcação de um agendamento é gratuita até 2 horas antes do horário marcado.", "tipo": "observacao", "publicacao": "publicado", "referencia": "politica:7d41a0" } ``` Respostas: - `201`: criado — `application/json` Knowledge - `200`: já existia — revisado (versão nova) ou idêntico (sem mudança) — `application/json` Knowledge - `400` (BadRequest): requisição ilegível — corpo que não é JSON, parâmetro malformado — `application/problem+json` Problem — type `https://abeesys.com/errors/bad-request` - `401` (Unauthorized): API key ausente, inválida, ou de tenant desativado — a mesma resposta — `application/problem+json` Problem — type `https://abeesys.com/errors/unauthorized` - `422` (ValidationFailed): Entrada que viola o schema ou regra de entrada: enum fora, texto vazio ou acima do limite, campo desconhecido, null onde se pede valor, credencial não cadastrada, texto acima da janela de tokens do vetorizador, ou identidade do vetorizador (repositório, arquivo, quantização, dimensão, pooling, janela) diferente da do índice. Não deixa registro. — `application/problem+json` Problem — type `https://abeesys.com/errors/validation`, `https://abeesys.com/errors/embedder-identity-mismatch`, `https://abeesys.com/errors/text-exceeds-window` ### GET /v1/conhecimento/{id} Lê a versão atual de um conhecimento - operationId: `getKnowledge` - autenticação: API key do tenant Parâmetros: - `id` (path, obrigatório): string, formato uuid Respostas: - `200`: o conhecimento — `application/json` Knowledge - `401` (Unauthorized): API key ausente, inválida, ou de tenant desativado — a mesma resposta — `application/problem+json` Problem — type `https://abeesys.com/errors/unauthorized` - `404` (NotFound): inexistente **ou de outro tenant** — indistinguíveis de propósito — `application/problem+json` Problem — type `https://abeesys.com/errors/not-found` ### GET /v1/conhecimento/{id}/versoes Lista as versões de um conhecimento, da mais nova para a mais antiga - operationId: `listKnowledgeVersions` - autenticação: API key do tenant Parâmetros: - `id` (path, obrigatório): string, formato uuid Respostas: - `200`: as versões, ordenadas por `versao` decrescente — `application/json` KnowledgeVersionList - `401` (Unauthorized): API key ausente, inválida, ou de tenant desativado — a mesma resposta — `application/problem+json` Problem — type `https://abeesys.com/errors/unauthorized` - `404` (NotFound): inexistente **ou de outro tenant** — indistinguíveis de propósito — `application/problem+json` Problem — type `https://abeesys.com/errors/not-found` ### GET /v1/conhecimento/{id}/versoes/{versao} Abre o texto inserido numa versão — é o caminho da origem de um trecho - operationId: `getKnowledgeVersion` - autenticação: API key do tenant Parâmetros: - `id` (path, obrigatório): string, formato uuid - `versao` (path, obrigatório): integer, de 1 a 2147483647 Respostas: - `200`: a versão — `application/json` KnowledgeVersion - `400` (BadRequest): requisição ilegível — corpo que não é JSON, parâmetro malformado — `application/problem+json` Problem — type `https://abeesys.com/errors/bad-request` - `401` (Unauthorized): API key ausente, inválida, ou de tenant desativado — a mesma resposta — `application/problem+json` Problem — type `https://abeesys.com/errors/unauthorized` - `404` (NotFound): inexistente **ou de outro tenant** — indistinguíveis de propósito — `application/problem+json` Problem — type `https://abeesys.com/errors/not-found` ### PUT /v1/conhecimento/{id}/veto O tenant segura o próprio conhecimento - operationId: `vetoKnowledge` - autenticação: API key do tenant A partir daqui o conhecimento não sustenta texto nenhum — nem como trecho, nem como origem, nem indo ao modelo. O registro continua publicado: veto não é rascunho. Idempotente. Parâmetros: - `id` (path, obrigatório): string, formato uuid Respostas: - `204`: vetado - `401` (Unauthorized): API key ausente, inválida, ou de tenant desativado — a mesma resposta — `application/problem+json` Problem — type `https://abeesys.com/errors/unauthorized` - `404` (NotFound): inexistente **ou de outro tenant** — indistinguíveis de propósito — `application/problem+json` Problem — type `https://abeesys.com/errors/not-found` ### DELETE /v1/conhecimento/{id}/veto Tira o veto — o conhecimento volta sem reinserir - operationId: `liftKnowledgeVeto` - autenticação: API key do tenant Parâmetros: - `id` (path, obrigatório): string, formato uuid Respostas: - `204`: sem veto - `401` (Unauthorized): API key ausente, inválida, ou de tenant desativado — a mesma resposta — `application/problem+json` Problem — type `https://abeesys.com/errors/unauthorized` - `404` (NotFound): inexistente **ou de outro tenant** — indistinguíveis de propósito — `application/problem+json` Problem — type `https://abeesys.com/errors/not-found` ### PUT /v1/credenciais/{nome} Cadastra ou troca uma credencial de modelo do tenant - operationId: `replaceCredential` - autenticação: API key do tenant Só troca — **nunca** devolve o segredo, em nenhuma rota, nem em erro. Cifrada em repouso (ADR 0006). O provedor da credencial responde, e o estado dela muda (spec 0034): - **401/403** — fica **inválida** e deixa de ser tentada; as perguntas que a citam saem do hospedado com `motivo: credencial_invalida`. - **402 (sem saldo)** — fica **sem saldo**, que não é inválida: ela **continua sendo tentada a cada pergunta**, e a primeira resposta bem-sucedida dela a devolve a válida. Enquanto o provedor disser 402, o hospedado responde, com `motivo: credencial_sem_saldo`. - **429 (limite de taxa)** — o estado não muda (ver `askQuestion`). Registrar de novo — inválida ou sem saldo — a traz de volta válida. Resposta já em cache dessa credencial (da mesma revisão) é servida também enquanto ela está sem saldo: o cache não chama o provedor. Parâmetros: - `nome` (path, obrigatório): CredentialName — nome que o tenant dá à credencial, e que ele cita em cada pergunta Corpo (`application/json`): CredentialInput - `provedor` (obrigatório): string (enum: `openai`, `deepseek`) — provedor do modelo; o endereço de cada um é fixo no serviço (`openai`: `https://api.openai.com/v1`; `deepseek`: `https://api.deepseek.com`). `deepseek` entrou na versão 1.2.0 (spec 0034) — enum de entrada, aditivo. - `modelo` (obrigatório): string, de 1 a 128 caracteres - `segredo` (obrigatório): string, de 1 a 512 caracteres, só de entrada — nunca volta em resposta — entra, nunca sai — nenhum schema de resposta o contém Exemplo de corpo: ```json { "provedor": "openai", "modelo": "gpt-4o-mini", "segredo": "sk-exemplo-falso" } ``` Respostas: - `204`: guardada - `400` (BadRequest): requisição ilegível — corpo que não é JSON, parâmetro malformado — `application/problem+json` Problem — type `https://abeesys.com/errors/bad-request` - `401` (Unauthorized): API key ausente, inválida, ou de tenant desativado — a mesma resposta — `application/problem+json` Problem — type `https://abeesys.com/errors/unauthorized` - `422` (ValidationFailed): Entrada que viola o schema ou regra de entrada: enum fora, texto vazio ou acima do limite, campo desconhecido, null onde se pede valor, credencial não cadastrada, texto acima da janela de tokens do vetorizador, ou identidade do vetorizador (repositório, arquivo, quantização, dimensão, pooling, janela) diferente da do índice. Não deixa registro. — `application/problem+json` Problem — type `https://abeesys.com/errors/validation`, `https://abeesys.com/errors/embedder-identity-mismatch`, `https://abeesys.com/errors/text-exceeds-window` ### POST /v1/perguntas Pergunta ao conhecimento do tenant que pergunta - operationId: `askQuestion` - autenticação: API key do tenant A resposta chega em **três tempos, nesta ordem e nada fora dela**: 1. `trechos` — o que sustenta, com a origem de cada um, e o desfecho; 2. `confianca` — o nível, calculado antes do texto, da cobertura textual da pergunta pelos trechos (nunca da distância do vetor), igual para qualquer motor; 3. `texto` — o texto verificado, sentença a sentença. Sentença sem origem válida sai **inteira**. Se nenhuma sobrevive, o texto vem vazio. `stream=true` (padrão) devolve SSE com os eventos nomeados `trechos`, `confianca` e `texto`, um de cada, nesta ordem. `stream=false` devolve os três tempos no fim, na mesma ordem. Perguntar grava só **cache da resposta** e **medição de uso** — mesmo quando o consumidor desiste no meio. Não grava conhecimento, veto, nem estado de resposta. **Quem escreve o texto** (spec 0034): a credencial do tenant, se a pergunta cita uma; o modelo hospedado da plataforma se ela falhar ou se a pergunta não citar nenhuma; nenhum, se os dois falharem — e aí os trechos e o nível saem do mesmo jeito, sem texto, nunca 500. A cadeia inteira tem um **teto somado** de tempo (35 s por padrão, configuração do serviço), com uma reserva para o hospedado: o 429 do provedor da credencial é tentado de novo, com espera crescente, só enquanto sobra a reserva do hospedado — esgotado, o hospedado responde com `motivo: limite_de_taxa`. Os dois primeiros tempos (trechos e nível) não esperam o motor. Resposta em que a credencial do tenant falhou (`credencial_falhou: true`, qualquer `motivo`) **não vai ao cache**: repetir a pergunta quando o provedor voltar dá a resposta dele, não a do hospedado guardada. Parâmetros: - `stream` (query, opcional): boolean, padrão `true` Corpo (`application/json`): QuestionInput - `pergunta` (obrigatório): string, de 1 a 1000 caracteres - `credencial` (opcional): CredentialName — nome da credencial do tenant que escreve o texto. Ausente: o modelo hospedado da plataforma. Credencial que o tenant não cadastrou é 422. Exemplo de corpo: ```json { "pergunta": "posso remarcar o agendamento no mesmo dia?", "credencial": "principal" } ``` Respostas: - `200`: `text/event-stream` com `stream=true`; `application/json` com `stream=false`. Os dois carregam os mesmos três objetos. — `text/event-stream` string — `application/json` Answer - `400` (BadRequest): requisição ilegível — corpo que não é JSON, parâmetro malformado — `application/problem+json` Problem — type `https://abeesys.com/errors/bad-request` - `401` (Unauthorized): API key ausente, inválida, ou de tenant desativado — a mesma resposta — `application/problem+json` Problem — type `https://abeesys.com/errors/unauthorized` - `422` (ValidationFailed): Entrada que viola o schema ou regra de entrada: enum fora, texto vazio ou acima do limite, campo desconhecido, null onde se pede valor, credencial não cadastrada, texto acima da janela de tokens do vetorizador, ou identidade do vetorizador (repositório, arquivo, quantização, dimensão, pooling, janela) diferente da do índice. Não deixa registro. — `application/problem+json` Problem — type `https://abeesys.com/errors/validation`, `https://abeesys.com/errors/embedder-identity-mismatch`, `https://abeesys.com/errors/text-exceeds-window` Exemplo de resposta 200 `text/event-stream`: ```text event: trechos data: {"desfecho":"encontrado","trechos":[...],"negativos":[],"procurado":{...}} event: confianca data: {"nivel":"alta"} event: texto data: {"resposta_id":"...","texto":"...","sentencas":[...],"motor":{...},"uso":{...}} ``` ### GET /openapi.yaml Este contrato, em YAML - operationId: `getOpenAPIYAML` - autenticação: sem API key Os bytes exatos de `contract/openapi.yaml` do commit que está no ar. Não exige API key: não carrega dado de tenant. Respostas: - `200`: o contrato — `application/yaml` string ### GET /openapi.json Este contrato, em JSON - operationId: `getOpenAPIJSON` - autenticação: sem API key O mesmo contrato do `/openapi.yaml`, convertido no arranque, na mesma ordem. Respostas: - `200`: o contrato — `application/json` object ### GET /llms.txt Índice curto para agentes (llmstxt.org) - operationId: `getLLMsIndex` - autenticação: sem API key Gerado deste contrato no arranque — o que o serviço faz, onde está e cada rota. Respostas: - `200`: o índice — `text/plain` string ### GET /llms-full.txt Documentação completa para agentes - operationId: `getLLMsFull` - autenticação: sem API key Gerada deste contrato no arranque: rotas, parâmetros, campos, enums, respostas, tipos de erro e exemplos, num arquivo só de texto. Respostas: - `200`: a documentação — `text/plain` string ## Schemas ### KnowledgeKind string (enum: `equivalencia`, `apelido`, `aplicacao`, `observacao`) tipo do conhecimento — enum fechado; valor fora é 422 ### Confidence string (enum: `alta`, `media`, `baixa`) ### Publication string (enum: `publicado`, `rascunho`) eixo de publicação — decide se o registro pode sustentar texto ### IndexStatus string (enum: `ok`, `pendente`, `recusado`) Eixo de indexação. `ok`: tem vetor e entra na busca vetorial. `pendente`: sem vetor ainda — o vetorizador estava fora; responde só pela busca textual, e o worker tenta de novo. `recusado`: o vetorizador recusou o texto por não caber na janela de tokens; responde só pela busca textual e **não** é reprocessado — só um texto novo na mesma chave o devolve à indexação. `recusado` entrou na versão 1.1.0 (spec 0029). É valor novo num enum de **saída**: cliente com `switch` exaustivo precisa tratá-lo. Nenhum registro estava `recusado` antes dessa versão. ### KnowledgeMark string (enum: `negativo`, `sugestao`) `negativo`: o cliente registrou que aquilo não serve — considerado, nunca sustenta frase. `sugestao`: proposta de algoritmo — segurada em rascunho até a marca ser retirada. ### Outcome string (enum: `encontrado`, `negativo`, `nao_encontrado`) Os três desfechos. `encontrado`: há conhecimento para afirmar. `negativo`: só um negativo registrado por pessoa. `nao_encontrado`: não há registro — nunca é tratado como negativa. ### SearchState string (enum: `ok`, `indisponivel`, `nao_tentada`) `ok`: a busca rodou. `indisponivel`: o vetorizador não respondeu, ainda carregava o modelo, respondeu com outra identidade, ou a pergunta não coube na janela de tokens dele — a resposta saiu **sem busca vetorial**. `nao_tentada`: base vazia. ### EngineSource string (enum: `tenant`, `hospedado`, `nenhum`) quem escreveu o texto — o modelo do tenant, o hospedado da plataforma, ou nenhum ### CredentialName string, de 1 a 64 caracteres, padrão `^[a-z0-9][a-z0-9_-]*$` ### KnowledgeInput objeto, sem campos além destes - `texto` (obrigatório): string, de 1 a 510 caracteres — O texto indexável. Acima de 510 caracteres é 422. Dentro do limite, o texto ainda precisa caber na janela de tokens do vetorizador: se não couber, 422 `text-exceeds-window` nomeando o limite em tokens — nunca vetor truncado. Só espaço, ou caractere de controle, é 422. - `tipo` (obrigatório): KnowledgeKind (enum: `equivalencia`, `apelido`, `aplicacao`, `observacao`) - `nivel` (opcional): Confidence (enum: `alta`, `media`, `baixa`) - `publicacao` (obrigatório): Publication (enum: `publicado`, `rascunho`) - `marca` (opcional): KnowledgeMark (enum: `negativo`, `sugestao`) - `referencia` (opcional): string, de 1 a 512 caracteres — id opaco de outro sistema; devolvido intacto, byte a byte, na origem ### Knowledge objeto, sem campos além destes - `id` (obrigatório): string, formato uuid - `versao` (obrigatório): integer, mínimo 1 - `texto` (obrigatório): string - `tipo` (obrigatório): KnowledgeKind (enum: `equivalencia`, `apelido`, `aplicacao`, `observacao`) - `nivel` (opcional): Confidence (enum: `alta`, `media`, `baixa`) - `publicacao` (obrigatório): Publication (enum: `publicado`, `rascunho`) - `indexacao` (obrigatório): IndexStatus (enum: `ok`, `pendente`, `recusado`) - `marca` (opcional): KnowledgeMark (enum: `negativo`, `sugestao`) - `referencia` (opcional): string - `vetado` (obrigatório): boolean - `criado_em` (obrigatório): string, formato date-time - `atualizado_em` (obrigatório): string, formato date-time ### KnowledgeVersion objeto, sem campos além destes - `id` (obrigatório): string, formato uuid - `versao` (obrigatório): integer, mínimo 1 - `texto` (obrigatório): string - `tipo` (obrigatório): KnowledgeKind (enum: `equivalencia`, `apelido`, `aplicacao`, `observacao`) - `nivel` (opcional): Confidence (enum: `alta`, `media`, `baixa`) - `publicacao` (obrigatório): Publication (enum: `publicado`, `rascunho`) - `marca` (opcional): KnowledgeMark (enum: `negativo`, `sugestao`) - `referencia` (opcional): string - `criado_em` (obrigatório): string, formato date-time ### KnowledgeVersionList objeto, sem campos além destes - `items` (obrigatório): lista de KnowledgeVersion - `meta` (obrigatório): objeto, sem campos além destes - `total` (obrigatório): integer, mínimo 0 - `ordem` (obrigatório): string (enum: `versao_desc`) ### CredentialInput objeto, sem campos além destes - `provedor` (obrigatório): string (enum: `openai`, `deepseek`) — provedor do modelo; o endereço de cada um é fixo no serviço (`openai`: `https://api.openai.com/v1`; `deepseek`: `https://api.deepseek.com`). `deepseek` entrou na versão 1.2.0 (spec 0034) — enum de entrada, aditivo. - `modelo` (obrigatório): string, de 1 a 128 caracteres - `segredo` (obrigatório): string, de 1 a 512 caracteres, só de entrada — nunca volta em resposta — entra, nunca sai — nenhum schema de resposta o contém ### QuestionInput objeto, sem campos além destes - `pergunta` (obrigatório): string, de 1 a 1000 caracteres - `credencial` (opcional): CredentialName — nome da credencial do tenant que escreve o texto. Ausente: o modelo hospedado da plataforma. Credencial que o tenant não cadastrou é 422. ### Origin objeto, sem campos além destes - `conhecimento_id` (obrigatório): string, formato uuid - `versao` (obrigatório): integer, mínimo 1 - `referencia` (opcional): string — a referência opaca exatamente como foi inserida - `caminho` (obrigatório): string — caminho que abre o texto inserido — GET nele com a mesma API key ### Passage objeto, sem campos além destes - `texto` (obrigatório): string - `tipo` (obrigatório): KnowledgeKind (enum: `equivalencia`, `apelido`, `aplicacao`, `observacao`) - `nivel` (opcional): Confidence (enum: `alta`, `media`, `baixa`) - `via` (obrigatório): string (enum: `vetorial`, `textual`) - `origem` (obrigatório): Origin ### Searched objeto, sem campos além destes - `pergunta` (obrigatório): string — a pergunta normalizada - `termos` (obrigatório): lista de string - `busca_vetorial` (obrigatório): SearchState (enum: `ok`, `indisponivel`, `nao_tentada`) - `busca_textual` (obrigatório): SearchState (enum: `ok`, `indisponivel`, `nao_tentada`) ### Passages objeto, sem campos além destes - `desfecho` (obrigatório): Outcome (enum: `encontrado`, `negativo`, `nao_encontrado`) - `trechos` (obrigatório): lista de Passage — o que pode sustentar texto, cada um com origem - `negativos` (obrigatório): lista de Passage — negativos registrados que foram considerados — nunca sustentam frase - `procurado` (obrigatório): Searched ### ConfidenceEvent objeto, sem campos além destes - `nivel` (obrigatório): Confidence (enum: `alta`, `media`, `baixa`) ### Engine objeto, sem campos além destes - `respondeu` (obrigatório): EngineSource (enum: `tenant`, `hospedado`, `nenhum`) - `modelo` (opcional): string — o modelo que escreveu o texto - `credencial` (opcional): CredentialName - `credencial_falhou` (obrigatório): boolean — a pergunta pediu a credencial do tenant e o modelo dele não respondeu - `motivo` (opcional): string (enum: `credencial_invalida`, `credencial_ilegivel`, `provedor_indisponivel`, `credencial_sem_saldo`, `limite_de_taxa`) — por que a credencial do tenant não respondeu: `credencial_invalida` — o provedor recusou o segredo (401/403), ou ela já estava inválida; `credencial_ilegivel` — o segredo guardado não abre com as chaves do serviço; `provedor_indisponivel` — fora do ar, lento ou com erro; `credencial_sem_saldo` — o provedor disse que a conta está sem saldo (402); `limite_de_taxa` — o provedor limitou a taxa (429) até acabar o tempo das novas tentativas. `credencial_sem_saldo` e `limite_de_taxa` entraram na versão 1.2.0 (spec 0034). São valores novos num enum de **saída**: cliente com `switch` exaustivo precisa tratá-los. Nenhuma resposta podia sair com eles antes dessa versão, e o `rag` não tinha consumidor fora da plataforma quando entraram. ### Usage objeto, sem campos além destes - `tokens_entrada` (obrigatório): integer, formato int64, mínimo 0 - `tokens_saida` (obrigatório): integer, formato int64, mínimo 0 - `do_cache` (obrigatório): boolean — resposta servida do cache — nenhum modelo foi chamado, zero tokens ### VerifiedSentence objeto, sem campos além destes - `texto` (obrigatório): string - `origens` (obrigatório): lista de Origin, mínimo 1 itens ### VerifiedText objeto, sem campos além destes - `resposta_id` (obrigatório): string, formato uuid - `texto` (obrigatório): string — as sentenças verificadas - `sentencas` (obrigatório): lista de VerifiedSentence - `motor` (obrigatório): Engine - `uso` (obrigatório): Usage ### Answer objeto, sem campos além destes os três tempos, na ordem - `trechos` (obrigatório): Passages - `confianca` (obrigatório): ConfidenceEvent - `texto` (obrigatório): VerifiedText ### Health objeto, sem campos além destes - `status` (obrigatório): string (enum: `ok`, `indisponivel`) - `motivo` (opcional): string ### FieldError objeto, sem campos além destes - `field` (obrigatório): string - `message` (obrigatório): string ### Problem objeto RFC 9457. Nunca carrega segredo, SQL, corpo de provedor ou stack trace. - `type` (obrigatório): string, formato uri - `title` (obrigatório): string - `status` (obrigatório): integer - `detail` (opcional): string - `errors` (opcional): lista de FieldError