In this quickstart, you'll learn how to leverage Snowflake Cortex's AI capabilities to create an intelligent weather assistant with tool use functionality. This guide demonstrates how Snowflake Cortex integrates with Claude to enable external API interactions, allowing you to define tools, process tool requests, and format tool results to create a seamless conversational experience powered by Snowflake's AI infrastructure.
To prepare your Snowflake environment, you'll need to create the necessary database objects, establish roles with appropriate permissions, and configure external network access for the WeatherAPI service.
Replace YOUR USER with your Snowflake username.
For this application to work, you'll need to:
To create and configure your Streamlit application in Snowflake:
You will need add a package. On the top left select Packages.
Below is the full code for the Weather Assistant application. Copy the Streamlit app from streamlit.py
This section explains how the weather assistant application implements Claude's tool use capabilities in Snowflake.
The Claude API in Snowflake uses several key structures for tool functionality:
tool_use_id
for trackingtool_use_id
The application demonstrates a complete end-to-end implementation with these components.
The heart of our tool use implementation is the get_weather
function, which executes when Claude invokes the weather tool and communicates with the WeatherAPI service:
def get_weather(location):
try:
apiKey = 'YOUR_API_KEY_HERE';
url = f'https://api.weatherapi.com/v1/current.json?key={apiKey}&q={location}';
headers = {
"Content-Type": "application/json"
}
response = re.get(url, headers=headers);
weatherData = response.json();
response.raise_for_status()
current_weather = weatherData.get('current')
condition = current_weather.get('condition')
text = condition.get('text')
icon = condition.get('icon')
return text, icon
except re.exceptions.HTTPError as err:
st.error(f"HTTP error occurred: {err}")
except Exception as e:
st.error(f"Error to get weather: {e}")
return "We were not able to get the weather.", ""
This function:
Next, we'll set up the tool specification and Claude integration through Snowflake's API. This is where we define what the weather tool does and how Claude should use it:
def call_snowflake_claude():
"""
Make an API call to Snowflake's Claude integration.
Args:
user_message (str): The message to send to Claude
location (str): The location to get weather for
Returns:
The response from the API
"""
text = ""
tool_name = None
tool_use_id = None
tool_input = ""
tool_input_json = None
payload = {
"model": "claude-3-5-sonnet",
"messages": messages,
"tool_choice": {
"type": "auto",
"name": [
"get_weather"
]
},
"tools": [
{
"tool_spec": {
"type": "generic",
"name": "get_weather",
"description": "Given a location return the weather",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. in San Francisco, CA"
}
},
"required": [
"location"
]
}
}
}
]
}
try:
resp = _snowflake.send_snow_api_request(
"POST", # method
API_ENDPOINT, # path
{}, # headers
{}, # params
payload, # body
None, # request_guid
API_TIMEOUT, # timeout in milliseconds,
)
# Response processing code...
return text, tool_use_id, tool_name, tool_input_json
except Exception as e:
st.error(f"Error making request: {str(e)}")
return None
Let's break down the key elements of the tool definition:
"model": "claude-3-5-sonnet"
Specifies which Claude model to use. Claude 3.5 Sonnet provides excellent tool use capabilities."tool_choice": {
"type": "auto",
"name": ["get_weather"]
}
"type": "auto"
- Let Claude decide when to use the tool. This is the most flexible option where Claude will determine if a query is appropriate for the tool."name": ["get_weather"]
- Suggests the specific tool when appropriate.type
field include:"type": "required"
- Forces Claude to use at least one of the provided tools. Use this when you want to ensure tool use happens, regardless of Claude's judgment."type": "tool"
- Specifies exactly which tool(s) Claude should use, requiring use of one of the tools specified in the name
array. This gives you the most control over which tool is selected."type": "none"
- Explicitly prevents Claude from using any tools, even if they're provided in the request."tool_spec": {
"type": "generic",
"name": "get_weather",
"description": "Given a location return the weather",
"input_schema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. in San Francisco, CA"
}
},
"required": ["location"]
}
}
"type": "generic"
- Standard tool interface"name"
- Unique identifier for the tool"description"
- Helps Claude understand when to use this tool"input_schema"
- Defines the expected parameters using JSON Schemafor response in response_content:
data = response.get('data', {})
for choice in data.get('choices', []):
delta = choice.get('delta', {})
content_list = delta.get('content_list', [])
for content in content_list:
content_type = content.get('type')
if content_type == 'text':
text += content.get('text', '')
if content_type is None:
if content.get('tool_use_id'):
tool_name = content.get('name')
tool_use_id = content.get('tool_use_id')
tool_input += content.get('input', '')
This code parses Claude's response, handling both regular text responses and tool use requests.This function:
tool_choice
parameter to suggest when Claude should use the toolThe most critical part of the tool use workflow is executing the tool when Claude requests it and properly formatting the results for Claude to incorporate into its response:
if tool_name == 'get_weather':
with st.spinner(f'Utilizing {tool_name} Tool..'):
location = tool_input_json.get('location')
if location:
weather, icon = get_weather(location)
messages.append(
{
'role': 'user',
'content' : query,
'content_list': [
{
'type': 'tool_results',
'tool_results' : {
'tool_use_id' : tool_use_id,
'name': tool_name,
'content' : [
{
'type': 'text',
'text': weather
}
]
}
}
]
}
)
text, tool_use_id, tool_name, tool_input_json = call_snowflake_claude()
with st.chat_message("assistant"):
st.markdown(text)
st.image(icon.replace('//','https://'))
st.session_state.messages.append({"role": "assistant", "content": text})
Let's break down the key elements of returning tool results to Claude:
if tool_name == 'get_weather':
Detects when Claude has requested the weather tool.location = tool_input_json.get('location')
Gets the structured parameter from Claude's tool use request.messages.append(
{
'role': 'user',
'content': query,
'content_list': [
{
'type': 'tool_results',
'tool_results': {
'tool_use_id': tool_use_id,
'name': tool_name,
'content': [
{
'type': 'text',
'text': weather
}
]
}
}
]
}
)
This structure is critical for Claude to process tool results correctly:'type': 'tool_results'
- Indicates this is a tool result response'tool_use_id': tool_use_id
- Must match the ID from Claude's request'name': tool_name
- Identifies which tool was executed'content'
- Array of content elements (text, JSON, etc.)text, tool_use_id, tool_name, tool_input_json = call_snowflake_claude()
Sends the tool results back to Claude so it can incorporate the information into its response.with st.chat_message("assistant"):
st.markdown(text)
st.image(icon.replace('//','https://'))
Displays both the textual response and weather icon in the Streamlit interface.This code demonstrates the complete tool use cycle:
tool_name
tool_results
format Claude expectstool_use_id
to maintain continuity between request and responseThis implements the full tool use lifecycle where Claude requests information, the application fetches it, and Claude then incorporates the results into its final response.
To ensure your application works correctly:
Test with simple weather queries:
Congratulations! You've built a powerful weather assistant application that combines the capabilities of Snowflake Cortex and Claude Sonnet 3.5 with real-time weather data. The tool use capabilities showcase how AI can interact with external services to provide valuable information to users in a conversational manner.
Documentation:
Sample Code & Resources: