Check what goes in and out, and ask a human before the agent does anything risky.
1# part4/guardrails.py - check what goes in, ask a human first, check what comes out
2import json
3from openai import OpenAI
4client = OpenAI()
5
6# Same helper as before: one agent = one API call with its own system prompt.
7def run_agent(system_prompt, task):
8 response = client.chat.completions.create(
9 model="gpt-4o-mini",
10 messages=[
11 {"role": "system", "content": system_prompt},
12 {"role": "user", "content": task},
13 ],
14 )
15 return response.choices[0].message.content
16
17# A guardrail can be a small agent: Cora answers with one word our code can read.
18checker_prompt = "You are Cora. You check messages for a school helper app. Reply SAFE or UNSAFE only."
19def is_safe(text):
20 verdict = run_agent(checker_prompt, text)
21 return verdict.strip().startswith("SAFE")
22
23# A pretend tool: it only prints. It never really sends anything.
24def send_email(to, body):
25 print(f"๐ง (pretend) Email to {to}: {body}")
26 return "Email sent."
27
28tools = [{"type": "function", "function": {
29 "name": "send_email", "description": "Send an email to someone.",
30 "parameters": {"type": "object", "properties": {
31 "to": {"type": "string", "description": "a name, e.g. Ms. Lee"},
32 "body": {"type": "string"}
33 }, "required": ["to", "body"]}
34}}]
35RISKY_TOOLS = {"send_email"} # actions a human must say yes to first
36
37max_prompt = "You are Max, a school helper. The student's teacher is Ms. Lee."
38request = "Email my teacher that I finished my science project."
39print("You:", request)
40
41# Gate 1 - input guardrail: Cora checks the request before Max sees it
42if not is_safe(request):
43 print("Sorry, I can't help with that. Let's keep things kind and safe.")
44 raise SystemExit # stop the program right here
45
46# Max gets the request and his tool menu (one round, like the Part 2 agent)
47messages = [{"role": "system", "content": max_prompt},
48 {"role": "user", "content": request}]
49response = client.chat.completions.create(model="gpt-4o-mini", messages=messages, tools=tools)
50message = response.choices[0].message
51messages.append(message)
52reply = message.content # his text answer (None if he asks for a tool)
53
54if message.tool_calls: # Max can only ASK for a tool; our code decides
55 tool_call = message.tool_calls[0]
56 name = tool_call.function.name
57 args = json.loads(tool_call.function.arguments)
58
59 # Gate 2 - human approval: a risky tool waits for a person's yes
60 allowed = True
61 if name in RISKY_TOOLS:
62 answer = input(f"Allow {name} with {args}? (y/n) ")
63 allowed = answer.strip().lower() == "y"
64 if allowed:
65 result = send_email(**args)
66 else:
67 result = "The human said no."
68
69 messages.append({"role": "tool", "tool_call_id": tool_call.id, "content": result})
70 final = client.chat.completions.create(model="gpt-4o-mini", messages=messages)
71 reply = final.choices[0].message.content
72
73# Gate 3 - output guardrail: Cora checks Max's answer before we show it
74if not is_safe(reply):
75 reply = "Sorry, I can't share that answer."
76print("Max:", reply)No output yet...