commons builds self-service data science agents for your organization: agents that answer data questions using the definitions your data team already maintains.
An agent is built from a data_source(), which is what it can query,
and a semantic_layer(), which is a pool of trusted calculations. When
a question matches a measure in the semantic layer, the agent runs that
measure. When nothing matches, it falls back to reading your data
documentation and writing a SQL query.
Installation
install.packages("commons")Usage
library(commons)Point a data source at a database and, optionally, at a data dictionary describing it:
con <- DBI::dbConnect(duckdb::duckdb()) DBI::dbWriteTable(con, "orders", data.frame( region = c("EMEA", "Americas", "EMEA", "APAC"), revenue = c(500, 900, 1200, 300), refunded = c(0, 100, 0, 0) )) sales <- data_source(con, tables = "orders")
Define the calculations you want the agent to prefer. Arguments that
aren’t in the arguments schema are hidden from the model. An argument
named after a data source receives that source’s connection.
measure_file <- tempfile(fileext = ".R") writeLines( c( "#' Net Revenue by Region", "#'", "#' @param region `enum[EMEA, Americas, APAC]` Sales region.", "#' @measure", "net_revenue_by_region <- function(region, warehouse) {", " DBI::dbGetQuery(", " warehouse,", " 'SELECT sum(revenue - refunded) AS net FROM orders WHERE region = ?',", " params = list(region)", " )", "}" ), measure_file ) layer <- semantic_layer(measure_file) unlink(measure_file)
Then, assemble the pieces with commons(). The function outputs an
ellmer::Chat, so it works with
shinychat out of the box.
agent <- commons( ellmer::chat_anthropic(), data_sources = list(warehouse = sales), semantic_layer = layer ) agent$chat("What was net revenue in EMEA?") #> Net revenue in EMEA was $1,700.
That answer came from net_revenue_by_region, not from SQL the model
wrote, so “net revenue” means what your organization says it means.
See vignette("commons") to learn more.