Example: OpenAI Assistant with Tavily Tool Calling
The OpenAI Assistants API allows you to build AI agents that maintain state (conversations) and can independently decide to call external functions ("Tools").
Tavily is designed to be the ultimate search tool for these agents. In this example, we define Tavily Search as a tool, instruct the Assistant on how to use it, and implement a CLI loop that handles the asynchronous tool execution lifecycle.
The Implementation
import os
import json
import time
from openai import OpenAI
from tavily import TavilyClient
# 1. Initialize Clients
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
tavily_client = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
# 2. Define the Agent's Persona
assistant_prompt_instruction = """You are a finance expert.
Your goal is to provide answers based on information from the internet.
You must use the provided Tavily search API function to find relevant online information.
You should never use your own knowledge to answer questions.
Please include relevant url sources in the end of your answers.
"""
# 3. Define the Python wrapper function
def tavily_search(query):
# We use get_search_context to get a flat, token-limited string of facts
search_result = tavily_client.get_search_context(
query,
search_depth="advanced",
max_tokens=8000
)
return search_result
# 4. Create the Assistant and Register the Tool Schema
assistant = client.beta.assistants.create(
instructions=assistant_prompt_instruction,
model="gpt-4-1106-preview",
tools=[{
"type": "function",
"function": {
"name": "tavily_search",
"description": "Get information on recent events from the web.",
"parameters": {
"type": "object",
"properties": {
# The LLM will generate this 'query' parameter autonomously
"query": {"type": "string", "description": "The search query to use. For example: 'Latest news on Nvidia stock performance'"},
},
"required": ["query"]
}
}
}]
)
# A Thread represents an ongoing conversation
thread = client.beta.threads.create()
print("Assistant initialized. Type 'exit' to quit.")
# 5. The Conversation Loop
while True:
user_input = input("\nYou: ")
if user_input.lower() == 'exit':
break
# Add the user's message to the thread
client.beta.threads.messages.create(
thread_id=thread.id,
role="user",
content=user_input,
)
# Start a Run (tell the Assistant to process the thread)
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id=assistant.id,
)
# 6. Polling Loop to wait for the Assistant's decision
while True:
time.sleep(1)
# Retrieve the current status of the run
run = client.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id)
# If the Assistant decides it needs external data, it pauses and 'requires_action'
if run.status == 'requires_action':
print("[Agent is searching the web...]")
tool_calls = run.required_action.submit_tool_outputs.tool_calls
tool_outputs = []
# Iterate over the tools the LLM requested to call
for tool in tool_calls:
if tool.function.name == "tavily_search":
# Parse the arguments the LLM generated
args = json.loads(tool.function.arguments)
# Execute our local Python function
output = tavily_search(query=args["query"])
# Append the result to send back to the LLM
tool_outputs.append({
"tool_call_id": tool.id,
"output": output
})
# Submit the search results back to unpause the LLM run
client.beta.threads.runs.submit_tool_outputs(
thread_id=thread.id,
run_id=run.id,
tool_outputs=tool_outputs
)
elif run.status == 'completed':
# The LLM finished generating its final response
break
elif run.status == 'failed':
print(f"Run failed: {run.last_error}")
break
# 7. Print the final message from the Assistant
messages = client.beta.threads.messages.list(thread_id=thread.id)
# The first message in the list is the most recent one
print(f"\nAssistant: {messages.data[0].content[0].text.value}")
Under the Hood
When you ask this script "Why did Tesla stock drop yesterday?", the following happens:
- The
gpt-4model realizes it doesn't know the answer. - Because we provided the JSON schema for
tavily_search, the model pauses execution (requires_action) and outputs a JSON blob requesting a search for "Tesla stock news yesterday". - Our Python
whileloop catches this status, parses the JSON, and fires thetavily_client.get_search_context()method. - Tavily returns a dense string of recent, factual news snippets.
- We submit this string back to OpenAI.
- The
gpt-4model resumes execution, reads the Tavily context, synthesizes a detailed response, appends the URLs as instructed by its prompt, and marks the run ascompleted.