Azure OpenAI Assistants function calling

The Assistants API supports function calling, which allows you to describe the structure of functions to an Assistant and then return the functions that need to be called along with their arguments.

Note

  • File search can ingest up to 10,000 files per assistant - 500 times more than before. It is fast, supports parallel queries through multi-threaded searches, and features enhanced reranking and query rewriting.
    • Vector store is a new object in the API. Once a file is added to a vector store, it's automatically parsed, chunked, and embedded, made ready to be searched. Vector stores can be used across assistants and threads, simplifying file management and billing.
  • We've added support for the tool_choice parameter which can be used to force the use of a specific tool (like file search, code interpreter, or a function) in a particular run.

Function calling support

Supported models

The models page contains the most up-to-date information on regions/models where Assistants are supported.

To use all features of function calling including parallel functions, you need to use a model that was released after November 6th 2023.

API Versions

API versions starting with 2024-02-15-preview.

Example function definition

Note

  • We've added support for the tool_choice parameter which can be used to force the use of a specific tool (like file_search, code_interpreter, or a function) in a particular run.
  • Runs expire ten minutes after creation. Be sure to submit your tool outputs before this expiration.
  • You can also perform function calling with Azure Logic apps
from openai import AzureOpenAI
    
client = AzureOpenAI(
    api_key=os.getenv("AZURE_OPENAI_API_KEY"),  
    api_version="2024-07-01-preview",
    azure_endpoint = os.getenv("AZURE_OPENAI_ENDPOINT")
    )

assistant = client.beta.assistants.create(
  name="Weather Bot",
  instructions="You are a weather bot. Use the provided functions to answer questions.",
  model="gpt-4", #Replace with model deployment name
  tools=[{
      "type": "function",
    "function": {
      "name": "get_weather",
      "description": "Get the weather in location",
      "parameters": {
        "type": "object",
        "properties": {
          "location": {"type": "string", "description": "The city name, for example San Francisco"}
        },
        "required": ["location"]
      }
    }
  }]
)

Reading the functions

When you initiate a Run with a user Message that triggers the function, the Run will enter a pending status. After it processes, the run will enter a requires_action state that you can verify by retrieving the Run.

{
  "id": "run_abc123",
  "object": "thread.run",
  "assistant_id": "asst_abc123",
  "thread_id": "thread_abc123",
  "status": "requires_action",
  "required_action": {
    "type": "submit_tool_outputs",
    "submit_tool_outputs": {
      "tool_calls": [
        {
          "id": "call_abc123",
          "type": "function",
          "function": {
            "name": "get_weather",
            "arguments": "{\"location\":\"Seattle\"}"
          }
        },
      ]
    }
  },
...

Submitting function outputs

You can then complete the Run by submitting the tool output from the function(s) you call. Pass the tool_call_id referenced in the required_action object to match output to each function call.


# Example function
def get_weather():
    return "It's 80 degrees F and slightly cloudy."

# Define the list to store tool outputs
tool_outputs = []
 
# Loop through each tool in the required action section
for tool in run.required_action.submit_tool_outputs.tool_calls:
  # get data from the weather function
  if tool.function.name == "get_weather":
    weather = get_weather()
    tool_outputs.append({
      "tool_call_id": tool.id,
      "output": weather
    })
 
# Submit all tool outputs at once after collecting them in a list
if tool_outputs:
  try:
    run = client.beta.threads.runs.submit_tool_outputs_and_poll(
      thread_id=thread.id,
      run_id=run.id,
      tool_outputs=tool_outputs
    )
    print("Tool outputs submitted successfully.")
  except Exception as e:
    print("Failed to submit tool outputs:", e)
else:
  print("No tool outputs to submit.")
 
if run.status == 'completed':
  print("run status: ", run.status)
  messages = client.beta.threads.messages.list(thread_id=thread.id)
  print(messages.to_json(indent=2))

else:
  print("run status: ", run.status)
  print (run.last_error.message)

After you submit tool outputs, the Run will enter the queued state before it continues execution.

See also