支持私有云部署
AI知识库

53AI知识库

学习大模型的前沿技术与行业应用场景


仅需2步,解锁 QwQ-32B 的 Function Call 超能力

发布日期:2025-03-21 21:33:04 浏览次数: 1567 来源:通义千问Qwen
推荐语

掌握QwQ-32B模型的Function Call技能,轻松实现工具调用与多步骤推理。

核心内容:
1. QwQ-32B模型在LiveBench榜单上的优异表现
2. 两种方法实现QwQ-32B的Function Call调用
3. 工具Schema定义与执行函数实现示例

杨芳贤
53A创始人/腾讯云(TVP)最具价值专家

前不久,我们发布了推理模型通义千问QwQ-32B,在 LiveBench 榜单上取得了开源模型的最佳成绩。


在针对模型的 Agent 能力的 BFCL 评测中,千问 QwQ-32B 模型在工具调用准确率、复杂参数解析等核心指标上均有不凡表现,展现出领先的函数调用与多步骤推理能力。


今天,我们将分享如何简单方便地基于 QwQ-32B 进行 Function Call 的调用,通过标准化代码案例,系统讲解其在工具调用场景中的技术实现与应用实践。


调用QwQ-32B的Function Call,我们以以下两种方法为例:

(1)百炼API

(2)Qwen-Agent开源框架


准备工作

(1)定义自己的工具 Schema

(2)实现工具的执行函数


TOOLS = [{    "name": "train_tickets",    "description": "Obtain train tickets and other information based on departure, arrival, and time.",    "parameters": {        "type": "object",        "properties": {            "start": {                "type": "string",                "description": "The departure city."            },            "end": {                "type": "string",                "description": "The arrival city."            },            "date": {                "type": "string",                "description": "The date, such as 2024-02-21. If not clear, do not fill in."            }        },        "required": [            "start",            "end",            "date"        ]    }},{    "name": "get_weather",    "description": "Weather inquiry.",    "parameters": {        "type": "object",        "properties": {            "area": {                "type": "string",                "description": "Regional name, such as 丽江"            }        },        "required": [            "area"        ]    }}]
import json
def get_weather(area: str):    # 作为示例,这里定义一个假的工具执行函数    res = {        "area": "上海",        "weather": {            "areaid": "101020100",            "temperature": "12",            "weather": "晴",            "wind_direction": "西风",            "wind_power": "0-3级 微风  <5.4m/s",            "weather_code": "00"        },    }    return json.dumps(res, ensure_ascii=False)

def train_tickets(start: str, end: str, date: str):    # 作为示例,这里定义一个假的工具执行函数    if start == '上海' and end == '杭州':        res = {                "costtime": "1小时19分",                "trainno": "C3629",                "arrivaltime": "17:34",                "endstation": "杭州西",                "terminalstationcode": "YWH",                "departstation": "上海虹桥",                "station": "上海虹桥",                "departuretime": "16:15",                "departstationcode": "AOH",            }    elif start == '杭州' and end == '上海':        res = {            "costtime": "0小时48分",            "trainno": "G7336",            "arrivaltime": "8:34",            "endstation": "上海南",            "terminalstationcode": "SNH",            "departstation": "苍南",            "station": "杭州东",            "departuretime": "7:46",            "departstationcode": "CEH",        }    else:        res = {"train_list": "No available train"}    return json.dumps(res, ensure_ascii=False)

TOOL_EXEC_MAP = {    'train_tickets': train_tickets,    'get_weather': get_weather}



百炼API

运行以下代码,完成一次含有工具调用的请求。

主要包含三个步骤:

(1)发起模型请求,输入用户问题和工具

(2)读取返回内容,如果返回内容包含工具调用,则执行工具,获得工具结果

(3)再次发起模型请求,输入工具结果。循环(1)-->(3)

import osfrom openai import OpenAI
# 初始化OpenAI客户端,配置阿里云DashScope服务client = OpenAI(    # 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",    api_key=os.getenv("DASHSCOPE_API_KEY"),  # 从环境变量读取API密钥    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",)
# 输入用户请求messages = [{"role": "user", "content": "今天是2025年3月17号,我马上要去上海出差,当天往返,请帮我查询今天从杭州到上海往返的火车票,此外,再帮我查询一下上海今天的天气。"}]
while True:    completion = client.chat.completions.create(        model="qwq-32b",        messages=messages,        tools=[{"type": "function", "function": fn} for fn in TOOLS],  # 百炼API要求输入的工具格式        parallel_tool_calls=True,        stream=True,    )
    # 打印模型流式回复    reasoning_content = ""    answer_content = ""    tool_calls = []    is_answering = False    print('\n[思考内容]: \n')    for chunk in completion:        delta = chunk.choices[0].delta        # AI的思考过程        if hasattr(delta, 'reasoning_content') and delta.reasoning_content is not None:            reasoning_content += delta.reasoning_content            print(delta.reasoning_content, end="", flush=True)  # 实时输出思考过程
       # 最终回复内容        if delta.content is not None:            if not is_answering:                is_answering = True                print('\n[回复内容]: \n')            answer_content += delta.content            print(delta.content, end="", flush=True)  # 流式输出回复内容
       # 工具调用信息(支持并行工具调用)        if delta.tool_calls is not None:            for tool_call in delta.tool_calls:                index = tool_call.index                # 动态扩展工具信息存储列表                if len(tool_calls) <= index:                    tool_calls.append({'type': 'function', 'function': {'name': tool_call.function.name, 'arguments': tool_call.function.arguments}})                else:                    # 收集函数参数(JSON字符串格式,需要后续解析)                    if tool_call.function and tool_call.function.arguments:                        tool_calls[index]['function']['arguments'] += tool_call.function.arguments
   # 判断是否发起工具调用,如果有,则执行工具    if tool_calls:        print('\n[工具调用]: \n', tool_calls)        response = [{'role': 'assistant', 'content': answer_content, 'reasoning_content': reasoning_content, 'tool_calls': tool_calls}]
       tool_response = []        for tool_call in tool_calls:            tool_name = tool_call['function']['name']            tool_args = json.loads(tool_call['function']['arguments'])            tool_exec_res = TOOL_EXEC_MAP[tool_name](**tool_args)            tool_response.append({'role': 'tool', 'content': tool_exec_res, 'name': tool_name})        print('\n[工具结果]: \n', tool_response)
       # 拼接工具结果,和LLM进行下一轮对话        messages.extend(response)        messages.extend(tool_response)    else:        # 无工具执行,对话结束        response = [{'role': 'assistant', 'content': answer_content, 'reasoning_content': reasoning_content}]        messages.extend(response)        break

以上代码输出为:

[    {"role": "user", "content": "今天是2025年3月17号,我马上要去上海出差,当天往返,请帮我查询今天从杭州到上海往返的火车票,此外,再帮我查询一下上海今天的天气。"},     {"role": "assistant", "content": "", "reasoning_content": "好的,用户今天需要从杭州到上海出差,当天往返,并且需要查询今天的火车票和上海的天气。首先,我需要确认用户提供的日期是否正确。用户提到今天是2025年3月17日,所以日期参数应该是当天。\n\n对于火车票查询,用户明确提到了出发地是杭州,目的地是上海,日期是今天,也就是2025-03-17。需要往返票,但函数参数里只需要start、end和date,所以可能需要两次查询?或者往返是否需要分开处理?不过根据函数描述,可能每次调用只能查单程,所以可能需要两次调用,但用户可能只需要一次查询往返的信息。不过根据提供的函数参数,必须包含start、end和date,所以可能需要调用一次,但往返可能需要分开处理。但用户可能希望往返的信息,但函数可能不支持往返参数,所以可能需要两次调用?或者可能函数返回的结果包含往返选项?不确定,但按照现有函数结构,可能需要先调用一次从杭州到上海的单程,然后返回时从上海到杭州的单程。因此需要两次调用train_tickets函数,分别查询去程和返程。\n\n不过用户可能只需要一次查询,但根据函数参数,可能需要两次。因此,首先处理去程:start是杭州,end是上海,date是2025-03-17。然后返程是start上海,end杭州,同样的日期。不过用户可能希望当天往返,所以需要确保返程的时间在当天。不过可能用户只需要一次查询往返,但根据函数设计,可能需要分开调用。\n\n接下来是天气查询,用户需要上海今天的天气,所以调用get_weather函数,area参数是上海。\n\n现在需要按照步骤调用这两个函数。首先处理火车票,两次调用,然后天气查询。但可能用户希望先处理火车票再去天气。所以先处理train_tickets两次,然后get_weather一次。不过需要确认是否必须所有参数都正确。例如,用户说当天往返,所以date都是同一天。所以两次train_tickets调用,参数分别是杭州到上海,和上海到杭州,日期都是2025-03-17。\n\n因此,首先生成两个tool_call,然后一个天气查询。", "tool_calls": [{"type": "function", "function": {"name": "train_tickets", "arguments": "{\"start\": \"杭州\", \"end\": \"上海\", \"date\": \"2025-03-17\"}"}}, {"type": "function", "function": {"name": "train_tickets", "arguments": "{\"start\": \"上海\", \"end\": \"杭州\", \"date\": \"2025-03-17\"}"}}, {"type": "function", "function": {"name": "get_weather", "arguments": "{\"area\": \"上海\"}"}}]},     {"role": "tool", "content": "{\"costtime\": \"0小时48分\", \"trainno\": \"G7336\", \"arrivaltime\": \"8:34\", \"endstation\": \"上海南\", \"terminalstationcode\": \"SNH\", \"departstation\": \"苍南\", \"station\": \"杭州东\", \"departuretime\": \"7:46\", \"departstationcode\": \"CEH\"}", "name": "train_tickets"},     {"role": "tool", "content": "{\"costtime\": \"1小时19分\", \"trainno\": \"C3629\", \"arrivaltime\": \"17:34\", \"endstation\": \"杭州西\", \"terminalstationcode\": \"YWH\", \"departstation\": \"上海虹桥\", \"station\": \"上海虹桥\", \"departuretime\": \"16:15\", \"departstationcode\": \"AOH\"}", "name": "train_tickets"},     {"role": "tool", "content": "{\"area\": \"上海\", \"weather\": {\"areaid\": \"101020100\", \"temperature\": \"12\", \"weather\": \"晴\", \"wind_direction\": \"西风\", \"wind_power\": \"0-3级 微风  <5.4m/s\", \"weather_code\": \"00\"}}", "name": "get_weather"},     {"role": "assistant", "content": "好的,以下是您今天(2025年3月17日)从杭州到上海的行程信息及天气情况:\n\n---\n\n### **火车票信息**\n#### **去程(杭州→上海)**\n- **车次**:G7336  \n- **出发站**:杭州东站(CEH)  \n- **出发时间**:7:46  \n- **到达站**:上海南站(SNH)  \n- **到达时间**:8:34  \n- **耗时**:48分钟  \n\n#### **返程(上海→杭州)**\n- **车次**:C3629  \n- **出发站**:上海虹桥站(AOH)  \n- **出发时间**:16:15  \n- **到达站**:杭州西站(YWH)  \n- **到达时间**:17:34  \n- **耗时**:1小时19分钟  \n\n---\n\n### **上海今日天气**\n- **温度**:12°C  \n- **天气**:晴  \n- **风力**:西风 0-3级(微风,<5.4m/s)  \n\n---\n\n### **建议**\n1. **行程安排**:  \n   - 去程建议提前1小时到杭州东站,返程注意上海虹桥站的乘车时间。  \n   - 上海虹桥站与上海南站距离较远,需预留足够换乘时间。  \n\n2. **天气提示**:  \n   - 白天晴朗但气温较低,建议携带外套和晴雨伞(备用)。  \n\n需要帮您进一步预订车票或提供交通接驳建议吗?", "reasoning_content": "好的,用户今天需要从杭州到上海出差,并且当天往返,还要查询上海的天气。首先,我需要整理一下用户提供的信息和工具返回的结果。\n\n用户给出的日期是2025年3月17日,今天。查询了杭州到上海的往返火车票,以及上海当天的天气。工具返回了两次火车票查询的结果和一次天气数据。\n\n首先看去程的火车票,杭州到上海的G7336次列车,出发时间是7:46,到达上海南站的时间是8:34,耗时48分钟。这趟车次应该很适合用户早上出发,当天就能到达上海开始工作。\n\n然后是返程的C3629次列车,从上海虹桥到杭州西,出发时间16:15,到达时间17:34,耗时1小时19分钟。用户可能需要在下午返回杭州,这样整个行程安排比较紧凑。\n\n接下来是天气情况,上海今天温度12度,天气晴朗,西风0-3级,微风。这样的天气适合出差,不会有降雨或大风影响出行。\n\n现在需要把这些信息以自然的方式呈现给用户。首先确认用户的需求是往返车票和天气,所以需要分点说明去程、返程和天气情况。要注意时间是否合理,比如用户是否能赶上返程的列车,是否有足够的停留时间。比如从早上8点到下午4点左右在上海,时间足够处理工作。\n\n另外,提醒用户注意天气情况,虽然天气晴朗,但温度较低,建议携带外套。同时,确认车次的出发和到达车站,确保用户知道具体站点,避免跑错车站。比如去程是杭州东到上海南,返程是上海虹桥到杭州西,可能需要提醒用户注意车站的不同,避免混淆。\n\n最后,总结一下信息,确保用户清楚所有安排,并询问是否需要进一步帮助,比如订票或交通建议。"}]



Qwen-Agent

项目地址

https://github.com/QwenLM/Qwen-Agent


Qwen-Agent 封装了适配Qwen的工具调用模版,支持直接使用 OAI 兼容 API(例如 vLLM 部署)或DashScope API 接口,为原生不支持工具调用的 LLM推理接口提供了工具调用能力。


  • LLM接口:运行以下代码,完成一次含有工具调用的请求:

from qwen_agent.llm import get_chat_modelimport os
# 获取封装的llm对象llm = get_chat_model({'model': 'qwq-32b',# 使用dashscope API'model_type': 'qwen_dashscope','api_key': os.getenv('DASHSCOPE_API_KEY')
# 使用自己部署的类OpenAI API(例如vLLM部署):# 'model_server': 'http://localhost:8000/v1',# api_base# 'api_key': 'EMPTY',})
# 输入用户请求messages = [{"role": "user", "content": "今天是2025年3月17号,我马上要去上海出差,当天往返,请帮我查询今天从杭州到上海往返的火车票,此外,再帮我查询一下上海今天的天气。"}]while True:responses = []for responses in llm.chat(messages=messages,functions=TOOLS,stream=True):passprint('\n[模型回复]: \n', responses)messages.extend(responses)tool_response = []for rsp in responses:if rsp.get('function_call'):tool_name = rsp['function_call']['name']tool_args = json.loads(rsp['function_call']['arguments'])tool_exec_res = TOOL_EXEC_MAP[tool_name](**tool_args)tool_response.append({'role': 'function', 'content': tool_exec_res, 'name': tool_name})print('\n[工具结果]: \n', tool_response)
if tool_response:messages.extend(tool_response)else:break

以上代码完整对话消息为:

[    {"role":"user","content":"今天是2025年3月17号,我马上要去上海出差,当天往返,请帮我查询今天从杭州到上海往返的火车票,此外,再帮我查询一下上海今天的天气。"},    {"role":"assistant","content":"","reasoning_content":"好的,用户今天要从杭州到上海出差,当天往返,需要查询今天的往返火车票,还有上海的天气。首先,我需要确认用户提供的日期是2025年3月17日,所以日期参数没问题。\n\n先处理火车票查询。用户需要往返票,但提供的函数参数里只有单程的信息,可能需要分开查询去程和返程?不过函数可能只支持单程,所以可能需要两次调用?不过用户可能希望往返一起查,但根据工具描述,可能只能先查去程和返程两次。不过用户说当天往返,所以出发和到达城市需要反过来。第一次是杭州到上海,日期今天;第二次是上海回杭州,同样日期。但用户可能希望一次查询往返,但工具可能不支持,所以可能需要两次调用train_tickets函数,分别处理去和回的行程。不过用户的问题里可能只需要一次查询,但参数需要明确。所以可能需要先处理去程,然后返程。\n\n接下来是天气查询,用户需要上海今天的天气,所以调用get_weather函数,参数是上海。\n\n现在需要检查参数是否正确。对于火车票,start是杭州,end是上海,date今天。然后返程的话start是上海,end杭州,date同天。但用户可能希望往返,但工具可能不支持往返查询,所以需要两次调用。但用户的问题可能只需要一次查询,但可能需要分开两次。所以应该生成两个train_tickets的调用,分别去和回。但用户的问题可能只需要一次查询,但根据工具的参数,必须三个参数,所以两次调用。\n\n然后天气查询只需要一次,参数是上海。\n\n现在需要按照工具的格式生成调用。首先处理去程:杭州到上海,日期2025-03-17。然后返程:上海到杭州,同日期。再查询上海天气。\n\n所以需要三个tool_call,两次train_tickets和一次get_weather。"},    {"role":"assistant","content":"","reasoning_content":"","function_call":{"name":"train_tickets","arguments":"{\\"start\\": \\"杭州\\", \\"end\\": \\"上海\\", \\"date\\": \\"2025-03-17\\"}"}},    {"role":"assistant","content":"","reasoning_content":"","function_call":{"name":"train_tickets","arguments":"{\\"start\\": \\"上海\\", \\"end\\": \\"杭州\\", \\"date\\": \\"2025-03-17\\"}"}},    {"role":"assistant","content":"","reasoning_content":"","function_call":{"name":"get_weather","arguments":"{\\"area\\": \\"上海\\"}"}},    {"role":"function","content":"{\\"costtime\\": \\"0小时48分\\", \\"trainno\\": \\"G7336\\", \\"arrivaltime\\": \\"8:34\\", \\"endstation\\": \\"上海南\\", \\"terminalstationcode\\": \\"SNH\\", \\"departstation\\": \\"苍南\\", \\"station\\": \\"杭州东\\", \\"departuretime\\": \\"7:46\\", \\"departstationcode\\": \\"CEH\\"}","name":"train_tickets"},    {"role":"function","content":"{\\"costtime\\": \\"1小时19分\\", \\"trainno\\": \\"C3629\\", \\"arrivaltime\\": \\"17:34\\", \\"endstation\\": \\"杭州西\\", \\"terminalstationcode\\": \\"YWH\\", \\"departstation\\": \\"上海虹桥\\", \\"station\\": \\"上海虹桥\\", \\"departuretime\\": \\"16:15\\", \\"departstationcode\\": \\"AOH\\"}","name":"train_tickets"},    {"role":"function","content":"{\\"area\\": \\"上海\\", \\"weather\\": {\\"areaid\\": \\"101020100\\", \\"temperature\\": \\"12\\", \\"weather\\": \\"晴\\", \\"wind_direction\\": \\"西风\\", \\"wind_power\\": \\"0-3级 微风  <5.4m/s\\", \\"weather_code\\": \\"00\\"}}","name":"get_weather"},    {"role":"assistant","content":"","reasoning_content":"好的,用户今天需要从杭州到上海出差并当天往返,所以需要查询往返的火车票和上海的天气。首先处理火车票的信息。\n\n用户提供的出发地是杭州,目的地上海,日期是2025年3月17日。我需要调用train_tickets两次,一次是杭州到上海,另一次是上海返回杭州。根据工具的参数要求,必须提供start、end和date,所以两次查询都填上日期。\n\n然后看返回的火车票信息。第一次查询杭州到上海的结果是G7336次列车,7:46从杭州东出发,8:34到达上海南,耗时48分钟。这趟车时间很合适,早上出发,很快就能到,适合出差上午的行程。\n\n第二次查询上海返回杭州的是C3629次,16:15从上海虹桥出发,17:34到达杭州西,耗时1小时19分。这趟车下午四点多出发,晚上七点前就能回到杭州,确保当天往返没问题。\n\n接下来是天气查询,用户需要上海当天的天气。调用get_weather,参数是上海。返回的数据显示温度12度,晴,西风0-3级,微风。这样的天气适合出行,但提醒用户可能早晚较凉,建议带件薄外套。\n\n现在需要把这些信息整理成用户易懂的回复。先列出往返的车次和时间,方便用户选择。然后说明天气情况,给出适当的建议。确保信息清晰,没有遗漏关键数据,比如车次号、时间、温度等。同时检查是否有其他需要注意的事项,比如是否需要提前取票或天气变化的可能性,但根据现有数据,可能不需要额外提醒。最后用友好的语气结束,让用户知道有其他需求可以继续询问。"},    {"role":"assistant","content":"好的,以下是您需要的信息:\n\n### 上海往返杭州火车票查询结果:\n1. **杭州→上海(去程)**  \n   - 车次:G7336  \n   - 出发时间:07:46(杭州东站)  \n   - 到达时间:08:34(上海南站)  \n   - 时长:48分钟  \n\n2. **上海→杭州(返程)**  \n   - 车次:C3629  \n   - 出发时间:16:15(上海虹桥站)  \n   - 到达时间:17:34(杭州西站)  \n   - 时长:1小时19分  \n\n建议您根据行程安排选择以上班次,并提前完成购票。\n\n### 上海今日天气:\n- **温度**:12℃  \n- **天气**:晴  \n- **风力**:西风 0-3级(微风,<5.4m/s)  \n- **建议**:白天适合出行,但早晚稍凉,可携带薄外套。\n\n祝您出差顺利,往返安全!如需其他帮助,请随时告诉我。","reasoning_content":""}]


一次完整的带有工具调用的对话 = “模型推理”+“工具执行”+“模型推理”,并且这个算法过程需要在模型外部自行实现。


为此,Qwen-Agent还提供了一个接口`Agent`,将以上过程封装起来,用户只需传入模型和工具,即可自动编排以上过程并获得完整的对话消息。


  • Agent接口:运行以下代码,完成一次和Agent的交互:

from qwen_agent.tools.base import BaseTool, register_toolfrom typing import Unionimport os
@register_tool('get_weather')class GetWeather(BaseTool):description = 'Weather inquiry.'parameters = {"type": "object","properties": {"area": {"type": "string","description": "Regional name, such as 丽江"},},"required": ["area"]}
def call(self, params: Union[str, dict], **kwargs) -> str:params = self._verify_json_format_args(params)tool_exec_res = TOOL_EXEC_MAP['get_weather'](**params)return tool_exec_res

@register_tool('train_tickets')class TrainTickets(BaseTool):description = 'Obtain train tickets and other information based on departure, arrival, and time.'parameters = {"type": "object","properties": {"start": {"type": "string","description": "The departure city."},"end": {"type": "string","description": "The arrival city."},"date": {"type": "string","description": "The date, such as 2024-02-21. If not clear, do not fill in."}},"required": ["start","end","date"]}
def call(self, params: Union[str, dict], **kwargs) -> str:params = self._verify_json_format_args(params)tool_exec_res = TOOL_EXEC_MAP['train_tickets'](**params)return tool_exec_res
from qwen_agent.agents import Assistant
# 获取Agent对象llm_cfg = {'model': 'qwq-32b',# 使用dashscope API'model_type': 'qwen_dashscope','api_key': os.getenv('DASHSCOPE_API_KEY')
# 使用自己部署的类OpenAI API(例如vLLM部署):# 'model_server': 'http://localhost:8000/v1',# api_base# 'api_key': 'EMPTY',}tools = ['train_tickets', 'get_weather']# 确保工具已经提前被注册到Qwen-Agent中bot = Assistant(llm=llm_cfg, function_list=tools)
# 对话messages = [{"role": "user", "content": "今天是2025年3月17号,我马上要去上海出差,当天往返,请帮我查询今天从杭州到上海往返的火车票,此外,再帮我查询一下上海今天的天气。"}]for responses in bot.run(messages=messages):# 流式输出,此处做演示直接跳过取最后结果passprint('\n[模型回复]: \n', responses)

以上代码完整对话消息和「 LLM接口 」完全一致。

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费场景POC验证,效果验证后签署服务协议。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询