Ya estoy inscrito ¿Todavía no tienes acceso? Nuestros Planes
Ya estoy inscrito ¿Todavía no tienes acceso? Nuestros Planes
0
respuestas

[Proyecto] Retos del Curso

Desafíos Técnicos Resueltos y Aprendizajes Clave

Durante el desarrollo de esta clase, nos enfrentamos a varios desafíos críticos de arquitectura en sistemas multi-agente:

1. Control de Loops Infinitos en Agentes ReAct (recursion_limit)

  • Problema: Al procesar correos que requerían una respuesta compleja (como el caso de prueba de Alice consultando por endpoints de la API), el agente de respuesta entraba en un bucle infinito (loop) intentando razonar o buscar herramientas inexistentes, consumiendo cuotas de la API de Groq sin detenerse.

  • Solución: Se implementó un freno de mano de seguridad inyectando un límite de recursión en la configuración del .invoke():

    python
    
    configuracion = {"recursion_limit": 10}
    response = app.invoke({"email_input": email_input}, config=configuracion)
    

Esto garantiza que el grafo se interrumpa de forma segura si realiza más de 10 saltos entre nodos.

  1. Error de Atributo en AIMessage ('AIMessage' object has no attribute 'classification')
  • Problema: El LLM en el enrutador (llm_router.invoke) devolvía texto plano envuelto en un objeto AIMessage, rompiendo la validación condicional result.classification == "respond" ya que las propiedades personalizadas no existen de forma nativa en los mensajes de chat.

  • Solución: Implementamos salida estructurada forzada combinando un esquema de Pydantic con el método .with_structured_output() de LangChain:

Python

from pydantic import BaseModel, Field

class TriageOutput(BaseModel):
    classification: Literal["respond", "ignore", "notify"] = Field(...)

llm_router = llm_base.with_structured_output(TriageOutput)

Esto obligó al modelo Llama 3.3 a responder con un JSON estricto que Python parsea nativamente con la propiedad requerida.

  1. Actualización de Sintaxis en LangGraph (state_modifier vs prompt)
  • Problema: El constructor preconstruido de agentes create_react_agent arrojaba un TypeError al intentar pasarle las instrucciones del sistema mediante la propiedad obsoleta state_modifier.

  • Solución: Se migró la sintaxis a los estándares actuales de LangGraph, reemplazando el argumento por prompt:

Python

agent = create_react_agent(model=llm, tools=[], prompt="Sos un asistente corporativo experto...")
  1. Rehidratación de Memoria tras Reinicios de Kernel
  • Problema: Al interrumpir o reiniciar el Kernel de Jupyter para frenar los bucles infinitos, la memoria dinámica se limpiaba por completo provocando errores en cascada de tipo NameError (State is not defined, triage_router is not defined, app is not defined).

  • Solución: Se diseñó un script de inicialización acoplado y centralizado en una única celda que declara contratos de tipado, inicializa modelos, compila el grafo e inyecta los mocks de datos (email_input, profile, prompt_instructions) de un solo tirón, garantizando idempotencia en el entorno de desarrollo.

  1. Formateo y Visualización de Trazas (pretty_print)
  • Problema: El print tradicional del último mensaje ocultaba el flujo interno de LangGraph y los metadatos de las interacciones.

  • Solución: Se implementó el bucle iterativo nativo de LangChain para renderizar de manera estética el ciclo de vida del estado en la consola:

Python

for m in response["messages"]:
    m.pretty_print()

Esto permitió contrastar visualmente cómo un agente con herramientas (tools=[write_email]) genera un mensaje con metadatos de Tool Calls y Call ID, a diferencia de un agente sin herramientas integradas (tools=[]) que responde con texto plano directo en el atributo content.
P/D: El proyecto lo realice con Groq por la gran cantidad de token diarios.