#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
Artículo Ricardo Paiva · dic 23, 2024 2m read

Monitoread los cambios incrementales en la base de datos mediante tareas programadas, mostrad las tendencias de cambio a través de gráficos, estableced umbrales de alarma y escribid la información en el archivo messages.log.

Cómo usarlo

Podéis instalarlo a través de Docker o ZPM.

Despliegue con Docker: Requisitos previos.

Aseguraos de tener instalados git y Docker Desktop.

Instalación

1. Clonad o haced git pull del repositorio en cualquier directorio local.

git clone https://github.com/Sara771dev/Database-Size-Monitoring.git

Abrid la terminal en este directorio y ejecutad:

docker-compose build

Iniciad el contenedor de IRIS

docker-compose up -d

Despliegue de paquetes ZPM

Abrid la terminal para ejecutar:

zpm "install databasesizemonitoring"

Crear tareas programadas

TipoDescripción
AlarmSizeAlarma de tamaño de la base de datos
DayActualSizeAumento diario del tamaño del volumen de alarma
IncrementalSizeAumento total actual del tamaño del volumen de alarma

image

Si el tamaño de la base de datos cambia por más del valor especificado, se escribirá información adicional en messages.log.

Al mismo tiempo, podéis contar las tendencias incrementales de la base de datos. Podéis visitar la siguiente página:

http://127.0.0.1:52773/csp/user/DataBases.Page.Chart.cls

imagetip: Si no podéis acceder a la página, es posible que tengáis que ajustar la aplicación web y cambiar el archivo del servidor de /csp/user a always y cache.

0
0 81
Artículo Jose-Tomas Salvador · nov 13, 2024 6m read

He estado trabajando en este proceso con algunos compañeros de equipo y pensé que podría ser útil para otros, especialmente si trabajáis con HL7 y Ensemble/HealthConnect/HealthShare y rara vez os aventuráis más allá de la sección de Interoperabilidad.

Primero, me gustaría establecer que este tutorial es una extensión de la documentación ya existente sobre la importación y exportación de datos SQL, que se encuentra aquí: https://docs.intersystems.com/iris20241/csp/docbook/DocBook.UI.Page.cls?KEY=GSQL_impexp#GSQL_impexp_import

0
0 56
Artículo Jose-Tomas Salvador · sep 30, 2024 3m read

Existen muchas aplicaciones para trabajar con mensajes HL7 V2, pero las herramientas para trabajar con XML en el Portal de Gestión o los IDE de IRIS son limitadas. Aunque hay muchas utilidades externas e IDEs que funcionan con mensajes XML e incluso documentos C-CDA, hay una razón convincente para poder hacer pruebas directamente en el marco de trabajo C-CDA de IRIS.

Hacer pruebas dentro del entorno de IRIS os proporciona el contexto necesario:

0
0 78
Artículo Jose-Tomas Salvador · jun 6, 2024 2m read

Al desarrollar una nueva Producción de Interoperabilidad, es bastante natural que los parámetros se añadan inicialmente en la Producción.

Sin embargo, en cuanto queréis mover la Producción de desarrollo a un entorno de prueba o staging, queda claro que algunos parámetros de configuración como Servidores HTTP, direcciones IP y/o puertos necesitan ser cambiados. Para evitar que estos parámetros se sobrescriban durante un redepliegue posterior, es esencial que mováis estos parámetros de la Producción a los Parámetros Predeterminados del Sistema.

Crear Parámetros Predeterminados del Sistema manualmente es posible, pero se vuelve complicado cuando tenéis muchos Componentes de Negocio en vuestra producción. Por lo tanto, @Wietze Drost pidió a @Theo Stolker desarrollar una herramienta que automatice este proceso permitiendo especificar qué parámetros o configuraciones deben crearse como Predeterminadas del Sistema usando una expresión de filtro. Esta expresión puede definirse como ":HTTPServer,SSLConfig", donde " * " significa "para cualquier Nombre de Clase de host". Después de los dos puntos, sigue una lista de parámetros a mover. Así, esta expresión significa "crear o actualizar Parámetros Predeterminados del Sistema para todos los parámetros que se denominen 'HTTPServer' y 'SSLConfig'". Podéis definir múltiples expresiones de filtro separadas por un punto y coma, por ejemplo, ":HTTPServer,SSLConfig;FullClassName2:xxx,yyy".

Basándome en su solicitud, escribí el Método de Clase o Class Method denominado GetSettingsFromProduction, que hace precisamente eso:

ClassMethod GetSettingsFromProduction(production As %String, filter As %String = "", removeFromProduction As %Boolean = 0, updateSettings As %Boolean = 1) As %Status

production - El nombre de la producción, si se deja en blanco se usará el nombre de la producción que se está ejecutando actualmente. filter - Un filtro para seleccionar parámetros, como "*:HTTPServer,SSLConfig". Podéis añadir múltiples filtros separados por ";", y se permite usar nombres de clases específicos. Si el filtro se deja en blanco, se procesarán todos los parámetros. removeFromProduction - Si se establece en 1, los parámetros de configuración seleccionados por el filtro se eliminarán de la producción. updateSettings - Si se establece en 0, los parámetros de configuración no se actualizarán en los Parámetros Predeterminados del Sistema.

Al ejecutarse, se escribirá información sobre las acciones tomadas en la terminal.

¡Vuestras preguntas y comentarios son bienvenidos!

0
0 115
Artículo Ricardo Paiva · oct 31, 2023 2m read

Preguntas frecuentes de InterSystems

Una herramienta (utilidad ^GLOBUFF) está disponible para verificar el uso de la memoria caché de la base de datos para cada global.

La utilidad se puede ejecutar directamente o mediante programación en el namespace %SYS .

Así se ejecutaría directamente:

0
0 113
Artículo Ricardo Paiva · ago 31, 2023 1m read

Preguntas frecuentes de InterSystems

Podéis ver el espacio libre disponible para la base de datos usando la opción "Free space view" (Ver espacio libre) en el Management Portal: System Operation > Databases.

Y se puede obtener mediante programación a través la consulta FreeSpace de la clase del sistema SYS.Database.

0
0 147
Artículo Dmitry Maslennikov · feb 17, 2023 4m read

Os presento mi nuevo proyecto: irissqlcli, REPL (Read-Eval-Print Loop) para InterSystems IRIS SQL.

  • Resaltado de sintaxis
  • Sugerencias (tablas, funciones)
  • +20 formatos de salida
  • Soporte a stdin
  • Salida a ficheros 

Instalación con pip

pipinstallirissqlcli

O se puede ejecutar con docker

dockerrun-itcaretdev/irissqlcliirissqlcliiris://_SYSTEM:SYS@host.docker.internal:1972/USER
1
0 131
Artículo Pietro Montorfano · jun 16, 2023 3m read

Introducción

Si alguna vez os habéis preguntado cómo depurar algunas solicitudes que se realizan hacia o desde IRIS, este es un pequeño tutorial sobre cómo se hace.

Durante un proyecto complejo, normalmente se obtienen las especificaciones y se implementa la comunicación entre IRIS y otros sistemas basándose en eso. Pero del papel al mundo real normalmente hay un gran trecho y hay que saber por qué se recibe un error en un parámetro o en una cabecera, por qué no se reciben los datos, etc.

Si la conexión es una conexión http sencilla, no hay problema, siempre se puede iniciar tcpdump y capturar el tráfico, pero ¿qué pasa con la comunicación https?

¿Qué tal tener una interfaz web limpia, algo que iniciáis y después el desarrollador puede mirar ese portal cuando quiera?

Si alguna vez habéis estado en esta situación, una solución sencilla es mitm proxy ( https://mitmproxy.org/ ).

Este programa tiene la capacidad de actuar como un proxy (se puede configurar en el Business Operation, por ejemplo), un proxy transparente (lo que me gusta), proxy upstream (proxy transparente que envía la conexión a otro proxy), etc.

0
0 104
Artículo Heloisa Paiva · feb 9, 2023 4m read

Por qué he decidido escribir esto

De nuevo se me planteó un reto que me costó algún tiempo y muchas pruebas obtener la mejor solución. Y ahora que lo logré, me gustaría compartir mi nuevo conocimiento.
 

¿Qué pasó?

En un namespace hay muchas clases similares, así que para dejarlas más sencillas hay una superclase con las propiedades comunes. Además, entre las clases hay relaciones. Yo tenía que hacer una exportación de una de esas clases a JSON, pero no podía cambiar las superclases, porque si no, podría descomponer el flujo de otras integraciones.

6
1 207
Artículo Daniel Aguilar · feb 5, 2023 2m read

Hola Comunidad!

Quiero compartir con vosotros mi primera aplicación del Open Exchange.

Es una herramienta para hacernos los desarrollos mas fáciles. Es un microservicio con IRIS en un docker que nos ayuda en los desarrollos de campañas de SMS, Mail y en los links para las tiendas de nuestras apps brindándonos un acortador de Url's.

Es muy fácil de usar.

Simplemente clona este repo:

https://github.com/daniel-aguilar-garcia/cos-url-shortener.git

Abre la carpeta en VSCode y arranca el docker:

 

2
0 223
Anuncio Jose-Tomas Salvador · ene 23, 2023

Hola desarrolladores,

Nos gustaría invitarte a unirte a nuestro próximo concurso dedicado a crear herramientas útiles que hagan más fácil la vida de tus compañeros programadores: 

🏆 Concurso de Herramientas para el Desarrollador de InterSystems 🏆

Envía una aplicación que ayude a desarrollar más rápido, o contribuya a un código de más calidad, y ayude en los tests, despliegues, soporte o monitorización de tu solución basada en InterSystems IRIS

Duración: Enero 23 - Febrero 12, 2023

Bolsa de premios: $13,500

 

0
0 136
Artículo Alberto Fuentes · nov 15, 2022 4m read

YASPE es el sucesor de YAPE (Yet Another pButtons Extractor). YASPE ha sido escrito desde cero con muchos cambios internos para facilitar el mantenimiento y añadir mejoras.

Funcionalidades de YASPE:

  • Analizar y representar gráficamente los archivos de InterSystems Caché pButtons e InterSystems IRIS SystemPerformance para un rápido análisis de rendimiento de las métricas de IRIS y del Sistema Operativo.
  • Facilitar un análisis profundo, creando gráficos tanto ad-hoc como combinando métricas de IRIS y del Sistema Operativo con la opción "Pretty Performance".
  • La opción "System Overview" te ahorra tener que buscar en los archivos SystemPerformance detalles del sistema u opciones de configuración comunes.

YASPE está escrito en Python y está disponible en GitHub como código fuente o para contenedores Docker en:


YASPE está más centrado en las versiones y Sistema Operativo actuales de IRIS. Si tienes versiones más antiguas y tienes problemas con YASPE, comprueba si puedes ejecutar correctamente tus archivos de rendimiento con YAPE. Si tienes problemas, no dudes en preguntarme a través de GitHub.


Ejemplos

Archivos de salida

Las opciones incluyen:

  • Gráficos en HTML o PNG para todas las columnas en mgstat y vmstat o windows perfmon y salida a carpetas.
  • Es opcional crear gráficos para iostat ya que puede llevar mucho tiempo si hay una lista de discos grande.
  • Un fichero CSV para posterior procesado manual, por ejemplo, con Excel.

Sample Chart

Pretty Performance

Debajo está el gráfico de ejemplo, Glorefs (mgstat) y Uso Total de CPU (vmstat).

image example1

Esta es una de las imágenes predeterminadas, que incluye un zoom para un momento específico (o por defecto de 13:00-14:00).

image example2

Descripción del sistema

yaspe incluye una descripción del sistema y una comprobación básica de la configuración (-s)

Esta comprobación está diseñada para evitar estar rebuscando en el archivo SystemPerformance para encontrar los detalles del sistema. Este es un ejemplo deoverview.txt:

System Summary for your site name

Hostname         : YOURHOST
Instance         : SHADOW
Operating system : Linux
Platform         : N/A
CPUs             : 24
Processor model  : Intel(R) Xeon(R) Gold 6248 CPU @ 2.50GHz
Memory           : 126 GB
Shared memory    : globals 71680 MB + routines 1023 MB + gmheap 1000 MB = 73,703 MB
Version          : Cache for UNIX (Red Hat Enterprise Linux for x86-64) 2018.1.4 (Build 505_1U) Thu May 28 2020 10:11:16 EDT
Date collected   : Profile run "24hours" started at 16:15:00 on Nov 22 2021.

Warnings:
- Journal freeze on error is not enabled. If journal IO errors occur database activity that occurs during this period cannot be restored.
- swappiness is 10. For databases 5 is recommended to adjust how aggressive the Linux kernel swaps memory pages to disk.
- Hugepages not set. For performance, memory efficiency and to protect the shared memory from paging out, use huge page memory space. It is not advisable to specify HugePages much higher than the shared memory amount because the unused memory are not be available to other components.
- dirty_background_ratio is 10. InterSystems recommends setting this parameter to 5. This setting is the maximum percentage of active memory that can be filled with dirty pages before pdflush begins to write them.
- dirty_ratio is 30. InterSystems recommends setting this parameter to 10. This setting is the maximum percentage of total memory that can be filled with dirty pages before processes are forced to write dirty buffers themselves during their time slice instead of being allowed to do more writes. These changes force the Linux pdflush daemon to write out dirty pages more often rather than queue large amounts of updates that can potentially flood the storage with a large burst of updates

Recommendations:
- Review and fix warnings above
- Set HugePages, see IRIS documentation: https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=GCI_prepare_install#GCI_memory_big_linux
- Total memory is 128,755 MB, 75% of total memory is 96,566 MB.
- Shared memory (globals+routines+gmheap) is 73,703 MB. (57% of total memory).
- Number of HugePages for 2048 KB page size for (73,703 MB + 5% buffer = 77,388 MB) is 38694

All instances on this host:
- >SHADOW            2018.1.4.505.1.a  56772  /cachesys

0
0 89
Artículo Ricardo Paiva · jun 4, 2021 4m read

Durante las últimas semanas, el equipo de Solution Architecture (Soluciones de Arquitectura) ha estado trabajando para terminar la carga de trabajo de 2019: esto incluyó la creación del código abierto de la Demostración de Readmisiones que llevó a cabo HIMSS el año pasado, para poder ponerla a disposición de cualquiera que busque una forma interactiva de explorar las herramientas proporcionadas por IRIS.

Durante el proceso de creación del código abierto de la demostración, nos encontramos de inmediato con un error crítico. Los datos subyacentes de los pacientes que se utilizaron para crear la demo no podían utilizarse como parte de un proyecto de código abierto porque no eran propiedad de InterSystems, eran propiedad de nuestro socio Baystate Health.

Nuestro equipo estaba en un pequeño aprieto y tenía que encontrar una forma de sustituir los datos originales por datos sintéticos que pudieran utilizarse, pero manteniendo la "historia" de las demos, o su funcionalidad subyacente, consistente. Dado que la demo muestra cómo IRIS admite el workflow de machine learning de un científico de datos, había un nivel de complejidad añadido porque cualquier dato que utilizáramos tenía que ser lo suficientemente realista como para poder apoyar nuestro modelo de investigación. Después de una breve investigación, Synthea vino a nuestro rescate.

Synthea es un generador de pacientes sintéticos, que modela sus historiales médicos. Es de código abierto. Synthea proporciona datos de alta calidad, realistas, pero no reales, de pacientes; en una variedad de formatos (incluido FHIR), con diferentes niveles de complejidad, cubriendo todos los aspectos de la atención médica. Los datos obtenidos no tienen coste, ni privacidad ni restricciones de seguridad, lo que permite investigar con datos de salud que de otra manera no estarían disponibles, de forma legal o práctica.

Después de una investigación inicial, se eligió Synthea como la herramienta para solucionar nuestro problema de datos. Synthea es una herramienta increíble; sin embargo, un problema que encontramos fue que, para ejecutar el software y obtener los pacientes, teníamos que instalar varias dependencias en nuestros equipos.

  • Java JDK 1.8
  • Gradle Build Tool

Cuando trabajas por tu cuenta, esto generalmente no es un problema, pero como nuestro equipo está formado por varias personas, es importante que todos puedan actualizarse con un nuevo software rápidamente; y la instalación de dependencias puede ser una pesadilla. Tenemos el propósito de que el menor número de personas posible sufra durante los procesos de instalación al integrar un nuevo software en nuestro flujo de trabajo.

Como necesitábamos que cualquier persona de nuestro equipo pudiera realizar actualizaciones en la Demo de readmisiones para poder generar pacientes fácilmente, y no queríamos que todos tuvieran que instalar Gradle en sus equipos, nos apoyamos en Docker e introdujimos el software de Synthea dentro de una imagen de Docker, permitiendo que la imagen se ocupe de las dependencias ambientales subyacentes.

Esto terminó funcionando muy bien para nuestro equipo, ya que nos dimos cuenta de que ser capaz de generar datos de pacientes sintéticos sobre la marcha es probablemente un caso de uso muy común al que se enfrentan nuestros compañeros Ingenieros de ventas, por lo que nuestro equipo quería compartirlo con la Comunidad de Desarrolladores.

Cualquiera puede utilizar la siguiente línea de código para generar rápidamente 5 historiales médicos de pacientes sintéticos en formato FHIR, y dejar los pacientes resultantes en una carpeta de salida en el directorio donde está trabajando actualmente.

docker run --rm -v $PWD/output:/output --name synthea-docker intersystemsdc/irisdemo-base-synthea:version-1.3.4 -p 5
  El código de esta imagen Docker tiene su propio repositorio en Github y se puede encontrar aquí para cualquier persona que quiera echar un vistazo, hacer cambios personalizados, o contribuir: https://github.com/intersystems-community/irisdemo-base-synthea

Ahora estamos realizando actualizaciones para que el proyecto sea compatible con módulos personalizados, de modo que cualquiera que desee agregar una enfermedad a sus pacientes generados pueda hacerlo, si Synthea no la proporciona de forma predeterminada, y se incorporará automáticamente a su imagen.

¿Dónde se usa actualmente?

El proceso actual de creación de la Demo de readmisiones utiliza la imagen irisdemo-base-synthea para generar 5 000 pacientes sintéticos sobre la marcha y cargarlos en nuestro repositorio de datos IRIS relacional, normalizado. Cualquier persona que esté interesada en verificar cómo analizar estos datos de pacientes generados de forma sintética (en formato FHIR), puede consultar la Demo de readmisiones creada recientemente con código abierto. La clase que hay que buscar es: IRISDemo.DataLake.Utils. a partir de la línea 613.

La Demo de readmisiones se puede encontrar aquí: https://github.com/intersystems-community/irisdemo-demo-readmission

1
0 316
Artículo Kurro Lopez · ago 18, 2022 2m read

¡Hola a todos!

El módulo de exportación es esencial en muchos de mis proyectos y se usa a menudo en todos mis servidores de productos.

He implementado varios escenarios en el módulo de iniciación del atributo invoke, ambos mayormente con muchos proyectos adicionales para demostrar en GCR , y mínimamente para instalar nativamente en instancia de producción.

zpm "install appmsw-sql2xlsx -Dzpm.demo=none"

Para mostrar las posibilidades, usé los proyectos fileserver y csvgen.

Para mostrar la posibilidad, propongo seguir los siguientes pasos: Cargar una demo e introducir el nombre y contraseña del superuser \ SYS

En la ventana que aparece, hacer clic en el botón Search y después en Export

image

A continuación, seleccionar csvgen en el menú

image

Hacer clic en el botón Load que aparece, después en Search y en Export

image

A continuación, seleccionar Fileserveren el menú image

Veremos una lista de ficheros Excel que podemos descargar con Download

image

Fichero Excel generado desde una plantilla

P.D. Y cuando su PR aún no se ha fusionado, es muy posible cargar su bifurcación modificada directamente desde el repositorio

0
0 219
Artículo Alberto Fuentes · jul 26, 2022 8m read

Servir el café: Cómo crear y programar una tarea

¿No te gustaría que una taza de café caliente te esperara justo al llegar a la oficina? ¡Vamos a automatizar eso!

Cache e IRIS incorporan un Administrador de tareas, que debería resultar familiar a quienes estén acostumbrados a utilizar el programador de tareas de Windows o a usar cron en Linux. Tu cuenta de usuario requerirá tener acceso al recurso %Admin_Task para utilizarlo, y puedes acceder a él desde el portal de administración en System Operation -> Task Manager. Cuando se instala por primera vez, hay aproximadamente 20 tipos de tareas que puedes programar.

Si quieres añadir tus propias tareas, empieza creando una clase que extienda %SYS.Task.Definition. Como mínimo, debes sobreescribir el método OnTask, que tiene una firma de Method OnTask() As %Status. El código de ese método se ejecutará cada vez que se lance la tarea. De hecho, si tu tarea arroja "Error #5003: No implementado (Error #5003: Not Implemented)" cada vez que se ejecuta, es porque este método no se sobreescribió correctamente. De manera muy básica, podría ser:

Class User.Pour Extends %SYS.Task.Definition{    Method OnTask() As %Status    {        write "Pour the coffee!",!        quit $$$OK    }}

Una vez que hayas desarrollado esa clase, puedes volver al portal de administración e ir a System Operation -> Task Manager -> New Task. Esta vez, si cambias el Namespace para ejecutar la tarea en el menú desplegable al *namespace* donde creaste esta clase, al hacer clic en el menú desplegable "Task type" y deberías ver tu nueva clase, en este caso User.Pour. También podrás darle a tu tarea un nombre y una descripción. Estos aparecerán en el Task Schedule una vez que hayas programado tu tarea. Elige un usuario con el que se ejecutará la tarea. Este usuario deberá tener los permisos adecuados que le permitan ejecutar cualquier código que se encuentre en el método OnTask.

También deberías indicar que la opción "Abrir el archivo de salida cuando la tarea está en ejecución (Open output file when task is running)" la tengas activada (Sí), y seleccionar un archivo para la salida. Cualquier sentencia en forma escrita o similar en la tarea se escribirá en ese archivo, y como eso es todo lo que hace nuestra tarea, no veremos un gran resultado si no configuramos esta parte.Este archivo se iniciará de nuevo cada día, no se anexará, por lo que solamente verás lo que se escribió desde que se ejecutó su tarea más reciente.  

 

Haz clic en "Next" para ver las opciones de programación. Verás que se puede ejecutar la tarea de forma automática diariamente, semanalmente, mensualmente (como en "el día 15 de cada mes"), o mensualmente por día (como en "el segundo martes de cada mes"). Las dos últimas opciones son un poco diferentes, ya que no necesariamente ejecutan una tarea a una hora específica programada.

"After another task completes" (Después de que se complete otra tarea) es útil para encadenar varias tareas en un orden determinado. Por ejemplo, una vez que tengamos esta tarea en el horario, podríamos crear una segunda tarea y llamarla "Add the creamer" (Añadir la leche) y cada vez que la tarea "Pour the coffee" (Servir el café) se complete, la tarea "Add the creamer" también se ejecutará, y siempre ocurrirán en ese orden, incluso si por alguna razón Servir el café llevó más tiempo de lo normal un día. Si la tarea Servir el café falla, no se ejecutará la tarea Añadir la leche en polvo.

"On Demand" (A Demanda) no añade la tarea al horario. En su lugar, solo crea una entrada en el portal de administración en System Operation -> Task Manager -> On Demand Task. De hecho, cualquier tarea, incluyendo las del horario, puede ejecutarse cuando se solicita a partir de ahí, o desde el propio Task Schedule. Solo ten en cuenta que cuando se ejecuta una tarea de esta manera, no se ejecuta inmediatamente. Está programada dentro del siguiente minuto.

Cuando hayas configurado tu horario y hayas hecho clic en "Finalizar", ¡felicidades! ¡Has programado tu primera tarea! Si miras el Task Schedule del Administrador de tareas, verás tu tarea en la parte inferior del horaio. En mi caso, he puesto Pour the coffee a las 9 de la mañana (¡sé que dormir hasta tan tarde es un poco extravagante para la mayoría de nosotros!) todos los días de la semana. En los días programados, mi archivo de salida se reescribirá para decir "Pour the coffee!", justo después de las 9:00 AM.


Son las cinco en algún lugar: Cómo crear opciones para tu tarea

¡¿Pero qué sucede a la hora de la salida?! No siempre queremos café. Necesitamos ser capaces de incorporar algunas opciones a nuestra tarea. Cualquier cosa que definas como una propiedad dentro de tu clase de tarea creará un aviso al programar la tarea. Vamos a añadir una propiedad a nuestra tarea y modificar el método OnTask para utilizarla:

Class User.Pour Extends %SYS.Task.Definition{Property Beverage As %String(DISPLAYLIST = ",coffee,bourbon", VALUELIST = ",coffee,bourbon") [ Required ];    Method OnTask() As %Status    {        write "Pour the "_..Beverage_"!",!        quit $$$OK    }}

En este ejemplo, he hecho que mi propiedad fuera una cadena de texto, pero puede ser de cualquier tipo de dato, y el formulario tendrá una entrada para ella. La mayoría de los tipos de datos tendrán de forma predeterminada una entrada de texto sin formato. Los booleanos tendrán una casilla de verificación. Si defines un DISPLAYLIST y un VALUELIST para la propiedad, como en el caso anterior, obtendrás un desplegable como alternativa, pero la primera opción debe estar en blanco o solo mostrará el cuadro de texto de forma predeterminada. Si la propiedad se marca como requerida, el indicador mostrará un * y el usuario no podrá continuar sin proporcionar un valor.

 

Ahora puedo crear una tarea que escriba "¡Sirve el café!" en un archivo de registro a las 9:00 AM y otra que escriba "¡Sirve el bourbon!" a las 5:00 PM añadiendo el mismo tipo de tarea al horario, pero con una opción diferente.


Mal servicio, 0 estrellas: Gestionando los fallos en las tareas

¡No tenía mi café esta mañana! ¿Qué ha pasado?

Hay un par de formas de comprobar el historial de tareas. Si seleccionas "Task History" (Historial de tareas) en el menú del Administrador de tareas del portal de administración, obtienes una lista cronológica y combinada con el historial de todas las tareas. Si vas a Task Schedule y haces clic en "History" (Historial), a la derecha de la tarea que te interesa, puedes ver el historial solo para esa tarea en particular. Allí podrás ver cualquier error.

También puedes ser más previsor y evitar las reseñas negativas en internet. Vuelve a tu Portal de administración y selecciona System Administration -> Additional Settings -> Task Manager Email. En esa sección puedes configurar los ajustes del correo electrónico de salida para recibir las notificaciones del Administrador de tareas. La configuración de SMTP está fuera del alcance de este artículo, pero deberías poder obtenerla de tu administrador de correo electrónico. Puedes fijar frases como asunto y mensajes tanto para el éxito como para el fracaso. No podrás crear un conjunto diferente de ajustes por tarea, pero en la parte inferior puedes ver una lista de variables que puedes incluir en tus correos electrónicos para proporcionar la información que necesitas. Los valores predeterminados proporcionan toda la información que normalmente se necesita.

Ahora, vamos a programar una tarea otra vez. En la parte inferior, aparecen los campos que no estaban antes si no se había configurado el SMTP. "Send completion email notification to" (Enviar notificación para completar la tarea) es donde se pone la dirección de correo electrónico a la que se enviará el mensaje cuando la tarea se complete correctamente. "Send error email notification to" (Enviar notificación de error por correo electrónico a) es donde se envía una notificación por correo electrónico cuando la tarea no se completa correctamente. Si eligió un archivo de salida, ese archivo también se adjuntará a las notificaciones por correo electrónico.

Vamos a hacer una pausa aquí para añadir claridad. Cuando manejemos esta configuración, "Error" significa que la tarea se ejecutó por completo, pero el método OnTask devolvió un estado de error. Todos los ajustes en la página de configuración de la tarea que se refieren al error o al éxito utilizan esa definición. Si el método OnTask devuelve un estado de error, se enviará el correo electrónico de notificación de error, y si "Suspend task on error?" (¿Suspender la tarea en caso de error?) se fijó en sí, la tarea se suspenderá hasta que le indiques que se reanude. Eso no se debe confundir con un error en el que un defecto en el método OnTask impidió que se completara. En ese tipo de error, no se enviarán notificaciones por correo electrónico y la tarea siempre se suspenderá. Debido a esto, ¡ten mucho cuidado con la forma de manejar los errores!

También hay una casilla desplegable para "Reschedule task after system restart?" (¿Reprogramar la tarea después de reiniciar el sistema?)" Esta opción determina cómo el sistema gestiona las tareas que debían ejecutarse, pero el sistema no funcionaba en ese momento. Si se establece en "No", la ejecución particular de la tarea solo se perderá y se reanudará de forma normal la siguiente vez que deba ejecutarse. Si se establece en "Sí" y la tarea se debería ejecutar mientras el sistema está inactivo, la tarea se ejecutará poco después de que el sistema se reinicie.


¡Pero es IMPORTANTE!: Esa opción que hemos ignorado

Prioridad Normal. Hazlo.

En realidad, eso es lo que querrás la gran mayoría de las veces. La Configuración Task Priority (Prioridad de Tareas) tiene que ver con la forma en que varios procesos compiten por los recursos de tu servidor cuando está ocupado, y rara vez querrás cambiarla. Si te preocupa tener la CPU con un porcentaje cercano al 99% todo el día y quieres que la tarea reciba una prioridad más alta o más baja que otras tareas que se llevan a cabo, puedes cambiar esta configuración para determinar cómo solucionar ese problema, pero humildemente te aviso que cambiar esta configuración no resuelve el verdadero problema.


¡Eso es todo! En este caso, mantuve mi método OnTask muy básico para mantener el foco en el uso real del administrador de tareas y la clase %SYS.Task.Definition, pero puedes poner lo que quieras allí. De este modo, podrás automatizar una gran cantidad de trabajo. Por ejemplo, en nuestros servidores, tenemos un servicio alojado en Tomcat que imprime, envía por correo electrónico y/o archiva Crystal Reports, y automatizamos un %Net.HttpRequest para llamar a ese proceso. Puedes programar cualquier cosa que puedas escribir en un método. Si se te ocurre alguna buena idea o tienes algún ejemplo, compártalo en los comentarios.

</body></html>
0
0 288
Artículo Muhammad Waseem · jun 28, 2022 3m read

¡Hola Comunidad!

Recientemente, migré una serie de repositorios de Objectscript de formato XML a UDL. Después de la migración, me decepcionó un poco la presentación en la interfaz web de GitLab.

Dado que la sintaxis de Objectscript es compatible con GitHub, pensé que también sería compatible con GitLab. Desafortunadamente, la librería utilizada por GitLab para resaltar el código no tiene una extensión para admitir Objectscript.

GitLab usa la librería Rouge, que puede resaltar más de 200 idiomas. Es una librería escrita en Ruby (consulta la página de GitHub), pero Objectscript no está en la lista. Así que decidí desarrollar una extensión de Objectscript.

El subproyecto Rouge está disponible en mi página de GitHub. Para propósitos de prueba, preparé un repositorio objectscript-syntax-for-gitlab para crear fácilmente un contenedor con un entorno Ruby listo y una página de prueba.

Estado de desarrollo actual:

CaracterísticasEstado
&JS<>implementado
&HTML<>implementado
&SQL<>Parcial
Método con lenguaje Pythonimplementado
Método con lenguaje Javascriptimplementado
XData contiene XMLimplementado
XData contiene JSONimplementado
Almacenamiento (definición XML)implementado
ConsultaParcial
Etiqueta en métodoimplementado
RutinaImplementado
CSPAún no
Archivo de macros (INC)Aún no

Instalación

Simplemente clona el repositorio, extrae la imagen y empieza:

git clone https://github.com/lscalese/objectscript-syntax-for-gitlab.git
cd objectscript-syntax-for-gitlab
docker pull ghcr.io/lscalese/objectscript-syntax-for-gitlab:latest
docker-compose up -d

Prueba

Cuando se inicia el contenedor, puedes abrir esta URL para mostrar una página de prueba: http://localhost:9592/objectscript

Es posible seleccionar un tema diferente en la parte inferior de la página.

Si quieres probar el resaltado con tu propio código, puedes usar este pequeño formulario: http://localhost:9692/csp/irisapp/lscalese.objectscript4gitlab.test.cls (el login/password es el estándar _system/SYS)

Copia/pega tu código en el área de texto y haz clic en enviar. Tu código se abrirá en una nueva pestaña Advertencia: El navegador podría bloquear la apertura de la nueva página. Por favor acepta si es necesario.

El botón “reset” permite restaurar la página de prueba por defecto.

No dudes en enviarme comentarios sobre tus pruebas creando un Issue en mi GitHub. Necesito información para detectar errores y mejorar tanto como sea posible antes de enviar un pull request a Rouge.

Espero que este proyecto sea de utilidad para la comunidad y merezca vuestro apoyo ;D

¡Gracias!

0
0 173
Anuncio David Reche · abr 7, 2022

Nos encanta anunciaros que hemos creado un nuevo Portal de Sugerencias: InterSystems Ideas.

El objetivo del Portal es mejorar los mecanismos para que podáis sugerir cómo mejorar nuestros productos y cómo hacerlos evolucionar para satisfacer vuestras necesidades. La sección de Preguntas es una excelente manera de interactuar con otros colegas sobre problemas específicos de código; y elSoporte a Clientes es la forma de obtener la solución a un problema.

0
0 130
Artículo Ricardo Paiva · ago 26, 2021 2m read

¡Hola desarrolladores!

Algunas veces necesito planificar una tarea por medio de un programa.

Y en el 99% de los casos necesito que algún método de clase sea llamado periódicamente.

Y quiero que la tarea programada comience con una línea. Como un trabajo en crontab.

Decidí incorporar un módulo de este tipo con el módulo iris-cron-task.

Os comento los detalles a continuación.

Instala el módulo utilizando:

USER>zpm "install iris-cron-task"

Entonces podrás programar tareas con una sola línea. 

Por ejemplo, si quiero ejecutar el siguiente comando

set ^A($I(^A))=$H

para que se inicie cada minuto, puedo llamar al siguiente comando:

zw ##class(dc.cron.task).Start("Task name","* * * * *","set ^A($I(^A))=$H",1,.taskid)

Esto creará una tarea con un taskid que se ejecutará cada minuto.

Cuando ya no necesites la tarea, puedes eliminarla con:

zw ##class(dc.cron.task).Kill(taskid)

Hice que fuera compatible con algunas configuraciones de cron, como cada minuto:

* * * * *

cada hora:

0 * * * *

y cada día a una hora determinada:

0 0 * * *

Puedes encontrar útil la aplicación cronmaker, para obtener la expresión cron para usarla en cualquier horario que necesites.

Gracias a @Lorenzo Scalese por haber presentado el soporte para una expresión cron arbitraria. 

Espero que os guste.

¡Cualquier comentario es bienvenido!

0
0 130
Artículo Ricardo Paiva · ago 19, 2021 2m read
Este es el ejemplo de un código que funciona en Caché 2018.1.3 e IRIS 2020.2 
No se mantendrá sincronizado con las nuevas versiones 
¡Además NO cuenta con el servicio de Soporte de InterSystems!

Durante mi búsqueda de un snapshot de un objeto persistente, conocí una característica que me gustaría compartir, ya que podría ser útil en algunas situaciones especiales. Mi objetivo era tener una imagen del antes y el después durante las pruebas unitarias.

0
0 114
Artículo Mathew Lambert · jul 7, 2021 1m read

A veces necesitas importar datos a IRIS de forma rápida y sencilla. Por eso se ha desarrollado un gestor de importación en IRIS.

Esta aplicación permite importar datos en formato JSON y también ofrece una interfaz muy sencilla para transferir datos desde colecciones en MongoDB a globals en IRIS. Nunca ha sido más fácil.

Vamos a ver unos ejemplos.

Importación de JSON

0
0 222