Olá a todos, aqui é o Marcus do ai7bot.com. Hoje é 27 de março de 2026, e eu andei lutando com algo bem específico recentemente em meus próprios projetos de bot: fazer com que os bots pareçam menos como… bem, bots. Mais como se realmente *entendessem* o que você está dizendo, mesmo quando você está sendo um pouco confuso com suas palavras. Esqueça aqueles serviços de NLU caros e sofisticados por um minuto. Estou falando de algo muito mais simples e, sinceramente, frequentemente negligenciado: correspondência difusa com Python. Especificamente, como usá-la de forma eficaz dentro de seus bots do Telegram para lidar com entradas de usuário que não são perfeitamente limpas.
Todos nós já construímos bots que esperam um comando preciso ou uma palavra-chave específica. E quando o usuário digita “pode me ajudar a configurar um novo usuário” em vez de “configurar usuário”, o bot só fica olhando em branco. Ou pior, dá uma mensagem genérica “não entendo.” Essa é uma forma rápida de frustrar os usuários e fazer seu bot parecer burro. Recentemente, passei por essa experiência de perto enquanto construía um pequeno bot de suporte interno para a startup de um amigo. Eles precisavam que ele respondesse a perguntas frequentes, mas a equipe continuava digitando variações das perguntas. “Como eu reinicio minha senha?” virou “ajuda para reiniciar senha” ou “esqueci minha senha.” Meu bot inicial estava falhando espetacularmente.
Então, hoje, quero explorar como você pode usar a biblioteca fuzzywuzzy do Python para adicionar uma camada de entendimento humano aos seus bots do Telegram sem precisar de um motor de NLU completo. Isso não é sobre aprendizado profundo ou linguística complexa; é sobre comparação de strings prática que faz uma grande diferença na experiência do usuário.
O Problema: Bots São Muito Literais
Meu primeiro bot do Telegram para essa startup era um simples manipulador de comandos. Se alguém digitasse `/faq`, ele listaria as FAQs. Se digitassem `/support`, ele linkaria para a página de suporte. Para perguntas específicas, eu tinha manipuladores como este:
@bot.message_handler(func=lambda message: message.text and "reiniciar senha" in message.text.lower())
def handle_reset_password(message):
bot.reply_to(message, "Para reiniciar sua senha, visite nosso portal em example.com/reset.")
Parece bom, certo? Exceto que, como mencionei, os usuários não digitam sempre “reiniciar senha.” Eles digitam “preciso reiniciar minha senha”, “esqueci minha senha”, “ajuda com senha”, “como eu obtenho uma nova senha?” Meu bot, coitado, só captava a frase exata. Era um pesadelo de usabilidade. Meu amigo me ligou, um pouco irritado, dizendo: “Marcus, seu bot só entende robôs, não humanos!” Ele tinha um ponto.
Essa correspondência estritamente literal é um erro comum. Nós, como desenvolvedores, muitas vezes projetamos para a entrada ideal, mas os usuários raramente fornecem isso. Eles digitam de forma conversacional, cometem erros de digitação, usam sinônimos. E nossos bots precisam estar prontos para isso.
Entra a Correspondência Difusa com fuzzywuzzy
É aí que entram bibliotecas como fuzzywuzzy. É uma biblioteca Python que implementa cálculos de distância de Levenshtein, que basicamente mede quantas mudanças você precisa fazer em uma string para obter outra. Quanto menor o número, mais semelhantes elas são. fuzzywuzzy então lhe dá uma pontuação de 0 a 100.
Pense assim: “maçã” e “maça” são muito próximas. “maçã” e “banana” não são. fuzzywuzzy pode lhe dizer *quão* próximas.
Primeiro, você precisará instalá-la:
pip install fuzzywuzzy python-Levenshtein
Você precisa de python-Levenshtein para melhor desempenho, pois fuzzywuzzy o utiliza se disponível.
Conceitos Básicos de Correspondência Difusa
Existem algumas funções principais que você usará do fuzzywuzzy.fuzz:
fuzz.ratio(string1, string2): Calcula uma razão simples de semelhança.fuzz.partial_ratio(string1, string2): Útil quando uma string é muito mais longa que a outra, mas contém uma substring semelhante. Por exemplo, “reiniciar senha” e “esqueci minha senha, pode me ajudar a reiniciar?”fuzz.token_sort_ratio(string1, string2): Ordena as palavras em ambas as strings alfabeticamente antes de comparar. Isso ajuda com palavras reordenadas, como “reiniciar senha” vs. “senha reiniciar.”fuzz.token_set_ratio(string1, string2): Semelhante aotoken_sort_ratio, mas lida melhor com palavras duplicadas e comuns. Muitas vezes a melhor escolha para entrada conversacional.
Vamos dar uma olhada em alguns exemplos rápidos no interpretador Python:
from fuzzywuzzy import fuzz
# Razão simples
print(fuzz.ratio("reiniciar senha", "senha reiniciar")) # Saída: 95
print(fuzz.ratio("reiniciar senha", "reiniciar senh")) # Saída: 94
print(fuzz.ratio("reiniciar senha", "esqueci senha")) # Saída: 62
# Razão parcial (ótima para frases mais longas)
print(fuzz.partial_ratio("Preciso reiniciar minha senha", "reiniciar senha")) # Saída: 100
# Razão de ordenação de tokens (lida com ordem das palavras)
print(fuzz.token_sort_ratio("reiniciar senha", "senha reiniciar")) # Saída: 100
# Razão de conjunto de tokens (geralmente a melhor para entrada conversacional)
print(fuzz.token_set_ratio("Como eu reinicio minha senha?", "ajuda para reiniciar senha")) # Saída: 90
print(fuzz.token_set_ratio("Onde está a FAQ?", "link da FAQ")) # Saída: 67
Note como token_sort_ratio e token_set_ratio dão pontuações mais altas quando as palavras estão reordenadas ou quando uma frase é um subconjunto da outra, que é exatamente o que precisamos para a entrada do usuário.
Integrando Correspondência Difusa em um Bot do Telegram
Agora, vamos ser práticos. Como colocamos isso em nosso bot do Telegram? A ideia é definir uma lista de frases “canônicas” ou esperadas para cada ação. Então, quando um usuário envia uma mensagem, nós a comparamos com todas essas frases canônicas e escolhemos a que tem a maior pontuação de semelhança, se estiver acima de um determinado limite.
Aqui está um exemplo simplificado usando a biblioteca python-telegram-bot (embora o conceito se aplique a qualquer estrutura de bot do Telegram).
Passo 1: Defina Seu Mapa de Intenções
Em vez de codificar “reiniciar senha” em um manipulador de mensagens, vamos criar um dicionário que mapeia uma “intenção” (o que o usuário quer fazer) a uma lista de frases que a desencadeiam.
INTENT_PHRASES = {
"reiniciar_senha": [
"reiniciar senha",
"esqueci minha senha",
"como reiniciar senha",
"trocar senha",
"obter nova senha"
],
"contatar_suporte": [
"contatar suporte",
"falar com humano",
"preciso de ajuda",
"equipe de suporte",
"problema técnico"
],
"ver_faq": [
"faq",
"perguntas frequentes",
"perguntas comuns",
"fazer uma pergunta"
]
}
# Mapeando intenções para funções manipuladoras
INTENT_HANDLERS = {} # Vamos preencher isso depois
Passo 2: Crie uma Função de Correspondência Difusa
Essa função receberá a mensagem do usuário e retornará a melhor intenção correspondente e sua pontuação.
from fuzzywuzzy import fuzz
from fuzzywuzzy import process
def get_best_intent(user_message, intent_map, threshold=70):
best_match_intent = None
best_score = 0
# Coletar todas as possíveis frases do mapa de intenções
all_phrases = []
for intent, phrases in intent_map.items():
for phrase in phrases:
all_phrases.append((phrase.lower(), intent)) # Armazena frase e sua intenção
# Use process.extractOne para eficiência
# Isso retorna (best_match_phrase, score, index_in_choices_list)
# Vamos adaptá-lo um pouco, pois precisamos mapear de volta para nossas intenções
# Vamos iterar manualmente para clareza, ou usar process.extract com um scorer personalizado
# Para simplicidade, criaremos uma lista plana de todas as frases “desencadeadoras”
# e depois mapeamos de volta para a intenção.
flat_trigger_phrases = [phrase for sublist in intent_map.values() for phrase in sublist]
# process.extractOne retorna (match_string, score)
# Isso compara a user_message com nossa lista plana de frases desencadeadoras
best_phrase_match, score = process.extractOne(
user_message.lower(),
flat_trigger_phrases,
scorer=fuzz.token_set_ratio # Muitas vezes o melhor para entrada geral
)
if score >= threshold:
# Agora, descubra a que intenção pertence essa best_phrase_match
for intent_name, phrases_list in intent_map.items():
if best_phrase_match in [p.lower() for p in phrases_list]:
best_match_intent = intent_name
best_score = score
break # Encontrou a intenção, sem necessidade de verificar outras frases
return best_match_intent, best_score
Uma rápida nota sobre process.extractOne: ele é projetado para encontrar a melhor correspondência para uma string dentro de uma lista de opções. É mais eficiente do que percorrer tudo manualmente. Meu exemplo acima mostra como usá-lo criando uma lista plana de todas as frases desencadeadoras e depois mapeando a melhor correspondência de volta para sua intenção original.
Passo 3: Implemente o Manipulador de Mensagens do Bot
Agora, modifique o manipulador de mensagens principal do seu bot para usar essa lógica.
import telebot # Supondo pyTelegramBotAPI
# from telegram.ext import Updater, MessageHandler, Filters # Se usando python-telegram-bot
# Inicialize seu bot (substitua pelo seu token real)
bot = telebot.TeleBot("YOUR_TELEGRAM_BOT_TOKEN")
# Defina manipuladores para cada intenção
def handle_reset_password_intent(message):
bot.reply_to(message, "Sem problemas! Para redefinir sua senha, por favor, visite nosso portal seguro em example.com/reset. Se precisar de mais assistência, entre em contato com o suporte de TI.")
def handle_contact_support_intent(message):
bot.reply_to(message, "Entendo que você precisa falar com alguém. Você pode entrar em contato com nossa equipe de suporte pelo e-mail [email protected] ou nos ligar no 1-800-BOT-HELP durante o horário comercial.")
def handle_view_faq_intent(message):
bot.reply_to(message, "Claro, aqui estão nossas Perguntas Frequentes: example.com/faq. Me avise se você tiver uma pergunta específica!")
# Preencha o mapa INTENT_HANDLERS
INTENT_HANDLERS = {
"reset_password": handle_reset_password_intent,
"contact_support": handle_contact_support_intent,
"view_faq": handle_view_faq_intent
}
@bot.message_handler(func=lambda message: True) # Captura todas as mensagens
def handle_all_messages(message):
user_text = message.text
if not user_text:
return
best_intent, score = get_best_intent(user_text, INTENT_PHRASES, threshold=75) # Ajuste o limite conforme necessário
if best_intent and best_intent in INTENT_HANDLERS:
INTENT_HANDLERS[best_intent](message)
else:
bot.reply_to(message, "Não tenho certeza se entendi isso. Você pode tentar reformular ou fazer uma pergunta diferente? Você também pode digitar 'ajuda' para opções.")
bot.polling()
O que está acontecendo aqui? Quando um usuário envia uma mensagem, nossa função handle_all_messages a intercepta. Em seguida, ela passa o texto da mensagem para get_best_intent. Se uma intenção adequada for encontrada (pontuação acima de 75 neste caso), a função manipuladora correspondente é chamada. Caso contrário, o bot fornece uma mensagem de retorno educada.
Defini o limite para 75 após algumas experiências. Se estiver muito baixo, o bot pode interpretar mal com frequência. Se estiver muito alto, ele se torna rígido novamente. Este é um valor que você deve ajustar para seu bot específico e seus usuários.
Um Cenário Prático: O Comando “Ajuda”
Digamos que um usuário digite “Eu preciso de ajuda, por favor.”
user_message: “Eu preciso de ajuda, por favor.”get_best_intentverifica contraINTENT_PHRASES.- Ele encontra “preciso de ajuda” em
contact_support, efuzz.token_set_ratio("Eu preciso de ajuda, por favor", "preciso de ajuda")pode gerar uma pontuação de, digamos, 85. - Como 85 > 75 (nosso limite), a intenção
"contact_support"é retornada. - O bot então chama
handle_contact_support_intent(message).
Essa é uma maneira muito mais flexível de lidar com variações do que por meio de correspondência de string estrita.
Considerações e Ajustes Avançados
Ajuste de Limite
Isso é crucial. Um limite de 70-80 é frequentemente um bom ponto de partida para token_set_ratio. Teste extensivamente com entradas reais de usuários ou variações simuladas para encontrar o ponto ideal. Se estiver muito baixo, você terá falsos positivos; se estiver muito alto, perderá o benefício da correspondência confusa.
Tratamento de Várias Possíveis Correspondências
E se duas intenções tiverem pontuações semelhantes? Por exemplo, “redefinir senha” e “esqueci a senha” estão próximas. Você pode querer introduzir um mecanismo de desempate ou, para pontuações muito próximas, pedir ao usuário para esclarecer:
"Você quis dizer redefinir sua senha ou entrar em contato com o suporte?"
fuzzywuzzy.process.extract (sem o “One”) pode retornar uma lista das N principais correspondências, o que pode ser útil aqui.
Pré-processamento da Entrada do Usuário
Antes da correspondência confusa, considere um pré-processamento básico:
- Converter para minúsculas:
user_message.lower()(já fazendo isso nos exemplos). - Remover pontuação: Use
str.translateestring.punctuation. - Remover palavras comuns (por exemplo, “a”, “o”, “é”) se não tiverem significado para suas intenções. Tenha cuidado com isso, pois às vezes as palavras paradas são importantes para o contexto.
Combinando com Correspondências Exatas
Para comandos críticos, você ainda pode querer uma verificação de correspondência exata primeiro. Por exemplo, se um usuário digitar `/admin`, você quer tratar isso de forma precisa antes que a correspondência confusa tente conectá-la a “adicionar novo usuário” por causa de “admi”.
Desempenho
Para bots com um número muito grande de intenções ou frases de ativação, chamar repetidamente funções de correspondência confusa pode ficar lento. No entanto, para a maioria dos bots pequenos a médios (centenas de frases), fuzzywuzzy com python-Levenshtein geralmente é rápido o suficiente. Se você encontrar gargalos de desempenho, pode procurar soluções de NLU mais avançadas ou pré-indexar suas frases.
Principais Lições Práticas
- Não confie apenas na correspondência exata de strings: Os usuários são confusos. Seu bot precisa ser tolerante.
- Use
fuzzywuzzy(ou bibliotecas semelhantes): É uma maneira rápida e eficaz de adicionar uma camada de “compreensão” ao seu bot sem ser um NLU completo. - Priorize
fuzz.token_set_ratio: Para entradas conversacionais, geralmente é a escolha mais flexível, pois lida bem com a ordem das palavras e subconjuntos. - Defina frases “canônicas” claras: Mesmo com correspondência confusa, fornecer ao seu bot bons exemplos do que procurar é vital.
- Ajuste seu limite: Experimente com o limite da pontuação de similaridade (por exemplo, 70-85) para encontrar o equilíbrio certo para a tolerância do seu bot em relação à ambiguidade.
- Implemente um retorno gracioso: Sempre tenha uma mensagem de “não entendi” que guie o usuário sobre o que fazer a seguir.
Adicionar correspondência confusa ao bot de suporte do meu amigo fez uma grande diferença. As reclamações “Marcus, seu bot só entende robôs!” pararam, e o bot realmente se tornou uma ferramenta útil para a equipe deles. É uma técnica relativamente simples, mas seu impacto na experiência do usuário é enorme. Experimente em seu próximo projeto de bot do Telegram e me conte como foi nos comentários!
🕒 Published: