1
0

function_calling.py 3.3 KB

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