基于 AI 大模型的短途旅游行程规划小程序「知途 AI 旅行」设计与实现
本文记录了笔者从 0 到 1 完成的一个课程设计项目:用微信小程序 + FastAPI + DeepSeek 大模型做一款 AI 智能行程规划工具。文章涵盖需求分析、技术选型、系统架构、数据库设计、核心代码实现、真实踩坑与解决方案,适合正在做类似项目或想了解"前端 + 后端 + 大模型"全链路的同学参考。
一、项目背景与痛点分析
1.1 真实痛点
短途旅行(1-4 天)是大学生、年轻上班族最高频的出行场景。但实际做攻略的过程极其碎片化:
-
在小红书搜景点 → 在美团比票价 → 在高德看路线 → 在大众点评找美食 → 在携程订票;
-
收藏了几十篇笔记,真正成行时却"收藏从未停止,行动从未开始";
-
景点之间怎么串、几点去避峰、哪个机位出片、附近吃什么,全靠人肉拼凑。
核心问题:信息分散、决策成本高、缺乏"一键成行"的工具。
1.2 项目目标
做一个一站式 AI 行程规划小程序:用户输入城市、天数、人群、预算、偏好,AI 直接生成一份可执行的逐日行程,包含景点、路线、拍照机位、附近美食、购票入口。
二、需求分析
2.1 功能需求
| 模块 | 功能点 |
|---|---|
| 行程创建 | AI 表单规划、一句话快规划、截图识行程、手动编排(4 种模式) |
| 路线策略 | 大众经典路线 + 小众宝藏路线双版本 |
| 智能问答 | 任意行程相关问题(天气、避峰、交通、备选) |
| 第三方直达 | 打车 / 酒店 / 门票 / 机票高铁一键跳转对应小程序 |
| 模板广场 | 发布、收藏、复用优质路线 |
| 会员体系 | 月卡 19.9、年卡 129,解锁高级生成次数 |
2.2 非功能需求
-
接口响应快(生成类异步 + 兜底,主流程不卡死);
-
安全(JWT 鉴权、ORM 防注入);
-
易演示(支持 Mock 模式,无后端也能跑通界面)。
三、技术选型与理由
| 层 | 选型 | 为什么 |
|---|---|---|
| 前端 | 微信原生小程序 | 直接调微信登录、跳转其他小程序、真机预览,最契合"小程序跳小程序"需求 |
| 后端 | FastAPI | 异步性能好、自带 OpenAPI 文档、类型提示强、开发快 |
| 数据库 | MySQL 8.0 | 关系型数据(用户/行程/订单)稳定可靠,utf8mb4 支持 emoji |
| 缓存 | Redis | 限流、热点模板缓存、会话态 |
| AI | DeepSeek 大模型 | 中文行程生成质量高、成本低、API 简单 |
| 地图 | 高德开放平台 | POI 搜索、路径规划、地理编码一站齐全 |
为什么不用 uni-app / Taro?本项目强依赖微信原生能力(如
navigateToMiniProgram跳第三方、真机预览),原生最稳;且单人开发,原生心智负担更小。
四、系统总体架构
4.1 分层架构
┌─────────────────────────────┐ │ 微信小程序(WXML/WXSS/JS) │ 表现层 └──────────────┬──────────────┘ │ HTTPS + JWT(Bearer) ┌──────────────▼──────────────┐ │ FastAPI 网关 │ │ ├─ routers (参数校验/路由)│ │ ├─ services (业务逻辑) │ │ ├─ schemas (Pydantic 模型)│ │ └─ deps (鉴权依赖) │ └──────┬───────┬───────┬──────┘ │ │ │ ┌───▼─┐ ┌─▼──┐ ┌─▼────────┐ ┌─────────┐ │MySQL │ │Redis│ │DeepSeek │ │高德 API │ │持久化│ │限流 │ │行程生成 │ │地图服务 │ └──────┘ └─────┘ └─────────┘ └─────────┘
4.2 项目目录(后端)
server/ ├── app/ │ ├── main.py # 入口,挂 StaticFiles、CORS、路由 │ ├── config.py # 配置(DB/Redis/JWT/高德 Key) │ ├── database.py # SQLAlchemy 引擎 + Session │ ├── deps.py # get_current_user 鉴权依赖 │ ├── utils/jwt_utils.py │ ├── routers/ # plan / trip / user / template / chat / membership / ocr │ └── services/ # plan_service / trip_service / image_service / route_service ... └── .env # 密钥与 Key(gitignore)
五、数据库设计(MySQL 8.0)
共 8 张核心表:user、trip、trip_day、trip_spot、template、collection、order、chat_history、city、service_link(含派生表)。行程内容用 JSON 字段存结构化日程,兼顾灵活性与查询性能。
5.1 核心表结构(节选)
user 用户表
CREATE TABLE `user` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`openid` VARCHAR(64) NOT NULL,
`nickname` VARCHAR(64) DEFAULT NULL,
`avatar_url` VARCHAR(512) DEFAULT NULL,
`role` ENUM('free','vip') NOT NULL DEFAULT 'free',
`vip_expire_time` DATETIME DEFAULT NULL,
`daily_plan_count` INT NOT NULL DEFAULT 3,
`daily_count_date` DATE DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_openid` (`openid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
trip 行程表
CREATE TABLE `trip` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`user_id` BIGINT NOT NULL,
`city_id` INT NOT NULL,
`title` VARCHAR(128),
`days` INT,
`content` JSON, -- 完整逐日行程(天/景点/餐食/交通/拍照攻略)
`route_type` ENUM('popular','niche'),
`budget_level` ENUM('low','mid','high'),
`crowd_type` VARCHAR(32),
`transport_mode` VARCHAR(32),
`status` ENUM('draft','saved','deleted'),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
设计取舍:行程是"文档型"数据,字段结构随 AI 生成变化大,用
JSON存主内容,关系型字段(user_id/city_id)保证可关联统计。
六、后端核心实现
6.1 AI 行程生成接口
前端提交表单 → 后端拼 Prompt → 调 DeepSeek → 校验 JSON → 落库。关键路由:
# server/app/routers/plan.py
@router.post("/form")
async def plan_form(req: PlanFormReq, user=Depends(get_current_user)):
# 个人主体不扣积分;企业/个体户开启变现后才计费
if settings.monetization_enabled and not await points_service.consume_plan(user["user_id"]):
return fail("积分不足,请充值后再生成行程", code=4001)
trip = await plan_service.generate_from_form(req)
return ok({"trip": {"id": None, **trip}}) # 预览态 id 为 None,保存时走新建
细节:预览态行程
id设为None。前端保存时,后端检测到 id 不是合法整数就自动"新建",避免把占位符当已有记录更新而报错(详见第八节踩坑 1)。
6.2 JWT 无状态鉴权(真实代码)
登录:wx.login 拿 code → 后端换 openid(不返回前端)→ HMAC 签名签发 token。
# server/app/utils/jwt_utils.py import datetime, jwt from app.config import settings def create_token(payload: dict) -> str: payload = dict(payload) payload["exp"] = datetime.datetime.utcnow() + datetime.timedelta(hours=settings.jwt_expire_hours) return jwt.encode(payload, settings.jwt_secret, algorithm="HS256") def decode_token(token: str) -> dict: return jwt.decode(token, settings.jwt_secret, algorithms=["HS256"])
接口通过依赖统一校验:
# server/app/deps.py
async def get_current_user(authorization: str = Header(None)):
if not authorization or not authorization.startswith("Bearer "):
raise HTTPException(status_code=401, detail="未登录")
token = authorization[7:]
try:
return decode_token(token) # 验签名 + 过期,失败抛 401
except Exception:
raise HTTPException(status_code=401, detail="token 无效")
为什么安全:token 里没有 openid(防泄露),服务端不存 session(易扩展),HS256 签名保证不可伪造,带 exp 自动过期。
6.3 ORM 防 SQL 注入
全程用 SQLAlchemy 参数化查询,绝不手拼 SQL:
# 查询:参数化,注入无效 stmt = select(User).where(User.id == uid, User.status == 'active') result = await session.execute(stmt) # 更新:ORM 对象赋值,框架自动转义 user.nickname = new_name await session.commit()
用户输入永远作为"值"传递,数据库驱动会转义,从根本上杜绝 ' OR '1'='1 这类注入。
6.4 高德 API 集成与超时兜底
生成行程后需调高德补全 POI 图片/坐标、公交路径规划。原实现串行调用且超时 12-15s,Key 配额超限时会拖垮主流程。优化:
# image_service.py / route_service.py 关键改动 r = requests.get(url, timeout=5) # 原 12-15s → 5s,快速失败
并在 plan_service._normalize 中给高德调用包 try/except:
try:
info = image_service.get_spot_info(spot.get("name", ""), city)
spot["image"] = info.get("image") or spot.get("image") or ""
except Exception as e:
logger.warning("高德补全失败,跳过: %s", e) # 失败不阻塞整体行程返回
6.5 城市封面图三级兜底
外部图床(loremflickr)常 500,直接白屏。采用三级兜底,保证永不白屏:
本地真实图 /images/cities/城市.jpg → 不存在则 在线图床 picsum/seed 兜底 → 再失败则 显示 emoji 占位
前端 binderror 监听加载失败,自动逐级降级。后续把真实摄影图丢进文件夹即自动生效。
七、前端核心实现(微信原生小程序)
7.1 页面结构(12 个核心页面)
index(首页) / form(AI 表单) / quick(一句话) / ocr(截图识行程) / detail(行程详情) / trips(我的行程) / template(模板广场) / published(我发布的) / collection(收藏) / chat(智能问答) / member(会员) / profile(个人中心)。
7.2 请求封装
统一在 request.js 中拼接 BASE_URL + /api/xxx,自动携带 Authorization 头,统一处理 code !== 0 的业务错误,避免每个页面重复写。
7.3 第三方小程序跳转
首页"服务直达"通过 wx.navigateToMiniProgram 跳美团 / 携程 / 腾讯地图等,需在 app.json 的 navigateToMiniProgramAppIdList 配置白名单。查不到真实 AppID 的渠道(如大众点评、12306)降级为"复制搜索词",保证功能不缺且真机不报错。
7.4 行程详情:拍照攻略 + 美食攻略双栏
每个景点下方展示:
-
📸 拍照攻略(1 条核心机位:位置 + 光线 + 避峰标签);
-
🍽 美食攻略(AI 按景点就近推荐的餐厅:店名 + 人均 + 团购渠道);
-
底部大按钮:公众号预约 / 门票购买。
美食匹配逻辑:优先用景点自带 nearby_food → 按 time_slot(上午配早/午,晚配晚)→ 按地址区域相似度 → 兜底时间最近,避免全天都推荐同一家店。
八、API 接口清单(部分)
后端共 29 个接口,命名统一 /api/模块/动作,返回 {code, msg, data}:
| 接口 | 说明 |
|---|---|
POST /api/plan/form | AI 表单规划 |
POST /api/plan/quick | 一句话快规划 |
POST /api/plan/chat-adjust | 对话微调行程 |
POST /api/trip/save | 保存行程(新建/更新) |
GET /api/trip/list | 我的行程列表 |
GET /api/trip/detail | 行程详情 |
POST /api/user/avatar | 头像永久上传 |
GET /api/template/hot | 热门模板 |
POST /api/template/publish | 发布到广场 |
POST /api/collection/add | 收藏 |
POST /api/chat/qa | 旅游智能问答 |
POST /api/membership/order | 会员下单 |
POST /api/ocr/recognize | 截图识行程 |
九、真实踩坑记录(含前后对比)
坑 1:保存行程报「行程 id 格式错误 gen」
-
现象:点保存提示
gen格式错误。 -
根因:
plan.py预览态返回"id": "gen"占位符,前端当成真实 id 传给/api/trip/save,int("gen")转型失败。 -
修复:预览态
id改为None;trip_service.save()仅当 id 能转整数才走更新,否则兜底新建。 -
前后对比:
return ok({"trip": {"id": "gen", **trip}})→return ok({"trip": {"id": None, **trip}})。
坑 2:高德 Key 配额超限,AI 生成卡死
-
现象:一直"AI 规划中"转圈。
-
根因:后端日志
CUQPS_HAS_EXCEEDED_THE_LIMIT,生成后要串行调高德 POI/路径规划,每请求超时十几秒,累积超时前端断开。 -
修复:高德调用包
try/except不阻塞主流程 + 超时 12-15s 缩到 5s + 更换为"Web服务"类型新 Key。
坑 3:跳转第三方小程序失败
-
现象:点"机票高铁"弹"跳转失败,请检查白名单"。
-
根因:白名单里 12306 AppID
wxb84362f15c06b3f2查不到权威值,真机严格校验失败。 -
修复:换成已确证的携程 AppID
wx0e6ed4f51db9d078;大众点评同理降级为"复制搜索词"。
坑 4:图片加载失败连带 DOM 警告
-
现象:控制台刷
removedNode、loremflickr 500。 -
修复:三级兜底 +
binderror清 src,控制台恢复干净。
十、部署与运行
# 后端(项目自带 venv,避免系统 Python 缺依赖) cd server venv/Scripts/python.exe -m uvicorn app.main:app --host 0.0.0.0 --port 8009 --reload # 前端 微信开发者工具导入 miniprogram/,USE_MOCK=true 可纯前端预览; 切真实后端:env.js 设 USE_MOCK=false + BASE_URL 指向后端地址。
注意:
BASE_URL不含/api(前端统一以/api开头拼接),否则会双前缀 404。
十一、总结与展望
11.1 收获
-
打通"前端 + 后端 + 大模型 + 第三方 API"全链路;
-
对 JWT 无状态鉴权、ORM 防注入、异步限流、超时兜底 从概念变成实操;
-
学会"外部依赖不可控时必须降级"的工程思维。
11.2 展望
-
接入真实视觉识别做"截图识行程";
-
用户画像驱动个性化推荐;
-
行程分享海报 + 社交裂变。
十二、项目声明
本文为笔者在校期间独立完成的课程设计/项目实践作品,文中系统架构、核心代码、界面设计均为本人原创或基于开源协议合法使用。项目依赖的微信小程序、FastAPI、MySQL、Redis、DeepSeek LLM、高德地图等均为公开技术栈,代码仅供学习交流,不做真实票务交易、不涉及真实支付收款。转载请注明出处,禁止用于商业用途。
如果这篇文章对你做课程设计 / 毕设有帮助,欢迎点赞收藏~ 有疑问评论区交流,看到会回。
更多推荐
所有评论(0)