liveBook · Manning

Guardrail

As explained in AI Agents and Applications

A guardrail is a constraint or control that limits model behavior to satisfy safety, quality, or policy requirements.

A travel assistant should not answer a question about football results or offer hotel advice for a region its data does not cover. A guardrail is an application-level check that keeps an agent within its intended scope and policies. It inspects a request or response at a chosen workflow stage and, when a check fails, changes the normal path—for example, by refusing the request or asking for clarification. section 14.2 section 14.2.1

Choose the check and its location together:

  • At the router, classify the user's latest question before sending it to a travel or booking agent. Accept travel topics; send unrelated questions directly to a polite refusal path. This avoids unnecessary downstream work, though classification itself still uses a lightweight LLM. section 14.2.1
  • At each agent, apply a narrower check before its main model call. The Cornwall travel and booking agents accept only Cornwall-related travel questions, even if someone calls an agent directly rather than through the router. section 14.2.2
  • After generation, consider checking answers before delivery or before a downstream action. Possible checks include outdated attractions, sensitive contact details, tone, and the format of booking information; these are proposed extensions, not part of the demonstrated input filters. section 14.3.3
Listing 14.5 Restricting questions to travel-related topics
class GuardrailDecision(BaseModel):  #1
    is_travel: bool = Field(
        ...,
        description=(
            """True if the user question is about travel information: 
            destinations, attractions, 
            lodging (hotels/BnBs), prices, availability, 
            or weather in Cornwall/England."""
        ),
    )
    reason: str = Field(..., 
        description="Brief justification for the decision.")

GUARDRAIL_SYSTEM_PROMPT = (  #2
    """You are a strict classifier. Given the user's 
    last message, respond with whether it is
    travel-related. Travel-related queries 
    include destinations, attractions, lodging (hotels/BnBs), 
    room availability, prices, or weather in Cornwall/England."""
)

REFUSAL_INSTRUCTION = (  #3
    """You can only help with travel-related questions 
    (destinations, attractions, lodging, prices, 
    availability, or weather in Cornwall/England). 
    The user's request is not travel-related. 
    Politely refuse and briefly explain what 
    topics you can help with."""
)

llm_guardrail = llm_model.with_structured_output(
    GuardrailDecision)  #4

The router policy gives the classifier explicit travel categories, returns a structured decision with a reason, and defines the refusal instruction. Defining scope first makes the routing decision testable. section 14.2.1

Listing 14.9 Agent-level guardrail function
def pre_model_guardrail(state: dict):
    messages = state.get("messages", [])
    last_msg = messages[-1] if messages else None
    if not isinstance(last_msg, HumanMessage):  #1
        return {}

    user_input = last_msg.content
    classifier_messages = [ #2
        SystemMessage(content=AGENT_GUARDRAIL_SYSTEM_PROMPT),
        HumanMessage(content=user_input),
    ]
    decision = llm_guardrail.invoke(classifier_messages)

    if decision.is_travel: #3
        # Allow normal flow; do not modify inputs
        return {}

    return {"llm_input_messages": 
        [SystemMessage(content=AGENT_REFUSAL_INSTRUCTION),
        *messages]}  #4

The agent-level function checks that the latest message is from the user, classifies it, and leaves valid input unchanged. On rejection, it supplies a refusal instruction through the pre-model hook rather than taking the router's early-exit path. section 14.2.2

Two different boundaries

“Can you give me the latest results of Inter Milan?” fails the travel router check and receives a travel-only refusal. “Can you give me some travel tips for Liverpool?” is travel-related but fails the narrower Cornwall agent check. The second check matters because the travel agent's vector store contains Cornwall data only. section 14.2.1 section 14.2.2

Guardrails can use explicit rules, approved-source checks, or classification and moderation models. Layering them helps catch different failures: an entry check limits irrelevant requests, an agent check protects a component reused elsewhere, and an output check can catch a plausible-looking but unsuitable answer. A pre-model check cannot, by itself, verify what the model eventually says. section 14.2 section 14.3.3

How AI Agents and Applications covers it

How deep it goes
Works through structured classification, a router refusal path, and an agent pre-model hook; proposes rather than implements post-model checks.
Examples
Tests a football-results question against a travel router and a Liverpool travel question against Cornwall-only agents.
What it assumes
Assumes an existing agent graph and message state while defining the guardrail policy and classifier decision explicitly.
What you can do after
Build it from scratch with a LangGraph router check and agent pre-model hooks that redirect out-of-scope requests.
How it connects
Connects guardrails to agent routing, classification models, vector-store coverage, output validation, and human-in-the-loop review.

Also explained in

Compare how 14 books explain guardrail →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of AI Agents and Applications. The section links point to the parts of the book it draws on.