4 pontos por GN⁺ 2024-04-14 | 1 comentários | Compartilhar no WhatsApp
  • A Truss operou recentemente recursos centrados em LLM por 6 meses, processando mais de 500 milhões de tokens com modelos da OpenAI, e reuniu os limites que encontrou na prática em resumo, análise e extração de texto para B2B
  • Prompts não ficaram mais estáveis ao receber muitas instruções detalhadas, e em casos de conhecimento geral que o GPT já dominava, instruções curtas e menos específicas às vezes produziram resultados melhores
  • Mesmo sem Langchain, JSON mode, function calling ou assistants, vários recursos foram operados apenas com a API chat e uma função de extração de JSON, e o código principal era basicamente uma função de 40 linhas mais tratamento de erros e corte automático
  • O GPT era fraco para lidar com hipótese nula (null hypothesis), como “se não houver nada, retorne valor vazio”, e também com saídas longas; separadamente da janela de entrada de 128k do GPT-4, a saída ainda ficava na faixa de 4k
  • RAG e bancos de vetores não se encaixaram bem no trabalho limitado de extração de texto da Truss; análise, resumo e extração com o contexto completo eram confiáveis, mas os problemas aumentavam muito quando a entrada estava vazia ou não havia informação relevante

Escopo de uso e premissas

  • A Truss lançou alguns recursos centrados em LLM nos últimos 6 meses, e o uso estimado passou um pouco de 500 milhões de tokens
  • Os modelos usados são da OpenAI, e o consumo de tokens foi 85% GPT-4 e 15% GPT-3.5
  • Os dados tratados são apenas texto, sem incluir recursos não textuais como gpt-4-vision, Sora ou Whisper
  • O contexto do produto é B2B, e as tarefas principais são resumo, análise e extração
  • 500 milhões de tokens equivalem a aproximadamente 750 mil páginas de texto

Prompts podem melhorar quando são menos específicos

  • Para conhecimento geral que o GPT já conhece, inserir listas exatas e instruções detalhadas demais podia piorar o resultado
  • Um pipeline precisava classificar a qual dos 50 estados dos EUA ou ao governo federal um bloco de texto se referia
    • O prompt inicial colocava no campo locality_id uma lista de IDs dos 50 estados e de federal em formato JSON para o modelo escolher
    • Essa abordagem funcionava em cerca de 98% ou mais dos casos, mas ainda falhava com frequência suficiente para exigir investigação adicional
  • Outro campo, name, retornava com estabilidade o nome completo correto do estado mesmo sem isso ser explicitamente pedido
    • Depois, ao mudar para uma abordagem que buscava o estado a partir da string retornada em name, o resultado funcionou bem
  • A abordagem melhor foi um prompt do tipo deixar no senso comum, como: “você conhece os 50 estados, então retorne o nome completo do estado correspondente ou Federal”
  • Houve também observações adicionais
    • As falhas apareciam com mais frequência em estados que começam com M, como Maryland, Maine, Massachusetts e Michigan
    • Ao fazer o modelo escolher IDs de uma lista, um JSON bem formatado com um estado por linha causava menos confusão do que uma lista contínua separada por vírgulas

API e abstrações continuaram simples

  • Neste caso, o Langchain ficou mais próximo de uma abstração prematura, e mesmo após milhões de tokens e 3 ou 4 recursos diferentes em produção, o arquivo openai_service ainda ficou com apenas uma função de 40 linhas
  • Na prática, a única API usada foi a chat
    • Sempre extraindo JSON
    • Não houve necessidade de JSON mode, function calling nem assistants
    • Também não foi usado system prompt
    • Quando o gpt-4-turbo foi lançado, só foi preciso trocar uma string no código
  • A maior parte da função cuidava de tratamento de erros da API da OpenAI, como erros 500 ou fechamento de socket
    • Esses erros melhoraram com o tempo, o que não é surpreendente dado o volume de carga da OpenAI
  • O limite de comprimento de contexto foi tratado com corte automático próprio
    • Se o tamanho da string passava de model_context_size * 3, ela era cortada
    • Quando havia muitos pontos finais ou números, a proporção podia ficar menor que 1 token para cada 3 caracteres e isso podia falhar
    • Se surgia context_length_exceeded, era feito novo corte com base em model_context_size * 3 / 1.3 e a chamada era tentada de novo

É difícil subestimar o valor de UX com streaming

  • Usar a API de streaming para reduzir a latência e mostrar ao usuário caracteres chegando em velocidade variável parecia, no começo, algo meio de brincadeira
  • Na prática, os usuários reagiram de forma muito positiva a esse indicador de “digitação” em velocidade variável
  • A sensação foi a de um momento equivalente ao UX de mouse e cursor no mundo da IA

Resultados vazios e saídas longas são pontos fracos

  • “Se não encontrar, retorne saída vazia” foi algo muito próximo da formulação de prompt com maior taxa de erro
    • Na prática, não significava literalmente não produzir nada, mas sim retornar uma representação de valor vazio como {value: ""}
    • O problema parecia menos ser um limite de saída e mais a dificuldade de decidir corretamente a hipótese nula em si
  • Quando deveria retornar um valor vazio, o GPT às vezes preferia alucinar; em outros casos, perdia confiança e devolvia vazio com frequência excessiva
  • Quando houve um bug em que blocos de texto podiam vir vazios, as alucinações aumentaram muito
    • Exemplos incluíram nomes falsos de padarias como Sunshine Bakery, Golden Grain Bakery e Bliss Bakery
    • A solução foi simplesmente não enviar prompt algum quando não havia texto
  • O GPT-4 pode ter uma janela de 128k tokens para entrada, mas a janela de saída continua na faixa de 4k
    • A expressão “context window” acaba confundindo entrada e saída
  • Ao pedir o retorno de uma lista de objetos JSON, era difícil passar de 10 itens mesmo com objetos simples
    • Ao pedir 15 itens, a taxa de sucesso era estimada em apenas cerca de 15%
    • Mesmo quando parava na faixa de 10 itens, a saída ainda tinha só cerca de 700 a 800 tokens
  • Dá para contornar o limite de saída pedindo um item por vez e reenviando o resultado anterior, mas isso vira uma espécie de telefone sem fio com o GPT e leva ao uso de ferramentas como Langchain

RAG e banco de vetores não combinam bem com este caso de uso

  • Banco de vetores e RAG/embeddings foram, em grande parte, inúteis no caso da Truss
  • A visão é que banco de vetores e RAG se encaixam melhor em busca, especialmente busca de verdade como Google e Bing
  • O problema central é o critério de relevância
    • Não existe um corte claro de relevância
    • Pode haver soluções como rerank da Cohere ou heurísticas próprias, mas elas não são estáveis
    • Há risco de poluir os resultados com itens irrelevantes ou, sendo conservador demais, perder resultados importantes
  • Também há perda ao armazenar vetores em um banco especializado e separado dos dados gerais
    • A menos que se esteja na escala de Google ou Bing, a perda de contexto não parece justificar esse trade-off
  • Em busca dentro de aplicações de negócio, muitas vezes o usuário é especialista no domínio
    • A ideia é que esse usuário não gosta de busca semântica que devolve significados que ele próprio não digitou
  • Na maioria dos casos de busca, pode ser melhor usar o LLM em um prompt de completion comum para transformar a consulta do usuário em faceted search, consulta complexa ou SQL
    • Isso não é RAG

Alucinação cai bastante quando o contexto é suficiente

  • Os casos de uso da Truss são, em sua maioria, do tipo “dar um bloco de texto e extrair algo dele”
  • Se for pedido o nome de uma empresa mencionada no texto, o GPT normalmente não retorna uma empresa aleatória
    • Mas, se não houver empresa no texto, o problema da hipótese nula reaparece
  • Também em código, o GPT normalmente não alucina no sentido de reinventar variáveis ou inserir erros de digitação aleatórios ao reescrever um bloco de código fornecido
    • Porém, se for pedido para criar algo, ele pode inventar a existência de funções da biblioteca padrão
    • Isso também parece mais próximo do problema de não conseguir dizer “não sei”
  • Em tarefas de análise, resumo e extração com o contexto completo fornecido, ele se mostrou muito confiável
  • O padrão parece ser: dados bons entram, respostas boas em tokens do GPT saem

Avaliação sobre as perspectivas futuras

  • A visão é que os transformers atuais, os dados da internet e mesmo o acesso a infraestrutura de dezenas de bilhões de dólares não bastam para chegar à AGI
  • O GPT-4 não é marketing, mas uma tecnologia 100% útil, e ainda parece estar numa fase comparável ao início da internet
    • Não é uma tecnologia que vai demitir todo mundo
    • O efeito importante é reduzir a barreira de entrada de ML/IA, antes acessível basicamente ao Google
  • Claude, Gemini e outros não foram comparados em testes A/B rigorosos
    • Em testes informais de programação no dia a dia, a sensação foi de que não chegam tão perto do GPT-4 na sutileza de captar a intenção
  • A avaliação é que não é preciso acompanhar todo o fluxo de novidades de LLM/IA
    • À luz de The Bitter Lesson, se a melhora de modelos gerais importa mais que otimizações específicas, então basta prestar atenção se o GPT-5 foi lançado ou não
    • Tirando áreas separadas como Sora, os lançamentos intermediários da OpenAI parecem ser em grande parte ruído
  • O GPT-5 provavelmente será uma melhoria incremental, não algo que muda tudo
    • Na transição de GPT-3 para GPT-3.5, a expectativa era de melhora superlinear, como dobrar a intensidade de treino e obter 2,2x de desempenho
    • Na prática, a evolução parece mais logarítmica, com velocidade de tokens e custo por token crescendo geometricamente para conseguir melhorias incrementais
  • O GPT-4 pode ser o ponto ótimo para o conjunto atual de tarefas
    • Havia disposição para pagar 20x mais pelo GPT-4 em relação ao GPT-3.5, mas não parece haver disposição para pagar 20x mais por token para ir de GPT-4 a GPT-5
    • O GPT-5 pode quebrar essa expectativa, ou pode ser algo como ir de um iPhone 4 para um iPhone 5

1 comentários

 
GN⁺ 2024-04-14
Opiniões no Hacker News
  • A equipe em que trabalho processa mais de 5 bilhões de tokens por mês, e esse número continua crescendo; há algumas coisas que aprendemos.
    Primeiro, há muita abstração precoce demais. Ferramentas como Langchain podem vir a ser úteis algum dia, mas, no fim das contas, prompts são apenas chamadas de API, e é mais fácil tratar chamadas a LLMs como chamadas de API instáveis em código padrão, em vez de tratá-las como algo especial.
    Segundo, alucinações são definitivamente um grande problema. Em testes, sumarização é bastante robusta, mas raciocínio é realmente difícil; e modelos de ação em que a LLM recebe a entrada do usuário e decide a próxima ação são especialmente difíceis, sobretudo em compreensão de contexto e em fazê-la dizer “não tenho certeza”. Ainda assim, o simples fato de isso ser possível muda o jogo.
    Terceiro, estou um pouco mais próximo do autor no lado de “muda o jogo”, mas não acho que seja o fim do mundo. Algumas profissões serão muito afetadas, e podemos ter alguns anos difíceis com bots manipulando a opinião pública em plataformas. No geral, parece mais um amplificador de capacidades do que uma ruptura como a internet.
    Pessoalmente, isso se parece com a mudança de DevOps dos anos 2000. Hoje não é mais necessário ter uma grande equipe dedicada para ajudar em deploys; contratam-se alguns especialistas e, na maior parte, compram-se soluções prontas. Da mesma forma, algumas tarefas de machine learning passaram a ser fáceis de implementar até para um desenvolvedor web como eu.

    • Essa analogia é útil ao explicar o que esperar das LLMs nos fluxos modernos de desenvolvimento, porque mostra que não são uma solução universal, mas sim uma troca de compromissos.
      Também houve compromissos na evolução do DevOps. Por exemplo, como consequência direta de “é só usar AWS RDS”, competências essenciais como administração de bancos de dados desapareceram, e as contas de cloud também dispararam. Em especial, os custos operacionais aumentaram até para startups sem grande escala de dados ou complexidade regional; e vejo essa tendência como algo que também levou a incidentes parecidos com a grande indisponibilidade do GitLab.
    • Fazer o modelo dizer “não tenho certeza” é quase uma função do próprio modelo de linguagem. Quando se chega à saída, a incerteza inerente ao cálculo desaparece dentro da previsão.
      É parecido com pedir a alguém para adivinhar cara ou coroa: se a resposta for “cara”, antes de responder ela poderia falar de uma incerteza como Pr[cara] = .5, mas essa incerteza desaparece na previsão efetiva e no resultado do lançamento. Em LLMs também, a incerteza durante o cálculo desaparece na previsão final dos tokens; portanto, a menos que a própria previsão seja uma expressão de incerteza, uma saída do tipo “não entendi” quase nunca aparecerá. Mas o motivo é que, para começo de conversa, ela não entende: ela prevê.
    • Eu nunca tinha pensado antes na analogia com DevOps, mas ela se encaixou de algum modo, então acabei de escrever um texto baseado nessa ideia: https://kenkantzer.com/gpt-is-the-heroku-of-ai
      Basicamente, vejo que estamos usando GPT como um equivalente a PaaS/Heroku/Render para operações de IA.
    • Concordo com “mais um amplificador de capacidades do que uma ruptura como a internet”. Clientes também estão sentindo um choque de preço nos resultados em relação ao custo dos modelos grandes. Com o tempo, os custos devem cair.
    • Concordo com a afirmação de que sumarização é robusta, mas raciocínio é difícil. A abordagem de pedir analogias foi interessante e surpreendentemente útil.
  • Fiquei curioso sobre a parte “sempre extraímos JSON; não precisamos do modo JSON”. No meu caso, funcionou muito bem.
    Concordo demais com “Lição 4: GPT é muito ruim em produzir a hipótese nula”. Ontem mesmo, enquanto testava um prompt de regras de edição de texto, escrevi no final: “se nenhuma regra se aplicar ao texto, retorne o texto original sem alterações”.
    Sabe o que o ChatGPT respondeu para um texto ao qual nenhuma regra se aplicava? Exatamente a string “The original text without any changes”.

    • Existem histórias em que um gênio caprichoso interpreta literalmente a formulação de um desejo e concede um desejo amaldiçoado; o que temos agora é isso. Pessoas que vêm usando prompts há muito tempo em modelos de geração de imagem já desenvolveram uma certa intuição, mas para quem chegou por causa das LLMs isso pode ser bem surpreendente.
      Certa vez, eu estava criando uma imagem de três mulheres bebendo vinho em um jardim elegante para cartas de tarô; quando coloquei “lush vegetation” no fim do prompt, por causa da ambiguidade de lush, o clima sofisticado virou algo mais como universitárias festeiras de nariz vermelho.
    • Li isso como “nosso método funciona bem, então não precisamos usar o modo JSON”. Na minha empresa é a mesma situação. Está em produção há um ano e não houve necessidade de mudar. Nosso prompt faz o GPT-3.5 gerar JSON de forma bastante consistente.
    • Basta olhar sites de falhas em decoração de bolos para ver que humanos também cometem esse tipo de erro o tempo todo.
  • Com prompts melhores, é possível usar modelos mais baratos.
    “Se não encontrar nada, não retorne nada” é uma abordagem nível 0 que dá uma saída para a LLM. É melhor oferecer uma saída mais suave. Por exemplo: “se não houver informações suficientes para fazer uma afirmação definitiva, você pode formular uma hipótese, desde que deixe claro que está fazendo isso e escreva as evidências e a base lógica da hipótese”; depois, no fim, peça para ela avaliar a própria resposta.

    • Prompts não devem ser desenvolvidos de forma abstrata. O objetivo de um prompt é ativar as representações internas do modelo para que ele execute a tarefa da melhor forma.
      Se não houver um método automatizado, é preciso testar repetidamente a reação do modelo a várias entradas, entender como ele interpreta a solicitação, onde falha e fechar essas lacunas. É preciso até verificar se o modelo sabe o que nothing significa.
  • Eu assino todos os três principais serviços da área de LLM e frequentemente mando o mesmo prompt para eles; a vantagem é muito unilateral para o GPT-4. Mesmo considerando que já faz um ano que o GPT-4 saiu e que houve algumas atualizações nesse meio-tempo, isso é surpreendente
    Pelo menos no meu padrão de uso, alucinações também são raras. Já o Claude inventa com bastante facilidade APIs plausíveis que não existem ao escrever código. O GPT-4 é mais teimoso e concorda menos quando sabe que está certo. Esse tipo de diferença quase não aparece nas métricas, então só dá para perceber usando pessoalmente

    • No meu caso, o Claude 3 Opus foi melhor que o GPT-4. Especialmente por explicar melhor e, mais importante, por ser mais minucioso
      Também em tarefas de programação, eu peço mais explicações sobre o assunto ou o código do que para ele escrever código, e ele tende a dar respostas muito mais sutis. Quando dou um texto longo e converso sobre ele, sinto que o Claude Opus entende o conteúdo mais profundamente; enquanto o GPT-4 fica mais na linha de resumir o texto fornecido, o Claude expande e raciocina melhor
    • Fico curioso se a comparação foi com o Claude Opus ou com uma variante inferior. O Opus me agrada muito para gerar textos em inglês
    • O GPT-4 lida melhor com prompts malformados, com pouca informação ou com estrutura bagunçada. Se você não estruturar um prompt grande de forma inteligente, o Claude pode ficar confuso sobre o que está sendo pedido
      Mas, em prompts bem construídos, o Claude Opus tende a produzir resultados melhores que o GPT-4. O Claude é mais flexível e fornece respostas mais longas, enquanto o ChatGPT/GPT-4 quase sempre soa como aquela resposta curta e “típica” característica dele
    • Minha experiência foi o oposto. Assino vários serviços e copio e colo as mesmas perguntas; em perguntas relacionadas a desenvolvimento de software, o Claude Opus está tão à frente que estou pensando que talvez eu nem precise mais usar o GPT-4
      Nos exemplos de código que eu pedia, o código gerado pelo GPT-4 muitas vezes nem compilava, enquanto com o Claude isso quase nunca aconteceu
    • Eu também assino os três serviços e comparo da mesma forma. Especialmente sempre que sai uma nova versão
      Meu teste decisivo ultimamente é: “me indique 10 bares incomuns a até 200 milhas de Austin”. Isso é extremamente difícil para todos; o GPT-4 chegou relativamente perto, mas o Claude simplesmente inventou e o Gemini desabou completamente
  • O GPT é muito legal, mas discordo fortemente da interpretação de dois parágrafos do texto
    Dá para resumir que uma abordagem melhor teria sido algo como: “GPT, você claramente conhece os 50 estados; então forneça o nome completo do estado ao qual isto se aplica ou responda Federal se se aplicar ao governo dos EUA”
    Mas acho exagerado interpretar que a qualidade e a generalização do GPT melhoram quando se fala de forma mais ambígua como um sinal típico de delegação/pensamento de alto nível. Linguagem natural é a saída mais provável para o GPT. Porque ela se parece com o texto no qual ele foi treinado. Nesse caso, o desenvolvedor apenas se apoiou mais no que o GPT faz bem; não fez ele trabalhar mais
    Há muitas tarefas simples que fazem o GPT falhar. Tarefas como substituição de letras ou erros de digitação deliberados são muito difíceis para o GPT. Mapeamento de IDs também, especialmente quando é muito diferente dos mapeamentos vistos durante o treinamento. Por exemplo, códigos de três letras parecidos, como códigos de países que não são ISO
    O interessante é o próprio fato de que o GPT “entende” o mapeamento. Para mim, isso é mais um indício real de reconhecimento de padrões de alto nível

    • Ou talvez ele esteja apenas memorizando o mapeamento. Não no sentido de reproduzi-lo exatamente, mas no de ter vetores parecidos com mapeamentos que já viu antes
  • Dica para o problema do ‘null’: LLMs são feitos para emitir tokens, não para deixar de emitir tokens
    Então, em vez de dizer “não retorne nada”, diga para “retornar o valor padrão de XYZ” quando não houver resultado e depois faça uma busca textual por esse valor padrão, por exemplo XYZ, no resultado, como se estivesse procurando o nome de um estado
    Além disso, prompts de sistema podem ser muito úteis. Basicamente, são uma chance de fazer o LLM encenar o papel X. Seria bom se fosse possível passar o prompt de sistema diretamente, mas ainda assim é melhor do que não ter nada

  • O fato de o GPT não conseguir retornar corretamente uma lista com mais de 10 objetos JSON é um problema de prompt. Eu já consegui fazê-lo retornar de forma confiável até 200 itens na ordem correta
    O truque é não usar listas de forma alguma e, na saída, usar chaves JSON como "item1": {...}. Quando há de 0 a n saídas para uma determinada entrada, é possível usar listas como valor

    • Estou dizendo que o usuário vem de uma cultura em que responder com uma lista incompleta é considerado rude e ofensivo
    • Gostaria que você pudesse explicar em mais detalhes. Estou quebrando a cabeça com esse problema agora
      Se eu der ao GPT-4 uma lista existente de itens com uma estrutura definida e pedir para convertê-la para JSON, como uma transformação de schema, ele faz isso o dia todo sem problemas. Mas, se for preciso algum tipo de inferência e ele basicamente tiver que criar a própria lista, ele só entrega um subconjunto muito limitado
      Tenho um problema parecido com outros LLMs. Estou muito curioso para saber como você aborda isso
  • Tarefas como “extraia nomes de empresas de um bloco de texto” podem ser divididas em duas etapas
    Primeiro, pergunte: “há alguma empresa mencionada neste bloco de texto?”. Se não houver, você obteve um resultado null. Se houver, então pergunte: “liste os nomes das empresas neste bloco de texto”

  • Uso modelos da OpenAI em um app pessoal de escrita, e este texto é realmente preciso. Aprendi algo relacionado à Lição 1, “quanto menos prompt, melhor”
    Ao criar uma função de busca inteligente nas minhas notas, eu tentei fazer o ChatGPT retornar dados JSON estruturados. Por exemplo, eu queria perguntar “me dê todas as minhas notas dos últimos 2 anos que mencionam Haskell e estão marcadas como rascunho” e deixar o ChatGPT decidir o que retornar. Isso só funcionava às vezes
    Em vez disso, coloquei os dados em um banco SQLite, enviei o schema ao ChatGPT e pedi para ele escrever a consulta que retorna o resultado desejado. Funcionou muito melhor

    • Isso parece ser mais adequado para um banco de dados e bons filtros de busca do que para um LLM
    • Fico curioso se você já tentou usar response_format=json_object
      Para obter respostas estruturadas, chamada de função funcionou melhor, mas tem mais restrições do que simplesmente receber um corpo JSON
  • O exemplo em que instruções precisas demais reduzem a precisão faz sentido segundo minha compreensão rudimentar de como esses sistemas funcionam
    Ao incluir a lista inteira de estados, você meio que ativa os vetores de todos os estados em certa medida. Se você apenas diz “state” e o texto enviado contém um estado explícito, menos vetores relacionados ao que se procura são ativados. Assim, ao executar o softmax, aumenta a probabilidade de o estado correto ser escolhido
    Na mesma linha, a comparação entre /n e vírgula provavelmente se deve a diferenças de tokenização