Skip to content

Commit b62672f

Browse files
[FEAT] Support JSON Schema in Responses (#1177)
Co-authored-by: =Richard Edgar <=> Co-authored-by: Roman Lutz <romanlutz13@gmail.com>
1 parent 4748750 commit b62672f

13 files changed

Lines changed: 778 additions & 86 deletions

build_scripts/check_links.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"https://platform.openai.com/docs/api-reference/introduction", # blocks python requests
1818
"https://platform.openai.com/docs/api-reference/responses", # blocks python requests
1919
"https://platform.openai.com/docs/guides/function-calling", # blocks python requests
20+
"https://platform.openai.com/docs/guides/structured-outputs", # blocks python requests
2021
"https://www.anthropic.com/research/many-shot-jailbreaking", # blocks python requests
2122
"https://code.visualstudio.com/docs/devcontainers/containers",
2223
"https://stackoverflow.com/questions/77134272/pip-install-dev-with-pyproject-toml-not-working",

doc/code/targets/1_openai_chat_target.ipynb

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@
2020
"id": "1",
2121
"metadata": {},
2222
"outputs": [
23+
{
24+
"name": "stdout",
25+
"output_type": "stream",
26+
"text": [
27+
"Found default environment files: ['/home/vscode/.pyrit/.env', '/home/vscode/.pyrit/.env.local']\n",
28+
"Loaded environment file: /home/vscode/.pyrit/.env\n",
29+
"Loaded environment file: /home/vscode/.pyrit/.env.local\n"
30+
]
31+
},
2332
{
2433
"name": "stdout",
2534
"output_type": "stream",
@@ -88,6 +97,91 @@
8897
"cell_type": "markdown",
8998
"id": "2",
9099
"metadata": {},
100+
"source": [
101+
"## JSON Output\n",
102+
"\n",
103+
"You can also get the output in JSON format for further processing or storage. In this example, we define a simple JSON schema that describes a person with `name` and `age` properties.\n",
104+
"\n",
105+
"For more information about structured outputs with OpenAI, see [the OpenAI documentation](https://platform.openai.com/docs/guides/structured-outputs)."
106+
]
107+
},
108+
{
109+
"cell_type": "code",
110+
"execution_count": null,
111+
"id": "3",
112+
"metadata": {},
113+
"outputs": [
114+
{
115+
"name": "stdout",
116+
"output_type": "stream",
117+
"text": [
118+
"Found default environment files: ['/home/vscode/.pyrit/.env', '/home/vscode/.pyrit/.env.local']\n",
119+
"Loaded environment file: /home/vscode/.pyrit/.env\n",
120+
"Loaded environment file: /home/vscode/.pyrit/.env.local\n"
121+
]
122+
},
123+
{
124+
"name": "stdout",
125+
"output_type": "stream",
126+
"text": [
127+
"{\n",
128+
" \"name\": \"Bob\",\n",
129+
" \"age\": 32\n",
130+
"}\n"
131+
]
132+
}
133+
],
134+
"source": [
135+
"import json\n",
136+
"\n",
137+
"import jsonschema\n",
138+
"\n",
139+
"from pyrit.models import Message, MessagePiece\n",
140+
"from pyrit.prompt_target import OpenAIChatTarget\n",
141+
"from pyrit.setup import IN_MEMORY, initialize_pyrit_async\n",
142+
"\n",
143+
"await initialize_pyrit_async(memory_db_type=IN_MEMORY) # type: ignore\n",
144+
"\n",
145+
"# Define a simple JSON schema for a person\n",
146+
"person_schema = {\n",
147+
" \"type\": \"object\",\n",
148+
" \"properties\": {\n",
149+
" \"name\": {\"type\": \"string\"},\n",
150+
" \"age\": {\"type\": \"integer\", \"minimum\": 0, \"maximum\": 150},\n",
151+
" },\n",
152+
" \"required\": [\"name\", \"age\"],\n",
153+
" \"additionalProperties\": False,\n",
154+
"}\n",
155+
"\n",
156+
"prompt = \"Create a JSON object describing a person named Bob who is 32 years old.\"\n",
157+
"# Create the message piece and message\n",
158+
"message_piece = MessagePiece(\n",
159+
" role=\"user\",\n",
160+
" original_value=prompt,\n",
161+
" original_value_data_type=\"text\",\n",
162+
" prompt_metadata={\n",
163+
" \"response_format\": \"json\",\n",
164+
" \"json_schema\": json.dumps(person_schema),\n",
165+
" },\n",
166+
")\n",
167+
"message = Message(message_pieces=[message_piece])\n",
168+
"\n",
169+
"# Create the OpenAI Chat target\n",
170+
"target = OpenAIChatTarget()\n",
171+
"\n",
172+
"# Send the prompt, requesting JSON output\n",
173+
"response = await target.send_prompt_async(message=message) # type: ignore\n",
174+
"\n",
175+
"# Validate and print the response\n",
176+
"response_json = json.loads(response[0].message_pieces[0].converted_value)\n",
177+
"print(json.dumps(response_json, indent=2))\n",
178+
"jsonschema.validate(instance=response_json, schema=person_schema)"
179+
]
180+
},
181+
{
182+
"cell_type": "markdown",
183+
"id": "4",
184+
"metadata": {},
91185
"source": [
92186
"## OpenAI Configuration\n",
93187
"\n",
@@ -125,7 +219,7 @@
125219
"name": "python",
126220
"nbconvert_exporter": "python",
127221
"pygments_lexer": "ipython3",
128-
"version": "3.11.13"
222+
"version": "3.11.14"
129223
}
130224
},
131225
"nbformat": 4,

doc/code/targets/1_openai_chat_target.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,59 @@
4444
result = await attack.execute_async(objective=jailbreak_prompt) # type: ignore
4545
await ConsoleAttackResultPrinter().print_conversation_async(result=result) # type: ignore
4646

47+
# %% [markdown]
48+
# ## JSON Output
49+
50+
# You can also get the output in JSON format for further processing or storage. In this example, we define a simple JSON schema that describes a person with `name` and `age` properties.
51+
#
52+
# For more information about structured outputs with OpenAI, see [the OpenAI documentation](https://platform.openai.com/docs/guides/structured-outputs).
53+
54+
# %%
55+
import json
56+
57+
import jsonschema
58+
59+
from pyrit.models import Message, MessagePiece
60+
from pyrit.prompt_target import OpenAIChatTarget
61+
from pyrit.setup import IN_MEMORY, initialize_pyrit_async
62+
63+
await initialize_pyrit_async(memory_db_type=IN_MEMORY) # type: ignore
64+
65+
# Define a simple JSON schema for a person
66+
person_schema = {
67+
"type": "object",
68+
"properties": {
69+
"name": {"type": "string"},
70+
"age": {"type": "integer", "minimum": 0, "maximum": 150},
71+
},
72+
"required": ["name", "age"],
73+
"additionalProperties": False,
74+
}
75+
76+
prompt = "Create a JSON object describing a person named Bob who is 32 years old."
77+
# Create the message piece and message
78+
message_piece = MessagePiece(
79+
role="user",
80+
original_value=prompt,
81+
original_value_data_type="text",
82+
prompt_metadata={
83+
"response_format": "json",
84+
"json_schema": json.dumps(person_schema),
85+
},
86+
)
87+
message = Message(message_pieces=[message_piece])
88+
89+
# Create the OpenAI Chat target
90+
target = OpenAIChatTarget()
91+
92+
# Send the prompt, requesting JSON output
93+
response = await target.send_prompt_async(message=message) # type: ignore
94+
95+
# Validate and print the response
96+
response_json = json.loads(response[0].message_pieces[0].converted_value)
97+
print(json.dumps(response_json, indent=2))
98+
jsonschema.validate(instance=response_json, schema=person_schema)
99+
47100
# %% [markdown]
48101
# ## OpenAI Configuration
49102
#

0 commit comments

Comments
 (0)