Function Calling
本教程将指导用户如何在调用 GenStudio 模型时使用 Function Calling。
支持的模型
GenStudio 以下模型已支持通过 Function Calling 访问外部函数。
qwq-32b
定义工具
以下示例展示了如何将外部函数 get_current_weather
定义为 Function Calling 可用的工具函数。
Python 字典需包括工具名称、描述和属性定义的参数。
python
# 定义工具
tools = [
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "The city to find the weather for, e.g. 'San Francisco'",
},
"state": {
"type": "string",
"description": "the two-letter abbreviation for the state that the city is"
" in, e.g. 'CA' which would mean 'California'",
},
"unit": {
"type": "string",
"description": "The unit to fetch the temperature in",
"enum": ["celsius", "fahrenheit"],
},
},
"required": ["city", "state", "unit"],
},
},
}
]
# 定义工具函数
def get_current_weather(city: str, state: str, unit: "str"):
return (
f"The weather in {city}, {state} is 85 degrees {unit}. It is "
"partly cloudly, with highs in the 90's."
)
定义消息
python
def get_messages():
return [
{
"role": "user",
"content": "What's the weather like in Boston today? And how about Paris? Use the tools to help you.",
}
]
messages = get_messages()
初始化客户端
GenStudio 大语言模型 API 服务提供一个实现 OpenAI 的 /v1/chat/completions
的 API 接口。可使用 OpenAI Python 客户端接入。
GENSTUDIO_API_KEY
:GenStudio API Key。DEFAULT_BASE_URL
:使用默认接口时,为https://cloud.infini-ai.com/maas/v1
python
import os
from openai import OpenAI
API_KEY = os.getenv("GENSTUDIO_API_KEY")
BASE_URL = os.getenv("DEFAULT_BASE_URL")
client = OpenAI(api_key=API_KEY, base_url=BASE_URL)
model_name = "qwq-32b"
非流式响应
python
# 非流式响应
response_non_stream = client.chat.completions.create(
model=model_name,
messages=messages,
temperature=0.1,
top_p=0.95,
max_tokens=1024,
stream=False, # 非流式
tools=tools,
)
print("==== Non-stream response ====")
print(response_non_stream)
print("==== reasoning ====")
print(response_non_stream.choices[0].message.reasoning_content)
print("==== content ====")
print(response_non_stream.choices[0].message.content)
print("==== tool_calls ====")
print(response_non_stream.choices[0].message.tool_calls)
输出结果:
shell
==== Non-stream response ====
ChatCompletion(id='d7ba9a8fc50642f187b8ade80f059432', choices=[Choice(finish_reason='tool_calls', index=0, logprobs=None, message=ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='chatcmpl-tool-3e6a83fdef174bc19d75ee284f7ad935', function=Function(arguments='{"city": "Boston", "state": "MA", "unit": "fahrenheit"}', name='get_current_weather'), type='function'), ChatCompletionMessageToolCall(id='chatcmpl-tool-6068afe92ef54ffab6b9df53972a023d', function=Function(arguments='{"city": "Paris", "state": "TX", "unit": "fahrenheit"}', name='get_current_weather'), type='function')], reasoning_content='Okay, the user is asking about the weather in Boston and Paris. Let me check the tools available. There\'s a get_current_weather function that requires city, state, and unit. Wait, Boston is in Massachusetts, so the state abbreviation is MA. But Paris isn\'t in the US; it\'s in France. The tool\'s parameters mention state as a two-letter US state abbreviation. Hmm, so maybe the tool is only for US locations? The user asked for Paris, which might be Paris, Texas, but that\'s not the usual assumption. Alternatively, maybe the tool can handle cities outside the US if state is optional? Wait, looking back, the required parameters are city, state, and unit. Oh, the state is required. So for Paris, France, I can\'t provide a state. That\'s a problem. Maybe the user made a mistake, but I should proceed with the information I have. For Boston, I can use city: Boston, state: MA, unit: let\'s pick celsius or fahrenheit. The user didn\'t specify, so maybe default to celsius, but perhaps the tool expects a choice. Wait, the parameters have unit as an enum, so I have to choose one. Let me assume the user wants Fahrenheit since it\'s common in the US, but maybe better to ask. But since the user told me to use the tools, I have to proceed. So for Boston, I can call get_current_weather with city=Boston, state=MA, unit=fahrenheit. But for Paris, since there\'s no state, maybe there\'s a Paris in the US? Like Paris, TX or Paris, KY? Alternatively, maybe the tool can accept a country code instead, but according to the tool\'s description, the parameters are city and state, with state being a US state. So perhaps the tool is only for US cities. The user might have intended Paris, TX, but that\'s unclear. Alternatively, maybe the user expects me to handle only Boston and explain that Paris isn\'t available. But the user said "use the tools to help you," so I need to use the tool for both. Wait, but the tool can\'t handle Paris, France. So perhaps I should make two tool calls: one for Boston with MA, and another for Paris, but since state is required, maybe the user meant Paris, TX. Let me check the state for Paris, Texas. Paris is in Texas (TX). So maybe the user is referring to that. Alternatively, maybe they meant Paris, France, but the tool can\'t handle that. Since the tool requires state, I have to proceed with the assumption that the user wants Paris in a US state. Let me check if there\'s a Paris in a US state. Yes, Paris, TX is a common one. Alternatively, Paris, KY or IL. Maybe the most well-known is Paris, TX. So I\'ll proceed with that. So two tool calls: one for Boston, MA and another for Paris, TX. But the user might have meant Paris, France, but the tool can\'t do that. Alternatively, maybe the user made a mistake. But given the tool\'s constraints, I have to work with that. So I\'ll make the two calls as best as possible.\n'), matched_stop=151645)], created=1742886704, model='qwq-32b', object='chat.completion', system_fingerprint=None, usage=CompletionUsage(completion_tokens=735, prompt_tokens=257, total_tokens=992, prompt_tokens_details=None))
==== reasoning ====
Okay, the user is asking about the weather in Boston and Paris. Let me check the tools available. There's a get_current_weather function that requires city, state, and unit. Wait, Boston is in Massachusetts, so the state abbreviation is MA. But Paris isn't in the US; it's in France. The tool's parameters mention state as a two-letter US state abbreviation. Hmm, so maybe the tool is only for US locations? The user asked for Paris, which might be Paris, Texas, but that's not the usual assumption. Alternatively, maybe the tool can handle cities outside the US if state is optional? Wait, looking back, the required parameters are city, state, and unit. Oh, the state is required. So for Paris, France, I can't provide a state. That's a problem. Maybe the user made a mistake, but I should proceed with the information I have. For Boston, I can use city: Boston, state: MA, unit: let's pick celsius or fahrenheit. The user didn't specify, so maybe default to celsius, but perhaps the tool expects a choice. Wait, the parameters have unit as an enum, so I have to choose one. Let me assume the user wants Fahrenheit since it's common in the US, but maybe better to ask. But since the user told me to use the tools, I have to proceed. So for Boston, I can call get_current_weather with city=Boston, state=MA, unit=fahrenheit. But for Paris, since there's no state, maybe there's a Paris in the US? Like Paris, TX or Paris, KY? Alternatively, maybe the tool can accept a country code instead, but according to the tool's description, the parameters are city and state, with state being a US state. So perhaps the tool is only for US cities. The user might have intended Paris, TX, but that's unclear. Alternatively, maybe the user expects me to handle only Boston and explain that Paris isn't available. But the user said "use the tools to help you," so I need to use the tool for both. Wait, but the tool can't handle Paris, France. So perhaps I should make two tool calls: one for Boston with MA, and another for Paris, but since state is required, maybe the user meant Paris, TX. Let me check the state for Paris, Texas. Paris is in Texas (TX). So maybe the user is referring to that. Alternatively, maybe they meant Paris, France, but the tool can't handle that. Since the tool requires state, I have to proceed with the assumption that the user wants Paris in a US state. Let me check if there's a Paris in a US state. Yes, Paris, TX is a common one. Alternatively, Paris, KY or IL. Maybe the most well-known is Paris, TX. So I'll proceed with that. So two tool calls: one for Boston, MA and another for Paris, TX. But the user might have meant Paris, France, but the tool can't do that. Alternatively, maybe the user made a mistake. But given the tool's constraints, I have to work with that. So I'll make the two calls as best as possible.
==== content ====
None
==== tool_calls ====
[ChatCompletionMessageToolCall(id='chatcmpl-tool-3e6a83fdef174bc19d75ee284f7ad935', function=Function(arguments='{"city": "Boston", "state": "MA", "unit": "fahrenheit"}', name='get_current_weather'), type='function'), ChatCompletionMessageToolCall(id='chatcmpl-tool-6068afe92ef54ffab6b9df53972a023d', function=Function(arguments='{"city": "Paris", "state": "TX", "unit": "fahrenheit"}', name='get_current_weather'), type='function')]
流式响应
在流式响应情况下,正确处理 data 事件输出结构非常重要。
GenStudio 在返回流式响应时,data 事件中的 choices
可能为空列表,示例如下:
shell
data: {"id":"c246fb420fae4859b5cfb55fb8280cee","object":"chat.completion.chunk","created":1743155679,"model":"qwq-32b","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning_content":null,"tool_calls":[{"id":"chatcmpl-tool-2e51fc034dd64c589c656117c151dcfc","type":"function","function":{"name":"get_current_weather","arguments":""}}]},"logprobs":null,"finish_reason":"tool_call","matched_stop":null}],"usage":null}
data: {"id":"c246fb420fae4859b5cfb55fb8280cee","object":"chat.completion.chunk","created":1743155679,"model":"qwq-32b","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning_content":null,"tool_calls":[{"id":"","type":"function","function":{"name":"","arguments":"elsius\"}"}}]},"logprobs":null,"finish_reason":"tool_call","matched_stop":null}],"usage":null}
data: {"id":"7d16ce44b6eb434a8c2e4fa5438ece5f","model":"qwq-32b","choices":[],"usage":{"prompt_tokens":257,"total_tokens":705,"completion_tokens":448}}
WARNING
流模式下,会出现空的 "choices":[]
。您可能需要为代码增加相应的安全检查。
以下示例在处理 chunk
时已增加必要的安全检查。
python
# 流式响应
response_stream = client.chat.completions.create(
model=model_name,
messages=messages,
temperature=0.1,
top_p=0.95,
max_tokens=1024,
stream=True, # 流式
tools=tools,
)
# 解析流式响应
reasoning_content = ""
content = ""
tool_calls = []
def process_chunk(chunk):
try:
if not (chunk.choices and len(chunk.choices) > 0):
return
delta = chunk.choices[0].delta
if getattr(delta, "reasoning_content", None):
return ("reasoning_content", delta.reasoning_content)
if getattr(delta, "content", None):
return ("content", delta.content)
if getattr(delta, "tool_calls", None):
return ("tool_calls", delta.tool_calls[0])
except AttributeError:
return None
for chunk in response_stream:
result = process_chunk(chunk)
if result is None:
continue
key, value = result
if key == "reasoning_content":
reasoning_content += value
elif key == "content":
content += value
elif key == "tool_calls":
tool_calls.append(value)
print("==== Content ====")
print(content)
print("==== Reasoning Content ====")
print(reasoning_content)
print("\n==== Tool Calls ====")
for tool_call in tool_calls:
print(tool_call)
输出结果:
shell
==== Content ====
==== Reasoning Content ====
Okay, the user is asking about the weather in Boston and Paris. I need to use the get_current_weather tool for each city. Let me check the parameters required. The tool needs city, state, and unit. Wait, Boston is in Massachusetts, so the state abbreviation is MA. But Paris isn't in the US; it's in France. The tool's description mentions the state as a two-letter US abbreviation. Hmm, maybe the tool isn't designed for international locations? The user might expect Paris, France, but the tool requires a US state. This could be a problem. Should I proceed with Boston using MA and note that Paris isn't covered? Or maybe the user made a mistake? Alternatively, perhaps the tool can handle cities without state, but the parameters require it. Let me stick to the tool's requirements. For Boston, I'll use city: "Boston", state: "MA", unit: let's pick celsius as default. For Paris, since there's no state, maybe the tool can't handle it. I should call the tool for Boston first, then explain that Paris isn't possible due to state requirement. Wait, but the user asked for both. Maybe I should check if there's a Paris in the US. There's a Paris, Texas. But that's probably not what the user wants. Alternatively, maybe the tool allows omitting state, but the parameters say it's required. So I can only answer Boston. I'll proceed with that and mention the issue with Paris.
==== Tool Calls ====
ChoiceDeltaToolCall(index=None, id='chatcmpl-tool-318c02d31d46401a8927c9f7f9493f01', function=ChoiceDeltaToolCallFunction(arguments='', name='get_current_weather'), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments='{"city": "', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments='Boston"', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments=', "state": "', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments='MA"', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments=', "unit": "', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments='c', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments='elsius"}', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='chatcmpl-tool-1b16d69ed36d4940a0144dce9dc0402b', function=ChoiceDeltaToolCallFunction(arguments='', name='get_current_weather'), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments='{"city": "', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments='Paris"', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments=', "state": "', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments='TX"', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments=', "unit": "', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments='c', name=''), type='function')
ChoiceDeltaToolCall(index=None, id='', function=ChoiceDeltaToolCallFunction(arguments='elsius"}', name=''), type='function')
NOTE
使用 Function Calling 时,响应体中的 content
字段可能为空。参考:Qwen Function Calling 文档