Crea un chatbot de inteligencia artificial con R

1/6/2026

shiny inteligencia artificial

Con R y los paquetes apropiados, en pocos minutos podrás crear un chat interactivo de inteligencia artificial dentro de una aplicación Shiny, para poder chatear con un modelo de lenguaje (LLM) de tu elección.

El objetivo es poder crear un chat interactivo e ir mejorándolo con la capacidad de consultar datos, realizar cálculos y otras capacidades propias de R, y además aumentar su conocimiento y la precisión de sus respuestas al permitirle consultar documentos y textos para responder.

¿Por qué crear un chatbot con R?

  • Te entrega el control para elegir el proveedor de inteligencia artificial, o el cerebro que usará el chatbot, así como cambiarlo cuando sea necesario
  • Aplicaciones: Puedes incluir el chatbot en cualquier parte de una aplicación Shiny, lo que te da libertad para crear interfaces adaptadas a tus necesidades
  • Datos: Permite complementar al chatbot con herramientas, funciones de R que hacen posible que el chatbot realice tareas especializadas, como consultar bases de datos
  • Conocimientos: Hace posible aumentar y afinar los conocimientos de la IA por medio de sistemas de generación aumentada por recuperación o RAG, donde recopilas documentos y textos para guiar las respuestas de la IA

Preparación

Crear un chatbot requiere de tres piezas principales: una aplicación donde introducir el chatbot, la funcionalidad de chat o conversación, y el modelo de lenguaje que será el motor de la conversación.

Estas tres piezas corresponden a los tres paquetes de R que usaremos: {shiny} para la aplicación, {shinychat} para la conversación, y {ellmer} para el modelo de lenguaje.

Si aún no tienes configurado un modelo de lenguaje en R, revisa este tutorial, donde explico cómo conectarte con el modelo de IA desde R.

Empezamos instalando los paquetes necesarios:

install.packages("ellmer")
install.packages("shiny")
install.packages("bslib")
install.packages("shinychat")

Ahora veremos paso a paso cómo empezar desde cero y llegar a un chatbot capaz de consultar datos y bases de conocimiento.

Crear un chatbot con Shiny

Hagamos un ayudamemorias de una aplicación Shiny mínima, sin ningún chat todavía:

library(shiny)
library(bslib)

ui <- page_fluid(
  h1("Mi chatbot")
)

server <- function(input, output, session) {
}

shinyApp(ui, server)

Tenemos la sección UI, con la interfaz de la aplicación, y una sección server, donde se hacen los cálculos de la aplicación.

Esto nos entregará una app mínima, que puedes probar con el botón Run que aparecerá en RStudio o en tu IDE.

En principio esta puede ser una app que ya hayas hecho, o puede ser el lienzo para que complementes tu chatbot con otros elementos de una aplicación normal.

Ahora vamos a transformar la aplicación en un chatbot en tres pasos: agregar la interfaz del chat, configurar el modelo de lenguaje, y conectar ambas partes en la sección server de la app.

Interfaz del chat

El paquete {shinychat} nos entrega una interfaz de conversación tipo chat, con burbujitas de mensaje y todo, que simplemente se agrega a tu app con la función chat_ui().

Se recomienda usar page_fillable() en la app para que ocupe toda la pantalla, y dentro ponemos chat_ui().

Por ahora la app iría quedando así:

library(shiny)
library(bslib)
library(ellmer)
library(shinychat)

ui <- page_fillable(
  chat_ui(
    id = "chat",
    messages = "**¡Hola!** ¿En qué te puedo ayudar hoy?"
  ),
  fillable_mobile = TRUE
)

server <- function(input, output, session) {
}

shinyApp(ui, server)

Con esto creamos la parte visible del chat, pero falta el funcionamiento y el cerebro.

Modelo de lenguaje para el chatbot

En la sección server, donde se realizan los cálculos de una app Shiny, creamos el chat que hará funcionar al chatbot.

Como vimos en el tutorial de chats de IA en R, creamos el chat con la función chat_anthropic(), chat_ollama(), o el proveedor que te corresponda a ti. Este objeto representa la conversación completa con el modelo de lenguaje: guarda el historial de mensajes y se encarga de comunicarse con la API.

library(shiny)
library(bslib)
library(ellmer)
library(shinychat)

ui <- page_fillable(
  chat_ui(
    id = "chat",
    messages = "**¡Hola!** ¿En qué te puedo ayudar hoy?"
  ),
  fillable_mobile = TRUE
)

server <- function(input, output, session) {

chat <- chat_anthropic(
    system_prompt = "Eres un chatbot respetuoso, útil y conciso."
  )
}

shinyApp(ui, server)

El argumento system_prompt son las instrucciones que le damos al modelo para guiar su comportamiento: el rol que debe cumplir, el tono que debe usar, explicaciones sobre su función principal, las formas apropiadas de responder, y sus restricciones.

Conectar la interfaz con el modelo

Ahora falta el último paso: conectar el modelo de lenguaje creado con chat_anthropic() con el chat_ui() que pusimos en la interfaz de la app.

library(shiny)
library(bslib)
library(ellmer)
library(shinychat)

ui <- page_fillable(
  chat_ui(
    id = "chat",
    messages = "**¡Hola!** ¿En qué te puedo ayudar hoy?"
  ),
  fillable_mobile = TRUE
)

server <- function(input, output, session) {
  chat <- chat_openai(
    system_prompt = "Eres un chatbot respetuoso, útil y conciso."
  )

  observeEvent(input$chat_user_input, {
    stream <- chat$stream_async(input$chat_user_input)
    chat_append("chat", stream)
  })
}

shinyApp(ui, server)

Siguiendo lo que aprendimos en el tutorial de Shiny, el bloque observeEvent() se activará cada vez que se envíe un mensaje en la interfaz de chat_ui(). Dentro de él ocurren dos cosas:

  1. La primera línea, chat$stream_async(input$chat_user_input), manda el mensaje del usuario/a al modelo de lenguaje (el objeto chat), y obtiene la respuesta que emita la IA.
  2. La segunda línea, chat_append("chat", stream), va añadiendo las burbujas de mensajitos a la interfaz del chat a medida que llega el texto. La app lo va recibiendo en tiempo real en vez de esperar la respuesta completa.
Código completo de la app con chatbot
library(shiny)
library(bslib)
library(ellmer)
library(shinychat)

ui <- page_fillable(
  chat_ui(
    id = "chat",
    messages = "**¡Hola!** ¿En qué te puedo ayudar hoy?"
  ),
  fillable_mobile = TRUE
)

server <- function(input, output, session) {
  chat <- chat_anthropic(
    system_prompt = "Eres un chatbot respetuoso, útil y conciso."
  )

  observeEvent(input$chat_user_input, {
    stream <- chat$stream_async(input$chat_user_input)
    chat_append("chat", stream)
  })
}

shinyApp(ui, server)

Probemos el chatbot!

Si configuraste bien tu proveedor de IA, vas a poder conversar con tu modelo mediante la aplicación Shiny.

Ahora pasamos a la gracia de todo esto: potenciar el chatbot con herramientas para que pueda acceder a datos, y darle una base de conocimientos con documentos específicos.

Entregar herramientas al chatbot

Para ilustrar el desarrollo de un chatbot enfocado en datos con R, hagamos que queremos desarrollar un chatbot que pueda decirnos cifras de la situación de pobreza en Chile.

Primero pongamos a prueba el chatbot que ya creamos, que no tiene ningún conocimiento específico (solamente el conocimiento propio del entrenamiento de la IA), y preguntémosle por un dato:

El modelo de lenguaje no supo responder! 🫤

Cuando la IA no sabe responder, usualmente rellena con cualquier cosa, o se atreve a una estimación. En la mayoría de lso casos, esto debería ser inaceptable.

Ver código completo del chatbot hasta ahora

Especificamos algunas cosas en el código: elejimos un modelo económico, Claude Haiku, definiendo model = "claude-haiku-4-5" dentro de chat_anthropic(), y además especifiquemos el system prompt: "Eres un chatbot respetuoso, útil y conciso. Responde muy brevemente solamente lo que se te pregunta." para que nos entregue menos cháchara.

library(shiny)
library(bslib)
library(ellmer)
library(shinychat)

ui <- page_fillable(
  chat_ui(
    id = "chat",
    messages = "**¡Hola!** ¿En qué te puedo ayudar hoy?"
  ),
  fillable_mobile = TRUE
)

server <- function(input, output, session) {
  chat <- chat_anthropic(
    model = "claude-haiku-4-5",
    system_prompt = "Eres un chatbot respetuoso, útil y conciso. Responde muy 
                     brevemente solamente lo que se te pregunta, sin rodeos."
  )
  
  observeEvent(input$chat_user_input, {
    stream <- chat$stream_async(input$chat_user_input)
    chat_append("chat", stream)
  })
}

shinyApp(ui, server)

Descargar datos

Bajemos un conjunto de datos que nos pueden servir: las estimaciones de pobreza comunal 2024 calculadas por el Ministerio de Desarrollo Social de Chile.

pobreza <- read_xlsx("sae_ingresos_2024.xlsx")

Cargamos y limpiamos los datos hasta que obtenemos una tabla ordenada:

Ver código de la limpieza de datos
library(readxl)
library(dplyr)
library(janitor)

pobreza <- read_xlsx("sae_ingresos_2024.xlsx")

# limpiar columnas
pobreza <- pobreza |> 
  row_to_names(2) |> 
  clean_names() |> 
  rename(poblacion = numero_de_personas_segun_proyecciones_de_poblacion,
         pobreza_personas = numero_de_personas_en_situacion_de_pobreza_de_ingresos,
         pobreza_porcentaje = porcentaje_de_personas_en_situacion_de_pobreza_de_ingresos_2024,
         pobreza_porcentaje_inf = limite_inferior,
         pobreza_porcentaje_sup = limite_superior)

# convertir a numéricos
pobreza <- pobreza |> 
  mutate(
    across(
      c(poblacion, starts_with("pobreza")),
      as.numeric)
  )
nombre_comuna poblacion pobreza_personas pobreza_porcentaje
Iquique 232455 37598 0.161
Alto Hospicio 144554 38759 0.268
Pozo Almonte 18811 3968 0.210
Camiña 1376 600 0.436
Colchane 1553 791 0.509
Huara 3111 1240 0.398
Pica 6313 1980 0.313
Antofagasta 445152 69705 0.156
Mejillones 15950 2239 0.140
Sierra Gorda 1807 256 0.141

Función de consulta de datos

Ahora que tenemos los datos, hagamos una función muy breve que nos permita filtrar la tabla de datos, siguiendo las instrucciones de este tutorial.

El objetivo es crear una función sencilla que opere como una API para consultar datos, una especie de herramienta que resuelve una necesidad de información.

# crear la función de consulta de datos
consultar_pobreza <- function(comuna) {
  message("comuna elegida: ", comuna)
  
  pobreza |> 
    filter(nombre_comuna == comuna) |> 
    select(region, pobreza_personas, pobreza_porcentaje,
           pobreza_porcentaje_inf, pobreza_porcentaje_sup)
}

La función tiene un sólo argumento, con el cual se filtra la columna nombre_comuna para obtener cifras exactas de pobreza.

Probemos la función de consulta de datos:

consultar_pobreza("Maipú")
$ nombre_comuna          <chr> "Maipú"
$ region                 <chr> "Metropolitana"
$ pobreza_personas       <dbl> 70661.29
$ pobreza_porcentaje     <dbl> 0.1203846
$ pobreza_porcentaje_inf <dbl> 0.09052756
$ pobreza_porcentaje_sup <dbl> 0.1502416

Estupendo! La función nos sirve para que con un sólo argumento podamos filtrar los datos.

Registrar la herramienta

Cualquier función de R que tengamos o que creemos podemos pasársela al modelo de lenguaje. Para que el modelo la entienda, tenemos que explicarle la herramienta. De esta manera, el modelo podrá usar funciones de R cuando sean relevantes para responder las preguntas que le hagamos.

Para enseñarle al modelo cómo se usa la función, usamos tool() de {ellmer}, donde entregamos la función, agregamos una descripción general, y describimos también sus argumentos:

herramienta <- tool(
  consultar_pobreza,
  description = "Función que entrega datos de la estimación de pobreza por ingresos 
                 a nivel de cantidad de personas estimada y porcentaje de la población, 
                 basándose en datos de la Encuesta de Caracterización Socioeconómica 
                 Nacional (Casen) 2024 del Ministerio de Desarrollo Social y Familia.",
  arguments = list(
    comuna = type_string(
      description = "Comuna de Chile que se desea consultar"
      )
  )
)

Esto es como hacer una especie de documentación de la función, pero enfocada en que los modelos de lenguaje sepan cómo y cuándo usar la función.

Para agregar herramientas al chatbot, basta con registrarlas en el objeto chat de esta manera:

chat$register_tool(herramienta)

Esta línea se agrega dentro de server, luego de crear el chat. Así, cuando se pregunte algo que active la herramienta, el modelo la usará automáticamente.

Ver código del chatbot con herramienta de consulta de datos
library(shiny)
library(bslib)
library(ellmer)
library(shinychat)

# código de limpieza de datos
source("datos_pobreza.R")

# código de la función de consulta de datos
source("funcion_pobreza.R")

ui <- page_fillable(
  chat_ui(
    id = "chat",
    messages = "**¡Hola!** ¿En qué te puedo ayudar hoy?"
  ),
  fillable_mobile = TRUE
)

server <- function(input, output, session) {
  
  # definir herramienta
  herramienta <- tool(
    consultar_pobreza,
    description = "Función que entrega datos de la estimación de pobreza por ingresos 
                   a nivel de cantidad de personas estimada y porcentaje de la población, 
                   basándose en datos de la Encuesta de Caracterización Socioeconómica 
                   Nacional (Casen) 2024 del Ministerio de Desarrollo Social y Familia.",
    arguments = list(
      comuna = type_string(
        description = "Comuna de Chile que se desea consultar"
      )
    )
  )
  
  # crear chat
  chat <- chat_anthropic(
    model = "claude-haiku-4-5",
    system_prompt = "Eres un chatbot respetuoso, útil y conciso. Responde muy 
                     brevemente solamente lo que se te pregunta, sin rodeos."
  )
  
  # entregar la herramienta al modelo
  chat$register_tool(herramienta)
  
  observeEvent(input$chat_user_input, {
    stream <- chat$stream_async(input$chat_user_input)
    chat_append("chat", stream)
  })
}

shinyApp(ui, server)

Ahora volvamos a probar el chatbot preguntándole lo mismo:

Ahora responde correctamente! 🥳

Si nos fijamos en la consola, vemos que el chatbot consultó correctamente la herramienta, y se basó en ella para responder:

Darle conocimientos especializados al chatbot

Por ahora el modelo responde correctamente desde los datos, pero si le preguntamos otras cosas, deja de responder bien:

Si bien la cifra es correcta, al preguntarle algo sobre la metodología de los datos, responde algo genérico para omitir que no sabe realmente de dónde viene la información.

Para hacer que el chatbot maneje conocimientos complejos o especializados, y que además responda preguntas limitándose a documentos específicos, podemos entregarle una herramienta para generación aumentada por recuperación o RAG. Esto significa que el modelo accederá a informes, manuales, papers, o cualquier material relevante para tu caso de uso.

Entonces descarguemos la metodología correspondiente a los datos que estamos trabajando:

Con el paquete {ragnar} podemos crear una base de conocimientos a partir de nuestros documentos y conectarla al chatbot, como se detalla en este tutorial.

Primero tenemos que crear una base de conocimientos:

library(ragnar)

store <- ragnar_store_create(
  location = "documentos.ragnar.duckdb",
  embed = NULL
)

Ahora cargamos los documentos y los procesamos:

metodologia <- read_as_markdown("content/blog/shinychat/estimaciones-sae-2024.pdf")

metodologia <- markdown_chunk(metodologia)

Finalmente los insertamos en la base y creamos el índice para que funcione:

ragnar_store_insert(store, informe_secciones)

ragnar_store_build_index(store)

Ahora, en el código de nuestro chatbot, agregamos la conexión a la base de conocimientos y luego, después de la creación del chat, ponemos el registro de la herramienta de RAG:

# conectarse a la base de conocimientos
store <- ragnar_store_connect("documentos.ragnar.duckdb", read_only = TRUE)
# registrar la herramienta de búsqueda en el modelo
ragnar_register_tool_retrieve(
  chat,
  store,
  store_description = "Base de conocimientos sobre metodología 
                       de cálculo de estimaciones de pobreza a
                       partir de la encuesta Casen 2024"
)
Ver código completo del chatbot con RAG
library(shiny)
library(bslib)
library(ellmer)
library(shinychat)
library(ragnar)

# código de limpieza de datos
source("datos_pobreza.R")

# código de la función de consulta de datos
source("funcion_pobreza.R")

ui <- page_fillable(
  chat_ui(
    id = "chat",
    messages = "**¡Hola!** ¿En qué te puedo ayudar hoy?"
  ),
  fillable_mobile = TRUE
)

server <- function(input, output, session) {
  
  # definir herramienta
  herramienta <- tool(
    consultar_pobreza,
    description = "Función que entrega datos de la estimación de pobreza por ingresos 
                   a nivel de cantidad de personas estimada y porcentaje de la población, 
                   basándose en datos de la Encuesta de Caracterización Socioeconómica 
                   Nacional (Casen) 2024 del Ministerio de Desarrollo Social y Familia.",
    arguments = list(
      comuna = type_string(
        description = "Comuna de Chile que se desea consultar"
      )
    )
  )
  
  # crear chat
  chat <- chat_anthropic(
    model = "claude-haiku-4-5",
    system_prompt = "Eres un chatbot respetuoso, útil y conciso. Responde muy 
                     brevemente solamente lo que se te pregunta, sin rodeos."
  )
  
  # entregar la herramienta al modelo
  chat$register_tool(herramienta)
  
  # conectarse a la base de conocimientos
  store <- ragnar_store_connect("documentos.ragnar.duckdb", read_only = TRUE)
  
  # registrar la herramienta de búsqueda en el modelo
  ragnar_register_tool_retrieve(
    chat,
    store,
    store_description = "Base de conocimientos sobre metodología 
    de cálculo de estimaciones de pobreza Casen 2024"
  )
  
  observeEvent(input$chat_user_input, {
    stream <- chat$stream_async(input$chat_user_input)
    chat_append("chat", stream)
  })
}

shinyApp(ui, server)

Igual que con las herramientas, esto va en el server junto al objeto chat. Una vez registrada, la IA decidirá cuándo necesita consultar los documentos para responder mejor, y lo hará automáticamente.

Ahora volvemos a probar el chatbot con una pregunta compleja:

Ahora sí, en vez de chamullar una respuesta, el chatbot se basa en el documento entregado para dar una respuesta precisa informada por el texto!


Con estos tres elementos (el chatbot base, las herramientas de consulta de datos y la consulta de documentos con RAG), y sumándole un buen system prompt, puedes construir en nada de tiempo asistentes de IA útiles y confiables, adaptados completamente a tus datos y necesidades, sin depender de ninguna plataforma de chat externa.

Estos asistentes puedes ponerlos en tus aplicaciones Shiny y luego publicar tus apps a internet, o insertarlos/embeberlos en otros sitios web.

Personalmente he desarrollado varios chatbots que consultan datos complejos de estudios, y su funcionamiento es excelente, incluso con los modelos de inteligencia artificial más pequeños, porque la gracia es que R apoya a la IA con datos e información para responder correctamente, en vez de depender de modelos de IA gigantes que aspiran a saberlo todo (cosa que es imposible).

Fecha de publicación:
June 1, 2026
Extensión:
15 minute read, 3016 words
Categorías:
Tutoriales
Tags:
shiny inteligencia artificial
Ver también:
Aumenta el conocimiento de inteligencias artificiales creando un sistema de RAG con R
Tutorial: Crea aplicaciones web interactivas en R con Shiny
Usando tipografías personalizadas en aplicaciones Shiny