--- title: "Análisis de texto" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Análisis de texto} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set(collapse = TRUE, comment = "#>", eval = FALSE) ``` > *English version:* `vignette("text-analysis", package = "ellmercodex")`. Los modelos de lenguaje son útiles en investigación cuando devuelven algo con lo que R puede trabajar, no solo prosa. Este artículo usa intervenciones de un debate parlamentario uruguayo sobre la regulación del cannabis para mostrar dos funciones de `ellmer` que funcionan con `ellmercodex`: los datos estructurados y las llamadas a herramientas. Los ejemplos están inspirados en el [artículo sobre `ellmercodex` en el blog](https://simxnherrera.github.io/blog/ellmercodex/). Las salidas que se muestran provienen de una sesión real con `gpt-6-luna`. ```{r} library(ellmercodex) chat <- chat_codex(model = "gpt-6-luna", effort = "low") ``` ## Clasifica un fragmento Con `$chat_structured()` describes el resultado que quieres con el sistema de tipos de `ellmer`, y el modelo tiene que responder con esa forma. Aquí pedimos una orientación sobre política de drogas, a partir de un conjunto fijo de códigos, junto con una breve justificación: ```{r} # Fragmento real del debate fragmento <- paste( "seguimos pensando que además de la represión y del combate al", "narcotráfico que debe seguir con firmeza y decisión como sociedad", "debemos apostar a dos o tres pilares fundamentales la educación", "la prevención y la rehabilitación" ) resultado <- chat$chat_structured( paste( "Clasifica el fragmento como PREVENTIVA, PUNITIVA, MIXTA o", "SIN_ORIENTACIÓN_ATRIBUIBLE.", "Usa MIXTA cuando se defiendan simultáneamente respuestas", "preventivas y punitivas.", "\n\nFragmento:", fragmento ), type = ellmer::type_object( codigo = ellmer::type_enum(c( "PREVENTIVA", "PUNITIVA", "MIXTA", "SIN_ORIENTACIÓN_ATRIBUIBLE" )), justificacion = ellmer::type_string() ) ) resultado #> $codigo #> [1] "MIXTA" #> #> $justificacion #> [1] "El fragmento defiende explícitamente la represión y el combate al #> narcotráfico, que son respuestas punitivas, y simultáneamente propone la #> educación, la prevención y la rehabilitación, de carácter preventivo o #> rehabilitador." ``` El resultado es una lista de R, así que puedes ponerlo en un `data.frame`, validarlo o analizarlo junto a los códigos de codificadores humanos. El artículo de `ellmer` sobre [datos estructurados](https://ellmer.tidyverse.org/articles/structured-data.html) (en inglés) explica el sistema de tipos en detalle, incluido cómo extraer varias filas a la vez. ## Deja que el modelo llame a tus funciones de R Supongamos que ya clasificaste muchas intervenciones: ```{r} intervenciones <- data.frame( partido = c("FA", "FA", "PN", "PN", "PN"), orientacion = c("PREVENTIVA", "MIXTA", "PUNITIVA", "PUNITIVA", "MIXTA") ) ``` En vez de pegar los datos en el prompt, puedes darle al modelo una herramienta: una función de R que puede llamar cuando necesita información. Esta cuenta las orientaciones de un partido y devuelve JSON, que es lo que `ellmer` espera de una herramienta: ```{r} resumir_partido <- function(partido_buscado) { intervenciones |> dplyr::filter(partido == partido_buscado) |> dplyr::count(orientacion) |> jsonlite::toJSON() } resumen_tool <- ellmer::tool( resumir_partido, name = "resumir_partido", description = "Cuenta las orientaciones discursivas de un partido.", arguments = list(partido_buscado = ellmer::type_string()) ) chat$register_tool(resumen_tool) chat$chat( paste( "Compara las orientaciones discursivas de FA y PN.", "Usa la herramienta disponible." ) ) #> FA presenta una orientación **mixta** y una **preventiva** (una observación #> de cada tipo). PN presenta una orientación **mixta** y dos **punitivas**. #> En común, ambos tienen una orientación mixta; la diferencia es que FA #> incluye una preventiva, mientras que PN se inclina más hacia lo punitivo. ``` El modelo decidió llamar a `resumir_partido()` para cada partido, recibió los resultados calculados por R y los usó en su respuesta. Una herramienta también podría consultar una base de datos, buscar en un corpus o llamar a una API. R siempre ejecuta las funciones: el modelo solo puede usar las herramientas que registres, y decide cuándo llamarlas y con qué argumentos. El artículo de `ellmer` sobre [llamadas a herramientas](https://ellmer.tidyverse.org/articles/tool-calling.html) (en inglés) explica cómo diseñar buenas herramientas. ## Combina las dos cosas Como en `ellmer`, `$chat_structured()` no usa las herramientas registradas. Cuando necesites ambas cosas, reúne primero el contexto con `$chat()` y después extrae el resultado con `$chat_structured()` en la misma conversación: ```{r} chat$chat("Usa la herramienta para obtener las orientaciones de FA y PN.") conteos <- chat$chat_structured( "Devuelve los conteos que acabas de obtener.", type = ellmer::type_array( ellmer::type_object( partido = ellmer::type_string(), orientacion = ellmer::type_string(), n = ellmer::type_integer() ) ) ) conteos #> # A tibble: 4 x 3 #> partido orientacion n #> #> 1 FA MIXTA 1 #> 2 FA PREVENTIVA 1 #> 3 PN MIXTA 1 #> 4 PN PUNITIVA 2 ```