一、项目前言

1.1 行业痛点

传统旅游规划依赖各类攻略平台,存在四大核心痛点:

  1. 全国景点数量庞大,人工筛选符合预算、评分的目的地效率极低;
  2. 多目的地自驾行程无法自动计算里程、时长、过路费,路线规划繁琐;
  3. 评分、票价、热度、地理位置数据分散,缺少统一可视化分析平台;
  4. 传统搜索仅关键词匹配,无法根据用户个性化偏好精准推荐景点。

1.2 项目概述

本项目名为途智・旅行规划师,基于纯 Python 开发,采用 Streamlit 快速搭建交互式 Web 平台,整合数据处理、多维可视化、机器学习混合推荐、DeepSeek RAG 智能问答、高德地图路线规划五大核心模块。系统面向普通游客、旅行规划者、旅游数据分析师三类用户,一站式实现景点浏览、个性化推荐、行程规划、数据洞察、AI 智能咨询全部功能。

1.3 整体技术栈

表格

分层 技术工具 核心作用
Web 展示层 Streamlit、自定义 CSS 多页面路由、交互界面美化、组件渲染
数据处理层 Pandas、NumPy、Scipy CSV 数据清洗、特征构造、独立样本 T 检验
机器学习层 Scikit-learn KNN 相似推荐、KMeans 聚类、PCA 降维、标准化处理
可视化层 PyEcharts 11 种交互式图表,包含分布、排名、热力、散点、地图等
AI 服务层 DeepSeek API、自研三级检索 RAG 景点 AI 介绍、旅游问答、知识库检索
地图服务层 高德 Web/JS API 地理编码、驾车路径规划、交互式路线地图

二、系统整体架构与页面设计

2.1 三层解耦架构

系统采用分层低耦合设计,分为数据层、服务层、展示层,模块职责清晰,便于维护迭代:

  1. 数据层 DataManager:统一加载清洗景点 CSV,构造衍生特征,构建省 - 区县三级树形数据,全局单例缓存数据集;
  2. 服务层(四大独立 Service)
    • RecommendService:偏好推荐、KNN 相似推荐、KMeans 聚类、混合加权推荐;
    • VisualizationService:封装全部可视化图表,支持省 / 区县数据联动筛选;
    • AIService:本地知识库构建、三级检索 RAG、DeepSeek 对话、多级降级容错;
    • MapService:地址转经纬度、驾车路线计算、地图 HTML 文件生成;
  3. 展示层 Streamlit UI:四页面导航、侧边联动筛选、分页列表、路线管理、AI 聊天窗口。

2.2 数据流逻辑

原始景点 CSV 数据集 → DataManager 清洗并构造特征矩阵 → 四大服务读取处理数据 → Streamlit 页面渲染图表、推荐列表、地图、AI 对话内容

2.3 四大功能页面划分

  1. 景点浏览页:省区县联动筛选、分页景点卡片、景点 AI 详情、自驾路线规划、RAG 聊天助手;
  2. 数据可视化页:4 个子标签,11 类交互式图表,完成数据分布、区域对比、空间热力分析;
  3. 智能推荐页:偏好筛选推荐、KNN 相似景点检索、KMeans 聚类分析 + PCA 降维散点图;
  4. 数据分析页:描述性统计、特征相关性矩阵、5A / 非 5A 景点 T 检验、聚类模型指标评估。

2.4 整体页面布局设计

系统统一布局结构:顶部标题栏 + 横向导航栏 + 左侧筛选侧边栏 + 主体内容区,景点 / 推荐页面采用左右双栏(主内容 + 详情面板),可视化、数据分析页面采用全屏布局。

三、数据集预处理模块

3.1 数据集基础信息

数据源为结构化景点数据.csv,共 13617 条完整有效数据。 原始核心字段:序号、景点名称、综合评分、景区等级、门票价格、销量热度、省份、完整区域、详细地址、景点简介。 衍生字段:

  1. heat_score综合热度:平衡评分与人气,计算公式:\(heat\_score=score×0.4 + (sales/max\_sales)×0.6\);
  2. district区县字段:从 region 字符串切割提取末级区县名称;
  3. 6 维机器学习特征:原始评分、归一化价格、对数销量、综合热度、编码景区等级、归一化省份编码。

3.2 数据清洗核心代码(data_manager.py)

仅过滤名称、评分、价格、销量为空的无效数据,价格为 0 代表免费景点,予以保留;同时完成热度特征、区县字段构造。

python

运行

def load_data(self):
    if not os.path.exists(DATA_FILE):
        raise FileNotFoundError(f"数据文件不存在: {DATA_FILE}")
    self.df = pd.read_csv(DATA_FILE)
    # 过滤关键字段空值
    self.df = self.df[self.df['name'].notna()]
    self.df = self.df[self.df['score'].notna()]
    self.df = self.df[self.df['price'].notna()]
    self.df = self.df[self.df['sales'].notna()]
    self.df = self.df.reset_index(drop=True)
    # 构造综合热度指标
    max_sales = self.df['sales'].max()
    self.df['heat_score'] = self.df['score'] * 0.4 + (self.df['sales'] / max_sales) * 0.6
    # 提取区县名称
    self.df['district'] = self.df['region'].apply(
        lambda x: x.split('-')[-1 if isinstance(x, str) and '-' in x else x
    )
    print(f"[OK] 数据加载成功: {len(self.df)} 条记录")

清洗前后对比统计表:

指标

清洗前

清洗后

记录总数

13617

13617

score 有效记录数

13617

13617

price 有效记录数

13617

13617

sales 有效记录数

13617

13617

3.3 特征标准化处理

对 6 维特征做编码、归一化、Z-score 标准化,消除量纲差异,保证模型距离计算准确。

def _build_features(self):
    le = LabelEncoder()
    level_encoded = le.fit_transform(df['level'].fillna('未评级'))
    province_le = LabelEncoder()
    province_encoded = province_le.fit_transform(df['province'])
    # 拼接6维原始特征
    features = np.column_stack([
        df['score'].values, df['price']/100, np.log1p(df['sales'])/10,
        df['heat_score'].values, level_encoded, province_encoded/32.0
    ])
    self.scaler = StandardScaler()
    self.feature_matrix = self.scaler.fit_transform(features)

标准化前后特征统计对比表格:

特征

标准化前均值

标准化后均值

标准化前 std

标准化后 std

score (评分)

7.6583

-0.000000000

0.95552

1.00003672

price/100 (价格)

0.76887

0.000000000

1.7334

1.00003672

log (sales+1)/10 (销量)

0.29999

-0.000000000

0.22779

1.00003672

heat_score (热度)

3.06556

0.000000000

0.3844

1.00003672

level_enc (等级)

2.53888

-0.000000000

0.9323

1.00003672

province_enc/32 (省份)

0.48008

0.000000000

0.2866

1.00003672

3.4 省 - 区县三级层级构建

构建字典层级结构hierarchy={省份:{区县:[景点列表]}},每个区县内景点按综合热度降序排列,供侧边筛选、页面列表快速读取。

def build_hierarchy(self):
    self.hierarchy = {}
    for _, row in self.df.iterrows():
        province = row['province']
        district = row['district']
        scenic = row.to_dict()
        if province not in self.hierarchy:
            self.hierarchy[province] = {}
        if district not in self.hierarchy[province]:
            self.hierarchy[province][district] = []
        self.hierarchy[province][district].append(scenic)
    # 区县内按热度降序
    for p in self.hierarchy:
        for d in self.hierarchy[p]:
            self.hierarchy[p][d].sort(key=lambda x:x["heat_score"], reverse=True)

四、机器学习推荐模型实现

4.1 KNN 余弦相似度相似推荐

以标准化 6 维特征向量计算余弦相似度,匹配风格近似景点,适合用户输入单一景点查找同类目的地。

# 模型初始化
self.knn_model = NearestNeighbors(n_neighbors=20, metric='cosine', algorithm='brute')
self.knn_model.fit(self.feature_matrix)

def knn_recommend(self, scenic_name: str, top_k: int = 10) -> List[Dict]:
    idx = self.df[self.df['name'].str.contains(scenic_name, na=False)].index[0]
    query_vec = self.feature_matrix[idx].reshape(1, -1)
    distances, indices = self.knn_model.kneighbors(query_vec)
    results = []
    for i, dist in zip(indices[0], distances[0]):
        if i == idx: continue
        scenic = self.df.iloc[i].to_dict()
        scenic['similarity'] = round(1 - dist, 4)
        results.append(scenic)
    return results[:top_k]

4.2 KMeans 聚类模型

自动适配聚类数量,固定随机种子保证实验可复现,同簇景点特征相近,用于聚类分组推荐。

n_clusters = min(8, len(self.df) // 500)
self.cluster_model = KMeans(n_clusters=n_clusters, random_state=42, n_init=10)
self.cluster_labels = self.cluster_model.fit_predict(self.feature_matrix)
self.df['cluster'] = self.cluster_labels

def cluster_recommend(self, scenic_name: str, top_k: int = 10) -> List[Dict]:
    idx = self.df[self.df['name'].str.contains(scenic_name)].index[0]
    cluster_id = self.cluster_labels[idx]
    same_cluster = self.df[self.cluster_labels == cluster_id]
    # 同簇内计算相似度排序
    ...

4.3 混合加权推荐(项目创新点)

融合 KNN 全局相似度(权重 0.6)、KMeans 同簇相似度(权重 0.4),合并去重后加权排序,兼顾全局风格与同类特征,解决单一算法局限性。

def hybrid_recommend(self, scenic_name: str, top_k: int = 12) -> List[Dict]:
    knn_results = self.knn_recommend(scenic_name, top_k * 2)
    cluster_results = self.cluster_recommend(scenic_name, top_k * 2)
    seen = set()
    merged = []
    # KNN加权入库
    for r in knn_results:
        if r['name'] not in seen:
            r['weight'] = 0.6 * r.get('similarity', 0.5)
            seen.add(r['name'])
            merged.append(r)
    # 聚类加权入库
    for r in cluster_results:
        if r['name'] not in seen:
            r['weight'] = 0.4 * r.get('similarity', 0.5)
            seen.add(r['name'])
            merged.append(r)
    merged.sort(key=lambda x: x.get('weight', 0), reverse=True)
    return merged[:top_k]

4.4 基于用户偏好内容推荐

通过滑块限定最低评分、最高票价、免费筛选,自定义推荐分数,优先推荐高性价比景点。

def content_recommend(self, preferences: Dict, top_k: int = 10, province=None, district=None):
    df = self.df.copy()
    # 地域筛选
    if province:
        df = df[df['province'] == province]
        if district: df = df[df['district'] == district]
    # 用户偏好过滤
    min_score = preferences.get('min_score')
    max_price = preferences.get('max_price')
    free_only = preferences.get('free_only')
    df = df[df['score'] >= min_score]
    df = df[df['price'] <= max_price]
    if free_only: df = df[df['price'] == 0]
    # 综合推荐打分
    df['rec_score'] = (df['score']/10)*0.45 + (df['sales']/df['sales'].max())*0.25 + (1/(df['price']+1))*0.15
    return df.nlargest(top_k, 'rec_score').to_dict('records')

五、多维可视化模块(VisualizationService)

基于 PyEcharts 实现 11 类交互式图表,全部封装为统一方法,支持省份、区县筛选过滤,统一返回 HTML 字符串嵌入页面。以评分分布直方图、全国热力地图为例:

5.1 景点评分分布直方图

def score_distribution(self, province: str = None, district: str = None) -> str:
    df = self._filter_df(province, district)
    scores = df['score'].dropna()
    bins = 20
    hist, bin_edges = np.histogram(scores, bins=bins)
    bar = Bar(init_opts=opts.InitOpts(width="100%", height="460px"))
    bar.add_xaxis([f"{bin_edges[i]:.1f}" for i in range(len(bin_edges)-1)])
    bar.add_yaxis("景点数量", hist.tolist(), itemstyle_opts=opts.ItemStyleOpts(...))
    bar.set_global_opts(title_opts=opts.TitleOpts(title=f"{province or '全国'}景点评分分布", ...))
    return self._wrap_chart(bar.render_embed(), 480)

5.2 全国省份景点热力地图

def china_heatmap(self) -> str:
    province_counts = self.df['province'].value_counts()
    data_pair = [(k, int(v)) for k, v in province_counts.items()]
    map_chart = Map(init_opts=opts.InitOpts(width="100%", height="500px"))
    map_chart.add("景点数量", data_pair, "china", is_map_symbol_show=False)
    map_chart.set_global_opts(visualmap_opts=opts.VisualMapOpts(range_color=[...]))
    return self._wrap_chart(map_chart.render_embed(), 520)

完整图表清单:评分直方图、价格玫瑰饼图、等级玫瑰图、免费景点仪表盘、省份柱状排名、区县柱状排名、热度 Top20 柱状图、评分 - 价格散点图、省份雷达对比、均价双柱图、评分箱型图、全国热力地图。

六、DeepSeek RAG 智能问答模块

6.1 三级本地检索策略

无需向量数据库,基于本地景点索引低成本检索,杜绝大模型凭空编造信息:

  1. 一级精确匹配:用户输入包含完整景点名,直接调取景点全部数据;
  2. 二级省份匹配:识别省份关键词,调取该省均分、均价、热门景点统计;
  3. 三级模糊关键词匹配:拆分关键词模糊检索景点名称补充候选数据。
def _search_knowledge(self, query: str, top_k: int = 5) -> List[Dict]:
    matched = []
    # 1.精确景点匹配
    for name in self.scenic_index:
        if name in query:
            matched.append(self.scenic_index[name])
    # 2.省份匹配
    for p in self.data_manager.get_provinces():
        if p in query and len(p) > 1:
            matched.append({"type":"province_stats", "province":p, "stats":self.province_stats[p]})
    # 3.关键词模糊检索
    if len(matched) < top_k:
        keyword_list = query.replace("推荐","").replace("好玩","").split()
        for kw in keyword_list:
            if len(kw)>=2:
                sub_df = self.data_manager.df[self.data_manager.df['name'].str.contains(kw)].head(top_k)
                for _,row in sub_df.iterrows(): matched.append(row.to_dict())
    return matched[:top_k]

6.2 四级降级容错对话架构

系统可用性保障,分层降级避免 API 失效导致功能崩溃:本地规则匹配→RAG 检索增强→DeepSeek API 生成→纯本地文本兜底。

def chat(self, user_message: str, context: Dict = None) -> str:
    # 第一层:本地规则直接回复
    local_response = self._local_response(user_message)
    if local_response: return local_response
    # 第二层:RAG检索本地知识库上下文
    rag_context = self._build_rag_context(user_message, context)
    # 第三层:调用DeepSeek大模型API
    if self.client:
        try:
            system_prompt = f"""你是旅游助手途智,仅依据下方景点数据回答,禁止编造景点信息。{rag_context}"""
            response = self.client.chat.completions.create(
                model="deepseek-chat",
                messages=[{"role":"system","content":system_prompt},{"role":"user","content":user_message}],
                temperature=0.7, max_tokens=800
            )
            return response.choices[0].message.content
        except Exception:
            pass
    # 第四层:API故障,仅返回检索到的本地数据兜底
    if rag_context:
        return f"检索到相关景点数据:{rag_context[:500]}"
    return "你可以询问省份、景点名称获取旅游推荐"

6.3 景点 AI 详情生成

输入景点原始数据,由 DeepSeek 生成 200 字左右专业景点介绍,API 失效时自动使用模板拼接基础信息兜底。

def analyze_scenic(self, scenic_name: str) -> Dict:
    scenic = self.data_manager.get_scenic_by_name(scenic_name)
    result = {"name":scenic['name'],"score":scenic['score'],"price":scenic['price'],...}
    if self.client:
        prompt = f"基于以下信息写200字景点介绍:名称{scenic['name']},等级{scenic['level']},评分{scenic['score']},简介{scenic['comments']}"
        resp = self.client.chat.completions.create(model="deepseek-chat", messages=[...])
        result['ai_intro'] = resp.choices[0].message.content
    else:
        # 本地模板兜底生成简介
        ...
    return result

七、高德地图路线规划模块

封装高德 Web、JS 双 API,实现地址解析、多途经点路线计算、交互式路线地图生成,完整行程可视化。

7.1 地理编码(地址转经纬度)

def geocode(address: str, city: str = "") -> Optional[Dict]:
    url = "https://restapi.amap.com/v3/geocode/geo"
    params = {"key": AMAP_WEB_API_KEY, "address": address, "city": city, "output":"JSON"}
    resp = requests.get(url, timeout=10)
    data = resp.json()
    if data["status"] == "1" and data["geocodes"]:
        lng, lat = data["geocodes"][0]["location"].split(",")
        return {"lng":float(lng), "lat":float(lat)}
    return None

7.2 多途经点驾车路线计算

支持最多 16 个途经景点,返回总里程、耗时、过路费、路线坐标串 polyline。

def route_planning(origin, destination, waypoints=None, strategy=0):
    url = "https://restapi.amap.com/v3/direction/driving"
    params = {"key":AMAP_WEB_API_KEY,"origin":f"{origin[0]},{origin[1]}","destination":f"{destination[0]},{destination[1]}","strategy":0}
    if waypoints:
        wp_str = ";".join([f"{wp[0]},{wp[1]}" for wp in waypoints[:16]])
        params["waypoints"] = wp_str
    resp = requests.get(url)
    data = resp.json()
    if data["status"] == "1":
        path = data["route"]["paths"][0]
        return {
            "distance": int(path["distance"]), "duration": int(path["duration"]),
            "tolls": int(path["tolls"]), "polyline": path["polyline"], "steps": path["steps"]
        }
    return None

7.3 交互式路线地图 HTML 生成

拼接高德 JS API 模板,生成带点位标记、行车路线、信息弹窗的独立 HTML 文件,在页面内嵌展示。

def generate_route_map_html(scenics: List[Dict], route_info: Dict = None) -> str:
    # 提取所有景点坐标,计算地图中心点
    lngs, lats = [], []
    for s in scenics:
        loc = s.get("location", "").split(",")
        lngs.append(float(loc[0])), lats.append(float(loc[1]))
    center = [sum(lngs)/len(lngs), sum(lats)/len(lats)]
    # 拼接前端HTML模板,注入路线、点位JSON
    html_template = f"""<!DOCTYPE html><html><head><script src="https://webapi.amap.com/maps?v=2.0&key={AMAP_JS_API_KEY}"></script>
    <body><div id="container"></div>
    <script>var markers = {json.dumps(markers)}; var routeData = {json.dumps(route_info)}; ... </script>
    </body></html>"""
    map_path = os.path.join(OUTPUT_DIR, "map_route.html")
    with open(map_path, "w", encoding="utf-8") as f:
        f.write(html_template)
    return map_path

八、Streamlit 主程序页面实现(app.py)

8.1 全局基础配置

必须放在所有 Streamlit 组件最前端,配置页面标题、图标、宽屏布局、侧边默认展开。

# 项目路径导入
import sys, os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
sys.path.append("E:\\daima")
import streamlit as st
# 全局页面配置(首行组件)
st.set_page_config(
    page_title="途 · 旅行规划师",
    page_icon="⛰️",
    layout="wide",
    initial_sidebar_state="expanded"
)

8.2 服务与会话状态缓存

使用@st.cache_resource全局缓存 AI、可视化、推荐服务,避免页面刷新重复初始化;session_state 持久保存筛选、对话、路线、页码状态。

@st.cache_resource
def get_services():
    ai_svc = DeepSeekService(data_manager)
    viz_svc = VisualizationService(data_manager)
    rec_svc = RecommendService(data_manager)
    return ai_svc, viz_svc, rec_svc

def init_session_state():
    # 筛选状态
    if "selected_province" not in st.session_state: st.session_state.selected_province = ""
    if "selected_district" not in st.session_state: st.session_state.selected_district = ""
    # 服务实例
    if "ai_service" not in st.session_state:
        st.session_state.ai_service, st.session_state.viz_service, st.session_state.rec_service = get_services()
    # 对话、分页、路线、页面路由
    if "chat_messages" not in st.session_state: st.session_state.chat_messages = []
    if "page_num" not in st.session_state: st.session_state.page_num = 0
    if "current_page" not in st.session_state: st.session_state.current_page = "景点浏览"
    if "route_scenics" not in st.session_state: st.session_state.route_scenics = []
init_session_state()

8.3 全局自定义 CSS 美化

覆盖原生 Streamlit 简陋样式,定义头部渐变、景点卡片、聊天气泡、统计网格统一样式。

def load_css():
    st.markdown("""
    <style>
    .main-header {
        background: linear-gradient(135deg, #1a237e, #283593);
        padding: 14px 24px; border-radius: 8px; color: white;
        display: flex; justify-content: space-between; align-items: center;
    }
    .scenic-list-item { background: #f8f9fa; border-radius: 6px; padding: 12px; margin:8px 0; }
    .chat-msg-user { background:#e8f0fe; padding:8px; border-radius:6px; margin:4px 0;}
    .chat-msg-ai { background:#f1f3f4; padding:8px; border-radius:6px; margin:4px 0;}
    ...
    </style>
    """, unsafe_allow_html=True)

8.4 顶部标题栏渲染

展示系统名称、实时日期、全局景点 / 省份统计数量。

def render_header():
    import pandas as pd
    st.markdown(f"""
    <div class="main-header">
        <div>
            <h1><span class="highlight">途智</span> · 旅行规划师</h1>
            <div class="subtitle">基于多源数据、机器学习与地图API智能分析系统</div>
        </div>
        <div style="text-align:right;">
            <div style="color:#ffd54f;">{pd.Timestamp.now().strftime('%Y年%m月%d日')}</div>
            <div>景点{len(data_manager.df)} | 省份{len(data_manager.get_provinces())}</div>
        </div>
    </div>
    """, unsafe_allow_html=True)

8.5 侧边栏省区县联动筛选

省份切换自动清空区县、重置分页,实现二级联动下拉框。

def _on_prov_change():
    prov = st.session_state.get("sidebar_prov", "")
    if prov == "全部": prov = ""
    if prov != st.session_state.selected_province:
        st.session_state.selected_province = prov
        st.session_state.selected_district = ""
        st.session_state.page_num = 0

def render_sidebar():
    with st.sidebar:
        st.markdown("""<div style="text-align:center;"><h2>🗺️途智规划师</h2></div>""", unsafe_allow_html=True)
        st.divider()
        # 省份下拉
        provinces = ["全部"] + data_manager.get_provinces()
        st.selectbox("📍省份", provinces, index=..., key="sidebar_prov", on_change=_on_prov_change)
        # 选中省份后展示区县下拉
        if st.session_state.selected_province:
            districts = ["全部"] + data_manager.get_districts(st.session_state.selected_province)
            st.selectbox("📍区县", districts, index=..., key="sidebar_dist", on_change=_on_dist_change)
        st.divider()
        # 路线列表、景点搜索...

8.6 顶部导航与页面路由分发

横向四按钮导航,点击切换页面,路由分发渲染对应页面内容。

def main():
    load_css()
    render_header()
    # 顶部导航
    current = st.session_state.current_page
    pages = ["🏯 景点浏览", "📊 数据可视化", "🤖 智能推荐", "📈 数据分析"]
    cols = st.columns(len(pages))
    for idx, page in enumerate(pages):
        with cols[idx]:
            clean_name = page.split(" ",1)[1]
            is_active = current == clean_name
            if st.button(page, use_container_width=True, type="primary" if is_active else "secondary"):
                st.session_state.current_page = clean_name
                st.rerun()
    st.divider()
    # 页面路由
    if current == "景点浏览":
        col_main, col_right = st.columns([2.2, 1])
        with col_main: page_scenic_browse(); render_chat()
        with col_right: render_detail_panel()
    elif current == "数据可视化":
        page_visualization()
    elif current == "智能推荐":
        ...
    render_sidebar()
if __name__ == "__main__":
    main()

九、项目创新点、不足与优化方向

9.1 核心创新亮点

  1. 混合加权推荐算法:融合 KNN 全局相似度、KMeans 聚类相似度,平衡全局风格与同类特征,提升推荐匹配度;
  2. 轻量化 RAG 本地检索:不依赖向量数据库,三级关键词检索低成本消除大模型幻觉,数据全部来自本地景点库;
  3. 地图与推荐深度联动:任意推荐景点可一键加入路线,批量生成多目的地自驾路线地图;
  4. 多级容错降级架构:AI、地图 API 异常均有本地兜底逻辑,系统不会崩溃;
  5. 一站式全链路 Python 项目:无需前端、后端分离,单语言完成数据处理、机器学习、可视化、GIS 地图、大模型集成。

9.2 现存不足

  1. 数据存储:当前采用内存 CSV 存储,百万级大数据加载缓慢;
  2. 推荐维度:仅使用数值特征,未引入景点文本评论 TF-IDF 语义特征;
  3. 路线功能:仅支持自驾,缺少公交、高铁规划;
  4. AI 能力:无 Agent 工具调用,无法自主查询、计算数据。

9.3 后续拓展优化方案

  1. 存储优化:迁移 SQLite/MySQL 数据库,实现分块读取、条件查询;
  2. 算法升级:新增协同过滤、XGBoost 打分,引入用户收藏行为;
  3. 功能拓展:接入天气、酒店、餐饮 API,完善出行配套信息;
  4. AI 升级:接入 FAISS 向量库实现语义检索,增加工具调用 Agent;
  5. 性能优化:图表、推荐结果增加缓存,异步请求外部 API。

十、项目部署运行说明

10.1 依赖安装命令

pip install streamlit pandas numpy scikit-learn pyecharts scipy requests openai

10.2 完整项目目录结构

project/
├── app.py                 # 主程序入口
├── config.py              # API密钥、文件路径配置
├── data_manager.py        # 数据加载、清洗、特征构造
├── recommend_service.py   # 四大推荐算法
├── visualization_service.py # 全部可视化图表
├── ai_service.py          # DeepSeek RAG问答
├── map_service.py        # 高德地图接口封装
├── ui_components.py       # 复用UI组件
├── data/
    └── 景点数据.csv       # 原始数据集
└── output/                # 运行生成地图HTML文件

10.3 项目启动命令

streamlit run app.py

十一、总结

本项目完整覆盖数据清洗→特征工程→机器学习建模→交互式可视化→RAG 大模型应用→GIS 地图开发→Web 系统搭建全数据科学开发流程,面向旅游行业真实业务场景,功能完整、模块化清晰,非常适合大数据、计算机专业实训、课程设计、毕业设计作业参考。系统全部基于 Python 实现,无需前端开发基础,一条命令即可运行完整可交互 Web 平台,兼具数据分析学术价值与真实落地使用价值。

以下为作品界面和部分功能展示:

途智 · 旅行规划师演示

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐