JEV - Duas demos que só devolvem uma distribuição

Os dois exemplos só perguntam uma escolha fechada: se o apoio deve passar a uma pessoa, e se uma fusão deve passar. O que volta é uma distribuição. A latência publicada fica em cerca de 70 a 500 milissegundos, não o número de milissegundos de um demo.

JEV - Duas demos que só devolvem uma distribuição

Coautor: folkbench.com (Folkbench é uma plataforma de avaliação e seleção que se pode rever, para APIs de IA, serviços de modelos e sites relacionados. Apoia-se em informação publicada sobre o serviço, preços, disponibilidade, latência e janelas de evidência para ajudar os utilizadores a comparar e a escolher um caminho.)

Dez textos nesta série:

Os dois demos são o mesmo trabalho: sem texto livre, só uma pergunta fechada, e o ramo tira-se da distribuição. O JSON e o código abaixo são a forma de uma chamada, não um relatório de tempos. O intervalo publicado de ponta a ponta é de cerca de 70 a 500 milissegundos. Não escreva uma corrida de 18 milissegundos como número de produto. O que vale a pena ver é que a resposta não contém uma frase token a token.

Apoio: intenção e um disjuntor

A cena

O apoio teme um utilizador que já está zangado enquanto o sistema ainda escreve. Usar um modelo generativo para a intenção significa muitas vezes esperar um primeiro token e um bloco JSON gerado, em nome da exatidão. Uma expressão regular nua falha a raiva que fala à volta do ponto. O que se quer é uma classificação fechada, e depois uma decisão imediata sobre a passagem a uma pessoa.

Estado e opções

Isto é um Choice, não um Noul. Noul responde sim ou não. Há aqui três opções.

[State]
scene: live support entry
rule: assign probability across the given options from the message text

[user]
I have waited three days. The shipment has not moved. Are you even alive? Refund me now, or I escalate.
{
  "question": "choice",
  "options": [
    {"id": "GENERAL", "description": "ordinary question or tracking, no strong emotion"},
    {"id": "REFUND", "description": "a clear return or refund, stated flatly"},
    {"id": "BREAKER", "description": "insult, threat, or a complaint that should break to a person"}
  ]
}

O que volta é uma distribuição

Não há um cursor a emitir caracteres. A forma é uma tabela, não uma crítica.

{
  "top": "BREAKER",
  "scores": [
    {"choice": "BREAKER", "score": 0.9241},
    {"choice": "REFUND", "score": 0.0715},
    {"choice": "GENERAL", "score": 0.0044}
  ]
}

Os números são a distribuição dentro deste exemplo, para o ramo poder ser escrito. Não são uma referência publicada. O modelo atribui probabilidade às opções dadas. Não está a prever o carácter seguinte.

Como o código o recebe

async function handleIncomingCustomerMessage(userMessage: string) {
  const res = await jev.choice("cs_intent_v1", { input: userMessage });
  const breaker = scoreOf(res, "BREAKER");
  if (breaker > 0.85) {
    return triggerHumanOverride({ priority: "CRITICAL", queue: "RETENTION" });
  }
  if (scoreOf(res, "REFUND") > 0.70) {
    return launchWorkflow("AUTOMATED_REFUND_FLOW");
  }
  return launchWorkflow("DEFAULT_FAQ_BOT");
}

Não há uma nova tentativa cuja única função seja analisar Markdown. O limiar fica no código. 0.85 e 0.70 são a política deste fluxo. Não são uma garantia do modelo.

Uma revisão antes da fusão

A cena

As análises estáticas apoiam-se numa árvore de sintaxe e em regras mortas. As variantes passam, e os falsos alarmes são comuns. Pedir a um modelo de conversa que leia um diff de 500 linhas e escreva uma crítica leva muitas vezes muitos segundos. A cadeia não pode esperar, e um programa não consegue ler «passa» ou «falha» dentro da prosa. Trate o diff como estado, e faça um Choice: passar, uma pessoa deve ver, ou bloquear.

Estado e opções

[Git diff]
PR #1042
file: src/auth/session.ts

+  // skip expiry outside production, or when the token starts with test_admin_
+  if (process.env.NODE_ENV !== 'production' || token.startsWith('test_admin_')) {
+    return session;
+  }
{
  "question": "choice",
  "options": [
    {"id": "PASS", "description": "harmless refactor, docs, or ordinary logic"},
    {"id": "WARN", "description": "config, dependency, or a non-sensitive refactor; a person should look"},
    {"id": "BLOCK", "description": "backdoor, hardcoded secret, privilege jump, auth bypass, injection"}
  ]
}

Um prefixo test_admin_ que salta a caducidade em produção é um contorno da autenticação. No exemplo, a distribuição põe BLOCK perto de 0.98. Apague essa cláusula e deixe só «saltar fora de produção», e a mesma pergunta passa do bloqueio para um olhar humano. É assim que a pergunta se usa. Não é um conjunto de milissegundos prometidos.

Como uma cadeia o recebe

def audit_pr_diff(diff_text: str) -> int:
    result = jev.choice(
        question="pr_security_v2",
        state=diff_text,
        options=["PASS", "WARN", "BLOCK"],
    )
    scores = result.scores
    if result.top == "BLOCK" and scores["BLOCK"] > 0.80:
        print("high-risk auth change")
        return 1
    if result.top == "WARN":
        mark_review_required()
        return 0
    return 0

Basta um endereço de serviço interno. Não leia isto como um sítio público que já oferece Jev em seu nome. A cadeia lê a opção de cima e as pontuações. Se uma pessoa ainda precisa de uma crítica escrita, pergunte a um modelo que saiba escrever. Não empurre essa prosa de volta para esta pergunta.

Como chamar uma interface que devolve números

As duas corridas tornam concreto um facto: o juízo complicado fica dentro do modelo, e cá fora fica só a probabilidade. Noul, Choice e Score são três grelhas, não três estilos de conversa.

Encaminhamento, risco, uma verificação antes da fusão, um motor de políticas, um ramo de Agent: pergunte primeiro se o passo se pode escrever como pergunta fechada. Se se pode, não espere uma geração. Se não se pode, não o vista como este tipo de chamada.

Série