Skip to main content

LlmWorker

Struct LlmWorker 

Source
pub struct LlmWorker<T> { /* private fields */ }
Expand description

Worker for executing LLM calls with tool support and typed responses.

LlmWorker<T> manages the full lifecycle of LLM interactions including:

  • Sending messages to the LLM
  • Executing tool calls requested by the LLM
  • Managing multi-turn tool execution loops
  • Combining multiple toolsets
  • Deserializing responses into typed values

§Type Parameters

  • T - The type to deserialize the LLM response into. Must implement DeserializeOwned. Use Thread if you want the raw conversation thread back without deserialization.

§Examples

use serde::Deserialize;

#[derive(Deserialize, JsonSchema)]
struct MyResponse {
    answer: String,
    confidence: f64,
}

let worker = LlmWorker::<MyResponse>::builder(my_llm)
    .with_tool(tool1)
    .build();

let response: MyResponse = worker.run(thread).await?;

Use [LlmWorker::builder(model)] to construct instances with the desired configuration.

Implementations§

Source§

impl<T> LlmWorker<T>
where T: LLMOutputTrait + JsonSchema + MaybeSend + MaybeSync + 'static,

Source

pub fn builder(model: impl BaseLlm + 'static) -> LlmWorkerBuilder<T>

Creates a new builder for constructing an LlmWorker<T>.

The model is required and must be provided upfront.

§Type Parameters
  • T - The response type to deserialize into
§Arguments
  • model - The LLM model to use for this worker
§Examples
use serde::Deserialize;

#[derive(Deserialize)]
struct Response { answer: String }

let worker = LlmWorker::<Response>::builder(my_llm)
    .with_tool(tool1)
    .build();
Source

pub fn builder_shared(model: Arc<dyn BaseLlm>) -> LlmWorkerBuilder<T>

Creates a new builder from an already-Arc-wrapped LLM.

Use this when you have a shared Arc<dyn BaseLlm> from the runtime and want to avoid re-wrapping it.

Source

pub async fn run<IT>(&self, input: IT) -> AgentResult<T>
where IT: Into<Thread>,

Runs the worker on the given input thread.

This method executes the LLM with the provided thread, handling any tool calls requested by the LLM. The worker will continue executing tools in a loop until the LLM produces a final response, which is then deserialized into type T.

§Arguments
  • input - Thread or any type that can be converted into a Thread
§Returns

Returns the deserialized response of type T.

§Errors

Returns an error if:

  • The LLM call fails
  • Tool execution fails
  • Response deserialization fails
§Examples
use radkit::models::Thread;
use serde::Deserialize;

#[derive(Deserialize)]
struct WeatherInfo {
    temp: f64,
    condition: String,
}

let thread = Thread::new().with_user("What's the weather?");
let response: WeatherInfo = worker.run(thread).await?;
println!("Temperature: {}°F", response.temp);
Source

pub async fn run_and_continue<IT>(&self, input: IT) -> AgentResult<(T, Thread)>
where IT: Into<Thread>,

Runs the worker and returns both the deserialized result and the thread for follow-up work.

This method executes the LLM with the provided thread, handling tool calls and executing them in a loop. After completion, it returns both the deserialized response and the updated thread, allowing for multi-turn conversations.

§Arguments
  • input - Thread or any type that can be converted into a Thread
§Returns

Returns a tuple of:

  • The deserialized response of type T
  • The updated Thread with all tool calls and responses included
§Errors

Returns an error if:

  • The LLM call fails
  • Tool execution fails
  • Response deserialization fails
§Examples
use radkit::models::Thread;
use serde::Deserialize;

#[derive(Deserialize)]
struct Response { answer: String }

let thread = Thread::new().with_user("What's the weather?");
let (response, continued_thread) = worker.run_and_continue(thread).await?;
println!("Answer: {}", response.answer);

// Continue the conversation with the same thread
let continued_thread = continued_thread
    .with_user("What about tomorrow?");
let (next_response, _) = worker.run_and_continue(continued_thread).await?;
Source

pub fn has_tools(&self) -> bool

Checks if this worker has any toolsets configured.

§Examples
if worker.has_tools() {
    println!("Worker can execute tools");
}
Source

pub fn toolset(&self) -> Option<&Arc<dyn BaseToolset>>

Returns a reference to the configured toolset, if any.

§Examples
if let Some(toolset) = worker.toolset() {
    let tools = toolset.get_tools().await;
    println!("Worker has {} tools", tools.len());
}

Auto Trait Implementations§

§

impl<T> !RefUnwindSafe for LlmWorker<T>

§

impl<T> !UnwindSafe for LlmWorker<T>

§

impl<T> Freeze for LlmWorker<T>

§

impl<T> Send for LlmWorker<T>
where T: Send,

§

impl<T> Sync for LlmWorker<T>
where T: Sync,

§

impl<T> Unpin for LlmWorker<T>
where T: Unpin,

§

impl<T> UnsafeUnpin for LlmWorker<T>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FutureExt for T

Source§

fn with_context(self, otel_cx: Context) -> WithContext<Self>

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Source§

fn with_current_context(self) -> WithContext<Self>

Attaches the current Context to this type, returning a WithContext wrapper. Read more
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> MaybeSend for T
where T: Send + ?Sized,

Source§

impl<T> MaybeSync for T
where T: Sync + ?Sized,

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more