The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

LLMRagent in 10 minutes

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 timing

Budgets: 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.

frugal <- agent("Frugal", cfg, budget = budget(max_calls = 2))
frugal$chat("one")
frugal$chat("two")
tryCatch(frugal$chat("three"),
         llmragent_budget_error = function(e) "stopped by budget, as designed")

Structured answers

schema <- list(
  type = "object",
  properties = list(stance = list(type = "string",
                                  enum = list("support", "oppose", "unsure")),
                    reason = list(type = "string")),
  required = list("stance", "reason")
)
ada$ask_structured("Should small samples use t or z intervals?", schema)

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 here

Pipelines: 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 trail

A 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$transcript

From 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.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.