Integration capabilities
The proxy can also carry the conversation, so policy applies across turns rather
than to one message at a time. That requires the caller to send a session key —
see Multi-turn conversations.
Before you start
Create the policy in Observe mode. Observe records decisions in Activity without enforcing
them. Review the results, then switch the policy to Enforce. See
Policies.
Set up the custom guardrail file
The guardrail uses thehttpx client included with LiteLLM, so it requires no
additional dependency. The supported enforcement actions are Monitor and Block.
This integration does not support redaction.
Custom guardrail: trustguard_guardrail.py
Custom guardrail: trustguard_guardrail.py
Mount it and declare it
trustguard_guardrail.TrustGuard is resolved relative to the directory the proxy
runs from, so the file has to sit next to your config.yaml, which is /app in the
official image. Mount it read-only as a volume, ship it as a ConfigMap with
subPath, or bake it into your image. Then declare it in config.yaml:
TRUSTGUARD_API_BASE is the full endpoint,
{TRUSTGUARD_BASE_URL}/v1/evaluate, not only the host.
Multi-turn conversations
A multi-turn attack spreads its intent across several messages. Each one reads as harmless on its own; the escalation, the reinforcement, or the reassembled instruction exists only across turns. See multi-turn attacks for the techniques involved — Crescendo, Echo Chamber, Multi-Turn Manipulation, and Payload Splitting. Their common target is a filter that inspects each message independently, which is what this guardrail does until you give it the conversation. Two inputs give TrustGuard the conversation, and they are complementary rather than alternatives:
Neither happens by default.
/v1/evaluate
synthesizes a session_id when the field is omitted,
so a proxy whose callers send no conversation key produces one session per
request. Nothing errors and no finding goes missing, so the gap is only visible
as single-turn conversations in Activity.
Send a session ID
LiteLLM does not invent a conversation key. The caller supplies one on every request of the conversation, and the proxy makes it available to the guardrail before thepre_call hook runs.
A header always overrides a body value, so audit whatever sits in front of the
proxy before telling application teams to use the body form.
With the OpenAI SDK, send the header on every call of the conversation:
_get_session_id_from_request_data, which checks the top-level
litellm_session_id field, then metadata.session_id, then
litellm_metadata.session_id, and sends the first non-empty one as session_id.
The post_call hook receives the same request data, so the output evaluation
carries the same session as the input evaluation.
Send conversation history
/v1/chat/completions is stateless, so messages holds whatever the caller sent
— for a normal chat client or agent loop, the whole conversation. scope decides
how much of it the guardrail forwards.
Tool results must keep
role: "tool" because the
indirect prompt injection detector
uses that role. Flattening every message to user disables that check. Agent
transcripts can also be large, so measure latency with representative payloads.
On
/v1/responses, previous_response_id does not supply either input. The
guardrail sees only the new turn’s input, because LiteLLM rehydrates the
earlier turns after the hook has already run, and the recovered identifier is not
the one the guardrail reads. The session headers work normally on that route, so
send x-litellm-session-id explicitly, and put the transcript in the request if
a single call needs the history.Verify
Assign an Enforce policy with a Block rule that matches the test prompt, then send a non-streaming request through the proxy:400 with error: "Blocked by TrustGuard", the
guardrail name, findings, and trace_id. It does not return request_id. Use
trace_id to find the same decision in Activity.
To verify monitoring before enforcement, set the policy to Observe and
LITELLM_LOG=INFO, then send a request that matches a rule. A non-streaming
request with both hooks enabled logs an input line followed by an output
line:
status=block without an output line because LiteLLM
does not call the model. To verify an output-side block, use a non-streaming
request and an Output rule; LiteLLM returns HTTP 400 after the model responds
but before returning the completion to the client.
Reference
Coverage
The custom guardrail supports monitoring and blocking for chat-style requests.
It does not support redaction, embeddings, image generation, or audio routes.
For streaming requests, LiteLLM invokes the output hook with the assembled
response after the stream closes. The result is recorded, but it cannot stop
tokens that have already been delivered. Input evaluation still runs before the
model call.
Tool content is covered only when LiteLLM includes it in the messages selected
by
scope. Tool results must retain role: "tool"; tool declarations and tool
calls are not evaluated as separate lifecycle events. Enforcement remains
request-level, so a finding in tool content blocks the complete LiteLLM request.
With pre_call and post_call enabled, a successful chat request with text
input and output adds two calls to TrustGuard. For streaming requests, the
output call occurs after the stream closes. Set timeout according to the
latency requirements of the proxy.
What is evaluated
The
pre_call and post_call hooks call
POST /v1/evaluate. The assigned policy’s
detectors determine the verdict. Configure both
hooks to evaluate input and output.
Verdict handling
Use Monitor or Block actions with this integration. A block response exposes the
findings to the caller. Use
trace_id to correlate the response with Activity.
Configuration
Define
TRUSTGUARD_API_BASE and TRUSTGUARD_API_KEY in the proxy environment,
then restart LiteLLM after changing the guardrail file or config.yaml.
Failure behavior. The custom guardrail handles connection errors, timeouts,
and every non-200 TrustGuard response according to fail_open:
Attributes
session_id: the conversation key the caller supplied, resolved by LiteLLM from a session header or a body field. LiteLLM does not generate one. See Multi-turn conversationsconsumer_id: derived from the virtual key’skey_alias,user_email,user_id, orteam_alias, then from request metadata if those fields are empty
Troubleshooting
Related
- Policies: configure Observe, Enforce, Monitor, and Block
- Evaluate API: request and response reference
- Python SDK: use the
trustguard-sdkpackage instead of direct HTTP calls - How it works: compare available collectors
- TrustGate: inspect streamed responses at the gateway
- LiteLLM proxy docs: LiteLLM reference
Experimental: BerriAI/litellm#37165
proposes a native
neuraltrust guardrail, configured with
guardrail: neuraltrust instead of a file. It is open, is not in any released
LiteLLM version, and is not part of the setup described on this page. It resolves
session_id the same way, from the same caller-supplied header or body field, so
the guidance in Multi-turn conversations applies to
either path. It has no scope setting and sends the full message array.