Find

Article
· Oct 8, 2024 5m read

Modelos LLM y aplicaciones RAG paso a paso - Parte I - Introducción

Seguramente hayáis oído en el último año hablar continuamente de los LLM (Large Language Model) y el desarrollo asociado a los mismos de las aplicaciones RAG (Retrieval Augmented Generation), pues bien, en esta serie de artículos desgranaremos los fundamentos de cada término utilizado y veremos como desarrollar una sencilla aplicación RAG.

¿Qué es un LLM?

Los modelos LLM forman parte de lo que conocemos como IA generativa y su fundamento es la vectorización de gigantescas cantidades de textos. Mediante esta vectorización obtendremos un espacio vectorial (valga la redundancia) en las que palabras o términos relacionadas estarán más próximas entre si que respecto a palabras menos relacionadas.

Si bien la forma más sencilla de visualizarlo es un gráfico de 3 dimensiones como el de la anterior imagen el número de dimensiones podrá ser tan grande como se desee, a mayores dimensiones más precisión en las relaciones entre términos y palabras y mayor consumo de recursos del mismo.

Estos modelos son entrenados con conjuntos masivos de datos que les permite disponer de la información suficiente para poder generar textos relacionados con la petición que se les haga, pero... ¿cómo sabe el modelo que términos están relacionados con la pregunta realizada? Muy sencillo, por la llamada "similitud" entre vectores, esto no es más que un cálculo matemático que nos permite dilucidar la distancia que hay entre dos vectores. Los cálculos más comunes son:

Mediante ese tipo de cálculo el LLM podrá montar una respuesta coherente basada en términos próximos a la pregunta realizada en relación a su contexto.

Todo esto está muy bien, pero estos LLM tienen una limitación de cara a su aplicación para usos específicos ya que la información con la que han sido entrenados suele ser bastante "general", si deseamos que un modelo LLM se adapte a las necesidades específicas de nuestro negocio tendremos dos opciones:

Fine tuning

El fine tuning es una técnica que permite el reentrenado de modelos LLM con datos relativos a una temática en específico (lenguaje procesal, terminología médica, etc). Mediante esta técnica se podrá disponer de modelos más ajustados a nuestra necesidad sin tener que entrenar un modelo desde 0.

La principal pega de esta técnica es que todavía necesitamos proporcionarle al LLM una cantidad ingente de información para dicho reentrenamiento y en ocasiones este puede quedarse "corto" para las expectativas de un determinado negocio.

Retrieval Augmented Generation

El RAG es una técnica que permite incluir al LLM el contexto necesario para contestar a una determinada pregunta sin necesidad de entrenar o reentrenar al modelo específicamente con la información relevante.

¿Cómo incluimos el contexto necesario a nuestro LLM? Muy sencillo, en el momento de enviar la pregunta al modelo le indicaremos explícitamente que tenga en consideración la información relevante que adjuntamos para contestar a la consulta realizada y para ello haremos uso de bases de datos vectoriales de las que podamos extraer el contexto relacionado con la pregunta remitida.

¿Cual es la mejor opción para mi problemática, Fine tuning o RAG?

Ambas opciones tienen sus ventajas y sus inconvenientes, por un lado el Fine tuning te permite incluir dentro del modelo LLM toda la información relativa al problema que quieres resolver, no necesitando de terceras tecnologías como puede ser una base de datos vectorial donde almacenar contextos, pero por otra parte te ata al modelo reentrenado, y si este no cubre las espectativas del mismo la migración a uno nuevo puede ser bastante tedioso.

Por otra parte RAG necesita de funcionalidades como las búsquedas vectoriales para poder conocer cual es el contexto más exacto a la pregunta que estamos pasando a nuestro LLM. Este contexto deberá almacenarse en una base de datos vectorial sobre la que posteriormente realizaremos consultas para extraer dicha información. La principal ventaja (a parte de indicarle al LLM explicitamente que utilice el contexto que le proporcionamos) es que no estamos atados al modelo LLM, pudiendo cambiarlo por otro que sea más ajustado a nuestras necesidades.

Como hemos presentado al comienzo del artículo, nos centraremos en el desarrollo de un ejemplo de aplicación en RAG (sin grandes pretensiones, sólo demostrar como podéis empezar).

Arquitectura de un proyecto RAG

Veamos de forma somera cual sería la arquitectura necesario para un proyecto RAG:

Por un lado tendremos los siguientes actores:

  • Usuarios: que interactuarán con el LLM enviando consultas.
  • Contexto: proporcionado previamente para incluirlo en las consultas del usuario.
  • Modelo de vectorización: para vectorizar los diferentes documentos asociados al contexto.
  • Base de datos vectorial: en este caso será IRIS y almacenará las diferentes partes de los documentos de contexto vectorizadas.
  • LLM: modelo LLM que recibirá las consultas, para este ejemplo hemos elegido MISTRAL.
  • Aplicación Python: destinada a la consulta sobre la base de datos vectorial para la extracción del contexto y su inclusión en la consulta al LLM.

Para no enredar demasiado el diagrama he obviado la aplicación encargada de la captura de los documentos del contexto, de su troceo y posterior vectorización e inserción. En la aplicación asociada podréis consultar este paso así como el posterior relativo a la consulta para la extracción, pero no os preocupéis, lo veremos con más detalle en los próximos artículos.

Asociado a este artículo tenéis el proyecto que usaremos como referencia para explicar con detalle cada paso, dicho proyecto está contenerizado en Docker y podéis encontrar una aplicación en Python haciendo uso de Jupyter Notebook y una instancia de IRIS. Necesitaréis una cuenta en MISTRAL AI para incluir la API Key que os permita el lanzamiento de consultas.

En la próxima entrega veremos como registrar nuestro contexto en una base datos vectorial. ¡Permanezcan a la escucha!

1 Comment
Discussion (1)1
Log in or sign up to continue
Announcement
· Oct 8, 2024

¡Global Masters está de vuelta! Fecha de lanzamiento: 3 de octubre de 2024

¡Hola comunidad!

¡Hemos echado de menos Global Masters, y estamos seguros de que vosotros también!

🚀 ¡Global Masters se relanza el 3 de octubre de 2024!

El 3 de octubre compartimos un enlace para que todos los miembros de la Comunidad de Desarrolladores puedan acceder a la nueva plataforma. ¡No os perdáis la publicación dedicada en la Comunidad de Desarrolladores! (anuncio siguiente)

Hemos trabajado arduamente para traer el programa de vuelta, pero tened paciencia si notáis algunos detalles por pulir: ¡todavía está en proceso de mejora! Nos hemos enfocado en ofreceros primero las características más valiosas: los desafíos (que ahora llamamos "Asks"... aunque a veces seguimos llamándolos "desafíos" mientras nos acostumbramos), recompensas y medallas.

Algunas características aún están en desarrollo:

1. Integración de API: La integración entre Global Masters, la Comunidad de Desarrolladores, Open Exchange y el Portal de Ideas aún está en proceso. Se estima que el lanzamiento será a finales de octubre. Mientras tanto, estamos registrando vuestras contribuciones y actualizaremos vuestros saldos de puntos una vez que la función esté activa.

2. Niveles: La nueva plataforma aún no soporta Niveles, pero estamos trabajando arduamente para reintegrarlos lo antes posible.

¡Terminó la espera! 🎉 ¡Hurra!

Discussion (0)0
Log in or sign up to continue
Article
· Oct 8, 2024 5m read

FHIR Object Model 简介

挑战

在使用FHIR进行开发的过程中,我们会面对海量的FHIR规范中定义的数据结构,具体来说在FHIR规范中定义了超过150个资源、700多个资源内元素。每个定义里都包括了对自身结构的描述以及数据约束、数据绑定值集等。对于一个开发人员要记住这些内容非常困难。

同时FHIR数据,特别是Json格式的FHIR数据是典型的“有向图”结构,它的资源中嵌套元素定义、集合以及复杂的资源间“关系”,在这些复杂结构的数据间导航并操作,非常困难。

解决方案

在InterSystems IRIS for Health 2024.1之前,我们会将FHIR数据以Json文档的方式载入 %DynamicAbstractObject,例如下面的代码

   set dynObject1 = ##class(%DynamicObject).%New()
   set dynObject1.SomeNumber = 42
   set dynObject1.SomeString = "a string"
   set dynObject1.SomeArray = ##class(%DynamicArray).%New()
   set dynObject1.SomeArray."0" = "an array element"
   set dynObject1.SomeArray."1" = 123
   set dynObject2 = {"SomeNumber":42,"SomeString":"a string"}
   set dynObject2.SomeArray = ["an array element",123]
   
   write "object 1: "_dynObject1.%ToJSON(),!,"object 2: "_dynObject2.%ToJSON()

可以看到这样的处理有下面不方便的地方:

  • 只能使用自己的方式解析、导航FHIR结构
  • 不能从IDE中获取提示信息
  • 没有数据类型安全
  • 没有上下文敏感的文档
  • 没有调试debug的支持

在InterSystems IRIS for Health 2024.1版本之后,引入了FHIR 对象模型。

FHIR 对象模型概览

在 HS.FHIRModel.R4 包下,每一个FHIR R4资源都对应一个ObjectScript类。比如 HS.FHIRModel.R4.AllergyIntolerance类对应于 AllergyIntolerance 资源。这些类通过为资源和组成元素提供一个共享的、可预测的数据结构和方法框架,简化了开发过程。

这样的结构,在VS Code环境下,会给出很好的提示

下面具体举例如何使用FHIR 对象模型:

1. 获取数据

按索引获取有序序列中的值

 Set patientName = patient.name.get(0)

获取嵌套定义中的值

 Set patientIdValue = patient.identifier.get(0).get(“value”)
 Set patientCity = patient.address.get(0).city

在获取数据前判断键key是否存在

 If patient.name.get(0).contains("family") {
     Set familyName = patient.name.get(0).get(“family”) 
 }

2. 更新数据

添加新的键值对

 Do patient.name.get(0).put("use","official")

更新存在的值

 Do observation.put("status","final")

3. 添加对象的引用

 Set claim = ##class(HS.FHIRModel.R4.Claim).%New()
 Do claim.IncludeType()
 Do claim.type.IncludeCoding()

4. 导航对象

 Set contactItr = patient.contact.get(0).telecom.iterator()
 While contactItr.hasNext() {
    Set contact = contactItr.next().value
    if contact.system = "phone" {
        Write !, contact.value
    }
 }

5 读取JSON格式 FHIR 数据

 Set rType = dao.resourceType
 Set cls = $CLASSMETHOD("I4H.FhirR4."_rType,"fromDao",dao)

6. 将FHIR 数据输出为 JSON 格式

 Set newDao = cls.toDao()

转为字符串

 Set payload = cls.toString()

7. 创建新的 FHIR 元素

 Do claim.IncludeType()
 Do claim.type.IncludeCoding()
 Set coding = ..MakeCoding("http://terminology.hl7.org/CodeSystem/claim-type","institutional")
 Do claim.type.coding.add(coding)

8. “图” 结构查询引擎

 Set key = "system"
 Set value = "email"
 Set query = "$[*]?(@."_key_"=='"_value_"')"
 Set email = doctor.telecom.apply(query)

更多资料

FHIR Object Model 在线文档:https://docs.intersystems.com/irisforhealth20242/csp/docbook/DocBook.UI.Page.cls?KEY=HXFHIR_data#HXFHIR_data_classes

 

下面是一个完整的创建患者资源的例子

ClassMethod MakeCoding(system As %String, code As %String, display As %String = "") As HS.FHIRModel.R4.Coding
{
    Set rec = ##class(HS.FHIRModel.R4.Coding).%New()
	Set rec.system = system
	Set rec.code = code
	If (display'="") Set rec.display = display
	Return rec
}

// Create a Patient using FHIR Object Model classes from R4 and then post
// this patient on the FHIR server
ClassMethod CreatePatient(ident As %String) As %Status
{
   #dim patient As HS.FHIRModel.R4.Patient
   Set patient = ##class(HS.FHIRModel.R4.Patient).%New()
   Do patient.IncludeName()
   Set name = patient.name.MakeEntry()
   Set firstName = "John"
   Do name.IncludeGiven()
   Do name.given.add(firstName)
   Set name.family = "Doe"
   Do patient.name.add(name)

    If patient.name.get(0).contains("family") {
    Set fName = patient.name.get(0).get("family") 
    }

    Do patient.name.get(0).put("use","official")

   Set patient.gender = "male"
   Set patient.birthDate = "1985-05-15"
   Do patient.IncludeAddress()
   Set addr = patient.address.MakeEntry()
   Do addr.IncludeLine()
   Set line1 = "123 Main Street"
   Do addr.line.add(line1)
   Set addr.city = "Boston"
   Set addr.state = "MA"
   Set addr.postalCode = "02111"
   Do patient.address.add(addr)

   Set address = ##class(HS.FHIRModel.R4.Address).%New()
   Do patient.put("address", address)

   Do patient.IncludeContact()
   Set contact = patient.contact.MakeEntry()

   Do contact.IncludeTelecom()
   Set telecom = contact.telecom.MakeEntry()
   Set telecom.system = "phone"
   Set telecom.value = "555-555-5555"
   Set telecom.use = "mobile"
   Do contact.telecom.add(telecom)
   Do patient.contact.add(contact)

   Set contactItr = patient.contact.get(0).telecom.iterator()
   While contactItr.hasNext() {
    Set contact = contactItr.next().value
    if contact.system = "phone" {
        Write !, contact.value
    }
   }

   Do patient.IncludeIdentifier()
   Set id = patient.identifier.MakeEntry()
   Set coding = ..MakeCoding("http://terminology.hl7.org/CodeSystem/v2-0203", "MR")
   Set id.type = coding
   Set id.value = ident
   Do patient.identifier.add(id)
   Set patientJSON = patient.toDao()



   Set service = ##class(HS.FHIRServer.Service).EnsureInstance(1)
   Do service.interactions.Add(patientJSON)
   Return $$$OK
}
Discussion (0)1
Log in or sign up to continue
Article
· Oct 8, 2024 4m read

iris-DataViz: Aplicación de análisis y visualización de datos al estilo de Tableau con función de arrastrar y soltar

image

Hola Comunidad,

En este artículo, os presentaré mi aplicación iris-DataViz.

iris-DataViz es una aplicación de análisis y visualización de datos exploratorios basada en Streamlit que aprovecha la funcionalidad de IRIS embebido en Python y SQLAlchemy para interactuar con IRIS, así como la biblioteca de Python PyGWalker para el análisis de datos y la visualización de datos. PyGWalker (Python Graphic Walker) es una biblioteca de visualización de datos interactiva creada para Python, que tiene como objetivo llevar la facilidad y funcionalidad de la visualización al estilo de Tableau con arrastrar y soltar a los entornos de Python.

Características de la aplicación

  • Visualización de arrastrar y soltar
  • Manipulación y limpieza de los datos dentro de la visualización
  • Amplia gama de tipos de gráficos:
  • Exploración interactiva de datos
  • Agregación y agrupación interactivas.
  • Visualizaciones exportables
  • Resumen automático de datos
  • Campos calculados / computados
  • Soporte para datos categóricos, numéricos y temporales
  • Leyendas y filtros interactivos
  • Generación interactiva de informes
  • Soporte de datos geoespaciales


Vista general de la aplicación

La aplicación ya incluye importados datos relacionados con coches. Para ver los datos, navegad al Portal de Gestión de SQL y visualizad los datos utilizando el siguiente comando SQL:

SELECT
Make, Model, Year, EngineFuelType, EngineHP,
EngineCylinders, TransmissionType, Driven_Wheels, 
NumberofDoors, MarketCategory, VehicleSize, 
VehicleStyle, highwayMPG, citympg, Popularity, MSRP
FROM DataViz.CarsInfo

image

Para ejecutar la aplicación, navegad a http://localhost:8051. Seleccionad el espacio de nombres, el esquema y la tabla. Haced clic en la pestaña de Datos para analizar los datos.


image

Seleccionad la pestaña de Visualización, arrastrad las columnas deseadas al eje X y al eje Y, y seleccionad el tipo de gráfico que queráis.
image

Fragmento de código de la aplicación

A continuación, se presenta el código de ObjectScript invocado desde Python embebido para obtener los espacios de nombres de IRIS:

Class dc.DataViz.Util Extends %RegisteredObject
{
ClassMethod getNameSpaces() As %String
{
 //init sql statement   
 set statement=##class(%SQL.Statement).%New()
 //Prepare Class Query
 set status=statement.%PrepareClassQuery("%SYS.Namespace","List")
 //Check the Error
 if $$$ISERR(status) 
 { 
    do $system.OBJ.DisplayError(status) 
 }
 //Execute the statement
 set resultset=statement.%Execute()
 set results = "1"
 while resultset.%Next() {
	//zw resultset    
    if results = "1" {
	    set results = resultset.%Get("Nsp")
	    }
    else
    {
    	set results = results _ "," _ resultset.%Get("Nsp")
    }
 }
 return results
}
}

Código de Python embebido que invoca el código de ObjectScript:

  import iris
  ns = iris.cls('dc.DataViz.Util').getNameSpaces()
  namespaces = ns.split(",")

El código a continuación obtendrá la lista de esquemas y tablas:

 def get_schema(self):
        #Establish IRIS Connection    
        with self.engine.connect() as conn:
            with conn.begin():     
                sql = text(""" 
                    SELECT distinct TABLE_SCHEMA
                    FROM INFORMATION_SCHEMA.TABLES                   
                    WHERE TABLE_TYPE='BASE TABLE'       
                    order by TABLE_SCHEMA
                    """)
                results = []
                try:
                    #Fetch records into results variable
                    results = conn.execute(sql).fetchall()
                    schemas="0"
                    for element in results:                                 
                       if schemas == "0":
                           schemas = element[0]
                       else:
                           schemas = schemas+","+element[0]
                except Exception as e:
                    print(e)
                    
        return schemas

    def get_tables(self,schema):
        #Establish IRIS Connection       
        with self.engine.connect() as conn:
            with conn.begin():     
                sql = text(""" 
                    SELECT TABLE_NAME
                    FROM INFORMATION_SCHEMA.TABLES                   
                    WHERE TABLE_TYPE='BASE TABLE'
                    AND TABLE_SCHEMA = :schema
                     order by TABLE_NAME
                    """).bindparams(schema=schema)            
                results = []
                try:
                    #Fetch records into results variable
                    results = conn.execute(sql).fetchall()                  
                    tables="0"
                    for element in results:                                 
                       if tables == "0":
                           tables = element[0]
                       else:
                           tables = tables+","+element[0]
                except Exception as e:
                    print(e)
                    
        return tables

Para más detalles, por favor, visitad la página de la aplicación iris-DataViz en Open Exchange.

Gracias.

Discussion (0)1
Log in or sign up to continue
Article
· Oct 8, 2024 9m read

GitLab を使用した InterSystems ソリューションの継続的デリバリー - パート X: コード以外の話

約 4 年のギャップを経て、私の CI/CD シリーズが帰ってきました! 長年にわたり、InterSystems の数社のお客様と連携し、様々なユースケースに対応する CI/CD パイプラインを開発してきました。 この記事で紹介する情報が誰かのお役に立てられれば幸いです。

この連載記事では、InterSystems テクノロジーと GitLab を使用したソフトウェア開発の様々な可能なアプローチを取り上げています。

取り上げたいトピックは広範にありますが、今回は、コードを超えた内容についてお話ししましょう。構成とデータについてです。

Discussion (0)1
Log in or sign up to continue