Toolhouse gives your the flexibility to use your local tools alongside any tools you install from the Tool Store. When you run your local tools with Toolhouse, you can simplify the boilerplate logic required to execute tools and convert their results into valid completion objections.
To execute your local tools just follow these two steps:
In your code, add the register_local_tool() decorator to the function that returns the response to the LLM. Specify the name of the tool as the decorator's parameter.
Your function's signature should accept all the arguments the LLM will pass, both required and optional. Toolhouse may throw an exception if the function signature does not match the required LLM arguments.
Your function should always return a string. Toolhouse will throw an exception if the function does not return a string or string-like value.
Ensure that the arguments you need from the LLM are mapped in the function signature:
import requestsfrom toolhouse import Toolhousefrom anthropic import Anthropicclient =Anthropic(api_key="YOUR_API_KEY")MODEL ="claude-3-5-sonnet-20240620"th =Toolhouse(provider="anthropic")# The parameter must match the name of the tool in your tool definition@th.register_local_tool("get_current_weather")defget_weather_forecast(# These arguments must match the name of the parameters # in your tool definitionlatitude:float,longitude:float) ->str: url = f"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}&hourly=temperature_2m&forecast_days=1"
response = requests.get(url)if response.status_code ==200:return response.textelse:returnf"Error: {response.status_code} - {response.text}"
import requestsfrom toolhouse import Toolhousefrom openai import OpenAIclient =OpenAI()MODEL ="gpt-4o"# If you don't specify an API key, Toolhouse will expect you# specify one in the TOOLHOUSE_API_KEY env variable.th =Toolhouse()# The parameter must match the name of the tool in your tool definition.# See the "name" field in my_local_tools.# The function name in your code can differ from that value.@th.register_local_tool("get_current_weather")defget_weather_forecast(# Must match the name of the parameters in your tool definitionlatitude:float,longitude:float) ->str: url = f"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}&hourly=temperature_2m&forecast_days=1"
response = requests.get(url)if response.status_code ==200:return response.textelse:returnf"Error: {response.status_code} - {response.text}"
import requestsfrom toolhouse import Toolhouseth =Toolhouse()# The parameter must match the name of the tool in your tool definition@th.register_local_tool("get_current_weather")defget_weather_forecast(# Must match the name of the parameters in your tool definitionlatitude:float,longitude:float) ->str: url = f"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}&hourly=temperature_2m&forecast_days=1"
response = requests.get(url)if response.status_code ==200:return response.textelse:returnf"Error: {response.status_code} - {response.text}"my_local_tools = [{"type":"function","function":{"name":"get_current_weather","description":"Retrieves the current weather for the location you specify.","parameters":{"type":"object","properties":{"latitude":{"type":"number","description":"The latitude of the location.",},"longitude":{"type":"number","description":"The longitude of the location.",},"required": ["latitude","longitude", ],},},},}]
import requestsfrom toolhouse import Toolhouseth =Toolhouse()# The parameter must match the name of the tool in your tool definition@th.register_local_tool("get_current_weather")defget_weather_forecast(# Must match the name of the parameters in your tool definitionlatitude:float,longitude:float) ->str: url = f"https://api.open-meteo.com/v1/forecast?latitude={latitude}&longitude={longitude}&hourly=temperature_2m&forecast_days=1"
response = requests.get(url)if response.status_code ==200:return response.textelse:returnf"Error: {response.status_code} - {response.text}"my_local_tools = [{"type":"function","function":{"name":"get_current_weather","description":"Retrieves the current weather for the location you specify.","parameters":{"type":"object","properties":{"latitude":{"type":"number","description":"The latitude of the location.",},"longitude":{"type":"number","description":"The longitude of the location.",},"required": ["latitude","longitude", ],},},},}]
Pass your local tools
Define your local tools as a variable like my_local_tools
Append your tools to the th.get_tools() call, then use th.run_tools() to run both your local and cloud tools.
my_local_tools = [{"name":"get_current_weather","description":"Retrieves the current weather for the location you specify.","input_schema":{"type":"object","properties":{"latitude":{"type":"number","description":"The latitude of the location.",},"longitude":{"type":"number","description":"The longitude of the location.",},},"required": ["latitude","longitude", ]}}]messages = [{"role":"user","content":"What's the weather in Oakland, CA?",}]response = client.messages.create( model=MODEL, messages=messages, max_tokens=1000, tools=th.get_tools() + my_local_tools,)# Runs your local tool, gets the result, # and appends it to the contexttool_run = th.run_tools(response)messages = messages + tool_runresponse = client.messages.create( model=MODEL, messages=messages, max_tokens=1000, tools=th.get_tools(),)print(response.content[0].text)
my_local_tools = [{"type":"function","function":{"name":"get_current_weather", "description": "Retrieves the current weather for the latitude and longitude belonging to a place you know. When you specify the latitude and longitude, IT IS CRUCIAL THAT YOU DO NOT SPECIFY ANYTHING ELSE. Before you use this tool, ensure that you only send the latitude and longitude of the place you know. If you are sending any other information, think again and remove any information that is not latitude and longitude.",
"parameters":{"type":"object","properties":{"latitude":{"type":"number","description":"The latitude of the location.",},"longitude":{"type":"number","description":"The longitude of the location.",}},"required": ["latitude","longitude", ],"additionalProperties":False},},} ]messages = [{"role":"user","content":"What's the weather in Oakland, CA?",}]response = client.chat.completions.create( model=MODEL, messages=messages, tools=th.get_tools() + my_local_tools,)# Runs your local tool, gets the result, # and appends it to the contexttool_run = th.run_tools(response)messages += tool_runresponse = client.chat.completions.create( model=MODEL, messages=messages, tools=th.get_tools() + my_local_tools,)print(response.choices[0].message.content)
import osfrom anthropic import AnthropicBedrockclient =AnthropicBedrock( aws_access_key=os.environ.get("AWS_ACCESS_KEY"), aws_secret_key=os.environ.get("AWS_SECRET_KEY"), aws_session_token=os.environ.get("AWS_SESSION_TOKEN"), aws_region=os.environ.get("AWS_REGION"),)MODEL ="anthropic.claude-3-5-sonnet-20240620-v1:0"messages = [{"role":"user","content":"What's the weather in Oakland, CA?",}]response = client.messages.create( model=MODEL, messages=messages, max_tokens=1000, tools=th.get_tools() + my_local_tools,)# Runs your local tool, gets the result, # and appends it to the contexttool_run = th.run_tools(response)messages.append(tool_run)response = client.chat.completions.create( model=MODEL, messages=messages, tools=th.get_tools(),)print(response.choices[0].text)
import osfrom openai import AzureOpenAIclient =AzureOpenAI( api_key=os.environ.get("AZURE_OPENAI_API_KEY"), api_version="2024-02-01", azure_endpoint = os.environ.get("AZURE_OPENAI_ENDPOINT") )DEPLOYMENT_ID ="REPLACE_WITH_YOUR_DEPLOYMENT_NAME"messages = [{"role":"user","content":"What's the weather in Oakland, CA?",}]response = client.chat.completions.create( model=DEPLOYMENT_ID, messages=messages,# Passes Code Execution as a tool tools=th.get_tools() + my_local_tools,)# Runs your local tool, gets the result, # and appends it to the contexttool_run = th.run_tools(response)messages.append(tool_run)response = client.chat.completions.create( model=MODEL, messages=messages, tools=th.get_tools(),)print(response.choices[0].text)
import osfrom groq import Groqclient =Groq(api_key=os.environ.get('GROQ_API_KEY'))MODEL ='llama3.1-70b-8192'messages = [{"role":"user","content":"What's the weather in Oakland, CA?",}]response = client.chat.completions.create( model=MODEL, messages=messages, tools=th.get_tools() + my_local_tools,)# Runs your local tool, gets the result, # and appends it to the contexttool_run = th.run_tools(response)messages.append(tool_run)response = client.chat.completions.create( model=MODEL, messages=messages, tools=th.get_tools(),)print(response.choices[0].text)
import osfrom together import Togetherclient =Together(api_key=os.environ.get('TOGETHER_API_KEY'))MODEL ='mistralai/Mixtral-8x7B-Instruct-v0.1'messages = [{"role":"user","content":"What's the weather in Oakland, CA?",}]response = client.chat.completions.create( model=MODEL, messages=messages,# Passes Code Execution as a tool tools=th.get_tools() + my_local_tools,)# Runs your local, gets the result, # and appends it to the contexttool_run = th.run_tools(response)messages.append(tool_run)response = client.chat.completions.create( model=MODEL, messages=messages, tools=th.get_tools(),)print(response.choices[0].text)
Toolhouse will always execute tools in the order chosen by the LLM. If your LLM supports parallel tool use, tools will be executed one by one as specified by the LLM.
Overriding cloud tools
Your local tools will always have priority over cloud tools. In other words, if your local tool has the same name as a cloud tool, Toolhouse will execute your local tool.
You can use tool override to bypass cloud execution when you need to do so. This is useful in situations where you need to cache or memoize a function's request, or if you want to inhibit the behavior of a function for a specific completion call.
Treat tool definitions as prompts
Describe your tools like you would you describe the behavior of your assistant. Ensure each tool description contains precise, detailed instructions. This is particularly important for models with fewer parameters, which tend to be less accurate in generating a valid tool call for your user prompts.