“`html
LangChain • boas práticas
Erros comuns em LangChain que você deve evitar
Se você já perdeu horas depurando fluxos “quase corretos”, este post é para você.
Aqui eu aponto os deslizes mais frequentes ao montar cadeias, integrá-las ao seu projeto e colocar validação
onde ela realmente importa.
1 Confundir entrada/saída (input keys) e deixar o contrato “implícito”
Um dos maiores causadores de falhas é tratar o formato de dados como se fosse “óbvio”.
Em LangChain, pequenas diferenças entre input_keys, nomes de variáveis, e o que a cadeia realmente entrega
viram erros silenciosos, resultados vazios ou composição quebrada.
O padrão que eu sigo: contrato explícito.
Defino claramente quais campos entram e quais saem, e garanto validação antes/depois.
- Montar a cadeia esperando uma chave (“question”, “query”, “text”) e mandar outra.
- Reutilizar componentes com formatos diferentes sem normalizar dados.
- Ignorar o retorno real (ex.: acessar uma chave que não existe) e seguir adiante.
- Padronize as chaves de entrada do seu fluxo (por exemplo:
{question}). - Defina uma função de “normalização” antes de chamar qualquer etapa.
- Valide o resultado com checks simples e erros descritivos (não “falhe depois”).
2 Esquecer de controlar contexto: prompt longo demais, memória errada e ausência de limites
Quando você não impõe limites, o seu fluxo tende a degradar: respostas inconsistentes,
maior custo, e lentidão.
“Funciona no teste” vira um problema clássico quando as entradas crescem ou quando o histórico
começa a poluir o contexto.
- Prompt inflado: repetir instruções, anexar dados desnecessários e não “compactar” antes de montar o texto final.
- Histórico sem política: deixar o histórico crescer indefinidamente ou misturar conversas de domínios diferentes.
- Ausência de janela: não escolher uma estratégia de recorte (últimos N turnos, sumarização controlada, ou tags).
trate o contexto como um recurso finito. Eu sempre defino limites por etapa (tamanho máximo, número de itens,
e regras de recorte) para manter previsibilidade.
3 Misturar responsabilidades: usar “prompt + regras” para tudo e ignorar validação e parsing
Outro erro recorrente é depender totalmente do texto para manter consistência.
Você monta uma frase, adiciona “por favor responda em formato JSON”, e assume que isso sempre será respeitado.
Em produção, você precisa de validação e parsing tolerante.
O que costuma dar errado:
- Você não separa “construção de entrada” de “interpretação de saída”.
- Não existe validação do schema esperado (mesmo que seja simples).
- O código falha com mensagens genéricas quando o formato sai do esperado.
sempre que você exigir um formato estruturado, faça o parsing em uma camada dedicada e trate erros
com mensagens claras (e fallback quando fizer sentido).
import json
def parse_structured_answer(raw: str) -> dict:
"""
Converte uma resposta textual em um objeto validado.
Exemplo: esperar campos 'intent' e 'confidence'.
"""
try:
data = json.loads(raw)
except json.JSONDecodeError as e:
raise ValueError(f"Resposta não é JSON válido: {e}. Conteúdo: {raw[:200]!r}")
# Validação mínima de schema
if not isinstance(data, dict):
raise ValueError("Resposta deve ser um objeto (dict).")
required = ["intent", "confidence"]
missing = [k for k in required if k not in data]
if missing:
raise ValueError(f"Campos ausentes na resposta: {missing}. Recebido: {list(data.keys())}")
if not isinstance(data["intent"], str) or not data["intent"].strip():
raise ValueError("Campo 'intent' inválido.")
if not isinstance(data["confidence"], (int, float)):
raise ValueError("Campo 'confidence' deve ser numérico.")
return data
# Uso:
# raw_answer = chain.invoke({"question": "..."})
# parsed = parse_structured_answer(raw_answer["output"])
# ...
4 Não instrumentar e não separar testes de execução: debug sem rastreio vira tentativa e erro
Quando algo quebra numa cadeia, você precisa enxergar:
o que entrou, em qual etapa,
o que saiu, e em que formato.
Sem rastreio, você fica dependente de “print” e vai perdendo velocidade.
- Executar tudo em linha: sem isolar etapas para teste unitário.
- Sem logs estruturados: não registra inputs/outputs (com cuidado para não vazar dados sensíveis).
- Sem métricas: sem medir tempo por etapa e taxas de falha (parse, validação, busca, etc.).
- Não reproduzir cenários: o teste não cobre inputs reais que quebram em produção.
- Testes unitários por componente (normalização, parsing, montagem de prompt, roteamento).
- Testes de integração com amostras reais (edge cases incluídos).
- Logs por etapa com IDs de correlação (ex.:
request_id). - Mensagens de erro que indiquem exatamente a causa (chave faltando, schema inválido, input vazio).
Quer deixar seu projeto ainda mais sólido?
Depois de evitar esses erros, você vai sentir o ganho de previsibilidade imediatamente.
Agora eu recomendo que você continue com outros conteúdos aqui no yurideveloper.com.
Se quiser, me diga seu caso (stack, tipo de fluxo e onde você sente mais instabilidade) que eu sugiro um caminho de refatoração.
“`
Sou Apaixonado pela programação e estou trilhando o caminho de ter cada diz mais conhecimento e trazer toda minha experiência vinda do Design para a programação resultando em layouts incríveis e idéias inovadoras! Conecte-se Comigo!