小白也可以快速学会构建接入AI的线上应用,纯干货
首先给大家推荐一个比赛,感兴趣的可以参加,跟着我的教程百分百能做出作品。奖金很丰厚,值得一试。https://h.datafuntalk.com/EsTvpL在信息爆炸的时代,旅行规划早已不再是翻阅几本旅游指南就能完成的任务。面对海量的景点、住宿、交通和美食信息,用户往往陷入“选择困难症”。而传统旅游平台提供的“千人一面”推荐,难以满足个性化需求。AI旅行管家的出现,正是为了解决这一痛点。它能够:
首先给大家推荐一个比赛,感兴趣的可以参加,跟着我的教程百分百能做出作品。奖金很丰厚,值得一试。https://h.datafuntalk.com/EsTvpL
🌍 引言:为什么我们需要AI旅行管家?
在信息爆炸的时代,旅行规划早已不再是翻阅几本旅游指南就能完成的任务。面对海量的景点、住宿、交通和美食信息,用户往往陷入“选择困难症”。而传统旅游平台提供的“千人一面”推荐,难以满足个性化需求。
AI旅行管家的出现,正是为了解决这一痛点。它能够:
- 理解用户的旅行风格、预算、兴趣点等个性化偏好;
- 基于大模型生成结构化、生动、可执行的旅行计划;
- 提供智能推荐、行程导出、愿望清单管理等完整功能;
- 通过用户反馈不断学习和优化。
在本篇深度教程中,我们将从零开始,构建一个功能完整的AI个性化旅游规划管家,使用 Qwen2-7B-Instruct 大模型作为核心引擎,结合 Gradio 构建直观的Web界面,实现一个可部署、可扩展的智能旅行助手。
🛠️ 技术栈概览
| 组件 | 技术/库 | 作用 |
|---|---|---|
| 大模型 | Qwen2-7B-Instruct | 生成旅行计划、推荐、报告等自然语言内容 |
| 模型加载 | OpenMind + snapshot_download |
高效下载并加载本地模型 |
| 推理设备 | 华为昇腾(Ascend)NPU | 加速推理,提升响应速度 |
| 前端界面 | Gradio | 快速构建交互式Web应用 |
| 数据管理 | JSON、文件系统 | 持久化用户资料、旅行记录 |
| 语言支持 | 多语言字典 | 支持中英文界面切换 |
🔧 第一步:环境准备与模型加载
1.1 安装依赖
确保你的环境中已安装以下库:
pip install gradio torch openmind openmind_hub matplotlib numpy
注意:
openmind和openmind_hub是华为昇腾生态的专用库,用于在NPU上高效运行大模型。
1.2 下载并加载Qwen2-7B-Instruct模型
我们使用 openmind_hub 的 snapshot_download 函数从云端下载模型,并加载到NPU上。
from openmind import AutoModelForCausalLM, AutoTokenizer
from openmind_hub import snapshot_download
MODEL_NAME = "Shanghai_Ascend/Qwen2-7B-Instruct"
model_path = snapshot_download(MODEL_NAME, resume_download=True)
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
model_path,
trust_remote_code=True
).to("npu").eval() # 加载到NPU并设置为评估模式
关键点:
trust_remote_code=True:允许加载自定义代码(如Qwen的特殊token处理)。.to("npu"):将模型移动到昇腾NPU,大幅提升推理速度。.eval():关闭Dropout等训练层,确保推理稳定。
🧠 第二步:构建AI核心——智能回复生成系统
2.1 设计智能回复函数
我们封装一个 generate_response 函数,负责与大模型交互。
def generate_response(prompt, max_new_tokens=768):
inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=4096)
inputs = {k: v.to("npu") for k, v in inputs.items()} # 移动到NPU
outputs = model.generate(
**inputs,
max_new_tokens=min(max_new_tokens, 2048),
do_sample=True,
temperature=0.7, # 控制随机性
top_p=0.9, # 核采样
repetition_penalty=1.1,
pad_token_id=tokenizer.eos_token_id,
eos_token_id=tokenizer.eos_token_id,
use_cache=True
)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
# 清理:去除原始prompt
prompt_end_pos = response.find(prompt)
clean_response = response[prompt_end_pos + len(prompt):].strip() if prompt_end_pos != -1 else response.strip()
return clean_response
参数说明:
temperature=0.7:适中,保证创意性与稳定性。top_p=0.9:保留概率最高的90%词汇,避免低质量输出。repetition_penalty=1.1:抑制重复内容。
2.2 智能截断优化
为防止输出过长,我们实现 truncate_response 函数,在合理标点处截断:
def truncate_response(text, max_chars=1000):
if len(text) <= max_chars:
return text
truncated = text[:max_chars]
last_punctuation = max(truncated.rfind('。'), truncated.rfind('!'), truncated.rfind('\n'))
if last_punctuation > max_chars * 0.6:
return truncated[:last_punctuation + 1]
else:
return truncated + "..."
🗺️ 第三步:核心功能开发
3.1 生成个性化旅行计划
def generate_travel_plan(destination, days, travel_style, budget_preference, interests=None):
user_info = f"""
用户信息:{user_profile['name']},{user_profile['age']}岁,{user_profile['gender']}
旅行偏好:{travel_style},预算{budget_preference}
目的地:{destination}
旅行天数:{int(days)}天
"""
if interests: user_info += f"兴趣点:{interests}\n"
prompt = f"""你是一位专业的旅行规划师,请根据以下信息生成详细的旅游计划:
{user_info}
请按以下格式生成:
1. 行程概览
2. 每日行程安排
3. 住宿推荐
4. 美食攻略
5. 交通指南
6. 实用贴士
使用活泼、亲切的语言,添加表情符号增强可读性。"""
response = generate_response(prompt, max_new_tokens=1024)
return truncate_response(response)
输出示例:
🌸 京都5日文化之旅计划 1. 行程概览:漫步古都,感受禅意与四季之美... 2. 每日安排: - Day 1:抵达京都 → 伏见稻荷大社 → 锦市场...
3.2 智能目的地推荐
根据用户偏好(季节、预算、天数)推荐国内外目的地。
def generate_destination_recommendation(travel_style, season, days, budget_preference):
user_prefs = f"旅行风格:{travel_style}\n出行季节:{season}\n天数:{days}天\n预算:{budget_preference}"
prompt = f"""作为旅行顾问,请根据以下偏好推荐目的地:
{user_prefs}
请输出:
1. 国内推荐(3-5个)
2. 国外推荐(3-5个)
3. 出行提示
语言生动,突出特色。"""
response = generate_response(prompt, max_new_tokens=512)
return truncate_response(response)
3.3 生成旅行报告
分析用户历史记录,生成个性化报告。
def generate_trip_report():
# 统计旅行记录、愿望清单
# 构造prompt,让AI分析用户偏好并提供建议
# 输出包含:偏好分析、推荐、趋势
...
🖼️ 第四步:Gradio界面设计与多语言支持
4.1 多语言字典设计
我们使用字典管理中英文标签:
supported_languages = {
"中文": {
"app_title": "✈️ 个性旅游规划管家",
"greeting": "欢迎使用个性旅游规划管家!",
...
},
"English": {
"app_title": "✈️ Personal Travel Planner",
"greeting": "Welcome to Personal Travel Planner!",
...
}
}
4.2 构建Gradio界面
使用 gr.Blocks() 构建模块化界面:
with gr.Blocks(theme=gr.themes.Soft(), title=labels['app_title']) as demo:
gr.HTML(f"<div class='header'>...</div>")
with gr.Row():
with gr.Column(scale=7):
with gr.Tab("👤 个人资料"):
# 表单输入
name_input = gr.Textbox(label="姓名")
age_input = gr.Number(label="年龄")
...
update_profile_btn = gr.Button("更新资料")
with gr.Column(scale=3):
gr.Markdown("### 🌍 旅行概览")
trip_count = gr.Textbox(label="旅行次数")
wish_count = gr.Textbox(label="愿望清单")
4.3 动态CSS美化
通过CSS提升用户体验:
.header {
background: linear-gradient(135deg, #1976d2 0%, #4caf50 100%);
border-radius: 15px;
padding: 30px;
color: white;
text-align: center;
}
.card {
background: white;
border-radius: 12px;
padding: 20px;
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
}
💾 第五步:数据持久化与状态管理
5.1 用户资料保存
def create_user_profile(name, age, ...):
global user_profile
user_profile = {...}
with open("travel_user_profile.json", "w") as f:
json.dump(user_profile, f, ensure_ascii=False, indent=2)
5.2 旅行记录与愿望清单
trip_records = [] # [(日期, 目的地, 类型, 评分)]
wishlist_destinations = [] # [(目的地, 兴趣点, 原因)]
def save_travel_data():
data = {"trip_records": trip_records, "wishlist_destinations": wishlist_destinations}
with open("travel_data.json", "w") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def load_travel_data():
if os.path.exists("travel_data.json"):
with open("travel_data.json", "r") as f:
data = json.load(f)
trip_records = data.get("trip_records", [])
...
5.3 行程导出为Markdown
def export_trip_as_shareable(destination, days, trip_plan):
markdown_content = f"""
# 🏖️ {destination} {days}天旅行计划
## 📅 行程概览
{trip_plan}
---
> 本计划仅供参考
"""
filename = f"{destination}_trip_plan.md"
with open(filename, "w", encoding="utf-8") as f:
f.write(markdown_content)
return [filename, "✅ 导出成功"]
🤖 第六步:对话式用户反馈系统
我们实现一个AI客服,实时响应用户反馈:
def feedback_chat(user_message):
prompt = f"""你是一位友好的AI客服助手...
用户建议:{user_message}
请回复:
1. 感谢
2. 表示重视
3. 承诺优化
4. 询问更多建议
"""
response = generate_response(prompt, max_new_tokens=384)
return response
# Gradio 绑定
send_btn.click(
respond_to_feedback,
inputs=[user_query, chat_history],
outputs=[chat_history, feedback_status, user_query]
)
🚀 第七步:启动与部署
demo.launch(
server_name="0.0.0.0",
server_port=7861,
share=False, # 内网访问
debug=False
)
访问
http://localhost:7861即可使用。
📊 代码模板
使用这个代码模板即可创建出属于你的应用,这个模板是基于文章前面内容总结出的框架,大家可以参考参考,不要直接复制我的代码哈,会被判为抄袭。
"""
generic_assistant_framework.py
一个可复用的 AI 助手框架,支持替换业务逻辑与前端 UI。
只需实现 `BusinessLogic` 接口和 `build_ui` 函数,即可快速构建新系统。
"""
# 这部分可不做修改,基本上包含了所能用到的依赖(可复用)
import gradio as gr
import torch
from openmind import AutoModelForCausalLM, AutoTokenizer
from openmind_hub import snapshot_download
import matplotlib.pyplot as plt
import numpy as np
import datetime
import os
import json
import re
from datetime import datetime, timedelta
import io
import base64
# 确保中文显示正常(可复用)
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
print("===== 启动个性旅游规划管家 ====")
# ----------------- 加载本地模型 (OpenMind)(可复用) -----------------
MODEL_NAME = "Shanghai_Ascend/Qwen2-7B-Instruct"
model_path = snapshot_download(MODEL_NAME, resume_download=True)
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
model_path, trust_remote_code=True
).to("npu").eval()
# ----------------- 回复长度配置 (可复用)-----------------
RESPONSE_LENGTH_CONFIG = {
"chat": 384, # 聊天对话
"quick_advice": 512, # 快速建议
"detailed_plan": 1024, # 详细旅游计划
"trip_report": 1536 # 旅行报告
}
def get_max_tokens(function_type):
return RESPONSE_LENGTH_CONFIG.get(function_type, 512)
def truncate_response(text, max_chars=1000):
"""智能截断回复,确保在字符限制内"""
if len(text) <= max_chars:
return text
# 在合适的标点处截断(可复用)
truncated = text[:max_chars]
last_punctuation = max(
truncated.rfind('。'), truncated.rfind('!'),
truncated.rfind('?'), truncated.rfind('\n'),
truncated.rfind(',')
)
if last_punctuation > max_chars * 0.6: # 确保保留有意义的内容
return truncated[:last_punctuation + 1]
else:
return truncated + "..."
# 支持的语言(可扩展)
SUPPORTED_LANGUAGES = {
"中文": {
"app_title": "智能助手",
"greeting": "欢迎使用智能助手!",
"update_profile": "更新资料",
"status": "状态",
"your_feedback": "### 💬 您的反馈对我们很重要",
# ... 更多通用标签
},
"English": {
"app_title": "AI Assistant",
"greeting": "Welcome to AI Assistant!",
"update_profile": "Update Profile",
"status": "Status",
"your_feedback": "### 💬 Your Feedback is Important",
# ...
}
}
# ---------------------------- #
# 2. 核心平台类(平台层)
# ----------------------------
class GenericAssistantPlatform:
def __init__(self, business_logic):
self.business_logic = business_logic # 注入业务逻辑
self.user_profile = {}
self.current_language = "中文"
self.labels = SUPPORTED_LANGUAGES[self.current_language]
# 数据文件
self.profile_file = "user_profile.json"
self.data_file = "user_data.json"
self.feedback_file = "user_feedback.json"
# 加载数据
self.load_profile()
self.load_data()
self.load_feedback()
def get_max_tokens(self, function_type):
return RESPONSE_LENGTH_CONFIG.get(function_type, 512)
def truncate_response(self, text, max_chars=1000):
if len(text) <= max_chars:
return text
truncated = text[:max_chars]
last_punctuation = max(
truncated.rfind('。'), truncated.rfind('!'), truncated.rfind('?'),
truncated.rfind('\n'), truncated.rfind(',')
)
if last_punctuation > max_chars * 0.6:
return truncated[:last_punctuation + 1]
else:
return truncated + "..."
# ---------- 数据持久化 ----------
def save_profile(self):
try:
with open(self.profile_file, "w", encoding="utf-8") as f:
json.dump(self.user_profile, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"保存用户资料失败: {e}")
def load_profile(self):
if os.path.exists(self.profile_file):
try:
with open(self.profile_file, "r", encoding="utf-8") as f:
self.user_profile = json.load(f)
except Exception as e:
print(f"加载用户资料失败: {e}")
def save_data(self):
try:
with open(self.data_file, "w", encoding="utf-8") as f:
json.dump(self.business_logic.get_data(), f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"保存用户数据失败: {e}")
def load_data(self):
if os.path.exists(self.data_file):
try:
with open(self.data_file, "r", encoding="utf-8") as f:
data = json.load(f)
self.business_logic.set_data(data)
except Exception as e:
print(f"加载用户数据失败: {e}")
def save_feedback(self, feedback_item):
feedback_list = self.load_feedback_list()
feedback_item["id"] = len(feedback_list) + 1
feedback_item["timestamp"] = dt.now().strftime("%Y-%m-%d %H:%M:%S")
feedback_list.append(feedback_item)
try:
with open(self.feedback_file, "w", encoding="utf-8") as f:
json.dump(feedback_list, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"保存反馈失败: {e}")
def load_feedback(self):
return self.load_feedback_list()
def load_feedback_list(self):
if os.path.exists(self.feedback_file):
try:
with open(self.feedback_file, "r", encoding="utf-8") as f:
return json.load(f)
except Exception:
return []
return []
# ---------- AI 回调通用封装 ----------
def generate_response(self, prompt, max_new_tokens=768):
# 此处可替换为其他模型(如 HuggingFace、OpenAI、本地 NPU 模型等)
try:
from openmind import AutoModelForCausalLM, AutoTokenizer
from openmind_hub import snapshot_download
model_path = snapshot_download(MODEL_NAME, resume_download=True)
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True).to("npu").eval()
inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=4096)
inputs = {k: v.to("npu") for k, v in inputs.items()}
outputs = model.generate(
**inputs,
max_new_tokens=min(max_new_tokens, 2048),
do_sample=True,
temperature=0.7,
top_p=0.9,
repetition_penalty=1.1,
pad_token_id=tokenizer.eos_token_id,
eos_token_id=tokenizer.eos_token_id,
)
response = tokenizer.decode(outputs[0], skip_special_tokens=True)
clean_response = response[len(prompt):].strip() if prompt in response else response.strip()
return self.truncate_response(clean_response or "暂无响应。")
except Exception as e:
return f"AI 响应失败: {str(e)}"
# ---------- 通用功能 ----------
def export_as_markdown(self, title, content, metadata=""):
"""通用导出为 Markdown 文件"""
try:
filename = f"{title.replace(' ', '_')}_export_{dt.now().strftime('%Y%m%d_%H%M%S')}.md"
filepath = os.path.join(os.getcwd(), filename)
with open(filepath, "w", encoding="utf-8") as f:
f.write(f"# {title}\n\n{content}\n\n---\n{metadata}")
return filepath, f"✅ 已导出为: {filename}"
except Exception as e:
return None, f"❌ 导出失败: {str(e)}"
# ---------------------------- #
# 3. 业务逻辑接口(需用户实现)
# ----------------------------
class BusinessLogic:
"""
所有业务系统的抽象基类。
子类需实现以下方法。
"""
def get_tabs(self):
"""返回 Gradio Tab 名称列表"""
raise NotImplementedError
def build_ui(self, platform):
"""构建 UI 组件,返回组件列表用于绑定事件"""
raise NotImplementedError
def get_data(self):
"""返回当前业务数据(用于保存)"""
raise NotImplementedError
def set_data(self, data):
"""加载业务数据"""
raise NotImplementedError
def get_overview_stats(self):
"""返回统计信息,如 {'trip_count': 5, 'wish_count': 3}"""
return {}
# ---------------------------- #
# 4. 旅游业务实现示例(可替换为其他系统)
# ----------------------------
class TravelBusinessLogic(BusinessLogic):
def __init__(self):
self.trip_records = []
self.wishlist_destinations = []
def get_tabs(self):
return ["👤 个人资料", "✈️ 旅行规划", "📸 旅行记录", "📝 用户反馈"]
def get_data(self):
return {
"trip_records": self.trip_records,
"wishlist_destinations": self.wishlist_destinations
}
def set_data(self, data):
self.trip_records = data.get("trip_records", [])
self.wishlist_destinations = data.get("wishlist_destinations", [])
def get_overview_stats(self):
return {
"trip_count": len(self.trip_records),
"wish_count": len(self.wishlist_destinations)
}
def build_ui(self, platform):
labels = platform.labels
user_profile = platform.user_profile
# 示例:构建旅行规划 UI(简化)
destination = gr.Textbox(label="目的地")
days = gr.Number(label="天数", value=7)
plan_output = gr.Textbox(label="详细计划", lines=10)
generate_btn = gr.Button("生成计划")
def generate_plan(dest, d):
prompt = f"请为前往{dest}的{d}天旅行生成详细计划。"
return platform.generate_response(prompt, max_new_tokens=platform.get_max_tokens("detailed_plan"))
generate_btn.click(generate_plan, inputs=[destination, days], outputs=plan_output)
return [destination, days, plan_output, generate_btn]
# ---------------------------- #
# 5. 构建主界面(通用 UI 框架)
# ----------------------------
def create_gradio_app(platform: GenericAssistantPlatform, business_logic: BusinessLogic):
with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue"), title=platform.labels["app_title"]) as app:
gr.HTML(f"<h1>{platform.labels['app_title']}</h1><p>{platform.labels['greeting']}</p>")
with gr.Tabs():
# 动态添加业务 Tab
for tab_name in business_logic.get_tabs():
with gr.Tab(tab_name):
components = business_logic.build_ui(platform)
# 可绑定事件
# 反馈 Tab(通用)
with gr.Tab("📝 用户反馈"):
chatbot = gr.Chatbot()
msg = gr.Textbox(label="输入反馈")
send = gr.Button("发送")
clear = gr.Button("清空")
def respond(message, history):
response = f"感谢您的反馈:{message}"
platform.save_feedback({"content": message})
history.append((message, response))
return history, ""
send.click(respond, [msg, chatbot], [chatbot, msg])
msg.submit(respond, [msg, chatbot], [chatbot, msg])
clear.click(lambda: ([], ""), None, [chatbot, msg])
# 右侧统计面板(通用)
with gr.Column():
gr.Markdown("### 📊 概览")
trip_count = gr.Textbox(label="记录数")
wish_count = gr.Textbox(label="愿望数")
def refresh_stats():
stats = business_logic.get_overview_stats()
lang = "中文"
return [
f"{stats.get('trip_count', 0)}次" if lang == "中文" else f"{stats.get('trip_count', 0)} items",
f"{stats.get('wish_count', 0)}个" if lang == "中文" else f"{stats.get('wish_count', 0)} items"
]
gr.Button("刷新").click(refresh_stats, outputs=[trip_count, wish_count])
return app
# ---------------------------- #
# 6. 启动入口(可复用)
# ----------------------------
def launch_assistant(business_logic_class):
# 初始化业务逻辑
logic = business_logic_class()
# 创建平台
platform = GenericAssistantPlatform(logic)
# 构建应用
app = create_gradio_app(platform, logic)
# 启动
app.launch(server_name="0.0.0.0", server_port=7861, share=False)
# ---------------------------- #
# 7. 使用方式(替换此部分即可)
# ----------------------------
if __name__ == "__main__":
# ✅ 只需替换这里为你的新业务类
class FitnessBusinessLogic(BusinessLogic):
def get_tabs(self): return ["🏋️ 健身计划", "🥗 饮食建议", "📊 进度记录"]
def get_data(self): return {}
def set_data(self, data): pass
def get_overview_stats(self): return {"trip_count": 0, "wish_count": 0}
def build_ui(self, platform):
gr.Markdown("### 健身计划生成器")
goal = gr.Dropdown(["增肌", "减脂", "塑形"], label="目标")
weeks = gr.Number(8, label="周数")
output = gr.Textbox(lines=10)
btn = gr.Button("生成计划")
def generate(g, w):
prompt = f"为{w}周的{g}目标生成健身饮食计划。"
return platform.generate_response(prompt, 1024)
btn.click(generate, [goal, weeks], output)
return [goal, weeks, output, btn]
# 启动健身助手
launch_assistant(FitnessBusinessLogic)
🎉 结语
通过本教程,你已经掌握了如何构建一个功能完整、界面美观、智能高效的AI旅行助手。这不仅是一个技术项目,更是AI赋能日常生活的典范。
代码已开源,欢迎Star与Fork!
👉 体验地址:https://modelers.cn/spaces/ghn221/Travel-Manager
本次打榜比赛是比点赞和收藏的,兄弟们多多支持支持,点点赞和收藏,随机抽30位小伙伴送技术书籍。感谢大家支持!!
更多推荐



所有评论(0)