A backend is a function function(prompt, model, row) that sends prompt
to model and returns the raw text response (a length-one character
vector). row is the corresponding row of the design and can be ignored.
A backend may instead return a list with elements text and meta;
meta (a named list, e.g. token counts or the model snapshot id
reported by the API) is stored with the run. Any client library can be
wrapped this way; three backends are provided.
Usage
backend_mock(
truth,
levels = NULL,
thresholds = NULL,
sd_prompt = 0.2,
sd_model = 0.2,
sd_rep = 0.3,
p_fail = 0,
template = "The result is: %s.",
seed = NULL
)
backend_ellmer(chats)
backend_openai_compatible(
base_url = "https://api.openai.com/v1",
api_key = Sys.getenv("OPENAI_API_KEY"),
temperature = 0,
system = NULL,
max_tokens = NULL,
timeout = 120,
...
)Arguments
- truth
A named vector giving the latent true value of every
item_id(numeric). For ordinal mocks this is the latent position; the label is obtained by cutting atthresholds.- levels
Optional ordered labels. If given, the mock returns a label; otherwise it returns a number.
- thresholds
Cut points on the latent scale (length
length(levels) - 1).- sd_prompt, sd_model, sd_rep
Standard deviations of the prompt effect, the model effect and the replicate noise on the latent scale. Prompt and model effects are drawn once per prompt id / model id and kept fixed.
- p_fail
Probability that the mock returns an unparseable response, to exercise failure handling.
- template
A sprintf-style sentence with one
%sfor the value.- seed
Seed for the mock's private random number stream. With an explicit seed, each row's noise and failure draw depend only on
block,item_id,prompt_id,model_idandrep, so a newly created mock can resume a stored run. Missingblockandrepdefault to 1. The row stream starts at the seed modulo 2147483647, then folds the UTF-8 bytes of each length-prefixed part (byte_length:part, concatenated in that order) withs = (131 * s + byte) %% 2147483647. These are integer hash parameters, not statistical reference constants. Prompt and model effects retain their separate per-ID streams. Private draws restore the caller's RNG state, including an absent state. WithNULL, construction samples a private seed from the caller's RNG as before.- chats
For
backend_ellmer(): anellmerChat object, or a named list of Chat objects keyed by model id.- base_url, api_key, temperature, system, max_tokens, timeout, ...
For
backend_openai_compatible(): server URL (without the trailing/chat/completions), API key (may be empty for local servers), sampling temperature, optional system message, token limit, request timeout in seconds, and further fields merged into the JSON body.temperature = NULLomits the temperature field. A non-empty, non-NArow$systemoverridessystemand precedes the user message. The reply'sid,model(asmodel_snapshot),usage,system_fingerprint(including null) and optionalproviderare recorded inmeta. A reasoning text inmessage.reasoning(as some OpenRouter endpoints return it) is recorded asreasoningwhen it is a non-empty string; otherwise the key is absent.reasoning_detailsis not stored.finish_reasonandnative_finish_reasonof the first choice are recorded under these names when they are non-empty strings, so that a reply cut at the token limit can be told apart from an unreadable one. Requested routing is recorded asprovider_order,quantizationsandallow_fallbacks. Requestedseed,temperatureandreasoning_effort, when present, are retained as metadata for comparison with the study plan, and the request timeout astimeout_s. Onlymessage.contentis parsed; credentials and headers are not stored.
Details
backend_mock()simulates an LLM for examples, tests and teaching. The default simulation draws a latent score from the item'struthplus prompt, model and replicate noise and writes a short sentence that contains the resulting label or number, so that the whole chain from prompt to parser can be exercised offline.backend_ellmer()wraps one or severalellmerchat objects (one per model id). Each call uses a fresh clone, so no conversation history leaks between calls. The last turn's response fieldsmodel,providerandusage, when present, are retained asmodel_snapshot,providerandusageinmeta. Missing fields are not inferred from the request. Without ellmer the diagnostic is: "Packageellmeris required for backend_ellmer()."backend_openai_compatible()talks to any server that implements the OpenAI chat-completions API: OpenAI itself, Ollama (base_url = "http://localhost:11434/v1"), vLLM, LM Studio, Azure-style proxies.
Examples
truth <- c(v1 = 1.2, v2 = -0.4)
bk <- backend_mock(truth, levels = c("Benign", "VUS", "Pathogenic"),
thresholds = c(-0.5, 0.5), seed = 1)
bk("Classify v1", "model-a", list(item_id = "v1", prompt_id = "P1", model_id = "model-a"))
#> $text
#> [1] "The result is: Pathogenic."
#>
#> $meta
#> $meta$mock
#> [1] TRUE
#>
#> $meta$latent
#> [1] 0.7722709
#>
#>