One interface to many large language model providers: a single configuration object and a single calling function serve chat and embedding models alike, so research code does not change when the provider does. The same calls scale to multi-model and multi-condition studies. Small open models can also run on the user's computer through 'llama.cpp', downloaded only on request, with access to next-token probabilities.

LLMR supplies a common provider interface for language-model studies in R.
One llm_config() object separates provider and model settings from the study
code. The same interface supports single calls, tidy data-frame operations,
multi-model experiments, and call records for replication and reporting.
Providers: OpenAI, Anthropic, Gemini (including Vertex), Groq, Together, DeepSeek, xAI, OpenRouter, Meta (Muse), Voyage, Ollama, Xiaomi MiMo, Alibaba (Qwen), Zhipu, and Moonshot, and small open models run on one's own computer through llama.cpp.
LLMR treats a model call as one part of a study workflow. You can apply one measurement instruction across rows, compare providers or conditions with a factorial design, repeat stochastic measurements, and retain the request, response, settings, status, timing, and token counts for each call. Results are data frames that can enter the rest of an R analysis.
install.packages("LLMR")
# remotes::install_github("asanaei/LLMR")
Store keys in environment variables such as GROQ_API_KEY, OPENAI_API_KEY,
or ANTHROPIC_API_KEY, commonly in ~/.Renviron. llm_config() reads the
provider's variable, so the key need not appear in the analysis code.
library(LLMR)
cfg <- llm_config(
"groq", "openai/gpt-oss-20b",
temperature = 0.2,
max_tokens = 256
)
llm_mutate() evaluates a glue-style instruction for each row and appends the
response and diagnostic columns.
reviews <- data.frame(
id = 1:3,
text = c("Clear and useful.", "It failed twice.", "The result was adequate.")
)
review_labels <- reviews |>
llm_mutate(
sentiment = "Classify {text} as positive, negative, or neutral. One word.",
.config = cfg
)
For a vector, llm_fn() uses {x} as the value in the instruction.
labels <- llm_fn(
reviews$text,
"Classify {x} as positive, negative, or neutral. One word.",
.config = cfg,
.return = "text"
)
build_factorial_experiments() crosses model configurations, instruction
conditions, system messages, and repetitions. It preserves labels for each
factor. call_llm_par() runs the design and returns an llmr_experiment data
frame with responses, status fields, timing, and token counts.
cfg_openai <- llm_config(
"openai", "gpt-4.1-nano",
temperature = 0.2,
max_tokens = 256
)
experiments <- build_factorial_experiments(
configs = list(cfg, cfg_openai),
config_labels = c("groq", "openai"),
user_prompts = c(
"Classify: The service was adequate.",
"Assign a sentiment label to: The service was adequate."
),
user_prompt_labels = c("classify", "assign"),
system_prompts = "Return positive, negative, or neutral.",
repetitions = 3
)
results <- call_llm_par(experiments, max_workers = 4, progress = TRUE)
For designs built in stages, call_llm_compare() compares configurations,
call_llm_sweep() varies generation settings, and llm_par_resume() reruns
failed or incomplete rows. See Small experiment with
LLMR.
Logging records calls made by single, tidy, chat, and parallel interfaces in a
JSONL file. llm_log_read() returns the stored records and a manifest with
request and record hashes.
log_path <- tempfile(fileext = ".jsonl")
llm_log_enable(log_path)
results <- call_llm_par(experiments, max_workers = 4)
llm_log_disable()
call_log <- llm_log_read(log_path)
call_log$manifest
llm_usage(results)
llm_failures(results)
report(results, task = "to compare sentiment instructions")
Repeated measurements require a configuration that permits sampling.
llm_replicate() adds one column per repetition, and llm_agreement()
summarizes per-row agreement and overall reliability.
replicated <- reviews |>
llm_replicate(
sentiment,
prompt = "Classify {text} as positive, negative, or neutral. One word.",
.config = cfg,
.times = 3
)
agreement <- llm_agreement(replicated, prefix = "sentiment")
See Reproducibility and cost for logging scope, token and cost summaries, caching, and provider batch jobs.
Schema mode requests typed JSON and validates it locally; supported providers can also enforce the schema. Tagged output extracts named fields from marked text when strict schema enforcement is unnecessary.
schema <- list(
type = "object",
properties = list(
label = list(
type = "string",
enum = list("positive", "negative", "neutral")
)
),
required = list("label"),
additionalProperties = FALSE
)
strict_labels <- reviews |>
llm_mutate(
classification = "Classify the sentiment of: {text}",
.config = cfg,
.structured = TRUE,
.schema = schema
)
tagged_labels <- reviews |>
llm_mutate(
classification = "Classify {text} and give a short reason.",
.config = cfg,
.tags = c("label", "reason")
)
Use llm_parse_structured_col() or llm_parse_tags_col() to parse fields from
an existing response column.
call_llm() accepts a string, named role vector, or message list and returns an
llmr_response with text, finish reason, identifiers, timing, and usage.
response <- call_llm(
cfg,
c(system = "Answer in one word.", user = "Capital of Mongolia?")
)
as.character(response)
tokens(response)
chat_session() creates a stateful conversation that retains prior turns. The
session object's send() method adds a turn and calls the model.
chat <- chat_session(cfg, system = "You teach statistics in short answers.")
See Simple chat with LLMR for the session methods.
Embedding configurations return numeric vectors for similarity or downstream models.
embedding_cfg <- llm_config("voyage", "voyage-3.5-lite", embedding = TRUE)
texts <- c("Quiet rivers mirror bright skies.", "Thunder crosses the valley.")
embeddings <- get_batched_embeddings(texts, embedding_cfg, batch_size = 8)
dim(embeddings)
llm_tool() and call_llm_tools() let a model request registered R functions.
call_llm_stream() supplies generated text to a callback. The
llm_batch_submit(), llm_batch_status(), llm_batch_fetch(), and
llm_batch_cancel() functions manage provider batch jobs whose timing and
pricing depend on the provider. See Interactive
calls and the
embeddings article.
A small open model can run on the researcher's computer through llama.cpp. One call downloads the llama.cpp server for the platform and the model, after showing their licenses and asking for agreement; every file is pinned and checked against its sha256.
llm_local_install("qwen3-0.6b")
cfg <- llm_config("llamacpp", "qwen3-0.6b", temperature = 0, thinking = FALSE)
call_llm(cfg, "What is the capital of France?")
Such a model shows what hosted models hide. llm_next_token() returns the
probability of every possible next token after a context, llm_continue()
continues a reply whose beginning the researcher writes, and llm_score()
gives the log-probability of a text the model did not write:
llm_next_token(cfg, messages = "Capital of France?", prefill = "The capital of France is", top_n = 10)
llm_continue(cfg, messages = "Is coffee good for you?",
prefill = "Honestly, I am not sure, but", n = 5, temperature = 1, seed = 110)
llm_score(cfg, " Lyon.", prompt = "The capital of France is")
Multilingual embedding models, from multilingual-e5-small (132 MB) to
bge-m3 (635 MB), install the same way and serve get_batched_embeddings(). See the local models
article.
| Task | Function |
|---|---|
| Configure a provider and model | llm_config() |
| Single prompt | call_llm() / call_llm_robust() |
| Vector of prompts | llm_fn() |
| Data-frame pipeline | llm_mutate() |
| Repeated row measurements | llm_replicate() + llm_agreement() |
| Factorial design | build_factorial_experiments() + call_llm_par() |
| Compare models or settings | call_llm_compare() / call_llm_sweep() |
| Resume incomplete parallel work | llm_par_resume() |
| Record and inspect calls | llm_log_enable() / llm_log_read() |
| Usage, failures, and methods text | llm_usage() / llm_failures() / report() |
| JSON with schema | .structured = TRUE / llm_mutate_structured() |
| Tag-based extraction | .tags / llm_mutate_tags() |
| Parse existing column | llm_parse_structured_col() / llm_parse_tags_col() |
| Stateful conversation | chat_session() |
| R function tools | llm_tool() + call_llm_tools() |
| Streaming response | call_llm_stream() |
| Embeddings | get_batched_embeddings() |
| Install and run a local model | llm_local_install() + llm_config("llamacpp", ...) |
| Next-token distribution, prefilled replies, text probabilities | llm_next_token() / llm_continue() / llm_score() |
| Provider batch job | llm_batch_submit() + llm_batch_status() + llm_batch_fetch() |
LLMR supplies the common provider interface for a family of packages for LLM-assisted research. LLMRagent builds agents and multi-agent designs on top of it. LLMRcontent codes text according to a codebook and compares the codes with human labels. It can examine estimates across alternative prompts and models and construct replication archives from LLMR's call logs. LLMRpanel administers surveys and experiments to panels of model personas. FocusGroup runs moderated discussions among model agents. An overview of the family lives at the package family page.
Bug reports and feature requests: GitHub Issues. Pull requests welcome. See CONTRIBUTING.md.
This project uses the MIT License; see LICENSE.