Skip to content

Commit e206e3e

Browse files
start on documentation
1 parent c54f26e commit e206e3e

File tree

1 file changed

+116
-0
lines changed

1 file changed

+116
-0
lines changed

docs/models/openai.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,122 @@ As of 7:48 AM on Wednesday, April 2, 2025, in Tokyo, Japan, the weather is cloud
143143

144144
You can learn more about the differences between the Responses API and Chat Completions API in the [OpenAI API docs](https://platform.openai.com/docs/guides/responses-vs-chat-completions).
145145

146+
### Freeform Function Calling
147+
148+
GPT‑5 can now send raw text payloads - anything from Python scripts to SQL queries - to your custom tool without wrapping the data in JSON using freeform function calling. This differs from classic structured function calls, giving you greater flexibility when interacting with external runtimes such as:
149+
150+
* code execution with sandboxes (Python, C++, Java, …)
151+
* SQL databases
152+
* Shell environments
153+
* Configuration generators
154+
155+
Note that freeform function calling does NOT support parallel tool calling.
156+
157+
You can enable freeform function calling for a tool using the `text_format` parameter when creating your tool. To use this the tool must take a single string argument (other than the runtime context) and the model must be one of the GPT-5 responses models. For example:
158+
159+
```python
160+
from pydantic_ai import Agent
161+
from pydantic_ai.models.openai import OpenAIResponsesModel
162+
163+
model = OpenAIResponsesModel('gpt-5') # (1)!
164+
agent = Agent(model)
165+
166+
@agent.tool_plain(text_format='text') # (2)!
167+
def freeform_tool(sql: str) -> ...
168+
```
169+
170+
1. The GPT-5 family (`gpt-5`, `gpt-5-mini`, `gpt-5-nano`) all support freeform function calling.
171+
2. If the tool or model cannot be used with freeform function calling then it will be invoked in the normal way.
172+
173+
You can read more about this function calling style in the [openai documentation](https://cookbook.openai.com/examples/gpt-5/gpt-5_new_params_and_tools#2-freeform-function-calling).
174+
175+
#### Context Free Grammar
176+
177+
Invoking tools using freeform function calling can result in errors when the tool expectations are not met. For example, a tool that queries an SQL database can only accept valid SQL. The freeform function calling of GPT-5 supports generation of valid SQL for this situation by constraining the generated text using a context free grammar.
178+
179+
A context‑free grammar is a collection of production rules that define which strings belong to a language. Each rule rewrites a non‑terminal symbol into a sequence of terminals (literal tokens) and/or other non‑terminals, independent of surrounding context—hence context‑free. CFGs can capture the syntax of most programming languages and, in OpenAI custom tools, serve as contracts that force the model to emit only strings that the grammar accepts.
180+
181+
The grammar can be written as either a regular expression:
182+
183+
184+
```python
185+
from pydantic_ai import Agent
186+
from pydantic_ai.models.openai import OpenAIResponsesModel
187+
from pydantic_ai.tools import FunctionTextFormat
188+
189+
model = OpenAIResponsesModel('gpt-5') # (1)!
190+
agent = Agent(model)
191+
192+
timestamp_grammar_definition = r'^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]) (?:[01]\d|2[0-3]):[0-5]\d$'
193+
194+
@agent.tool_plain(text_format=FunctionTextFormat(syntax='regex', grammar=timestamp_grammar_definition) # (2)!
195+
def timestamp_accepting_tool(timestamp: str) -> ...
196+
```
197+
198+
1. The GPT-5 family (`gpt-5`, `gpt-5-mini`, `gpt-5-nano`) all support freeform function calling with context free grammar constraints. Unfortunately gpt-5-nano often struggles with these calls.
199+
2. If the tool or model cannot be used with freeform function calling then it will be invoked in the normal way, which may lead to invalid input.
200+
201+
Or as a [LARK](https://lark-parser.readthedocs.io/en/latest/how_to_use.html) grammar:
202+
203+
```python
204+
from pydantic_ai import Agent
205+
from pydantic_ai.models.openai import OpenAIResponsesModel
206+
from pydantic_ai.tools import FunctionTextFormat
207+
208+
model = OpenAIResponsesModel('gpt-5') # (1)!
209+
agent = Agent(model)
210+
211+
timestamp_grammar_definition = '''
212+
start: timestamp
213+
214+
timestamp: YEAR "-" MONTH "-" DAY " " HOUR ":" MINUTE
215+
216+
%import common.DIGIT
217+
218+
YEAR: DIGIT DIGIT DIGIT DIGIT
219+
MONTH: /(0[1-9]|1[0-2])/
220+
DAY: /(0[1-9]|[12]\d|3[01])/
221+
HOUR: /([01]\d|2[0-3])/
222+
MINUTE: /[0-5]\d/
223+
'''
224+
225+
@agent.tool_plain(text_format=FunctionTextFormat(syntax='lark', grammar=timestamp_grammar_definition) # (2)!
226+
def i_like_iso_dates(date: str) -> ...
227+
```
228+
229+
1. The GPT-5 family (`gpt-5`, `gpt-5-mini`, `gpt-5-nano`) all support freeform function calling with context free grammar constraints. Unfortunately gpt-5-nano often struggles with these calls.
230+
2. If the tool or model cannot be used with freeform function calling then it will be invoked in the normal way, which may lead to invalid input.
231+
232+
There is a limit to the grammar complexity that GPT-5 supports, as such it is important to test your grammar.
233+
234+
##### Best Practices
235+
236+
Lark grammars can be tricky to perfect. While simple grammars perform most reliably, complex grammars often require iteration on the grammar definition itself, the prompt, and the tool description to ensure that the model does not go out of distribution.
237+
238+
Keep terminals bounded – use /[^.\n]{0,10}*\./ rather than /.*\./. Limit matches both by content (negated character class) and by length ({M,N} quantifier).
239+
Prefer explicit char‑classes over . wildcards.
240+
Thread whitespace explicitly, e.g. using SP = " ", instead of a global %ignore.
241+
Describe your tool: tell the model exactly what the CFG accepts and instruct it to reason heavily about compliance.
242+
243+
Troubleshooting
244+
245+
API rejects the grammar because it is too complex ➜ Simplify rules and terminals, remove %ignore.*.
246+
Unexpected tokens ➜ Confirm terminals aren’t overlapping; check greedy lexer.
247+
When the model drifts "out‑of‑distribution" (shows up as the model producing excessively long or repetitive outputs, it is syntactically valid but is semantically wrong):
248+
Tighten the grammar.
249+
Iterate on the prompt (add few-shot examples) and tool description (explain the grammar and instruct the model to reason to conform to it).
250+
Experiment with a higher reasoning effort (e.g, bump from medium to high).
251+
252+
Resources:
253+
254+
Lark Docs – https://lark-parser.readthedocs.io/en/stable/
255+
Lark IDE – https://www.lark-parser.org/ide/
256+
LLGuidance Syntax – https://github.com/guidance-ai/llguidance/blob/main/docs/syntax.md
257+
Regex (Rust crate) – https://docs.rs/regex/latest/regex/#syntax
258+
259+
260+
You can read more about this function calling style in the [openai documentation](https://cookbook.openai.com/examples/gpt-5/gpt-5_new_params_and_tools#3-contextfree-grammar-cfg).
261+
146262
## OpenAI-compatible Models
147263

148264
Many providers and models are compatible with the OpenAI API, and can be used with `OpenAIChatModel` in Pydantic AI.

0 commit comments

Comments
 (0)