Skip to main content
Predict<S> is the leaf module. One Predict is one prompt template and one LM call: it formats a signature’s fields, instruction, and demos into a prompt, sends it to the configured LM, and parses the response into S::Output. Every other module ultimately delegates to one or more Predict leaves, and optimizers tune a program by rewriting Predict state (instruction override and demos). See How DSRs thinks for the mental model.

Usage

The derive generates QAInput and QAOutput from the field markers. .call() returns Result<Predicted<QAOutput>, PredictError>, and Predicted<O> implements Deref<Target = O>, so output fields read directly off the result. Everything beyond the defaults, such as demos, an instruction override, tools, or a per-instance LM, goes through the builder.

Construction

PredictBuilder<S>

Demo<S> is the typed input/output pair for few-shot prompting: Demo::new(input, output) with public fields input: S::Input and output: S::Output. Demos render as user/assistant exchanges in the prompt, and the types guarantee a demo matches the signature — a Demo<QA> cannot be attached to a Predict<SummarizeSig>. To seed a demo from a labeled trainset row, project the row through its ToInput/ToOutput impls: Demo::new(row.to_input()?, row.to_output()?), see Data. Tools are settable only at build time. Demos and the instruction override are also writable after construction through the optimizer seam (DynPredictor::apply_update, load_state), see State. The formatted system message and demo turns are cached once per (instruction, demos) configuration; every state mutation invalidates the cache.

Calling

Each call executes this pipeline:
  1. Build the chat: cached system + demo prefix, plus the input formatted as the live user message.
  2. Resolve the LM: the per-instance .lm(...) if set, otherwise the global configure() LM.
  3. Consult any active replay scope (see below).
  4. Send via LM::call_with_toolset in ToolLoopMode::Auto, executing tool calls up to max_tool_iterations.
  5. Parse the response into S::Output through the [[ ## field ## ]] protocol, evaluating #[check] and #[assert] constraints.
  6. Record a trace span when inside a capture() scope.

Replay interception

Before constructing any client, Predict consults the active replay scope. A Serve directive returns the recorded span with zero provider calls and zero tool re-executions; a Refuse directive returns PredictError::Replay; Live (or no scope) proceeds normally. Served predictions carry no per-field parse metadata. See Traces.

Predicted<O>

Every call returns Predicted<O>: the typed output plus runtime bookkeeping. It implements Deref<Target = O>, so output fields read directly (result.answer).

CallMetadata

Each FieldMeta records raw_text (the text the LM produced for that field), flags (Vec<Flag>, non-fatal coercion observations such as a stripped code fence), and checks (Vec<ConstraintResult> with label, expression, passed). Accessors: field_meta(), field_raw(field), field_flags(field), field_checks(field), field_names(), and has_failed_checks() for a quick scan across all fields. Failed #[check] constraints land here; failed #[assert] constraints become a Parse error instead.

PredictError

PredictError::class() buckets into ErrorClass (BadRequest, NotFound, Forbidden, Temporary, BadResponse, Internal); is_retryable() drives retry logic. Parse errors include the raw response and the token usage: failed parses still consume tokens.

ToolSet

ToolSet is pre-fetched tool definitions plus name-indexed executors, built once and reused across calls. Predict builds and caches one ToolSet per instance from its builder tools on first use. To put Code Mode on a predictor, add the CodeModeTool (re-exported by dspy_rs under the code-mode feature) as the single tool:
A ToolSet::code_mode(...) set drops into LM::call_with_toolset directly. See Code Mode.

See also