代码,一个简单的例子:
# Reference: https://platform.openai.com/docs/guides/function-calling
import json
import os
# DASHSCOPE_API_KEY
from qwen_agent.llm import get_chat_model
# Example dummy function hard coded to return the same weather
# In production, this could be your backend API or an external API
def get_current_weather(location, unit='fahrenheit'):
"""Get the current weather in a given location"""
if 'tokyo' in location.lower():
return json.dumps({'location': 'Tokyo', 'temperature': '10', 'unit': 'celsius'})
elif 'san francisco' in location.lower():
return json.dumps({'location': 'San Francisco', 'temperature': '72', 'unit': 'fahrenheit'})
elif 'paris' in location.lower():
return json.dumps({'location': 'Paris', 'temperature': '22', 'unit': 'celsius'})
else:
return json.dumps({'location': location, 'temperature': 'unknown'})
def test():
llm = get_chat_model({
# Use the model service provided by DashScope:
# 'model': 'qwen-max',
'model': 'qwen-plus',
'model_server': 'dashscope',
'api_key': 'sk-c78替换下c8',#os.getenv('DASHSCOPE_API_KEY'),
# Use the model service provided by Together.AI:
# 'model': 'Qwen/Qwen1.5-14B-Chat',
# 'model_server': 'https://api.together.xyz', # api_base
# 'api_key': os.getenv('TOGETHER_API_KEY'),
# Use your own model service compatible with OpenAI API:
# 'model': 'Qwen/Qwen1.5-72B-Chat',
# 'model_server': 'http://localhost:8000/v1', # api_base
# 'api_key': 'EMPTY',
})
# Step 1: send the conversation and available functions to the model
messages = [{'role': 'user', 'content': "What's the weather like in San Francisco?"}]
functions = [{
'name': 'get_current_weather',
'description': 'Get the current weather in a given location',
'parameters': {
'type': 'object',
'properties': {
'location': {
'type': 'string',
'description': 'The city and state, e.g. San Francisco, CA',
},
'unit': {
'type': 'string',
'enum': ['celsius', 'fahrenheit']
},
},
'required': ['location'],
},
}]
print('# Assistant Response 1:')
responses = []
for responses in llm.chat(messages=messages, functions=functions, stream=True):
print(responses)
messages.extend(responses) # extend conversation with assistant's reply
# Step 2: check if the model wanted to call a function
last_response = messages[-1]
print("*"*88)
print(last_response)
print("*"*88)
if last_response.get('function_call', None):
# Step 3: call the function
# Note: the JSON response may not always be valid; be sure to handle errors
available_functions = {
'get_current_weather': get_current_weather,
} # only one function in this example, but you can have multiple
function_name = last_response['function_call']['name']
function_to_call = available_functions[function_name]
function_args = json.loads(last_response['function_call']['arguments'])
function_response = function_to_call(
location=function_args.get('location'),
unit=function_args.get('unit'),
)
print('# Function Response:')
print(function_response)
# Step 4: send the info for each function call and function response to the model
messages.append({
'role': 'function',
'name': function_name,
'content': function_response,
}) # extend conversation with function response
print('# Assistant Response 2:')
for responses in llm.chat(
messages=messages,
functions=functions,
stream=True,
): # get a new response from the model where it can see the function response
print(responses)
if __name__ == '__main__':
test()
运行效果:
# Assistant Response 1:
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'get_current_weather', 'arguments': ''}}]
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'get_current_weather', 'arguments': ''}}]
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'get_current_weather', 'arguments': '{\n "location'}}]
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'get_current_weather', 'arguments': '{\n "location": "San Francisco'}}]
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'get_current_weather', 'arguments': '{\n "location": "San Francisco, CA",'}}]
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'get_current_weather', 'arguments': '{\n "location": "San Francisco, CA",\n "unit": "'}}]
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'get_current_weather', 'arguments': '{\n "location": "San Francisco, CA",\n "unit": "celsius"\n}'}}]
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'get_current_weather', 'arguments': '{\n "location": "San Francisco, CA",\n "unit": "celsius"\n}'}}]
****************************************************************************************
{'role': 'assistant', 'content': '', 'function_call': {'name': 'get_current_weather', 'arguments': '{\n "location": "San Francisco, CA",\n "unit": "celsius"\n}'}}
****************************************************************************************
# Function Response:
{"location": "San Francisco", "temperature": "72", "unit": "fahrenheit"}
# Assistant Response 2:
[{'role': 'assistant', 'content': 'The'}]
[{'role': 'assistant', 'content': 'The current'}]
[{'role': 'assistant', 'content': 'The current weather'}]
[{'role': 'assistant', 'content': 'The current weather in San Francisco,'}]
[{'role': 'assistant', 'content': 'The current weather in San Francisco, California is 7'}]
[{'role': 'assistant', 'content': 'The current weather in San Francisco, California is 72 degrees Fahrenheit ('}]
[{'role': 'assistant', 'content': 'The current weather in San Francisco, California is 72 degrees Fahrenheit (approximately 22'}]
[{'role': 'assistant', 'content': 'The current weather in San Francisco, California is 72 degrees Fahrenheit (approximately 22.2 degrees Celsius'}]
[{'role': 'assistant', 'content': 'The current weather in San Francisco, California is 72 degrees Fahrenheit (approximately 22.2 degrees Celsius).'}]
再来一个复杂的工具调用例子:
import json
import os
from qwen_agent.llm import get_chat_model
# Example dummy function hard coded to return the same weather
# In production, this could be your backend API or an external API
def get_current_weather(location, unit='fahrenheit'):
"""Get the current weather in a given location"""
if 'tokyo' in location.lower():
return json.dumps({'location': 'Tokyo', 'temperature': '10', 'unit': 'celsius'})
elif 'san francisco' in location.lower():
return json.dumps({'location': 'San Francisco', 'temperature': '72', 'unit': 'fahrenheit'})
elif 'paris' in location.lower():
return json.dumps({'location': 'Paris', 'temperature': '22', 'unit': 'celsius'})
else:
return json.dumps({'location': location, 'temperature': 'unknown'})
def check_inventory(flower_type: str = "玫瑰花") -> int:
"""
查询特定类型花的库存数量,默认为玫瑰花。
参数:
- flower_type: 花的类型
返回:
- 库存数量
"""
# 实际应用中这里应该是数据库查询或其他形式的库存检查
return '130' # 假设每种花都有130个单位
def get_extra_asset_price() -> float:
"""
获取额外的固定资产价格。get extra asset price。
参数: 无
返回:
- 额外的固定资产价格
"""
return '500'
def process_responses(llm, messages, functions):
print('# Assistant Response with:', messages)
responses = []
for responses in llm.chat(messages=messages, functions=functions, stream=True):
print(responses)
# responses.append(response)
print("llm.chat over")
# 注意,这里添加了回复,方便递归调用工具
messages.extend(responses) # Extend conversation with assistant's replies
def handle_function_calls(llm, messages, functions):
process_responses(llm, messages, functions)
last_response = messages[-1]
print("last_res:", last_response)
while last_response.get('function_call', None):
available_functions = {
'get_current_weather': get_current_weather,
'check_inventory': check_inventory,
'get_extra_asset_price': get_extra_asset_price
}
function_name = last_response['function_call']['name']
function_to_call = available_functions.get(function_name)
if function_to_call:
function_args = json.loads(last_response['function_call']['arguments'])
function_response = function_to_call(**function_args)
else:
function_response = "Function not found or not available in available_functions"
print('# Function Response:', function_response)
messages.append({
'role': 'function',
'name': function_name,
'content': function_response,
}) # Extend conversation with function response
print("check messages:", messages)
process_responses(llm, messages, functions) # Get a new response from the model
print("*" * 88)
last_response = messages[-1] # Update last response for next iteration
# process_responses(llm, messages, functions)
def test():
llm = get_chat_model({
# Use the model service provided by DashScope:
# 'model': 'qwen-max',
'model': 'qwen-plus',
'model_server': 'dashscope',
'api_key': 'sk-c78896504df24xxxx7bf67529c8',#os.getenv('DASHSCOPE_API_KEY'),
# Use the model service provided by Together.AI:
# 'model': 'Qwen/Qwen1.5-14B-Chat',
# 'model_server': 'https://api.together.xyz', # api_base
# 'api_key': os.getenv('TOGETHER_API_KEY'),
# Use your own model service compatible with OpenAI API:
# 'model': 'Qwen/Qwen1.5-72B-Chat',
# 'model_server': 'http://localhost:8000/v1', # api_base
# 'api_key': 'EMPTY',
})
# Step 1: send the conversation and available functions to the model
# messages = [{'role': 'user', 'content': "What's the weather like in San Francisco?"}]
messages = [{'role': 'user', 'content': "通过使用工具(函数),查询玫瑰花的库存数量。已知玫瑰花的单价是10元,帮我计算玫瑰花总价加上额外固定资产的总价是多少?"}]
functions = [{
'name': 'get_current_weather',
'description': 'Get the current weather in a given location',
'parameters': {
'type': 'object',
'properties': {
'location': {
'type': 'string',
'description': 'The city and state, e.g. San Francisco, CA',
},
'unit': {
'type': 'string',
'enum': ['celsius', 'fahrenheit']
},
},
'required': ['location']}
},
{
"name": "check_inventory",
"description": "Check the inventory for a specific type of flower, default is roses",
"parameters": {
"type": "object",
"properties": {
"flower_type": {
"type": "string",
"description": "Type of flower to check inventory for"
}
},
"required": []
}
},
{
"name": "get_extra_asset_price",
"description": "Get the price of an extra fixed asset",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
}
]
handle_function_calls(llm, messages, functions)
if __name__ == '__main__':
test()
发现千问agent效果还不错,基本上每次都能得到正确结果!
D:\Python\Python312\python.exe D:\source\pythonProject\qianwen_x.py
# Assistant Response with: [{'role': 'user', 'content': '通过使用工具(函数),查询玫瑰花的库存数量。已知玫瑰花的单价是10元,帮我计算玫瑰花总价加上额外固定资产的总价是多少?'}]
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'check_inventory', 'arguments': ''}}]
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'check_inventory', 'arguments': '{"'}}]
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'check_inventory', 'arguments': '{"flower_type": "'}}]
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'check_inventory', 'arguments': '{"flower_type": "roses"}'}}]
[{'role': 'assistant', 'content': '', 'function_call': {'name': 'check_inventory', 'arguments': '{"flower_type": "roses"}'}}]
llm.chat over
last_res: {'role': 'assistant', 'content': '', 'function_call': {'name': 'check_inventory', 'arguments': '{"flower_type": "roses"}'}}
# Function Response: 130
check messages: [{'role': 'user', 'content': '通过使用工具(函数),查询玫瑰花的库存数量。已知玫瑰花的单价是10元,帮我计算玫瑰花总价加上额外固定资产的总价是多少?'}, {'role': 'assistant', 'content': '', 'function_call': {'name': 'check_inventory', 'arguments': '{"flower_type": "roses"}'}}, {'role': 'function', 'name': 'check_inventory', 'content': '130'}]
# Assistant Response with: [{'role': 'user', 'content': '通过使用工具(函数),查询玫瑰花的库存数量。已知玫瑰花的单价是10元,帮我计算玫瑰花总价加上额外固定资产的总价是多少?'}, {'role': 'assistant', 'content': '', 'function_call': {'name': 'check_inventory', 'arguments': '{"flower_type": "roses"}'}}, {'role': 'function', 'name': 'check_inventory', 'content': '130'}]
[{'role': 'assistant', 'content': '当'}]
[{'role': 'assistant', 'content': '当前'}]
[{'role': 'assistant', 'content': '当前我们'}]
[{'role': 'assistant', 'content': '当前我们有130'}]
[{'role': 'assistant', 'content': '当前我们有130朵玫瑰花在'}]
[{'role': 'assistant', 'content': '当前我们有130朵玫瑰花在库存。'}]
[{'role': 'assistant', 'content': '当前我们有130朵玫瑰花在库存。'}, {'role': 'assistant', 'content': '', 'function_call': {'name': 'get_extra', 'arguments': ''}}]
[{'role': 'assistant', 'content': '当前我们有130朵玫瑰花在库存。'}, {'role': 'assistant', 'content': '', 'function_call': {'name': 'get_extra_asset_price', 'arguments': ''}}]
[{'role': 'assistant', 'content': '当前我们有130朵玫瑰花在库存。'}, {'role': 'assistant', 'content': '', 'function_call': {'name': 'get_extra_asset_price', 'arguments': '{}'}}]
[{'role': 'assistant', 'content': '当前我们有130朵玫瑰花在库存。'}, {'role': 'assistant', 'content': '', 'function_call': {'name': 'get_extra_asset_price', 'arguments': '{}'}}]
llm.chat over
****************************************************************************************
# Function Response: 500
check messages: [{'role': 'user', 'content': '通过使用工具(函数),查询玫瑰花的库存数量。已知玫瑰花的单价是10元,帮我计算玫瑰花总价加上额外固定资产的总价是多少?'}, {'role': 'assistant', 'content': '', 'function_call': {'name': 'check_inventory', 'arguments': '{"flower_type": "roses"}'}}, {'role': 'function', 'name': 'check_inventory', 'content': '130'}, {'role': 'assistant', 'content': '当前我们有130朵玫瑰花在库存。'}, {'role': 'assistant', 'content': '', 'function_call': {'name': 'get_extra_asset_price', 'arguments': '{}'}}, {'role': 'function', 'name': 'get_extra_asset_price', 'content': '500'}]
# Assistant Response with: [{'role': 'user', 'content': '通过使用工具(函数),查询玫瑰花的库存数量。已知玫瑰花的单价是10元,帮我计算玫瑰花总价加上额外固定资产的总价是多少?'}, {'role': 'assistant', 'content': '', 'function_call': {'name': 'check_inventory', 'arguments': '{"flower_type": "roses"}'}}, {'role': 'function', 'name': 'check_inventory', 'content': '130'}, {'role': 'assistant', 'content': '当前我们有130朵玫瑰花在库存。'}, {'role': 'assistant', 'content': '', 'function_call': {'name': 'get_extra_asset_price', 'arguments': '{}'}}, {'role': 'function', 'name': 'get_extra_asset_price', 'content': '500'}]
[{'role': 'assistant', 'content': '额'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵 * 10'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵 * 10元/朵 ='}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵 * 10元/朵 = 130'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵 * 10元/朵 = 1300元。\n\n所以'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵 * 10元/朵 = 1300元。\n\n所以,玫瑰花总价'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵 * 10元/朵 = 1300元。\n\n所以,玫瑰花总价加上额外固定资产的'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵 * 10元/朵 = 1300元。\n\n所以,玫瑰花总价加上额外固定资产的总价是13'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵 * 10元/朵 = 1300元。\n\n所以,玫瑰花总价加上额外固定资产的总价是1300元 +'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵 * 10元/朵 = 1300元。\n\n所以,玫瑰花总价加上额外固定资产的总价是1300元 + 500'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵 * 10元/朵 = 1300元。\n\n所以,玫瑰花总价加上额外固定资产的总价是1300元 + 500元 = 1'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵 * 10元/朵 = 1300元。\n\n所以,玫瑰花总价加上额外固定资产的总价是1300元 + 500元 = 1800元'}]
[{'role': 'assistant', 'content': '额外固定资产的价格是500元。\n\n现在,玫瑰花的总价是130朵 * 10元/朵 = 1300元。\n\n所以,玫瑰花总价加上额外固定资产的总价是1300元 + 500元 = 1800元。'}]
llm.chat over
****************************************************************************************
Process finished with exit code 0
不同模型的表现情况:
'model': 'qwen-max',
# 'model': 'qwen-turbo',
# 'model': 'qwen-long', # 无法正常执行
# 'model': 'qwen-7b-chat', #无法得到正确结果
# 'model': 'qwen-1.8b-chat', # 无法得到正确结果
# 'model': 'qwen-max-0428',
# 'model': 'qwen-plus',
整体来说,比langchain的react框架好用不少!