Skip to contents

react() builds an agent that alternates between reasoning and calling tools until it can answer, then returns a structured answer that follows the signature (the ReAct pattern).

Usage

react(
  signature,
  tools = list(),
  max_iterations = 10L,
  chat = NULL,
  template = "",
  demos = list(),
  config = list(),
  ...
)

Arguments

signature

A signature from signature(), or a signature string.

tools

A list of ellmer tool definitions, made with ellmer::tool(), ragnar_tool(), create_search_tool() or as_ellmer_tool(). Their names must be unique. The module's $add_tool(tool, replace = FALSE) adds one later; with replace = TRUE it replaces the tool of the same name.

max_iterations

Maximum number of tool-calling rounds. Several tool calls in one model turn count as one round. Exceeding the limit is an error.

chat, template, demos, config

As in module().

...

Must be empty.

Value

A module (an R6 object of class ReactModule) to use with run() and run_dataset().

Details

ellmer runs the tool-calling loop: the model's tool requests are executed and their results sent back, keeping ellmer's turn history and tool-call IDs. After the loop, one more request asks for the final answer in the signature's output format. ReAct calls do not use the response cache.

run() accepts one input at a time for this module; use run_dataset() for several. With .return_format = "structured", the metadata records iterations, tool_calls and tools_used.

Examples

lookup_population <- ellmer::tool(
  function(city) {
    switch(city, Paris = "2.1 million", Lyon = "0.5 million", "unknown")
  },
  name = "lookup_population",
  description = "Look up the population of a French city.",
  arguments = list(city = ellmer::type_string("City name"))
)

agent <- react(
  "question -> answer",
  tools = list(lookup_population),
  max_iterations = 5L
)
agent
#> 
#> ── ReactModule ──
#> 
#> ── Signature 
#> 
#> ── Signature ──
#> 
#> ── Inputs 
#> • question: "string" - Input: question
#> 
#> ── Output 
#> Type: "object(answer: string)"
#> 
#> ── Instructions 
#> Given the fields `question`, produce the fields `answer`.
#> 
#> ── Tools 
#> • lookup_population
#> Max iterations: 5

if (FALSE) { # \dontrun{
llm <- ellmer::chat_openai(model = "gpt-6-luna")
run(agent, question = "How many more people live in Paris than in Lyon?", .llm = llm)

questions <- data.frame(question = c("Population of Paris?", "Population of Lyon?"))
run_dataset(agent, questions, .llm = llm)
} # }