Guardrails agent
The Guardrails Agent is our first line of defense. It checks if the user's question is about e-commerce data, a greeting, or completely off-topic.
Guardrails agent pipeline
The three-stage validation pipeline that protects your database from bad queries.
It is possible but unlikely. The LLM understands semantics, not just keywords. Asking "what is the weather for my order delivery?" would still be classified as out-of-scope because weather data is not in our database. The key is listing the available data explicitly in the prompt so the LLM knows what is and is not queryable.
def guardrails_agent(state: AgentState) -> AgentState:
"""Check if the question is within scope (e-commerce related)"""
question = state["question"]
prompt = f"""You are a guardrails system for an e-commerce database chatbot.
Your job is to determine if a user's question is:
1. Related to e-commerce data (IN-SCOPE)
2. A greeting (GREETING)
3. Off-topic (OUT-OF-SCOPE)
The chatbot has access to data about:
- Customers and locations
- Orders and status (2016-2018)
- Products and categories
- Sellers, Payments, Reviews
User Question: {question}
Respond in JSON format:
{{"is_in_scope": true/false, "is_greeting": true/false, "reason": "..."}}
"""The prompt classifies user questions into three categories. We list the available data so the LLM understands what counts as "in scope."
With the prompt built, we send it to the LLM using LiteLLM. Notice we use JSON mode so the response is always machine-parseable.
# Call the LLM with JSON mode for structured output
response = completion(
model=DEFAULT_MODEL,
messages=[
{"role": "system", "content": AGENT_CONFIGS["guardrails_agent"]["system_prompt"]},
{"role": "user", "content": prompt}
],
temperature=0,
response_format={"type": "json_object"}
)temperature=0 ensures deterministic classification so the same question always gets the same verdict. JSON mode guarantees a parseable response.
Finally, we parse the JSON response and update the shared state. If the question is off-topic, the agent short-circuits the pipeline immediately.
# Parse the response and update state
result = json.loads(response.choices[0].message.content)
state["is_in_scope"] = result.get("is_in_scope", False)
state["guardrails_reason"] = result.get("reason", "")
# Handle greeting or out-of-scope
if result.get("is_greeting", False):
state["final_answer"] = "Hi! I'm your e-commerce assistant..."
elif not state["is_in_scope"]:
state["final_answer"] = "I can only answer e-commerce questions..."
return stateThe parsed result updates the shared state. If the question is off-topic or a greeting, we set the final_answer immediately with no need to run the SQL Agent.
Quiz: Quiz
Loading practiceโฆ
Validation checklist: Guardrails agent concepts
Loading practiceโฆ
The Guardrails Agent is the first line of defense. It filters every question before any SQL is generated. Next, we will build the SQL Agent that converts natural language into database queries.