Connect Desearch to OpenAI models through tool calling, so GPT can run live search queries when it needs fresh data.
Function Calling with GPT
1. Installation and Requirements
pip install openai desearch_py rich
- openai: OpenAI API client
- desearch_py: Desearch search
- rich: terminal output
2. Setting Environment Variables
Create a .env file in the root of your project:
OPENAI_API_KEY=your_openai_api_key
DESEARCH_API_KEY=your_desearch_api_key
Get your API keys from:
- <Anchor label="OpenAI API Key" target="_blank" href="https://platform.openai.com/api-keys">OpenAI API Key</Anchor>
- <Anchor label="Desearch API Key" target="_blank" href="https://console.desearch.ai/api-keys">Desearch API Key</Anchor>
3. What Is Tool Calling?
Tool calling lets OpenAI models return structured calls to functions you define. A sample schema:
{
"name": "desearch_search",
"description": "Performs a search and returns relevant information.",
"input_schema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search query to run."
}
},
"required": ["query"]
}
}
OpenAI returns a function name and its parameters. Your code executes the actual call.
4. Integrating Desearch as an OpenAI Tool
Step 1: Initialize Your Clients
from dotenv import load_dotenv
from desearch_py import Desearch
from openai import OpenAI
import os
load_dotenv()
openai = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
desearch = Desearch(api_key=os.getenv("DESEARCH_API_KEY"))
Step 2: Define Tool Schema
TOOLS = [
{
"name": "desearch_search",
"description": "Perform a web search and return relevant results.",
"input_schema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search term to use."
}
},
"required": ["query"]
}
}
]
Step 3: Define the System Prompt:
SYSTEM_MESSAGE = {
"role": "system",
"content": "You are a smart assistant with access to a powerful search engine. Use the provided tool to help the user find answers."
}
Step 4: Create the Desearch Function
def desearch_search(query: str) -> dict:
return desearch.ai_search(
prompt=query,
tools=["twitter"],
model="NOVA",
date_filter="PAST_24_HOURS",
streaming=False
)
Step 5: Handle Tool Calls
def process_tool_calls(tool_calls, messages):
for call in tool_calls:
args = json.loads(call.function.arguments)
if call.function.name == "desearch_search":
results = desearch_search(**args)
messages.append({
"role": "tool",
"content": str(results),
"tool_call_id": call.id
})
return messages
Step 6: Build the Main Loop
def main():
messages = [SYSTEM_MESSAGE]
while True:
user_input = Prompt.ask("🔎 What do you want to search for?")
messages.append({"role": "user", "content": user_input})
response = openai.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=TOOLS
)
message = response.choices[0].message
tool_calls = message.tool_calls
if tool_calls:
messages.append(message)
messages = process_tool_calls(tool_calls, messages)
messages.append({
"role": "user",
"content": "Use the search results to answer my last question."
})
final_response = openai.chat.completions.create(
model="gpt-4o-mini",
messages=messages
)
console.print(Markdown(final_response.choices[0].message.content))
else:
console.print(Markdown(message.content))
5. Run the App
Save the code as openai_search.py with your .env file in the same directory. Run it:
You'll be prompted:
What do you want to search for?
Type a query and the assistant answers using Desearch results:
What do you want to search for?: What is bittensor?
Context updated with desearch_search (None): What is bittensor?
Bittensor is a decentralized AI network designed to create a marketplace for machine learning models and AI training services. Unlike traditional AI systems, which are often restricted by centralized APIs or paywalls, Bittensor utilizes blockchain technology to allow open and permissionless participation in AI development. The primary aim is to democratize access to AI and build a collaborative ecosystem where contributors earn rewards for training and enhancing AI models.
At its core, Bittensor functions as a decentralized marketplace where participants, referred to as miners, contribute computational resources to train machine learning models. In return, these miners earn TAO tokens as rewards. This structure fosters a competitive market based on incentives, encouraging ongoing innovation and improvement of AI technologies.
Bittensor is characterized as a network of incentive-driven subnets rather than a traditional blockchain like Bitcoin or Ethereum. Each subnet acts as a competitive market for AI training, promoting a self-sustaining economy wherein AI models are continuously refined through collective contributions.
The ecosystem aims to integrate AI with Web3 principles, emphasizing ownership, control, and open participation. By facilitating a decentralized AI marketplace, Bittensor seeks to drive innovation through collaborative effort and financial incentives, potentially leading to more diverse and powerful AI models.
In summary, Bittensor represents an innovative approach to merging blockchain technology with AI training and marketplace dynamics, promoting a shift towards decentralized AI ownership and collaboration.
Full code
import json
import os
from dotenv import load_dotenv
from typing import Any, Dict
from desearch_py import Desearch
from openai import OpenAI
from rich.console import Console
from rich.markdown import Markdown
from rich.prompt import Prompt
load_dotenv()
openai = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
desearch = Desearch(api_key=os.getenv("DESEARCH_API_KEY"))
console = Console()
TOOLS = [
{
"type": "function",
"function": {
"name": "desearch_search",
"description": "Perform a web search and return relevant results.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search term to use.",
}
},
"required": ["query"],
},
},
}
]
SYSTEM_MESSAGE = {
"role": "system",
"content": "You are a smart assistant with access to a powerful search engine. Use the provided tool to help the user find answers.",
}
def desearch_search(query: str) -> dict:
return desearch.ai_search(
prompt=query,
tools=["twitter"],
model="NOVA",
date_filter="PAST_24_HOURS",
streaming=False,
)
def process_tool_calls(tool_calls, messages):
for call in tool_calls:
args = json.loads(call.function.arguments)
if call.function.name == "desearch_search":
results = desearch_search(**args)
messages.append(
{"role": "tool", "content": str(results), "tool_call_id": call.id}
)
console.print(
f"[bold cyan]Context updated[/bold cyan] [i]with[/i] "
f"[bold green]desearch_search ({args.get('mode')})[/bold green]: ",
args.get("query"),
)
return messages
def main():
messages = [SYSTEM_MESSAGE]
while True:
try:
user_input = Prompt.ask("🔎 What do you want to search for?")
messages.append({"role": "user", "content": user_input})
response = openai.chat.completions.create(
model="gpt-4o-mini", messages=messages, tools=TOOLS
)
message = response.choices[0].message
tool_calls = message.tool_calls
if tool_calls:
messages.append(message)
messages = process_tool_calls(tool_calls, messages)
messages.append(
{
"role": "user",
"content": "Use the search results to answer my last question.",
}
)
final_response = openai.chat.completions.create(
model="gpt-4o-mini", messages=messages
)
console.print(Markdown(final_response.choices[0].message.content))
else:
console.print(Markdown(message.content))
except Exception as e:
console.print(f"[bold red]An error occurred:[/bold red] {str(e)}")
if __name__ == "__main__":
main()