Overview
LLMWithBackend pairs a frontend LLM, which keeps the conversation with the user fluent, with a backend LLM that handles work needing tools or careful reasoning. It goes where the LLM goes in your pipeline and runs the backend as an agent of its own. The frontend hands work to the backend with a delegate tool and keeps talking with the user, and what the backend has to say comes back into the frontend’s conversation for it to relay to the user.
Composite services hold one or more services and stand in a pipeline where a single service would. LLMWithBackend holds the frontend service; the backend is a BackendLLMWorker.
For a walkthrough, see LLM with a Backend.
Example
An engineering assistant with text and speech-to-speech frontends
BackendLLMWorker
The worker that runs the backend LLM
LLMWithBackend
LLMWithBackend is a Pipeline, not an LLMService: functions, settings updates, event handlers and a FlowManager go on its frontend. The backend’s tools go in the backend’s own context.
Configuration
LLMService
required
The conversational LLM service, text or speech-to-speech.
BackendLLMWorker | str
required
The backend worker, or the name of one registered elsewhere: in the app, or in
another process on a shared bus. A worker given here is added to the pipeline
worker when the pipeline starts.
BackendConnector | None
default:"None"
How delegation works. A default
BackendConnector when
None.PredictiveDelegation | None
default:"None"
A
PredictiveDelegation, to start the backend sooner
on turns that need it. Text frontends only.ValueError when:
- The frontend is
InworldRealtimeLLMService,UltravoxRealtimeLLMServiceorOpenAILiveLLMService, which can’t be a frontend (see Notes). - The frontend is speech-to-speech and the request strategy is
TranscriptBackendRequestStrategy, which reads the frontend’s context. predictive_delegationis given with a speech-to-speech frontend, or withExplicitBackendRequestStrategy, whosedelegatecall takes arequestargument.
Properties
BackendConnector
BackendConnector manages the interaction between the frontend and the backend. It defines the delegate tool, holds the session with the backend for the pipeline’s life, and turns what the backend produces into messages in the frontend’s conversation.
BackendRequestStrategy | None
default:"None"
How a
delegate call becomes the backend’s request. When None,
TranscriptBackendRequestStrategy for a
text frontend and
ExplicitBackendRequestStrategy for a
speech-to-speech one.str
default:"FRONTEND_PAIRING_INSTRUCTION"
How the frontend’s model works with a backend, appended to its system
instruction. A custom override has to cover everything the default does: when
and how to delegate, that to the user there is one assistant, what to do after
delegating, and what to do with the backend’s messages. The request strategy’s
guidance goes where
PAIRING_INSTRUCTION_STRATEGY_PLACEHOLDER stands, or
after the text when it has none.bool
default:"True"
Whether the frontend replies as soon as a delegation is sent, which is where
its acknowledgement comes from. Set
False to delegate without a reply.float | None
default:"30"
How long the backend may take to acknowledge a request, including the wait for
it to become ready.
bool
default:"False"
Whether to send every exchange with the backend to the client as an RTVI
server-message, for debugging. See Frames.Request Strategies
A request strategy defines thedelegate tool’s parameters and description, and builds the request the backend receives from each delegate call.
TranscriptBackendRequestStrategy
The frontend’s model callsdelegate with no arguments, and the request is the transcript of the user and assistant turns since the previous delegation (the whole conversation the first time). The default for a text frontend. Its delegate call needs no arguments, so it works with predictive delegation. It reads the frontend’s context, so a speech-to-speech frontend refuses it.
str | None
default:"TRANSCRIPT_FRONTEND_INSTRUCTION"
The strategy’s guidance to the frontend’s model, placed in the pairing
instruction.
str
default:"TRANSCRIPT_TOOL_DESCRIPTION"
How the
delegate tool is described.str
default:"TRANSCRIPT_REQUEST_INSTRUCTION"
What the backend should do with the transcript, placed after it.
ExplicitBackendRequestStrategy
The frontend’s model words the request itself, in thedelegate tool’s request argument. The default for a speech-to-speech frontend, which replies to the user’s audio before that audio’s transcript reaches its context.
str | None
default:"EXPLICIT_FRONTEND_INSTRUCTION"
The strategy’s guidance to the frontend’s model, placed in the pairing
instruction.
str
default:"EXPLICIT_TOOL_DESCRIPTION"
How the
delegate tool is described.str
default:"EXPLICIT_REQUEST_INSTRUCTION"
What the backend should do with the request, placed after it.
PredictiveDelegation
PredictiveDelegation starts the backend sooner on turns that need it.
How it works: on each user turn, a yes/no classifier races the frontend’s inference, asking whether the turn needs the backend. A “yes” that arrives before the frontend’s first output delegates the turn at once and cancels the inference. A “no”, a late answer, or a classifier error leaves the turn to the frontend as usual. The frontend is never slowed down waiting for the classifier.
The classifier reads what the frontend’s model reads: its system instruction, pairing instruction included, the delegate tool’s description, and the latest messages of the conversation.
BaseClassifier
required
The yes/no classifier to ask,
such as
JevClassifier.delegate call takes no arguments, such as the default TranscriptBackendRequestStrategy. It leaves speculative turns (eager end of turn) to the frontend, and every turn while the frontend filters incomplete user turns. The classifier’s metrics are pushed as MetricsFrames.
Constants
The constants are inpipecat.pipeline.llm_with_backend.prompts, except the request instructions, which are in pipecat.workers.llm.backend_llm_worker, and DELEGATE_TOOL_NAME, which is in pipecat.pipeline.llm_with_backend.connector. Read the source for the default texts’ wording.
Frames
Pushed by
Notes
- Backend messages in the frontend’s context: What the backend produces is appended to the frontend’s context as
developermessages. A message for the user starts withBackend:and ends withBACKEND_MESSAGE_RELAY_INSTRUCTION, and the rest are silent:Backend (note):for text not meant for the user,Backend (working):for a function call the backend is making, andBackend (thinking):for a reasoning summary. - The
delegatetool: The frontend getsdelegateas a built-in tool: it is sent with every inference beside the frontend’s own tools and never enters the context’s tool list. - Services that can’t be a frontend:
InworldRealtimeLLMService: its model callsdelegateagain in place of taking in the backend’s messages.UltravoxRealtimeLLMService: built-in tools such asdelegatedon’t reach its session.OpenAILiveLLMService: it is already a frontend with a backend of its own, set up with its delegation modes. It can’t be a backend either.