A pre-model hook is a callback that runs before a language model invocation. It can inspect the current state and either leave the input unchanged or modify what the model receives. This makes it useful for enforcing scope and safety before an agent spends tokens or calls tools. section 14.2 section 14.2.2
A guardrail hook can enforce an agent boundary in four steps:
- Read the latest message and confirm that it is a user message. section 14.2.2
- Send the query to a classifier with a strict scope prompt, such as travel questions about Cornwall. section 14.2.2
- Return an empty update for an in-scope request so normal processing continues. section 14.2.2
- For an out-of-scope request, prepend a refusal instruction to the model input instead of allowing normal handling. section 14.2.2
Restricting a travel agent to Cornwall
Attach the same pre_model_guardrail to a travel-information agent and an accommodation-booking agent. A request for travel tips in Liverpool is classified as outside scope, so the assistant returns a polite refusal and suggests Cornwall destinations instead.
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 implementation listing shows how the hook reads state, invokes a classifier, permits valid input, and injects refusal instructions for invalid input. section 14.2.2
