An agent is three things: a model (an
LLMR::llm_config()), a persona (a system prompt), and
machinery around them: memory, tools, and budgets. This vignette builds
one of each component. Examples use the open-weight
gpt-oss-20b on Groq; set GROQ_API_KEY and
LLMRAGENT_RUN_VIGNETTES=true to run them.
library(LLMRagent)
cfg <- LLMR::llm_config("groq", "openai/gpt-oss-20b", temperature = 0.7)A first agent
ada <- agent(
"Ada", cfg,
persona = "You are Ada, a meticulous statistician. Answer in one or two sentences."
)
ada$chat("What is overfitting?")
ada$chat("How would I detect it in practice?") # remembers the thread
ada$usage()chat() is stateful: the agent keeps its own memory (last
40 messages by default; see ?memory for summarizing and
retrieval policies). reply() is the stateless sibling, used
internally by conversations. For long answers,
chat(stream = TRUE) prints tokens as they are
generated:
ada$chat("Explain cross-validation to a newcomer, in one paragraph.",
stream = TRUE)Tools: let the agent call your R functions
Anything you can write as an R function can become a tool. The agent decides when to call it; LLMRagent executes the call and feeds the result back.
lookup_gdp <- LLMR::llm_tool(
function(country) {
gdp <- c(chile = 335, uruguay = 81, bolivia = 47) # USD bn, illustrative
val <- gdp[tolower(country)]
if (is.na(val)) "unknown" else paste0("$", val, " billion")
},
name = "lookup_gdp",
description = "Look up a country's GDP in USD billions.",
parameters = list(country = list(type = "string", description = "Country name"))
)
analyst <- agent("Analyst", cfg, tools = lookup_gdp,
persona = "A careful economic analyst. Use tools for any figure.")
analyst$chat("Compare the GDPs of Chile and Uruguay using the lookup tool.")
analyst$trace() # every model call and tool call, with tokens and timingBudgets: spend ceilings the agent cannot cross
Budgets are checked before each call; the call that would exceed a limit is refused with a typed error, so a loop cannot spend without you seeing it.
Agents calling agents
agent_as_tool() turns an agent into a tool, so another
agent can consult it. The supervisor decides for itself when to
delegate; each consultation runs on the specialist’s own meter (its
usage(), its budget()).
stat <- agent("Stat", cfg,
persona = "A PhD statistician. Precise about assumptions.")
hist <- agent("Hist", cfg,
persona = "An economic historian. Institutional context.")
lead <- agent("Lead", cfg,
persona = "A research lead. Consult specialists, then synthesize.",
tools = list(agent_as_tool(stat), agent_as_tool(hist)))
lead$chat("Crime fell while policing budgets rose, across many cities.
What would it take to argue causality?")
stat$usage() # the consultation showed up herePipelines: a fixed sequence of specialists
When the routing is fixed rather than model-chosen, chain agents with
agent_pipeline(): each stage transforms the previous
stage’s output, and every intermediate product is kept.
run <- agent_pipeline(
list(
agent("Extractor", cfg, persona =
"Extract every factual claim as a numbered list. Nothing else."),
agent("Checker", cfg, persona =
"Mark each numbered claim VERIFIABLE or VAGUE, one line each."),
agent("Editor", cfg, persona =
"Rewrite the original passage keeping only VERIFIABLE claims.")
),
input = "Our app doubled retention, won three design awards, and users love it."
)
run$output
run$steps # step, agent, input, output -- the full audit trailA two-agent conversation
Conversations run over a shared, speaker-attributed transcript: every agent sees the full dialogue each turn, and the transcript comes back as a tidy tibble, ready for text analysis.
rosa <- agent("Rosa", cfg, persona = "A pragmatic city planner. Concrete and brief.")
hugo <- agent("Hugo", cfg, persona = "A skeptical economist. Numbers first. Brief.")
conv <- conversation(
list(rosa, hugo),
topic = "Should the city pedestrianize its center?",
max_turns = 4,
instruction = "At most three sentences per turn."
)
conv$transcriptFrom here: vignette("designed-conversations") tours the
ready-made study formats (debates, focus groups, interviews,
deliberations); vignette("deliberation-experiment") runs a
complete factorial study with agent_experiment(); and
vignette("super-brain") shows strong-plus-cheap model
orchestration with think_harder(). For a per-call audit
file of everything an agent did, turn on
LLMR::llm_log_enable() before running.
