Documentação

Confiança

Como a TypeSafe reporta certeza, como isso difere da probabilidade e como usá-la para controlar o comportamento do sistema.

Todas as respostas de Score e Choice da TypeSafe incluem uma propriedade probabilities que representa a distribuição de probabilidade entre as opções (no caso de Choice) ou os níveis (no caso de Score). A forma dessa distribuição é o que diz quão certo o modelo está: concentrada em um resultado significa uma resposta confiante, espalhada significa uma resposta incerta.

A propriedade confidence da resposta condensa essa forma em um único número de 0 a 1, para que você possa aplicar um limiar sobre ele sem fazer as contas. Ela é 1 quando toda a probabilidade está em um único resultado e 0 quando a probabilidade está espalhada por igual. (As respostas de Noul não a incluem; veja mais abaixo Noul.)

A confiança é derivada das probabilidades

confidence é uma estatística calculada a partir da distribuição de probabilidade que a resposta já fornece. A TypeSafe a calcula para você e a devolve em cada resposta de Choice e Score, então o caso comum não exige trabalho extra do seu lado.

Exemplo: pergunta choice com três opções

Veja como a distribuição de probabilidade muda a confiança

Confiança

0.85

Arraste um controle para mudar a probabilidade de uma opção. As demais se ajustam sozinhas para manter o total em 100%.

Selecionado: Opção A

Como esta demonstração calcula a confiança

O TypeSafe calcula a confiança a partir de como a probabilidade se espalha entre as opções. Tudo em uma só opção dá 1.0; quanto mais uniforme, menor a confiança. Esta demonstração usa (3 × probabilidade máxima − 1) / 2 para aproximar a confiança com três opções.

Para um Choice, a distribuição é a probabilities entre as suas opções. Para um Score, é a distribuição entre os seus níveis. Nos dois casos, uma distribuição mais plana significa menor confiança: confiança baixa em um Choice geralmente significa que nenhuma das opções vence claramente as outras, e confiança baixa em um Score geralmente significa que os níveis são ambíguos, multidimensionais, ou que o estado não contém informação suficiente.

A fórmula exata de cada tipo de pergunta está em Como a confiança é calculada, para que você veja como qualquer valor de confidence decorre das probabilities da própria resposta.

“Não sei” é um sinal útil

Se um sistema inteligente, seja humano ou máquina, não consegue expressar incerteza com honestidade, não se pode confiar nele.

A confiança dá ao modelo um mecanismo integrado para dizer “não tenho certeza quanto a isto”. Isso permite que o seu código implemente comportamentos diferentes para níveis diferentes de certeza, que é a base para construir sistemas em que você realmente pode confiar.

Três caminhos para usar a confiança no seu código

Um padrão inicial útil é dividir a confiança em três faixas, cada uma produzindo um comportamento diferente do sistema:

Confiança alta: Aja automaticamente. O modelo tem uma leitura clara e você pode prosseguir sem envolvimento humano.

Confiança média: Prossiga com cautela. O modelo tem uma resposta razoável, mas não tem certeza. Dependendo do contexto, você pode pedir confirmação ao usuário, sinalizar para revisão ou reunir mais informações antes de agir.

Confiança baixa: Não aja. Encaminhe para uma pessoa, peça esclarecimento ou recorra a outro sistema. O modelo está dizendo que não tem informação suficiente ou que a pergunta não é adequada.

Onde você traça esses limites depende do que está em jogo.

Os limiares acompanham o risco

Um limiar de confiança não é um número único. Ações diferentes dentro do mesmo sistema devem ser condicionadas a níveis diferentes, dependendo das consequências de errar.

response = client.system_one(
    state=user_message,
    questions={
        "action": Choice(
            instructions="What is the user trying to do?",
            criteria={
                "check_balance": "View account balance",
                "approve_transfer": "Approve the pending withdrawal request",
                "support": "Get help with an issue",
            },
        ),
    },
)

action = response.answers["action"]
confidence = action.confidence

if confidence < 0.5:
    # Model is genuinely unsure. Don't guess.
    route_to_human(user_message)

elif action.choice == "check_balance":
    # Low stakes. Showing the wrong screen is recoverable.
    show_balance(account_id)

elif action.choice == "approve_transfer":
    if confidence > 0.9:
        # High stakes, high confidence. Proceed with confirmation.
        confirm_then_execute(account_id)
    else:
        # High stakes, moderate confidence. Verify first.
        ask_user_to_confirm(account_id)

O piso de confiança de 0.5 captura tudo o que o modelo reporta como genuinamente incerto. Acima disso, o limiar para agir sem confirmação é mais alto para uma operação destrutiva do que para uma de leitura. O seu código codifica a tolerância ao risco.

Como a confiança é calculada

Cada tipo de pergunta resume a sua distribuição de um jeito um pouco diferente. Um Noul tem dois resultados, um Choice tem qualquer número de opções em ordem alguma, e os níveis de um Score são ordenados, então cada fórmula abaixo se apoia na anterior.

A confidence da TypeSafe é uma forma razoável de resumir uma distribuição, não a única. Devolvemos uma medida fixa para que toda resposta venha com um padrão sensato: você pode condicionar por confidence desde a primeira chamada, na mesma escala de 0 a 1 para toda pergunta, sem antes escolher e validar uma estatística própria. Como as fórmulas abaixo são exatas e toda resposta inclui as suas probabilities completas, você pode calcular em vez dela a medida que mais importa para a sua aplicação.

Noul

Uma resposta de Noul é uma única probabilidade $p$ de que a resposta seja sim, e a TypeSafe não devolve um confidence separado para ela. A probabilidade já carrega a incerteza: um valor próximo de 0.5 é o modelo dizendo que não tem certeza, e a página Noul explica como aplicar um limiar diretamente sobre ela.

Se você ainda quiser um número no estilo da confiança, por exemplo para condicionar Nouls e Choices com o mesmo código, use a distância até 0.5:

$$ \text{confidence} = |2p - 1| $$

Isso dá 0 em $p = 0.5$ e 1 em $p = 0$ ou $p = 1$. É também a fórmula de Choice abaixo aplicada a um Choice de sim/não, então fica na mesma escala da confiança de Choice.

Choice

Um Choice estende a mesma ideia a qualquer número de opções. Para um Choice com $n$ opções, em que $p_{\max}$ é a probabilidade da opção selecionada:

$$ \text{confidence} = \frac{p_{\max} - \frac{1}{n}}{1 - \frac{1}{n}} $$

Isso mede o quanto a probabilidade mais alta fica acima de uma divisão igual de $\frac{1}{n}$ por opção, numa escala em que a divisão igual é 0 e a certeza é 1. Só a probabilidade mais alta conta, então $(0.6, 0.3, 0.1)$ e $(0.6, 0.2, 0.2)$ têm ambas confiança 0.4.

def choice_confidence(probabilities: list[float]) -> float:
    n = len(probabilities)
    return (max(probabilities) - 1 / n) / (1 - 1 / n)

choice_confidence(list(answer.probabilities.values()))

O explorador no topo desta página usa esta fórmula com três opções.

Outras duas medidas mais simples, calculadas a partir das mesmas probabilities, costumam ser muito eficazes na prática e valem a pena ser testadas junto com confidence:

  • Probabilidade mais alta, $p_{\max}$. Ela se lê diretamente como “quão provável é a opção selecionada”, o que torna os limiares fáceis de raciocinar. O seu significado depende do número de opções, já que 0.5 é uma resposta fraca entre duas opções e forte entre dez, então defina o seu limiar por pergunta.
  • Razão entre a mais alta e a segunda, $p_{\max} / p_{\text{second}}$. Ela mede com que clareza a opção selecionada supera a vice-colocada e ignora como o restante se espalha. Muitas decisões reais se resumem aos dois candidatos principais, e essa razão mira exatamente isso.

Score

Os níveis de um Score são ordenados, então a sua fórmula também conta o quão longe a probabilidade está do nível mais provável. Para um Score com $n$ níveis numerados de $0$ a $n - 1$, em que $p_i$ é a probabilidade do nível $i$ e $m$ é o nível mais provável:

$$ \text{confidence} = \max\left(0,\ 1 - \frac{\sum_i p_i , |i - m|}{\text{MAD}{\text{unif}}}\right) \qquad \text{MAD}{\text{unif}} = \frac{1}{n} \sum_i \left| i - \frac{n - 1}{2} \right| $$

A soma no numerador é a distância média ponderada pela probabilidade, em níveis, entre a resposta e o nível mais provável. $\text{MAD}_{\text{unif}}$ é o mesmo tipo de distância média para uma distribuição igual entre todos os níveis, medida a partir do nível central. A confiança compara as duas e tem piso 0 quando a resposta está pelo menos tão espalhada quanto uma divisão igual.

Probabilidade num nível vizinho reduz a confiança menos do que a mesma probabilidade num nível mais distante. Com três níveis, $(0, 0.5, 0.5)$ tem confiança 0.25, porque o modelo está dividido entre dois níveis adjacentes. $(0.5, 0, 0.5)$ tem confiança 0, porque está dividido entre extremos opostos. A fórmula de Choice daria 0.25 às duas distribuições.

Pergunta de pontuação com cinco níveis

Veja como a distância entre níveis muda a confiança

Confiança

0.92

Mova um controle para alterar a probabilidade de um nível. As demais se ajustam para manter o total em 100%.

Pontuação
2.00
Fórmula do Choice com as mesmas probabilidades
0.88
Como esta demonstração calcula a confiança

Esta demonstração usa a fórmula do Score: calcula a distância média, em níveis, entre a resposta e o pico, ponderada pela probabilidade. Divide esse valor por 1.2, a mesma média para uma distribuição uniforme em cinco níveis medida a partir do nível central, e subtrai o resultado de 1, parando em 0. Probabilidade em um nível vizinho ao pico reduz menos a confiança do que probabilidade distante dele, algo que a fórmula do Choice não considera.

def score_confidence(probabilities: list[float]) -> float:
    n = len(probabilities)
    m = probabilities.index(max(probabilities))
    spread = sum(p * abs(i - m) for i, p in enumerate(probabilities))
    even_spread = sum(abs(i - (n - 1) / 2) for i in range(n)) / n
    return max(0.0, 1 - spread / even_spread)

levels = sorted(answer.probabilities)
score_confidence([answer.probabilities[level] for level in levels])

A resposta de bug_severity no exemplo de resposta de Score tem probabilidades $(0, 0.57, 0.43)$. O nível mais provável é 1, a distância é $0.43$, e o $\text{MAD}_{\text{unif}}$ para três níveis é $\frac{2}{3}$, então a confiança é $1 - 0.43 / \frac{2}{3} \approx 0.35$.