Skip to content

Commit 188ac44

Browse files
committed
function calling example with weather tool
1 parent 456fbdd commit 188ac44

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed

examples/function_calling.py

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import json
2+
import re
3+
import requests
4+
5+
def get_current_weather(location: str, unit: str = "celsius"):
6+
"""Mock weather data function"""
7+
# Hardcoded response for demo purposes
8+
return {
9+
"location": location,
10+
"temperature": 22 if unit == "celsius" else 72,
11+
"unit": unit,
12+
"forecast": "Sunny with light clouds"
13+
}
14+
15+
def try_parse_tool_calls(content: str):
16+
"""Try parse the tool calls."""
17+
tool_calls = []
18+
offset = 0
19+
for i, m in enumerate(re.finditer(r"<tool_call>\n(.+)?\n</tool_call>", content)):
20+
if i == 0:
21+
offset = m.start()
22+
try:
23+
func = json.loads(m.group(1))
24+
tool_calls.append({"type": "function", "function": func})
25+
if isinstance(func["arguments"], str):
26+
func["arguments"] = json.loads(func["arguments"])
27+
except json.JSONDecodeError as e:
28+
print(f"Failed to parse tool calls: the content is {m.group(1)} and {e}")
29+
pass
30+
if tool_calls:
31+
if offset > 0 and content[:offset].strip():
32+
c = content[:offset]
33+
else:
34+
c = ""
35+
return {"role": "assistant", "content": c, "tool_calls": tool_calls}
36+
return {"role": "assistant", "content": re.sub(r"<\|im_end\|>$", "", content)}
37+
38+
def chat_completion(messages):
39+
"""Send chat completion request to local server"""
40+
response = requests.post(
41+
"http://localhost:52415/v1/chat/completions",
42+
json={
43+
"model": "qwen-2.5-1.5b",
44+
"messages": messages,
45+
"tools": [{
46+
"type": "function",
47+
"function": {
48+
"name": "get_current_weather",
49+
"description": "Get the current weather in a given location",
50+
"parameters": {
51+
"type": "object",
52+
"properties": {
53+
"location": {
54+
"type": "string",
55+
"description": "The city and state, e.g. San Francisco, CA"
56+
},
57+
"unit": {
58+
"type": "string",
59+
"enum": ["celsius", "fahrenheit"]
60+
}
61+
},
62+
"required": ["location"]
63+
}
64+
}
65+
}],
66+
"tool_choice": "auto"
67+
}
68+
)
69+
return response.json()
70+
71+
def main():
72+
# Initial conversation
73+
messages = [{
74+
"role": "user",
75+
"content": "Hi there, what's the weather in Boston?"
76+
}]
77+
78+
# Get initial response
79+
response = chat_completion(messages)
80+
print(f"First response: {response}")
81+
assistant_message = try_parse_tool_calls(response["choices"][0]["message"]["content"])
82+
messages.append(assistant_message)
83+
84+
# If there are tool calls, execute them and continue conversation
85+
if "tool_calls" in assistant_message:
86+
for tool_call in assistant_message["tool_calls"]:
87+
if tool_call["function"]["name"] == "get_current_weather":
88+
args = tool_call["function"]["arguments"]
89+
weather_data = get_current_weather(**args)
90+
91+
# Add tool response to messages
92+
messages.append({
93+
"role": "tool",
94+
"content": json.dumps(weather_data),
95+
"name": tool_call["function"]["name"]
96+
})
97+
98+
# Get final response with weather data
99+
response = chat_completion(messages)
100+
print(f"Final response: {response}")
101+
messages.append({
102+
"role": "assistant",
103+
"content": response["choices"][0]["message"]["content"]
104+
})
105+
106+
# Print full conversation
107+
for msg in messages:
108+
print(f"\n{msg['role'].upper()}: {msg['content']}")
109+
110+
if __name__ == "__main__":
111+
main()

0 commit comments

Comments
 (0)