New post

Find

Article
· Oct 8, 2024 4m read

LLM Models and RAG Applications Step-by-Step - Part I - Introduction

You have probably heard a lot about LLMs (Large Language Models) and the associated development of RAG (Retrieval Augmented Generation) applications over the last year. Well, in this series of articles we will explain the fundamentals of each term used and see how to develop a simple RAG application.

What is an LLM?

LLM models are part of what we know as generative AI and their foundation is the vectorization of huge amounts of texts. Through this vectorization we will obtain a vector space (excuse the redundancy) in which related words or terms will be closer to each other than to less related words.

Although the simplest way to visualize it is a 3-dimensional graph like the one in the previous image, the number of dimensions can be as large as desired; the greater the dimensions, the greater the precision in the relationships between terms and words and the greater the resource consumption of the same.

These models are trained with massive data sets that allow them to have enough information to be able to generate texts related to the request made to them, but... how does the model know which terms are related to the question asked? Very simple, by the so-called "similarity" between vectors, this is nothing more than a mathematical calculation that allows us to elucidate the distance between two vectors. The most common calculations are:

Through this type of calculation, the LLM will be able to put together a coherent answer based on terms close to the question asked in relation to its context.

All this is very well, but these LLMs have a limitation when it comes to their application for specific uses, since the information with which they have been trained is usually quite "general." If we want an LLM model to adapt to the specific needs of our business, we will have two options:

Fine tuning

Fine tuning is a technique that allows the retraining of LLM models with data related to a specific topic (procedural language, medical terminology, etc.). Using this technique, we can have models that are better suited to our needs without having to train a model from scratch.

The main drawback of this technique is that we still need to provide the LLM with a huge amount of information for such retraining and sometimes this can fall "short" of the expectations of a particular business.

Retrieval Augmented Generation

RAG is a technique that allows the LLM to include the context necessary to answer a given question without having to train or retrain the model specifically with the relevant information.

How do we include the necessary context in our LLM? It's very simple: when sending the question to the model, we will explicitly tell it to take into account the relevant information that we attach to answer the query made, and to do so, we will use vector databases from which we can extract the context related to the question submitted.

What is the best option for my problem, Fine tuning or RAG?

Both options have their advantages and disadvantages. On the one hand, Fine tuning allows you to include all the information related to the problem you want to solve within the LLM model, without needing third-party technologies such as a vector database to store contexts. On the other hand, it ties you to the retrained model, and if it does not meet the model's expectations, migrating to a new one can be quite tedious.

On the other hand, RAG needs features such as vector searches to be able to know which is the most exact context for the question we are passing to our LLM. This context must be stored in a vector database on which we will later perform queries to extract said information. The main advantage (apart from explicitly telling the LLM to use the context we provide) is that we are not tied to the LLM model, being able to change it for another one that is more suited to our needs.

As we have presented at the beginning of the article, we will focus on the development of an application example in RAG (without great pretensions, just to demonstrate how you can start).

Architecture of a RAG project

Let's briefly look at what architecture would be necessary for a RAG project:

On the one hand we will have the following actors:

  • Users : who will interact with the LLM by sending queries.
  • Context : Provided in advance to be included in user queries.
  • Vectorization model : to vectorize the different documents associated with the context.
  • Vector database : in this case it will be IRIS and it will store the different vectorized parts of the context documents.
  • LLM : LLM model that will receive the queries, for this example we have chosen MISTRAL.
  • Python application : intended for querying the vector database for context extraction and its inclusion in the LLM query.

In order not to complicate the diagram too much, I have omitted the application in charge of capturing the documents from the context, their division and subsequent vectorization and insertion. In the associated application you can consult this step as well as the subsequent one related to the query for extraction, but do not worry, we will see it in more detail in the next articles.

Associated with this article you have the project that we will use as a reference to explain each step in detail. This project is containerized in Docker and you can find a Python application using Jupyter Notebook and an instance of IRIS. You will need an account in MISTRAL AI to include the API Key that allows you to launch queries.

In the next article we will see how to register our context in a vector database. Stay tuned!

1 Comment
Discussion (1)1
Log in or sign up to continue
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