LLMs + Saída Estruturada como um Serviço de Tradução

Outras línguas: English Español 日本語 한국어 中文

Em um post anterior dedicado à localização de um app com AI, discutimos sobre automatizar a tradução de strings da interface do usuário. Para essa tarefa, optei por uma ferramenta de tradução ao invés de uma LLM, baseado na seguinte justificativa:

…Eu estava planejando usar o GPT3.5 Turbo da OpenAI, mas como ele não é estritamente um modelo de tradução, ele requer esforço extra para configurar o prompt. Além disso, seus resultados tendem a ser menos estáveis, então escolhi um serviço de tradução dedicado que primeiro veio à mente…

Posteriormente naquele ano, vários provedores de LLM introduziram o recurso de saída estruturada, tornando as LLMs significativamente mais adequadas para o caso de uso discutido. Hoje, vamos dar uma olhada mais detalhada no problema e como este recurso resolve.

O problema

As LLMs são inerentemente não determinísticas, o que significa que podem produzir diferentes saídas para a mesma entrada. Esta aleatoriedade torna as LLMs “criativas”, mas também reduz a confiabilidade delas quando é necessário seguir um formato de saída específico.

Considere o caso de uso de tradução como exemplo. Uma solução ingênua seria descrever o formato requerido no prompt:

> Translate 'cat' to Dutch. ONLY GIVE A TRANSLATION AND NOTHING ELSE.

Isso funciona, embora ocasionalmente, uma LLM possa interpretar errado as instruções:

> Certainly, allow me to provide the translation for you.
The word 'cat' is translated as 'kat' in Dutch. Sometimes, female cats may also be referred to as 'poes'.

Como o aplicativo espera uma única palavra como resposta, qualquer coisa diferente de uma única palavra pode levar a erros ou dados corrompidos. Mesmo com verificações adicionais e tentativas de nova execução, tais inconsistências comprometem a confiabilidade do fluxo de trabalho.

O que é saída estruturada

A saída estruturada aborda os problemas com formatação inconsistente, permitindo que você defina um esquema para a resposta. Por exemplo, você pode solicitar uma estrutura assim:

{
  "word": "cat",
  "target_locale": "nl",
  "translation_1": "kat",
  "translation_2": "poes"
}

Por trás das cortinas, a implementação de saída estruturada pode variar entre modelos. Algumas abordagens comuns incluem:

Estes mecanismos adicionais ajudam a alcançar uma maior confiabilidade em comparação com simplesmente adicionar instruções de formato ao prompt.

Código

Vamos atualizar o script de tradução. Para começar, vamos definir o objeto que representa o esquema:

response_format={
    "type": "json_schema",
    "json_schema": {
        "name": "translation_service",
        "schema": {
            "type": "object",
            "required": [
                "word",
                "translation"
            ],
            "properties": {
                "word": {
                    "type": "string",
                    "description": "The word that needs to be translated."
                },
                "translation": {
                    "type": "string",
                    "description": "The translation of the word in the target language."
                }
            },
            "additionalProperties": False
        },
        "strict": True
    }
}

Em seguida, podemos usar o objeto do esquema na função que executa a requisição:

def translate_property_llm(value, target_lang):
    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {openai_key}',
    }
    url = 'https://api.openai.com/v1/chat/completions'
    data = {
        'model': 'gpt-4o-mini',
        'response_format': response_format,
        'messages': [
            {'role': 'system',
             'content': f'Translate "{value}" to {target_lang}. '
                        f'Only provide the translation without any additional text or explanation.'},
            {'role': 'user', 'content': value}
        ],
    }

    response = requests.post(url, headers=headers, data=json.dumps(data))
    try:
        content_json = json.loads(response.json()["choices"][0]["message"]["content"])
        return content_json["translation"]
    except (json.JSONDecodeError, KeyError) as e:
        raise ValueError(f"Failed to parse translation response: {str(e)}")

Isso é tudo para a codificação! Para mais contexto, você é bem-vindo para explorar e experimentar o projeto no repositório do GitHub.

Comparação com a abordagem anterior

O processo de tradução demorou um pouco mais para a versão atualizada em comparação com o baseado em serviço de tradução. Dito isto, o código fornecido é o exemplo de trabalho mais simples, e poderíamos torná-lo muito mais rápido fazendo as solicitações de forma assíncrona.

Em termos de despesas, a tradução para 5 locais me custou menos de 0,01$, o que é mais de 10 vezes mais barato que a versão anterior:

Painel do OpenAI mostrando um gasto de <0.01$

Percorrendo os pacotes de mensagens resultantes, não notei nada suspeito. Enquanto eu não posso ler nenhum dos novos idiomas adicionados, a formatação parece boa, e eu não encontrei ocorrências de ‘Claro, vou traduzir isso para você’🙂

Por que é importante

Embora o experimento descrito aborde um problema de nicho, ele destaca um aspecto mais amplo e significativo dos grandes modelos de linguagem. Embora eles possam ou não superar serviços especializados na resolução de uma tarefa específica, o que é realmente notável sobre LLMs é a capacidade delas de servir como uma solução rápida e prática e uma alternativa de propósito geral a ferramentas mais especializadas.

Como alguém com apenas um conhecimento básico de aprendizagem de máquina, eu costumava evitar classes inteiras de tarefas, porque mesmo uma solução medíocre exigia conhecimentos que eu não tinha. Agora, no entanto, tornou-se incrivelmente fácil juntar classificadores, serviços de tradução, LLMs como juiz, e inúmeras outras aplicações.

Claro, a qualidade ainda é uma consideração, mas realisticamente, não precisamos de 100% de perfeição para muitos problemas de qualquer maneira. Uma razão a menos para não hackear!

Conclusão

Eu não consegui pensar em uma maneira significativa de encerrar este artigo, então aqui está uma foto do gato que encontrei hoje (não gerado por IA!):

A foto de um gato aleatório
all posts ->