Organización de código en LangGraph para sistemas complejos de AI

Clase 11 de 26Curso para Crear Agentes de AI con LangGraph

Contenido del curso

Resumen

Escalar un sistema con múltiples nodos, prompts, RAGs y tools exige una organización clara. Aquí verás cómo refactorizar hacia una arquitectura modular en Landgraf para mejorar mantenimiento, visibilidad de la orquestación y crecimiento controlado, separando agente, estado, nodos, prompts y tools en carpetas consistentes.

¿Por qué reorganizar el código para escalar en Landgraf?

Una sola base de código en un archivo se vuelve frágil cuando crecen los nodos y las dependencias. La propuesta: convertir cada agente en una carpeta con subcarpetas por nodo y archivos específicos para estado, grafo, prompts y tools. Así:

  • Mantenibilidad: localizar y mejorar un nodo es inmediato.
  • Escalabilidad: añadir nodos no rompe la base existente.
  • Claridad: cada responsabilidad vive en su lugar: estado, grafo, nodo, prompt, tools.
  • Visibilidad: entender qué pasa con los nodos y la orquestación es más simple.

Conceptos clave integrados: agente y grafo del flujo, nodos con su propio large language model (LLM), system prompt, tools y manejo del estado del mensaje. También se menciona el uso de LangGraph UI para depurar y validar el flujo.

¿Cómo estructurar agentes, nodos y prompts para RAG?

La idea central: el agente “Support” deja de ser un archivo y pasa a ser una carpeta. Dentro, se separan el estado, el grafo y los nodos. Cada nodo tiene su propio prompt y, si aplica, sus tools.

¿Qué carpetas y archivos crear?

Estructura sugerida para “Support”:

agents/ support/ __init__.py state.py # estado del mensaje. agent.py # construcción del grafo del agente. nodos/ extractor/ __init__.py node.py # lógica del nodo extractor. prompt.py # system prompt del extractor. conversation/ __init__.py node.py # lógica del nodo conversation. prompt.py # system prompt del conversation. tools.py # tools ligadas a este nodo.

Puntos clave:

  • Cada nodo es una carpeta con su node.py, prompt.py y, si aplica, tools.py.
  • Los imports se corrigen para apuntar a paths claros: por ejemplo, al estado desde "agents.support.state".
  • Se evita crear carpetas innecesarias como “rutas” si aún no se usan.

¿Cómo separar prompts y tools por nodo?

  • Prompt por nodo: se define un archivo prompt.py por nodo con su system prompt declarado de forma explícita.
  • Tools por nodo: en conversation/tools.py se listan las tools y se exportan en un array para inyectarlas al LLM del nodo.

Ejemplo mínimo de prompt y combinación con historial del estado:

# extractor/prompt.py SYSTEM_PROMPT = """ Tú eres un asistente que ayuda a extraer información dada una conversación. """ # extractor/node.py from agents.support.state import message_state from .prompt import SYSTEM_PROMPT # history proviene del estado; se concatena al prompt del sistema. def build_messages(history): return [SYSTEM_PROMPT] + history

Notas prácticas:

  • Se usa un system prompt claro para guiar el nodo extractor.
  • La concatenación del system prompt con el history puede requerir ajustarlo a tu API de mensajes: array de uno o tupla, según el formato que uses.

¿Cómo se construye el agente con el grafo?

  • agent.py importa el estado y cada nodo ya modularizado.
  • Cada nodo declara su propio LLM: por ejemplo, conversation con OpenAI para habilitar tools.
  • Se inyectan prompts y tools en el nodo correspondiente, manteniendo la configuración aislada.

Ejemplo mínimo del nodo conversation con tools:

# conversation/tools.py # Define y exporta las tools de este nodo. tools = [ # ...instancias de tools específicas del nodo... ] # conversation/node.py from .tools import tools from .prompt import SYSTEM_PROMPT def configure_conversation_node(llm): llm_with_tools = llm.bind_tools(tools) # se inyecta el system prompt simple; la dinamización llegará después. return {"llm": llm_with_tools, "system_prompt": SYSTEM_PROMPT}

¿Qué prácticas aplicar para mantener y crecer el proyecto?

  • Un agente, una carpeta: facilita navegación y escalabilidad.
  • Estado centralizado: un state.py con el message state único.
  • Nodo autocontenido: cada nodo con su node.py, prompt.py y tools.py si aplica.
  • LLM por nodo: declarar en el nodo el large language model que usará.
  • Prompts declarativos: mantener el system prompt por archivo y por nodo.
  • Tools agrupadas: exportar un array de tools por nodo y enlazarlas al LLM.
  • Imports limpios: rutas explícitas evitan confusiones y errores.
  • Refactor incremental: trasladar estado, luego nodos, luego prompts y tools.
  • Prueba continua: validar en LangGraph UI y en el debugger que todo sigue funcionando.
  • Preparación para prompts dinámicos: dejar el system prompt simple ahora y planear la inyección de variables después.

Si te sirvió esta guía práctica de organización y refactor, cuéntame en comentarios qué nodo planeas modularizar primero y por qué.