简介
本文介绍一个基于Assistant API实现的旅游助手最佳实践,通过智能调用各类函数实现,可以动态地实现各类旅游查询。在本示例代码中通过虚拟函数查询接口实现,支持查询多个旅游问题。
开发者可以替换成自己真实的API接口或复写其中的各类函数。
依赖功能
Assistant API的基础API参数生成能力。
Assistant API的Function calling能力。
实现代码
概述
通过下文的三个代码文件,运行tour-assistant.py 即可测试相关代码(配置api-key后)。
目前虚拟的旅游相关函数支持问“丽江“ 和”北京“相关的问题。
前期准备
已开通百炼服务:开通阿里云百炼大模型服务产品。
设置您的API-KEY,替换YOUR_DASHCOPE_API_KEY为您自己的API key
export DASHSCOPE_API_KEY=YOUR_DASHSCOPE_API_KEY
主函数(tour_assistant.py)
# -*- encoding: utf-8 -*-
import json
import sys
from http import HTTPStatus
from dashscope import Assistants, Messages, Runs, Threads
from function_utils import *
def create_assistant():
# create assistant with information
assistant = Assistants.create(
model='qwen-max',
name='smart helper',
description='一个旅游助手,可以通过用户诉求,调用天气查询,路径推荐,当地餐厅推荐等帮助用户。',
instructions='你是一个旅游助手,可以通过调用插件解决问题。插件例如,天气查询,路径推荐,当地餐厅推荐等,当你无法回答问题时应当结合插件回复进行回答。请根据插件结果适当丰富回复内容。',
tools=[{
'type': 'function',
'function': {
'name': '天气查询',
'description': '用于查询天气的插件和函数',
'parameters': {
'type': 'object',
'properties': {
'location': {
'type': 'str',
'description': '待查询的地点'
},
'date': {
'type': 'str',
'description': '待查询的具体日期'
}
},
'required': ['location', 'date']
}
}
},
{
'type': 'function',
'function': {
'name': '路径规划',
'description': '用于推荐出行和旅游的路径规划,包含查询路线,规划起点到终点的路线。也用于推荐最近最热门的旅游行程。',
'parameters': {
'type': 'object',
'properties': {
'start': {
'type': 'str',
'description': '待查询路径规划的出发点'
},
'destination': {
'type': 'str',
'description': '待查询路径规划的终点.'
},
'recommendation': {
'type': 'int',
'description': '用于控制是否随机推荐,用于在无法判断有路径规划终点时,设置为1,其他情况为0。此时会推荐最热门的旅游路线.'
}
},
'required': ['destination', 'start', 'recommendation']
}
}
},
{
'type': 'function',
'function': {
'name': '获取目的地建议',
'description': '用于推荐最近热门的旅游目的地。',
'parameters': {
'type': 'object',
'properties': {
'query': {
'type': 'str',
'description': '可能需要的信息'
},
},
'required': ['query']
}
}
},
{
'type': 'function',
'function': {
'name': '获取景点推荐',
'description': '用于推荐指定城市的旅游景点。',
'parameters': {
'type': 'object',
'properties': {
'city': {
'type': 'str',
'description': '城市名称'
},
},
'required': ['city']
}
}
},
{
'type': 'function',
'function': {
'name': '获取餐饮推荐',
'description': '用于推荐指定城市的餐饮。',
'parameters': {
'type': 'object',
'properties': {
'city': {
'type': 'str',
'description': '城市名称'
},
},
'required': ['city']
}
}
},
{
'type': 'function',
'function': {
'name': '获取旅行提示',
'description': '用于获取指定城市的旅行注意事项。',
'parameters': {
'type': 'object',
'properties': {
'city': {
'type': 'str',
'description': '城市名称'
},
},
'required': ['city']
}
}
},
{
'type': 'function',
'function': {
'name': '获取当地风俗',
'description': '用于获取指定城市的当地风俗。',
'parameters': {
'type': 'object',
'properties': {
'city': {
'type': 'str',
'description': '城市名称'
},
},
'required': ['city']
}
}
},
],
)
return assistant
function_mapper = {
"天气查询": get_weather,
"路径规划": get_path_recommendation,
"获取目的地建议": get_destination_recommendation,
"获取景点推荐": get_attraction_recommendation,
"获取餐饮推荐": get_dining_recommendation,
"获取旅行提示": get_life_tips,
"获取当地风俗": get_local_customs,
}
def verify_status_code(res):
if res.status_code != HTTPStatus.OK:
sys.exit(res.status_code)
def send_message(assistant, message='查询杭州天气'):
print(f"Query: {message}")
# create thread.
# create a thread.
thread = Threads.create()
print(thread)
# create a message.
message = Messages.create(thread.id, content=message)
# create run
run = Runs.create(thread.id, assistant_id=assistant.id)
print(run)
# # get run statue
# run_status = Runs.get(run.id, thread_id=thread.id)
# print(run_status)
# wait for run completed or requires_action
run_status = Runs.wait(run.id, thread_id=thread.id)
# print(run_status)
# if prompt input tool result, submit tool result.
if run_status.required_action:
f = run_status.required_action.submit_tool_outputs.tool_calls[0].function
func_name = f['name']
param = json.loads(f['arguments'])
print(f)
if func_name in function_mapper:
output = function_mapper[func_name](**param)
else:
output = ""
tool_outputs = [{
'output':
output
}]
run = Runs.submit_tool_outputs(run.id,
thread_id=thread.id,
tool_outputs=tool_outputs)
# should wait for run completed
run_status = Runs.wait(run.id, thread_id=thread.id)
# print(run_status)
verify_status_code(run_status)
run_status = Runs.get(run.id, thread_id=thread.id)
print(run_status)
# verify_status_code(run_status)
# get the thread messages.
msgs = Messages.list(thread.id)
# print(msgs)
# print(json.dumps(msgs, default=lambda o: o.__dict__, sort_keys=True, indent=4))
print("运行结果:")
for message in msgs['data'][::-1]:
print("content: ", message['content'][0]['text']['value'])
print("\n")
if __name__ == '__main__':
assistant = create_assistant()
send_message(assistant=assistant, message="丽江天气怎么样?")
# send_message(assistant=assistant,message="年假打算出去玩,有什么地点推荐吗")
# send_message(assistant=assistant,message="从北京去丽江怎么出行方便?")
# send_message(assistant=assistant,message="丽江有什么好玩的地方?")
# send_message(assistant=assistant,message="我喜欢吃,丽江有什么美食推荐吗")
# send_message(assistant=assistant,message="去丽江还应该注意什么?")
# send_message(assistant=assistant,message="能告诉我丽江当地有什么风俗吗")
# send_message(assistant=assistant,message='从杭州到北京的出行推荐')
自定义函数(function_utils.py)
在tour assistant 中用到了多个自定义函数,开发者也可以根据自己的需求改写和增加相关函数。
from mocked_information import *
def get_destination_recommendation(query):
return destination
def get_attraction_recommendation(city):
return attraction
def get_dining_recommendation(city):
return dining
def get_life_tips(city):
return life_tips
def get_local_customs(city):
return local_customs
def get_current_date():
return "今天"
def get_weather(location, date=""):
if date == "":
date = get_current_date()
return date + "天气是" + "晴天"
def get_current_location():
return "北京"
def get_path_recommendation(destination, start='', recommendation=False):
return "建议通过飞机从" + start + "到" + destination + "\n以下是航班信息\n" + flight
虚拟的信息(mocked_information.py)
对于部分函数中用到的信息(如航班信息),我们虚拟的信息置于下述文件。
destination="""
以下是一些推荐的旅游目的地:
1. 杭州(中国)
西湖:享有“人间天堂”的美誉,是中国最著名的自然景观之一。
灵隐寺:杭州最古老的寺庙之一,提供宁静的精神修养场所。
西溪湿地:天然的湿地生态区,可以近距离接触自然和野生生物。
2. 丽江(中国)
古城:保留了完好的历史建筑和纳西族文化,是一个不可多得的步行城市。
玉龙雪山:雄伟的山峰,提供滑雪和登山活动,景色壮观。
束河古镇:比丽江古城更为宁静的地方,适合品茶和静思。
3. 巴黎(法国)
埃菲尔铁塔:法国的象征,提供城市全景视角。
卢浮宫:世界上最大的艺术博物馆之一,收藏有《蒙娜丽莎》等珍贵艺术品。
凡尔赛宫:法国历史上的王宫,代表了欧洲花园和宫殿的顶峰。
4. 开普敦(南非)
桌山:通过缆车访问,顶部可俯瞰开普敦市和罗宾岛的壮丽景色。
好望角:著名的海角,为航海家提供的历史地标。
克尔斯滕博施植物园:世界上生物多样性最丰富的植物园之一。
"""
attraction = """
1. 丽江古城(大研古城)
特色:丽江古城是一个完美保存的古老纳西族城镇,以其石板路、流水和古桥而著名。无需购票即可进入,但维护古城的费用需购买一种维护费证书。
建议时间:建议早上开始您的游览以避开人群。
提示:晚上的古城特别迷人,有许多酒吧和咖啡馆可以享受。
2. 黑龙潭公园
特色:位于丽江古城北边,是欣赏玉龙雪山倒影的绝佳地点。
建议时间:上午或傍晚。
提示:入园免费,是拍照和散步的好地方。
3. 玉龙雪山
特色:这座壮观的雪山是丽江的标志性景点,您可以乘坐索道至冰川公园或牦牛坪。
建议时间:全天,但需留出足够的时间上山下山。
提示:高海拔可能引起高反,建议提前做好准备。
4. 白沙古镇
特色:相对于丽江古城,白沙古镇更加宁静,保留了更多传统纳西族文化。
建议时间:下午。
提示:可以尝试纳西族的传统手工艺品制作体验。
5. 束河古镇
特色:比丽江古城小而更为宁静,是了解纳西族文化的另一个好地点。
建议时间:晚上。
提示:束河古镇的夜生活相对平和,适合享受安静的晚餐。
"""
dining = """
餐饮建议
早餐:在丽江古城的小巷内尝试当地的酸奶和烧饵块。
午餐:在玉龙雪山下的餐厅尝试藏族或纳西族风味的菜肴。
晚餐:束河古镇有许多提供地道纳西菜的餐馆,推荐尝试纳西烤鱼。
"""
life_tips = """
旅行提示
衣着:丽江日夜温差大,即使在夏天也需携带厚外套。
高反:丽江海拔约2400米,部分人可能会有高原反应。建议游客到达后先适应一下高海拔环境,适当休息,多喝水,少进行剧烈运动。前往高海拔地区如玉龙雪山前,建议预防高原反应。
"""
local_customs = """
纳西族礼仪:
纳西族是丽江的主要民族,他们非常看重礼仪。与长辈交谈时,说话要礼貌且避免直视对方的眼睛,这是尊重的表现。
在参观纳西族家庭或参与当地活动时,接受主人提供的食物和饮料是礼貌的表现。
传统服饰:
当地人在特定节日或有重要活动时可能会穿着传统服装。游客可以租借纳西民族服饰拍照,但应保持尊重,不要对服饰进行任何不适当的处理。
节日和庆典:
参与当地节日如三月街(每年农历三月举行的大型集市和庆典)、庙会等,需遵守当地的规矩和传统,比如不大声喧哗、不随意涉足祭祀区域等。
"""
flight = """
航班号 机型 起飞时间 起飞机场 降落时间 降落机场 班期 餐食服务 票价
CA1469 32N 06:30 首都国际机场 T2 10:25 三义机场 每天 93% ¥1730 起
ZH1469 32N 06:30 首都国际机场 T2 10:25 三义机场 每天 93% 查看时价
JD5181 32Q 06:55 大兴国际机场 10:15 三义机场 每天 97% ¥630 起
CA1459 32N 16:20 首都国际机场 T2 20:15 三义机场 每天 97% ¥1150 起
ZH1459 32N 16:20 首都国际机场 T2 20:15 三义机场 每天 97% 查看时价
3U5234 737 16:55 大兴国际机场 20:05 三义机场 每天 - ¥2860 起
KN6139 737 16:55 大兴国际机场 20:05 三义机场 每天 - 查看时价
MU5716 737 16:55 大兴国际机场 20:05 三义机场 每天 - ¥900 起
3U5234 737 17:00 大兴国际机场 20:05 三义机场 每天 - ¥2860 起
KN6139 737 17:00 大兴国际机场 20:05 三义机场 每天 - 查看时价
MU5716 737 17:00 大兴国际机场 20:05 三义机场 每天 - ¥900 起
"""
运行结果
开发者可以将上述代码复制到IDE中,通过下面的方法运行。
运行tour_assistant.py 并修改相关问题为“年假打算出去玩,有什么地点推荐吗”
运行结果见下,成功调用“recommendation”函数,并生成最终结果:
运行结果:
content: 年假打算出去玩,有什么地点推荐吗
content: 根据当前的热门程度,我为您推荐以下几个旅游目的地:
1. **杭州, 中国**
- **西湖**:在这里,您能体验到被誉为“人间天堂”的绝美自然景观。
- **灵隐寺**:作为杭州最古老的寺庙之一,它提供了宁静的环境,非常适合精神修养。
- **西溪湿地**:自然爱好者的好去处,您可以在这里享受大自然的宁静与美丽。
2. **丽江, 中国**
- **丽江古城**:漫步在历史悠久的街道上,感受纳西族文化的独特魅力。
- **玉龙雪山**:不论是滑雪还是登山,这里的壮观景色都会让您难以忘怀。
- **束河古镇**:相比热闹的丽江古城,这里更加宁静,适合慢慢品味一杯茶,享受悠闲时光。
3. **巴黎, 法国**
- **埃菲尔铁塔**:作为法国的象征,登顶后可将整个巴黎的美景尽收眼底。
- **卢浮宫**:艺术爱好者的圣地,亲眼目睹《蒙娜丽莎》的神秘微笑。
- **凡尔赛宫**:宏伟的宫殿与精致的花园,展示了法国皇室昔日的辉煌。
4. **开普敦, 南非**
- **桌山**:乘坐缆车到达山顶,您将被开普敦和罗宾岛的壮丽景色所震撼。
- **好望角**:作为历史上海洋航行的重要地标,这里的自然风光同样令人赞叹。
- **克尔斯滕博施植物园**:探索世界上生物多样性最为丰富的植物园,感受自然界的奇妙。
每个地方都有其独特的风情和不可错过的体验,选择一个符合您兴趣和放松需求的目的地,享受您的年假吧!
目前Assistant API使用代码均支持流式输出版本,详细可查阅SDK示例。
若有收获,就点个赞吧
文档内容是否对您有帮助?