hellmer
enables sequential or parallel batch processing
for chat
models supported by ellmer
.
Process multiple chat interactions with:
You can install the package from CRAN with:
install.packages("hellmer")
ellmer
will look for API keys in your environmental
variables. I recommend the usethis
package to setup API
keys in your .Renviron
such as
OPENAI_API_KEY=your-key
.
::edit_r_environ(scope = c("user", "project")) usethis
library(hellmer)
<- chat_sequential(
chat
chat_openai, system_prompt = "Reply concisely, one sentence"
)
<- list(
prompts "What is R?",
"Explain base R versus tidyverse"
)
<- chat$batch(prompts) result
Access the results:
$progress()
result#> $total_prompts
#> [1] 2
#>
#> $completed_prompts
#> [1] 2
#>
#> $completion_percentage
#> [1] 100
#>
#> $remaining_prompts
#> [1] 0
#>
#> $state_path
#> [1] "/var/folders/.../chat_c5383b1279ae.rds"
$texts()
result#> [[1]]
#> [1] "R is a programming language and software environment used for
#> statistical computing, data analysis, and graphical representation."
#>
#> [[2]]
#> [1] "Base R refers to the original set of R functions and packages,
#> while tidyverse is a collection of R packages designed for data science
#> that offer a more consistent and readable syntax."
$chats()
result#> [[1]]
#> <Chat turns=3 tokens=22/21>
#> ── system ────────────────────────────────────────────────────────────
#> Reply concisely, one sentence
#> ── user ───────────────────────────────────────────────────────────────
#> What is R?
#> ── assistant ──────────────────────────────────────────────────────────
#> R is a programming language and software environment used for
#> statistical computing, data analysis, and graphical representation.
#> ...
<- chat_future(chat_openai,
chat system_prompt = "Reply concisely, one sentence")
When using parallel processing with chat_future
, there’s
a trade-off between safety and performance:
chunk_size
ensures progress is saved to the disk more
frequently, allowing recovery if something goes wrong (default: number
of prompts / 10)chunk_size
equal to the number of prompts results in a 4-5x
faster processing speed but progress will not be saved to the disk until
all chats are processed$batch(prompts, chunk_size = length(prompts)) chat
Register and use tools/function calling:
<- function(tz = "UTC") {
get_current_time format(Sys.time(), tz = tz, usetz = TRUE)
}
$register_tool(tool(
chat
get_current_time,"Gets the current time in the given time zone.",
tz = type_string(
"The time zone to get the current time in. Defaults to `\"UTC\"`.",
required = FALSE
)
))
<- list(
prompts "What time is it in Chicago?",
"What time is it in New York?"
)
<- chat$batch(prompts)
result
$texts()
result#> [[1]]
#> [1] "The current time in Chicago is 9:29 AM CDT."
#>
#> [[2]]
#> [1] "The current time in New York is 10:29 AM EDT."
Extract structured data using type specifications:
<- type_object(
type_sentiment "Extract sentiment scores",
positive_score = type_number("Positive sentiment score, 0.00 to 1.00"),
negative_score = type_number("Negative sentiment score, 0.00 to 1.00"),
neutral_score = type_number("Neutral sentiment score, 0.00 to 1.00")
)
<- list(
prompts "The R community is really supportive and welcoming.",
"R has both base functions and tidyverse functions for data manipulation.",
"R's object-oriented system is confusing, inconsistent, and painful to use."
)
<- chat$batch(prompts, type_spec = type_sentiment)
result
$texts()
result#> [[1]]
#> $positive_score
#> [1] 0.95
#>
#> $negative_score
#> [1] 0.05
#>
#> $neutral_score
#> [1] 0
#> ...
To iteratively refine structured data extractions, implement
LLM-as-a-judge into the chat turns using the judgements
parameter (increases token use):
<- chat$batch(prompts, type_spec = type_sentiment, judgements = 1)
result
$texts()
result#> [[1]]
#> [[1]]$positive_score
#> [1] 0.95
#>
#> [[1]]$negative_score
#> [1] 0
#>
#> [[1]]$neutral_score
#> [1] 0.05
#> ...
Batch processing automatically saves progress to an .rds
file on the disk and allows you to resume interrupted operations:
<- chat$batch(prompts, state_path = "chat_state.rds") result
If state_path
is not defined, a temporary file will be
created by default.
Control verbosity with the echo
parameter (sequential
only):
"none"
: Silent operation with progress bar"text"
: Show chat responses only"all"
: Show both prompts and responses<- chat_sequential(
chat
chat_openai, echo = "none"
)
Automatically retry failed requests with exponential backoff, which
serves as a wide guardrail against errors while ellmer
and
httr2
serve as a narrow guardrail against specific API
limits:
<- chat_sequential(
chat # ellmer chat model
chat_openai, max_retries = 3, # maximum retry attempts
initial_delay = 20, # initial delay in seconds
max_delay = 80, # maximum delay between retries
backoff_factor = 2 # multiply delay by this factor after each retry
)
If a request fails, the code will:
initial_delay
backoff_factor
)max_retries
is reachedIf the code detects an authorization or API key issue, it will stop immediately.
The timeout parameter specifies the maximum time to wait for a response from the chat model for each prompt. However, this parameter is still limited by the timeouts propagated up from the chat model functions.
<- chat_future(
chat
chat_openai,system_prompt = "Reply concisely, one sentence"
timeout = 60
)
Toggle sound notifications on batch completion, interruption, and error:
<- chat_sequential(
chat
chat_openai,beep = TRUE
)
progress()
: Returns processing statustexts()
: Returns response texts in the same format as
the input prompts (i.e., a list if prompts were provided as a list, or a
character vector if prompts were provided as a vector). When a type
specification is provided, it returns structured data instead of plain
text.chats()
: Returns a list of chat objectschat_openai()
as a user-defined object instead of the
chat_openai
function? Of course you can! Learn more about
the two methods and the default interface.