What are the best practices for handling function calling when circular references are involved? I have attached image of an openapi spec that has a circular reference. How should I feed this to the function calling api?
If it can’t be unwrapped and expanded, I don’t think it can be done.
The function call AI-received language has a pretty limited “vocabulary” for placing functions. When strict, the function also has to form a grammar for enforcing JSON output, by object key name.
Infinitely deep JSON, whenever the AI might want, isn’t in the cards. You might consider the practical flattened schema that can specify the tool output you need that can be validated.
hmm I am unsure as to why my post was blocked. As long as graphs are well managed it shows a working system I wrote 20 years ago to fix this very issue soon after JSON came out.
I wont repost as I haven’t been given any information as to why it was blocked other than.
" Your post was flagged as off-topic"
As a known working solution it is hardly off-topic and as @arata says:
As I said in my post.
“This may not directly fix OpenAI’s issue but it may give you ideas on how you might overcome this issue.”
o1’s take on this:
Short Summary
Using this in a node-based architecture can be perfectly valid if you manage security, avoid unwanted cycles, and keep performance in check. As long as you understand the risks and plan the architecture thoroughly, this approach offers a flexible way to execute dynamic code.
It is likely that your post was plugging some GPTs that have no skill in creating structured output function schemas for OpenAI API models.
No lol I have tested a few GPTs to help beginners but clearly GPTs have issues. The GPTs I have written simply show methods that are replicatable in code. They are tests of the GPT system that show basic concepts programmers take for granted but others don’t understand. I have written these as they are intended, as an educational tool.
My post and 4 threads I have produced on the forum that show the structure of this system represents a complete working application I have written with over 30k lines of code.
I am not out to plug anything. I make no money/have no benefit from the solutions I post here. I post everything simply to help.
In my opinion OP should take a look at the underlying data structures and resolve the circular reference there. This appears to be a very basic problem that can be resolved by adding an abstraction layer, unifying the data into one table, keeping a duplicate of one of the tables, among many other approaches. Ultimately, I just don’t see any reason why the circular reference should be there. I could be wrong though?
@phyde1001
If you find the time I would be interested to learn how your suggested approach can be used to answer OP’s question.
I won’t get into the discussion about the flag here. That would be off-topic.
Welcome to the dev forum @andrewhlayer
You don’t feed an OpenAPI YAML schema directly for function calls. Instead, you define the specific functions (endpoints) you want the model to be able to call—along with their parameters—and let the model generate structured arguments for those functions.
Consider the schema you shared for reference.
Here’s how we can write function definitions for:
Listing all pets (no parameters)
{
"type": "function",
"function": {
"name": "listAllPets",
"description": "Retrieves a list of all pets in the Petstore. No parameters needed.",
"strict": true,
"parameters": {
"type": "object",
"properties": {},
"required": [],
"additionalProperties": false
}
}
}
Looking up an owner by Pet ID
{
"type": "function",
"function": {
"name": "getOwnerForPet",
"description": "Fetches the owner object for a specific Pet by pet_id.",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"pet_id": {
"type": "integer",
"description": "The unique ID of the Pet whose owner you want."
}
},
"required": ["pet_id"],
"additionalProperties": false
}
}
}
Looking up pets by Owner ID
{
"type": "function",
"function": {
"name": "getPetsByOwner",
"description": "Fetches all pets belonging to a specific owner by owner_id.",
"strict": true,
"parameters": {
"type": "object",
"properties": {
"owner_id": {
"type": "integer",
"description": "The unique ID of the Owner whose pets you want."
}
},
"required": ["owner_id"],
"additionalProperties": false
}
}
}
Typically, you only need shallow relationships. If you want the model to get more details, you can chain these function calls. For instance, once you have the pet_id
, you can pass it to the getOwnerForPet
function; if you have an owner_id
, you can call getPetsByOwner
, etc.
How This Maps to the Original Schema
-
listAllPets
In your OpenAPI snippet,GET /pets
simply returns all pets, so no parameters are needed. A function with no parameters is enough. -
getOwnerForPet
If you need to look up an owner, you don’t necessarily embed the entireOwner
object inside aPet
. You can define a dedicated function that takes a pet’s ID and returns the owner info. -
getPetsByOwner
Conversely, if you have anowner_id
and want to see their pets, define a function that returns all pets owned by them.
tl;dr
Rather than feeding the entire OpenAPI document to the model, you pick which real actions you want—list pets, get an owner, get an owner’s pets—and define concise function calling schemas for them. You can always chain them if you need multi-step queries.