#Herramientas

0 Seguidores · 48 Publicaciones

Una herramienta de programación o para el desarrollo de software es un programa informático que utilizan los desarrolladores de software para crear, depurar, mantener o dar soporte a otros programas y aplicaciones.

Artículo Ricardo Paiva · sep 15, 2025 3m read

Algo que he aprendido a lo largo de los años es que, por muy pulida que esté vuestra lógica de aplicación, el rendimiento de la base de datos acabará haciendo o deshaciendo la experiencia de usuario. Trabajando con InterSystems IRIS, recientemente me topé con esto de primera mano. Un cliente nuestro estaba construyendo un panel de informes que funcionaba a la perfección en las pruebas, pero cuando el conjunto de datos de producción creció hasta millones de registros, los tiempos de respuesta se arrastraban.

0
0 30
Artículo Jose-Tomas Salvador · sep 11, 2025 1m read

Una ventaja de usar Doxygenerate es que Doxygen hace más que generar salida en HTML. Ajustad el Doxyfile que le indica a Doxygen qué hacer y podréis crear fácilmente un PDF. Nuestro ejemplo de la aplicación MARINA produjo un PDF de 524 páginas. Así se ve la página 94:

0
0 27
Artículo Alberto Fuentes · sep 1, 2025 7m read

Las preguntas de atención al cliente pueden abarcar datos estructurados (pedidos, productos 🗃️), conocimiento no estructurado (docs/FAQs 📚) y otros sistemas integrados (actualizaciones de envío 🚚). En este post vamos a construir un agente de IA compacto que cubre los tres—usando:

  • 🧠 Python + smolagents para orquestar el “cerebro” del agente
  • 🧰 InterSystems IRIS para SQL, Búsqueda Semántica (RAG) e Interoperabilidad (una API de seguimiento de envío simulada)

⚡ TL;DR (versión express)

  • Construye un Agente de Atención al Cliente funcional con Python + smolagents orquestando herramientas sobre InterSystems IRIS (SQL, Búsqueda Semántica/RAG, Interoperabilidad con una API simulada).
  • Responde preguntas reales (p. ej., “¿Se entregó el pedido #1001?”“¿Cuál es el plazo de devolución?”) combinando tablas, documentos y llamadas de interoperabilidad.
  • Inicia IRIS en Docker, carga el esquema y datos de ejemplo, prepara los embeddings de los documentos para RAG, registra herramientas (SQL/RAG/API) y ejecuta el agente por línea de comando o interfaz gráfica.

image


🧭 Lo que vas a construir

Un Agente de Atención al Cliente capaz de:

  • 🔎 Consultar datos estructurados (clientes, pedidos, productos, envíos) vía SQL
  • 📚 Recuperar conocimiento no estructurado (FAQs y documentos) con RAG sobre IRIS Vector Search (Búsqueda Vectorial)
  • 🔌 Llamar a una API de seguimiento envío (simulada) mediante el framework de Interoperabilidad de IRIS, con Visual Trace para inspeccionar cada llamada

Arquitectura (resumida)

Usuario ➜ Agente (smolagents CodeAgent)
               ├─ Herramienta SQL ➜ Tablas en IRIS
               ├─ Herramienta RAG ➜ Búsqueda Vectorial en IRIS (embeddings + chunks)
               └─ Herramienta Seguimiento Envío ➜ Interoperabilidad IRIS (simulada) ➜ Visual Trace

¿Conoces smolagents? Es un framework ligero de agentes de Hugging Face en el que el modelo planifica y utiliza tus herramientas; como alternativas, puedes considerar LangGraph y LlamaIndex.


🧱 Prerrequisitos

  • 🐍 Python 3.9+
  • 🐳 Docker para ejecutar IRIS en un contenedor
  • 🧑‍💻 VS Code para revisar el código
  • 🔑 Clave de API de OpenAI (para el LLM y los embeddings) — o ejecútalo localmente con Ollama si lo prefieres

1) 🧩 Clona el repositorio y prepara un entorno Python

git clone https://github.com/intersystems-ib/customer-support-agent-demo
cd customer-support-agent-demo

python -m venv .venv
# macOS/Linux
source .venv/bin/activate
# Windows (PowerShell)
# .venv\Scripts\Activate.ps1

pip install -r requirements.txt
cp .env.example .env   # añade tu clave de OpenAI

2) 🐳 Arranca InterSystems IRIS (Docker)

docker compose build
docker compose up -d

Abre el Management Portal (http://localhost:52773 en esta demo).


3) 🗃️ Carga los datos estructurados (SQL)

Desde el SQL Explorer de IRIS o tu cliente SQL favorito:

LOAD SQL FROM FILE '/app/iris/sql/schema.sql' DIALECT 'IRIS' DELIMITER ';';
LOAD SQL FROM FILE '/app/iris/sql/load_data.sql' DIALECT 'IRIS' DELIMITER ';';

Este es el esquema que acabas de cargar: image

Ejecuta algunas consultas para familiarizarte con los datos. El agente usará estas tablas para resolver preguntas:

-- Listado de clientes
SELECT * FROM Agent_Data.Customers;

-- Pedidos de un cliente
SELECT o.OrderID, o.OrderDate, o.Status, p.Name AS Product
FROM Agent_Data.Orders o
JOIN Agent_Data.Products p ON o.ProductID = p.ProductID
WHERE o.CustomerID = 1;

-- Info de envío de un pedido
SELECT * FROM Agent_Data.Shipments WHERE OrderID = 1001;

✅ Si ves filas, tu parte estructurada está lista.


4) 📚 Añade conocimiento no estructurado con Vector Search (RAG)

Crea una configuración de embeddings (el ejemplo usa un modelo de OpenAI; ajústalo a tu gusto):

INSERT INTO %Embedding.Config
  (Name, Configuration, EmbeddingClass, VectorLength, Description)
VALUES
  ('my-openai-config',
   '{"apiKey":"YOUR_OPENAI_KEY","sslConfig":"llm_ssl","modelName":"text-embedding-3-small"}',
   '%Embedding.OpenAI',
   1536,
   'a small embedding model provided by OpenAI');

¿Quieres los pasos y opciones exactos? Consulta la documentación

Después, genera los embeddings del contenido de ejemplo:

python scripts/embed_sql.py

Comprueba que los embeddings están en las tablas:

SELECT COUNT(*) AS ProductChunks FROM Agent_Data.Products;
SELECT COUNT(*) AS DocChunks     FROM Agent_Data.DocChunks;

🔎 Bonus: Búsqueda híbrida + vectorial directamente desde SQL con EMBEDDING()

Una gran ventaja de IRIS es que puedes hacer búsqueda semántica (vectorial) dentro de SQL y mezclarla con filtros clásicos—sin microservicios extra. La función EMBEDDING() de SQL crea al vuelo el vector de tu texto de búsqueda y puedes compararlo con vectores almacenados usando operaciones como VECTOR_DOT_PRODUCT.

Ejemplo A — Búsqueda híbrida de productos (filtro por precio + ranking semántico):

SELECT TOP 3
    p.ProductID,
    p.Name,
    p.Category,
    p.Price,
    VECTOR_DOT_PRODUCT(p.Embedding, EMBEDDING('headphones with ANC', 'my-openai-config')) score
FROM Agent_Data.Products p
WHERE p.Price < 200
ORDER BY score DESC

Ejemplo B — Búsqueda semántica de fragmentos de documentos (ideal para alimentar RAG):

SELECT TOP 3
    c.ChunkID  AS chunk_id,
    c.DocID      AS doc_id,
    c.Title         AS title,
    SUBSTRING(c.ChunkText, 1, 400) AS snippet,
    VECTOR_DOT_PRODUCT(c.Embedding, EMBEDDING('warranty coverage', 'my-openai-config')) AS score
FROM Agent_Data.DocChunks c
ORDER BY score DESC

¿Por qué es potente? Puedes pre-filtrar por precio, categoría, idioma, tenant, fechas, etc., y luego ordenar por similitud semántica—todo en una sola sentencia SQL.


5) 🔌 Conecta una API de envíos (mock) con Interoperability

El proyecto expone un pequeño endpoint /api/shipping/status a través de la Interoperabilidad de IRIS — perfecto para simular llamadas “del mundo real”:

curl -H "Content-Type: application/json" \
  -X POST \
  -d '{"orderStatus":"Processing","trackingNumber":"DHL7788"}' \
  http://localhost:52773/api/shipping/status

Ahora abre Visual Trace en el Portal para ver el flujo de mensajes paso a paso (como el radar de un aeropuerto ✈️).


6) 🤖 Conoce al agente (smolagents + tools)

Echa un vistazo a estos archivos:

  • agent/customer_support_agent.py — inicia un CodeAgent y registra las herramientas
  • agent/tools/sql_tool.py — utilidades SQL parametrizadas
  • agent/tools/rag_tool.py — búsqueda vectorial + recuperación de documentos
  • agent/tools/shipping_tool.py — llamadas al endpoint de Interoperability

El CodeAgent planifica qué pasos dar y genera código que llama a tus herramientas. Tú pones las herramientas; él pone el cerebro con un modelo LLM.


7) ▶️ Ejecútalo

Modo one-shot (pruebas rápidas)

python -m cli.run --email alice@example.com --message "Where is my order #1001?"
python -m cli.run --email alice@example.com --message "Show electronics that are good for travel"
python -m cli.run --email alice@example.com --message "Was my headphones order delivered, and what’s the return window?"

CLI interactivo

python -m cli.run --email alice@example.com

Web UI (Gradio)

python -m ui.gradio
# open http://localhost:7860

🛠️ ¿Cómo funciona?

Flujo del agente (simplificado):

  1. 🧭 Planifica cómo resolver la pregunta y qué herramientas usar: p. ej., “comprobar estado del pedido → buscar política de devoluciones”.

  2. 🛤️ Llama a las herramientas según se necesite

    • 🗃️ SQL para clientes/pedidos/productos
    • 📚 RAG sobre embeddings para FAQs/docs (recuerda que puedes prototipar RAG directamente en SQL con EMBEDDING() + operaciones vectoriales como arriba)
    • 🔌 Interoperability API para estado de envíos
  3. 🧩 Sintetiza: compone una respuesta clara y precisa.

Añade o cambia herramientas según crezca tu caso de uso: promociones, garantías, inventario, etc.


🎁 Resumen

Ya tienes un Agente de Atención al Cliente compacto que combina:

  • 🧠 Razonamiento LLM (smolagents CodeAgent)
  • 🗃️ Datos estructurados (IRIS SQL)
  • 📚 Conocimiento no estructurado (IRIS Vector Search + RAG) — con el plus de que EMBEDDING() te permite búsqueda híbrida + vectorial directamente desde SQL
  • 🔌 Llamadas a sistemas en vivo (IRIS Interoperability + Visual Trace)
1
1 60
Artículo Yuri Marx · jul 28, 2025 8m read

Los documentos de Word se utilizan ampliamente en el mercado. Los usuarios crean con frecuencia contratos, memorandos, currículums, informes, análisis y otros documentos que pueden requerir datos de InterSystems IRIS o que este los capture. Sin embargo, IRIS no dispone de una API, SDK, biblioteca ni adaptador para ello. Esta limitación ya no existe.

La nueva biblioteca de Open Exchange, iris4word (https://openexchange.intersystems.com/package/iris4word), ofrece un SDK de ObjectScript donde el desarrollador pasa cualquier %DynamicObject como parámetro, una plantilla de archivo de Word y recibe un documento listo para usar, con la estructura y el formato definidos en su plantilla.


0
0 23
Artículo Kurro Lopez · jun 30, 2025 16m read

Aprenda a diseñar agentes de IA escalables y autónomos que combinen razonamiento, búsqueda vectorial e integración de herramientas utilizando LangGraph.

cover

Demasiado Largo; No lo Leí

  • Los agentes de IA son sistemas proactivos que combinan memoria, contexto e iniciativa para automatizar tareas que van más allá de los chatbots tradicionales.
  • LangGraph es un framework que nos permite crear flujos de trabajo complejos de IA, utilizando nodos (tareas) y aristas (conexiones) con gestión de estado integrada.
  • Esta guía te guiará en la creación de un agente de atención al cliente basado en IA que clasifica prioridades, identifica temas relevantes y determina si escalar o responder automáticamente.

Entonces, ¿Qué son Exactamente los Agentes de Inteligencia Artificial?

Seamos realistas: los "agentes de IA" pueden parecer los robots que tomarán el control de su sala de juntas. En realidad, son sus aliados proactivos que pueden optimizar flujos de trabajo complejos y eliminar tareas repetitivas. Piense en ellos como el siguiente paso evolutivo más allá de los chatbots: no se limitan a esperar indicaciones; inician acciones, coordinan múltiples pasos y se adaptan sobre la marcha.

Antes, crear un sistema "inteligente" significaba hacer malabarismos con distintos modelos para la comprensión del lenguaje, la generación de código, la búsqueda de datos, etc., y luego unirlos con cinta adhesiva. La mitad del tiempo se perdía en el infierno de la integración, mientras que la otra mitad se dedicaba a depurar el pegamento.

Los agentes dan la vuelta al guión. Combinan contexto, iniciativa y adaptabilidad en un único flujo orquestado. No se trata sólo de automatización, sino de inteligencia con una misión. Y gracias a marcos de trabajo como LangGraph, crear tu propio equipo de agentes puede ser... ¿me atrevería a decir que divertido?

image

¿Qué es LangGraph, Exactamente?

LangGraph es un framework innovador que revoluciona la forma de crear aplicaciones complejas con grandes modelos lingüísticos (LLM).

Imagina que diriges una orquesta: cada instrumento (o "nodo") necesita saber cuándo tocar, con qué volumen y en qué secuencia. LangGraph, en este caso**,** es tu batuta, dándote lo siguiente:

  • Estructura gráfica: Emplea una estructura de tipo gráfico con nodos y aristas, lo que permite a los desarrolladores diseñar flujos de trabajo flexibles y no lineales que admiten ramas y bucles. Refleja procesos complejos de toma de decisiones que se asemejan al funcionamiento de las vías neuronales.
  • Gestión de estados: LangGraph ofrece herramientas integradas para la persistencia del estado y la recuperación de errores, lo que simplifica el mantenimiento de los datos contextuales a través de diversas etapas dentro de una aplicación. Puede alternar eficazmente entre la memoria a corto y a largo plazo, mejorando la calidad de la interacción gracias a herramientas como Zep.
  • Integración de herramientas: Con LangGraph, los agentes LLM pueden colaborar fácilmente con servicios externos o bases de datos para obtener datos del mundo real, mejorando la funcionalidad y capacidad de respuesta de sus aplicaciones.
  • Human-in-the-Loop: Más allá de la automatización, LangGraph da cabida a las intervenciones humanas en los flujos de trabajo, que son cruciales para los procesos de toma de decisiones que requieren supervisión analítica o consideración ética.

Tanto si está construyendo un chatbot con memoria real, un motor de historias interactivo o un equipo de agentes que abordan un problema complejo, LangGraph convierte la fontanería que provoca dolores de cabeza en una máquina de estados limpia y visual.

Primeros Pasos

Para empezar con LangGraph, necesitarás una configuración básica que normalmente implica la instalación de bibliotecas esenciales como langgraph y langchain-openai. A partir de ahí, puedes definir los nodos (tareas) y las aristas (conexiones) dentro del grafo, implementando de forma efectiva puntos de control para la memoria a corto plazo y utilizando Zep para necesidades de memoria más persistentes.

Cuando utilices LangGraph, ten en cuenta lo siguiente:

  • Diseñar con flexibilidad: Aproveche la potente estructura gráfica para tener en cuenta las posibles ramificaciones e interacciones del flujo de trabajo que no sean estrictamente lineales.
  • Interactuar con herramientas cuidadosamente: Mejore, pero no sustituya, las capacidades de LLM con herramientas externas. Proporcione a cada herramienta descripciones completas para permitir un uso preciso.
  • Emplear soluciones de memoria enriquecida: Utilice la memoria de forma eficiente, tenga en cuenta la ventana de contexto del LLM y considere la posibilidad de integrar soluciones externas para la gestión automática de hechos.

Ahora que hemos cubierto los fundamentos de LangGraph, vamos a sumergirnos en un ejemplo práctico. Para ello, desarrollaremos un agente de IA diseñado específicamente para la atención al cliente.

Este agente recibirá solicitudes por correo electrónico, analizará la descripción del problema en el cuerpo del mensaje y determinará la prioridad de la solicitud y el tema/categoría/sector apropiado.

Así que abróchense los cinturones y ¡adelante!

buckle up

Para empezar, tenemos que definir qué es una "Herramienta" (Tool). Puedes pensar en ella como un "gestor asistente" especializado para tu agente, que le permite interactuar con funcionalidades externas.

El decorador @tool es esencial aquí. LangChain simplifica la creación de herramientas personalizadas, lo que significa que primero se define una función de Python y luego se aplica el decorador @tool.

tools

Ilustremos esto creando nuestra primera herramienta. Esta herramienta ayudará al agente a clasificar la prioridad de un ticket de soporte de TI basándose en su contenido de correo electrónico:

    from langchain_core.tools import tool
    
    @tool
    def classify_priority(email_body: str) -> str:
        """Classify the priority of an IT support ticket based on email content."""
        prompt = ChatPromptTemplate.from_template(
            """Analyze this IT support email and classify its priority as High, Medium, or Low.
            
            High: System outages, security breaches, critical business functions down
            Medium: Non-critical issues affecting productivity, software problems
            Low: General questions, requests, minor issues
            
            Email: {email}
            
            Respond with only: High, Medium, or Low"""
        )
        chain = prompt | llm
        response = chain.invoke({"email": email_body})
        return response.content.strip()

Excelente. Ahora tenemos un aviso que ordena a la IA recibir el cuerpo del correo electrónico, analizarlo y clasificar su prioridad como Alta, Media o Baja.

¡Ya está!. ¡Acaba de componer una herramienta que su agente puede llamar!

A continuación, creemos una herramienta similar para identificar el tema principal (o categoría) de la solicitud de asistencia:


    @tool
    def identify_topic(email_body: str) -> str:
        """Identify the main topic/category of the IT support request."""
        prompt = ChatPromptTemplate.from_template(
            """Analyze this IT support email and identify the main topic category.
            
            Categories: password_reset, vpn, software_request, hardware, email, network, printer, other
            
            Email: {email}
            
            Respond with only the category name (lowercase with underscores)."""
        )
        chain = prompt | llm
        response = chain.invoke({"email": email_body})
        return response.content.strip()

Ahora tenemos que crear un estado, y en LangGraph esta pequeña pieza es, más o menos, una gran cosa.

Considéralo el sistema nervioso central de tu gráfico. Es la forma en que los nodos se comunican entre sí, pasándose notas como si fueran alumnos aventajados en clase.

Según los documentos:

"Un estado es una estructura de datos compartida que representa la instantánea actual de tu aplicación".

¿En la práctica? El estado es un mensaje estructurado que se mueve entre nodos. Transporta la salida de un paso como entrada para el siguiente. Básicamente, es el pegamento que mantiene unido todo el flujo de trabajo.

Por lo tanto, antes de construir el gráfico, debemos definir la estructura de nuestro estado. En este ejemplo, nuestro estado incluirá lo siguiente:

  • La solicitud del usuario (cuerpo del correo electrónico)
  • La prioridad asignada
  • El tema identificado (categoría)

Es sencillo y limpio, para que puedas moverte por el gráfico como un profesional.

    from typing import TypedDict

    # Define the state structure
    class TicketState(TypedDict):
        email_body: str
        priority: str
        topic: str
        
    
    # Initialize state
    initial_state = TicketState(
        email_body=email_body,
        priority="",
        topic=""
    )

Nodos vs. Aristas: Componentes Clave de LangGraph

Los elementos fundamentales de LangGraph son los nodos y las aristas.

  • Nodos: Son las unidades operativas dentro del grafo, que realizan el trabajo real. Un nodo suele consistir en código Python que puede ejecutar cualquier lógica, desde cálculos hasta interacciones con modelos lingüísticos (LLM) o integraciones externas. Esencialmente, los nodos son como funciones individuales o agentes en la programación tradicional.
  • Aristas: Las aristas definen el flujo de ejecución entre nodos, determinando lo que ocurre a continuación. Actúan como conectores que permiten la transición del estado de un nodo a otro basándose en condiciones predefinidas. En el contexto de LangGraph, las aristas son cruciales para orquestar la secuencia y el flujo de decisiones entre nodos.

Para comprender la funcionalidad de las aristas, consideremos una simple analogía de una aplicación de mensajería:

  • Los nodos se asemejan a los usuarios (o sus dispositivos) que participan activamente en una conversación.
  • Las aristas simbolizan los hilos de conversación o las conexiones entre usuarios que facilitan la comunicación.

Cuando un usuario selecciona un hilo de chat para enviar un mensaje, se crea efectivamente un borde que lo vincula a otro usuario. Cada interacción, ya sea el envío de un mensaje de texto, voz o vídeo, sigue una secuencia predefinida, comparable al esquema estructurado del estado de LangGraph. Esto garantiza la uniformidad y la interpretabilidad de los datos transmitidos a lo largo del borde.

A diferencia de la naturaleza dinámica de las aplicaciones basadas en eventos, LangGraph emplea un esquema estático que se mantiene constante durante toda la ejecución. Simplifica la comunicación entre nodos, permitiendo a los desarrolladores confiar en un formato de estado estable, garantizando así una comunicación de borde sin fisuras.

Diseño de un Flujo de Trabajo Básico

La ingeniería de flujos en LangGraph puede conceptualizarse como el diseño de una máquina de estados. En este paradigma, cada nodo representa un estado o paso de procesamiento distinto, mientras que las aristas definen las transiciones entre esos estados. Este enfoque es particularmente beneficioso para los desarrolladores que buscan un equilibrio entre las secuencias de tareas deterministas y las capacidades de toma de decisiones dinámicas de la IA. Empecemos a construir nuestro flujo inicializando un StateGraph con la clase TicketState que definimos anteriormente.

    from langgraph.graph import StateGraph, START, END
    
    workflow = StateGraph(TicketState)

Adición de Nodos: Los nodos son bloques de construcción fundamentales, definidos para ejecutar tareas tan específicas como clasificar la prioridad de un ticket o identificar su tema.

Cada función de nodo recibe el estado actual, realiza su operación y devuelve un diccionario para actualizar el estado:

   def classify_priority_node(state: TicketState) -> TicketState:
        """Node to classify ticket priority."""
        priority = classify_priority.invoke({"email_body": state["email_body"]})
        return {"priority": priority}

    def identify_topic_node(state: TicketState) -> TicketState:
        """Node to identify ticket topic."""
        topic = identify_topic.invoke({"email_body": state["email_body"]})
        return {"topic": topic}
        
        
    workflow.add_node("classify_priority", classify_priority_node)
    workflow.add_node("identify_topic", identify_topic_node)

Los métodos classify_priority_node e identify_topic_node cambiarán el TicketState y enviarán la entrada de parámetros.

Creación de Aristas: Definir aristas para conectar nodos:


    workflow.add_edge(START, "classify_priority")
    workflow.add_edge("classify_priority", "identify_topic")
    workflow.add_edge("identify_topic", END)

El classify_priority establece el inicio, mientras que el identify_topic determina el final de nuestro flujo de trabajo hasta el momento.

Compilación y Ejecución: Una vez configurados los nodos y las aristas, compile el flujo de trabajo y ejecútelo.


    graph = workflow.compile()
    result = graph.invoke(initial_state)

¡Genial! También puede generar una representación visual de nuestro flujo LangGraph.

graph.get_graph().draw_mermaid_png(output_file_path="graph.png")

Si ejecutara el código hasta este punto, observaría un gráfico similar al siguiente:

first_graph.png

Esta ilustración visualiza una ejecución secuencial: inicio, seguido de clasificación de la prioridad, luego identificación del tema y, por último, finalización.

Uno de los aspectos más potentes de LangGraph es su flexibilidad, que nos permite crear flujos y aplicaciones más complejos. Por ejemplo, podemos modificar el flujo de trabajo para añadir aristas desde START a ambos nodos con la siguiente línea:

    workflow.add_edge(START, "classify_priority")
    workflow.add_edge(START, "identify_topic")

Este cambio implicará que el agente ejecute classify_priority e identify_topic simultáneamente.

Otra característica muy valiosa de LangGraph es la posibilidad de utilizar aristas condicionales. Permiten que el flujo de trabajo se ramifique en función de la evaluación del estado actual, permitiendo el enrutamiento dinámico de las tareas.

Vamos a mejorar nuestro flujo de trabajo. Crearemos una nueva herramienta que analice el contenido, la prioridad y el tema de la solicitud para determinar si se trata de un problema de alta prioridad que requiere escalado (es decir, la apertura de un ticket para un equipo humano). Si no es así, se generará una respuesta automática para el usuario.


    @tool
    def make_escalation_decision(email_body: str, priority: str, topic: str) -> str:
        """Decide whether to auto-respond or escalate to IT team."""
        prompt = ChatPromptTemplate.from_template(
            """Based on this IT support ticket, decide whether to:
            - "auto_respond": Send an automated response for simple/common or medium priority issues
            - "escalate": Escalate to the IT team for complex/urgent issues
            
            Email: {email}
            Priority: {priority}
            Topic: {topic}
            
            Consider: High priority items usually require escalation, while complex technical issues necessitate human review.
            
            Respond with only: auto_respond or escalate"""
        )
        chain = prompt | llm
        response = chain.invoke({
            "email": email_body,
            "priority": priority,
            "topic": topic
        })
        return response.content.strip()
        

Además, si se determina que la solicitud es de prioridad baja o media (lo que lleva a una decisión de "auto_responder"), realizaremos una búsqueda vectorial para recuperar respuestas históricas. Esta información se utilizará entonces para generar una respuesta automática adecuada. Sin embargo, se necesitarán dos herramientas adicionales:


    @tool
    def retrieve_examples(email_body: str) -> str:
        """Retrieve relevant examples from past responses based on email_body."""
        try:
            examples = iris.cls(__name__).Retrieve(email_body)
            return examples if examples else "No relevant examples found."
        except:
            return "No relevant examples found."

    @tool
    def generate_reply(email_body: str, topic: str, examples: str) -> str:
        """Generate a suggested reply based on the email, topic, and RAG examples."""
        prompt = ChatPromptTemplate.from_template(
            """Generate a professional IT support response based on:
            
            Original Email: {email}
            Topic Category: {topic}
            Example Response: {examples}
            
            Create a helpful, professional response that addresses the user's concern.
            Keep it concise and actionable."""
        )
        chain = prompt | llm
        response = chain.invoke({
            "email": email_body,
            "topic": topic,
            "examples": examples
        })
        return response.content.strip()

Ahora, definamos los nodos correspondientes a esas nuevas herramientas:

    
    def decision_node(state: TicketState) -> TicketState:
        """Node to decide on escalation or auto-response."""
        decision = make_escalation_decision.invoke({
            "email_body": state["email_body"],
            "priority": state["priority"],
            "topic": state["topic"]
        })
        return {"decision": decision}
        
    
    def rag_node(state: TicketState) -> TicketState:
        """Node to retrieve relevant examples using RAG."""
        examples = retrieve_examples.invoke({"email_body": state["email_body"]})
        return {"rag_examples": examples}

    def generate_reply_node(state: TicketState) -> TicketState:
        """Node to generate suggested reply."""
        reply = generate_reply.invoke({
            "email_body": state["email_body"],
            "topic": state["topic"],
            "examples": state["rag_examples"]
        })
        return {"suggested_reply": reply}
        
    
    def execute_action_node(state: TicketState) -> TicketState:
        """Node to execute final action based on decision."""
        if state["decision"] == "escalate":
            action = f"&#x1f6a8; ESCALATED TO IT TEAM\nPriority: {state['priority']}\nTopic: {state['topic']}\nTicket created in system."
            print(f"[SYSTEM] Escalating ticket to IT team - Priority: {state['priority']}, Topic: {state['topic']}")
        else:
            action = f"&#x2705; AUTO-RESPONSE SENT\nReply: {state['suggested_reply']}\nTicket logged for tracking."
            print(f"[SYSTEM] Auto-response sent to user - Topic: {state['topic']}")
        
        return {"final_action": action}
        
        
        
    workflow.add_node("make_decision", decision_node)
    workflow.add_node("rag", rag_node)
    workflow.add_node("generate_reply", generate_reply_node)
    workflow.add_node("execute_action", execute_action_node)

El borde condicional utilizará entonces la salida del nodo make_decision para dirigir el flujo:

    workflow.add_conditional_edges(
        "make_decision",
        lambda x: x.get("decision"),
        {
            "auto_respond": "rag",
            "escalate": "execute_action"
        }
    )

Si la herramienta make_escalation_decision (a través de decision_node) da como resultado "auto_respond", el flujo de trabajo procederá a través del nodo rag (para recuperar ejemplos), luego a generate_reply (para elaborar la respuesta), y finalmente a execute_action (para registrar la auto-respuesta).

Por el contrario, si la decisión es "escalar", el flujo pasará por alto el RAG y tomará pasos de generación, moviéndose directamente a execute_action para manejar la escalada. Para completar el gráfico añadiendo las aristas estándar restantes, haga lo siguiente:

    workflow.add_edge("rag", "generate_reply")
    workflow.add_edge("generate_reply", "execute_action")
    workflow.add_edge("execute_action", END)

Nota sobre el Dataset: Para este proyecto, el dataset que utilizamos para alimentar la generación mejorada de recuperación (RAG) procedía del dataset Customer Support Tickets dataset on Hugging Face. El dataset se filtró para incluir exclusivamente los elementos categorizados como "Asistencia técnica" y se restringió a entradas en inglés. De este modo, se garantizaba que el sistema RAG sólo recuperara ejemplos muy relevantes y específicos del ámbito de las tareas de asistencia técnica.

Llegados a este punto, nuestro gráfico debería parecerse al siguiente:

graph.png

Cuando ejecute este gráfico con un correo electrónico que resulte en una clasificación de alta prioridad y una decisión de "escalar", verá la siguiente respuesta:

image.png

Al mismo tiempo, una solicitud clasificada como de baja prioridad y que dé lugar a una decisión "auto_respuesta" desencadenará una respuesta parecida a la que se muestra a continuación:

image.png

Entonces... ¿Esto es todo Solete?

No del todo. Hay que tener cuidado con algunos puntos débiles:

  • Privacidad de los datos: Tenga cuidado con la información sensible - estos agentes requieren barandillas.
  • Costes de computación: Algunas configuraciones avanzadas requieren recursos importantes.
  • Alucinaciones: Los LLMs pueden ocasionalmente inventar cosas (aunque son más inteligentes que la mayoría de los internos).
  • No determinismo: La misma entrada puede devolver diferentes salidas, lo que es genial para la creatividad, pero complicado para los procesos estrictos.

Sin embargo, la mayoría de estos puntos débiles pueden gestionarse con una buena planificación, las herramientas adecuadas y -lo has adivinado- un poco de reflexión.

LangGraph hace que los agentes de IA dejen de ser palabras de moda para convertirse en soluciones reales y operativas. Tanto si desea automatizar la atención al cliente, gestionar incidencias informáticas o crear aplicaciones autónomas, este marco lo hace posible y, de hecho, agradable.

¿Tienes alguna pregunta o comentario? Hablemos. La revolución de la IA necesita constructores como tú.

2
0 71
Artículo Alberto Fuentes · mayo 28, 2025 4m read

Con el lanzamiento de InterSystems IRIS Cloud SQL, recibimos cada vez más preguntas sobre cómo establecer conexiones seguras mediante JDBC y otras tecnologías de drivers. Aunque contamos con una documentación resumida y detallada sobre las tecnologías de los drivers, nuestra documentación no describe herramientas cliente individuales, como nuestra favorita personal, DBeaver. En este artículo, describiremos los pasos para crear una conexión segura desde DBeaver a vuestra implementación de Cloud SQL.

0
0 30
InterSystems Official Jose-Tomas Salvador · ene 22, 2025

¡Tenemos un nuevo curso para ti!... pero sólo si te interesa estar a la última en el mundo de la interoperabilidad en entornos sanitarios. 

Igual no lo sabes, pero la familia de productos de InterSystems, con IRIS for Health y Health Connect a la cabeza, son la tecnología base para gestionar e integrar datos clínicos y administrativos de más de la mitad de la población de España... (por no hablar de EEUU, UK, Paises Bajos,...). Así que, teniendo en cuenta esto, si te dedicas al desarrollo de soluciones  o a la implementación de interfaces o integraciones en el sector salud, este es otro curso que no te puedes perder. Pincha y regístrate. ¡¡No lo dudes!!. Más que nada porque las plazas son limitadas... (ahí lo dejo, que luego me dicen que no lo aviso 😉).

1
0 89