首先给大家推荐一个比赛,感兴趣的可以参加,跟着我的教程百分百能做出作品。奖金很丰厚,值得一试。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

注意openmindopenmind_hub 是华为昇腾生态的专用库,用于在NPU上高效运行大模型。

1.2 下载并加载Qwen2-7B-Instruct模型

我们使用 openmind_hubsnapshot_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位小伙伴送技术书籍。感谢大家支持!!

Logo

一座年轻的奋斗人之城,一个温馨的开发者之家。在这里,代码改变人生,开发创造未来!

更多推荐