Ir al contenido principal

🧩 Hacia un Manager de Agentes: arquitectura modular con Python, LangChain y MCP

En los últimos meses el ecosistema de agentes de IA se ha disparado: frameworks, herramientas, RAGs, memorias… y cada proyecto acaba resolviendo el mismo problema: ¿cómo organizo todas estas piezas de forma coherente?

En este artículo propongo una arquitectura modular para gestionar agentes en Python, apoyándonos en LangChain, wrappers de MCP (Model Context Protocol) y un manager común que facilite tanto a programadores como a perfiles de negocio trabajar con agentes de distinta complejidad

 
 

En este artículo vamos a profundizar en un manager de agentes escrito en Python, que organiza de forma modular los distintos elementos que necesitamos para crear y ejecutar agentes:

  • Agentes (instancias) → Son configuraciones concretas que indican qué tipo de agente se usará, con qué propiedades iniciales (ej. temperatura, límites de tokens, idioma) y qué herramientas estarán disponibles.
    Estas instancias se ejecutan siempre dentro de un contexto, que se encarga de proveer las dependencias (como memorias o RAGs) y de conectar con las herramientas seleccionadas.
    Ejemplo: un WikiAgent instanciado con temperatura=0.2 y habilitado con la tool de Wikipedia.
  • Tipos de agentes → Son las implementaciones en Python (clases que heredan de la interfaz Agent). Cada tipo define:
    • Su modelo de configuración (config_model),
    • Sus dependencias requeridas (deps_model).
    • La lógica de ejecución de instrucciones (_execute).
    Ejemplo: un tipo WikiAgent que resuelve preguntas usando LangChain y la tool de Wikipedia.
  • Utils → Son implementaciones reutilizables de dependencias, como memorias conversacionales, expansores RAG o caches locales. Se registran en el manager y se inyectan automáticamente a los agentes que las declaren como dependencia.
    Ejemplo: un MiRag que expande consultas con embeddings o una ShortTermMemory que guarda el último turno de conversación.
  • Tools → Son las herramientas que el agente puede invocar durante su ejecución. Pueden ser:
    • Tools nativas de LangChain (Wikipedia, SerpAPI, SQLDatabase, etc.).
    • Wrappers a MCP (Model Context Protocol), que exponen servicios externos como calendarios, CRMs o buscadores.
    Ejemplo: una tool Wikipedia() que hace consultas a Wikipedia en español.

⚙️ Tipos de agentes

Cada agente hereda de una clase base Agent y define su lógica en un método _execute. Son implementaciones en Python, donde los programadores podrán aplicar los patrones de razonamiento, iteración, verificación... hasta donde su imaginación llegue.

Para resolver la petición, el tipo de agente delcara declara explícitamente qué dependencias necesita:

  • Memoria
  • Expansores RAG (desde bases de datos, directorios, servicios externos...)

El agente no “elige” qué hay disponible, ni necesita configurarlo por su cuenta: simplemente declara sus requisitos, y el manager los rellenará en tiempo de ejecución.

El manager permitirá configurar uno o varios repositorios git desde los que importar tipos de agentes concretos, facilitando compartir implementaciones.

El punto de entrada siempre es un método resolve, que valida configuración, dependencias y contexto antes de ejecutar.

# wiki_agent.py
from agent import Agent
from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

class WikiAgent(Agent):
    class Config(BaseModel):
        temperature: float = Field(default=0.0, ge=0, le=1)

    @classmethod
    def config_model(cls):
        return WikiAgent.Config

    def _execute(self, instruction: str) -> str:
        llm = ChatOpenAI(
            model="gpt-4o-mini",
            temperature=self._cfg.temperature
        )
        prompt = ChatPromptTemplate.from_messages([
            ("system", "Eres un agente que usa Wikipedia para responder."),
            ("human", "{input}"),
            MessagesPlaceholder("agent_scratchpad")
        ])
        agent = create_tool_calling_agent(llm, self._tools, prompt)
        executor = AgentExecutor(agent=agent, tools=self._tools, verbose=False)
        result = executor.invoke({"input": instruction})
        return result.get("output", "")

Usan como base una clase genérica de agente, que permite definir sus dependencias y sus variables de configuración

🛠️ Útiles (utils)

Son implementaciones concretas en python de dependencias escritas en ficheros independientes. Por ejemplo:

  • Una clase RAG que expande consultas con embeddings.
  • Una ShortTermMemory que mantiene la última conversación.

Se registran en el manager como instancias Python reutilizables.

class MiRag:
    def expand(self, query: str) -> str:
        return f"RAG-contexto para: {query}"

Igual que con los tipos de agentes, el manager permitirá configurar uno o varios repositorios git desde los que importar utils concretos.

🚀 Tools

Son las herramientas que el agente puede invocar:

  • Tools nativas de LangChain (WikipediaQueryRun, SerpAPI, etc.).
  • Wrappers sobre MCP para exponer servicios externos (buscadores, calendarios, CRMs…).

Desde el punto de vista del manager todas las tools se gestionan igual, ya sean locales o remotas.

from langchain_community.utilities import WikipediaAPIWrapper
from langchain_community.tools import Tool

def Wikipedia():
    return Tool.from_function(
        name="wikipedia",
        description="Busca en Wikipedia (es) y devuelve resumen",
        func=WikipediaAPIWrapper(lang="es").run
    )

Siguen siendo ficheros python que se podrán compartir fácilmente por repositorios git. 

🧩 Agentes (instancias)

Los agentes son los elementos operativos del manager. Aquí hay un matiz importante, a diferencia de los otros elementos: los agentes en ejecución no son código Python.

  • Se definen como estructuras de propiedades de configuración: qué tipo de agente usar, qué parámetros iniciales, qué tools están habilitadas.
  • El manager toma esa configuración, prepara el contexto con utils y tools, y finalmente instancia el tipo de agente correspondiente
  • .

Esto abre la puerta a que una persona de negocio pueda derivar agentes ajustando parámetros de configuración, sin necesidad de programar nuevas clases.

Por cada agente construido tenemos un endpoint HTTP que permitirá a los usuarios comunicarse.

Flujo de trabajo

  1. El programador añade un nuevo tipo de agente (clase Python heredando de la interfaz base).
  2. El manager ya sabe listar ese tipo como disponible.
  3. El usuario de negocio crea un nuevo agente derivado ajustando propiedades en JSON/YAML/GUI.
  4. El manager valida dependencias y configura el contexto con utils y tools.
  5. El agente se ejecuta y resuelve las instrucciones recibidas.
  6. El manager registra la ejecución, los tokens consumidos, coste aproximado, e información de traza detallada.

🎯 Conclusión

  1. Los programadores amplían el ecosistema añadiendo nuevos tipos de agentes, utils y tools.
  2. Los usuarios de negocio instancian agentes ajustando configuración en JSON/GUI.
  3. Un manager de agentes valida dependencias, inyecta contexto y expone un endpoint unificado.
  4. Extensible a N8n u otros orquestadores: cada nodo puede invocar agentes ya configurados.

👉 Así conseguimos un ecosistema flexible: código modular + configuración desacoplada + interoperabilidad.

Comentarios