旅游星推官|全城市通用AI行程规划项目方案
一、项目概述
产品名称:旅游星推官 产品能力:用户输入【出发城市+目的城市+游玩天数】,全国任意城市均可规划,AI自动结构化输出整套旅行方案 输出内容清单:
- 往返交通:飞机/高铁/大巴、参考票价、耗时、班次参考
- 逐日行程:上下午打卡景点、门票价格、开放时段
- 本地特色美食:店名、品类、人均消费
- 住宿推荐:经济型民宿、舒适型酒店(景点就近)
- 目的地天气、穿搭提醒、整体游玩总预算、避坑贴士 客户端:微信小程序 + H5(UniApp一套代码多端发布) 后端技术:Golang + Gin(首选方案,适配SSE流式逐token推送、高并发AI接口)
二、整体技术栈
1.后端 Golang
| 组件 | 作用说明 |
|---|---|
| Go1.23 + Gin | HTTP接口、SSE流式打字返回AI内容、路由管理 |
| GORM (github.com/gorm.io/driver/postgres) | PostgreSQL操作:用户数据、历史行程存储、城市基础配置 |
| Redis | 热点目的地POI、天气、攻略缓存,减少第三方API调用,节省费用 |
| langchaingo | AI核心:大模型对接、Agent工具调用、RAG知识库检索 |
| Chroma | 轻量级向量数据库(通过HTTP API交互),存放全国各城市旅游攻略,RAG补充真实数据 |
| Docker | 项目容器打包,一键部署云服务器 |
2.前端 UniApp(Vue3 + uViewUI)
- 对话页面:输入出行需求,SSE长链接实时接收流式AI回复
- 行程卡片页:交通、景点、美食、住宿分模块排版展示
- 历史行程:云端存储历史规划记录,支持查看、重新编辑规划
3.存储分层
- PostgreSQL:业务结构化数据(用户、行程记录)
- Chroma向量库:全国旅游PDF/游记攻略向量化存储(RAG数据源)
- Redis:临时缓存热点数据,规避重复请求第三方接口
4.用户认证体系(微信小程序)
- 前端调用
wx.login()获取临时 code,发送至后端 - 后端通过 code 换取微信 OpenID 和 SessionKey
- 签发 JWT Token 返回前端,后续请求 Bearer Token 鉴权
- 用户行程数据按 OpenID 隔离,确保数据安全与隐私
5.核心数据库表设计(PostgreSQL)
| 表名 | 说明 | 核心字段 |
|---|---|---|
users | 微信用户 | id (BIGSERIAL PK), openid (VARCHAR UNIQUE), nickname, avatar_url, created_at |
trips | 行程记录 | id (BIGSERIAL PK), user_id (FK→users), from_city, to_city, days, raw_content (JSONB), created_at |
city_config | 城市基础配置 | id (BIGSERIAL PK), city_name, province, hot_tags (JSONB), is_active |
注:PostgreSQL 用
BIGSERIAL代替 MySQL 的AUTO_INCREMENT;JSONB 存储 AI 回复的完整结构化数据,方便后续解析展示。
6.API 限流与安全
- 单用户限流:同一用户每日最多发起 10 次行程规划,防刷防滥用
- 全局限流:Gin 中间件(
ulule/limiter或didip/tollbooth),全站 QPS 上限控制 - 第三方 API 调用计数:Redis 原子计数器,实时监控高德/天气 API 调用量,接近免费额度自动告警
- 敏感词过滤:用户输入城市名做白名单校验,拒绝非中国城市或恶意输入
7.开发顺序建议:后端先行,前端跟进
核心原则:后端始终比前端快一个阶段,前端对接真实接口,不做 mock。
| 阶段 | 后端 | 前端 | 说明 |
|---|---|---|---|
| 阶段1 | ✅ AI + SSE 核心链路,curl 验证 | 极简聊天框(能发请求、看流式文字即可) | 后端先跑通核心价值 |
| 阶段2 | ✅ 高德 3 个 Tool + 自动化测试 | 行程卡片 UI 开发(此时对接真实数据) | 后端稳定后前端再跟 |
| 阶段3 | ✅ RAG + Chroma | 历史行程、登录等页面补全 | 前端此时基本不动 |
| 阶段4-6 | 完善部署 | 联调 + 真机测试 | 最后合拢 |
为什么后端先行?
- 核心价值在后端:AI 行程生成 + SSE 流式是项目灵魂,前端本质是「聊天框 + 卡片」,复杂度远低于后端。后端不通,前端再好看也没意义。
- SSE 必须后端先跑通:EventSource 的
Last-Event-ID、retry、分块传输编码等行为 mock 不出来,前端用假数据开发后期必然返工。 - 第三方 API 是不确定性最大的部分:高德 POI 字段结构、DeepSeek function calling 与 langchaingo 适配程度,这些必须最先消除风险。
- AI 输出结构会迭代多版:契约守不住,约定 JSON 格式然后前后端并行的模式在 AI 项目里行不通。
反模式提醒:
| 做法 | 为什么不好 |
|---|---|
| 前端先写完所有页面再调后端 | SSE 行为不对齐,后期大量返工 |
| 前后端完全并行、约定 JSON 格式 | AI 输出结构会迭代多版,契约守不住 |
| 前端 mock 大量假数据开发 | 真数据到了之后布局必崩(文本长度、卡片数量不可预测) |
三、第三方API明细&资费(交通/美食/民宿/天气)
3.1 高德地图(交通+景点+美食+民宿POI,主力数据源)
- 开户:个人实名认证免费开通,无开户费、无年费、不开通自动扣费
- 免费配额(个人开发者永久)
- 城际路线规划:每日免费2000次
- POI关键词检索(美食/酒店/景区):每日免费5000次
- 地理编码:每日免费5000次
- 计费规则:免费额度用尽直接接口报错,不自动扣费;商用大批量使用按需充值:约0.015元/次
开发、内测、小流量运营完全够用,零成本。
3.2 美食、民宿酒店三种数据源方案
方案1【推荐·零成本】仅使用高德POI
通过关键词城市+民宿/特色美食/景区酒店查询,获取门店名称、地址、商圈、评分,满足行程推荐展示,不走其他付费接口。
方案2【小规模上线可选】美团开放平台
- POI基础查询:每月免费100万次,超出0.15元/百次
- 实时房价、预订接口:前期不接入预订功能,无需开通
方案3【后期商业化】携程开放平台
- 仅展示酒店信息免费,产生订单成交后收取商家佣金,开发者无查询扣费;前期不做预订不用接入。
3.3 和风天气API
个人开发者每日免费3000次,查询目的地近3日天气,依据天气智能调整行程(雨天替换室内景点)。
3.4 大模型接口(DeepSeek/通义千问)
新用户赠送大量免费token,开发内测全免费;正式商用按量计费,成本极低。
四、省钱优化方案(降API开销)
- Redis缓存:同一目的地7天内重复请求优先读取缓存,不再调用高德API
- RAG本地知识库:全国攻略提前入库向量库,小众景点、本地美食优先读取本地数据,减少接口请求
- 分层使用数据源:内测全免费POI+RAG;日活500以内靠缓存维持免费;高流量后按需小额充值高德
五、六阶段落地开发计划
阶段1:基础对话交互(3天)
- UniApp聊天框对接Gin后端,接收用户出行参数
- 固定通用Prompt(全城市通用) 你是专业旅游星推官,根据用户给出的出发地、目的地、游玩天数生成规范旅行方案:
- 往返交通:高铁 / 飞机参考票价、行程时长;
- 每日行程:分上午下午推荐景点、标注门票、开放时间;
- 当日周边特色美食,附带人均消费;
- 就近推荐 2 家经济型民宿、2 家中端酒店;
- 汇总整体预估预算、出行注意事项; 无准确数据时标注【暂无精准信息】,禁止编造虚假景点与店铺。 plaintext
- 对接大模型,SSE流式输出内容,纯文本行程测试。
阶段2:接入高德+AI工具函数(5天)
基于langchaingo自定义3个AI工具,AI缺真实数据时自动调用高德接口:
- GetTraffic(startCity, targetCity):城际飞机/高铁查询
- GetScenicSpot(cityName):城市景点POI检索
- GetFoodAndHotel(city,area):周边美食、民宿POI查询
- 编写接口自动化测试,验证3个Tool函数返回数据结构正确
- AI输出质量人工抽检(30条测试用例,覆盖不同城市+天数组合)
阶段3:搭建全国RAG知识库(5天)
- 搜集全国各省市旅游攻略、游记、PDF文档
- Go脚本批量解析文档、文本向量化存入Chroma
- 用户发起行程规划,优先检索本地知识库,结合高德数据生成方案,降低大模型杜撰概率
阶段4:天气接入+前端优化(2天)
- 接入和风天气API,根据目的地天气动态调整行程安排
- 前端拆分行程卡片样式,历史规划落地存入PostgreSQL
- 登录鉴权联调:wx.login → JWT签发 → 接口鉴权中间件
阶段5:测试与质量保障(2天)
- 微信小程序真机测试(iOS/Android 各2款机型)
- 接口压力测试:wrk/vegeta 模拟 100 并发 SSE 连接,验证系统稳定性
- AI 输出质量复查:确认 RAG 检索相关度、幻觉率控制在可接受范围
- 边界场景测试:网络断开重连、Token 过期、空城市名、超长天数等异常输入
阶段6:容器打包上线(1.5天)
- Docker Compose 编排:Gin 后端 + PostgreSQL + Redis + Chroma,一键启动
- 配置 Nginx 反向代理 + SSL 证书(Let's Encrypt 免费)
- PostgreSQL 初始化脚本:自动建表 + 种子数据(热门城市列表)
- 部署阿里云 2核4G 轻量服务器(建议比1核2G高一级,PG/Chroma 较吃内存)
- 配置日志收集:Gin 访问日志 + 错误日志落盘,按天切割
- UniApp 打包提交微信小程序审核上线
六、测试策略(四层质量保障体系)
核心思路:AI 项目的输出不固定,不能简单断言"返回值等于某个字符串"。测试要分层——确定性逻辑用自动化,不确定性输出用结构校验 + 人工抽检。
第一层:单元测试(确定性部分)
传统单测方法,针对输入输出明确的函数。
1.1 Tool Function 返回结构校验
func TestGetScenicSpot(t *testing.T) {
spots, err := GetScenicSpot("成都") // 高德 POI 真实调用
if err != nil {
t.Fatalf("高德API调用失败: %v", err)
}
if len(spots) == 0 {
t.Fatal("成都应该有景点返回,实际为0条")
}
for _, s := range spots {
if s.Name == "" {
t.Error("景点名称为空")
}
if s.Rating < 0 || s.Rating > 5 {
t.Errorf("%s 评分异常: %.1f", s.Name, s.Rating)
}
}
}测什么: 字段非空、数值在合理范围、热门城市返回条数 > 0。
1.2 JSON Schema 结构校验
AI 输出需符合预定义的 JSON Schema,用 gojsonschema 验证:
{
"type": "object",
"required": ["traffic", "daily_plan", "food", "hotel", "budget"],
"properties": {
"daily_plan": {
"type": "array",
"minItems": 1,
"items": { "required": ["day", "morning", "afternoon"] }
}
}
}AI 返回了合法 JSON 但缺了 traffic 或 daily_plan → 测试直接挂。
1.3 幻觉关键词检测
func TestNoHallucination(t *testing.T) {
forbidden := []string{"虚构景区", "不存在的", "据我所知"}
output := callAI("北京出发,三亚3天")
for _, word := range forbidden {
if strings.Contains(output, word) {
t.Errorf("输出包含可疑内容: %s", word)
}
}
}第二层:集成测试(AI + 工具协作链路)
这是项目最关键的一层测试。 模拟用户真实请求,验证整条链路。
2.1 SSE 流式连通性
| 检查点 | 方法 | 断言 |
|---|---|---|
| Content-Type | resp.Header.Get("Content-Type") | 必须包含 text/event-stream |
| data 帧持续到达 | bufio.Scanner 逐行读取 | 60s 内至少收到 1 个 data 帧 |
| 超时保护 | context.WithTimeout | 流断开后优雅结束,不 hang |
2.2 AI 格式化输出检查点
不走 SSE,直接调 /api/plan 拿完整结果,分层检查:
| 检查项 | 方法 | 断言示例 |
|---|---|---|
| 交通覆盖 | 关键字匹配 | 必须出现「高铁」「飞机」「大巴」≥1 个 |
| 逐日行程 | 正则 | 第\d+天.*上午.*下午 天数匹配 |
| 数据诚实性 | 字符串包含 | 缺失真实数据时必须有【暂无精准信息】 |
| 美食推荐 | 关键字匹配 | 「美食」「餐厅」「人均」「小吃」≥1 个 |
| 住宿推荐 | 关键字匹配 | 「民宿」「酒店」「入住」≥1 个 |
| 预算汇总 | 正则 | \d+元 或「预算」关键字 |
| 工具调用追踪 | 埋点计数器 | GetTraffic / GetScenicSpot 调用次数 > 0 |
工具调用追踪是最重要的防线——工具没被调用 = AI 在自由发挥 = 大概率幻觉:
func TestToolCallTrace(t *testing.T) {
trafficCalled := atomic.LoadInt32(&trafficCallCount)
scenicCalled := atomic.LoadInt32(&scenicCallCount)
callAIWithTools("深圳出发,成都3天")
if trafficCalled == 0 {
t.Error("GetTraffic 没有被调用,AI可能在编造交通数据")
}
if scenicCalled == 0 {
t.Error("GetScenicSpot 没有被调用")
}
}第三层:人工评测(体感质量)
自动化能测"有没有",测不了"好不好"。
3.1 评测样本集(30 条)
| 场景 | 示例 | 预期行为 |
|---|---|---|
| 常规热门 | 深圳→成都 3天 | 完整规划,数据丰富 |
| 小众目的地 | 北京→婺源 2天 | 数据偏少但不编造 |
| 同城游 | 上海→上海 1天 | 不走城际交通,纯市内 |
| 不合理输入 | 地球→火星 10天 | 拒绝或标注无数据 |
| 极长行程 | 广州→新疆 15天 | 每日都有内容 |
| 跨省多城 | 杭州→西安+兰州 7天 | 路线合理不绕路 |
3.2 打分卡(1-5 分)
| 维度 | 权重 | 标准 |
|---|---|---|
| 信息准确性 | 40% | 景点/店名真实存在,票价合理 |
| 结构完整性 | 30% | 交通/每日行程/美食/住宿/预算全部覆盖 |
| 实用性 | 20% | 路线合理,不会上午城东下午城西 |
| 可读性 | 10% | 排版清晰,无大段重复废话 |
通过标准:30 条平均分 ≥ 3.5,单项 ≤ 2 分标记为 badcase 回溯。
第四层:回归测试(持续保障)
4.1 Golden File 基线对比
把 30 条用例的第一版输出保存为 testdata/golden/,后续每次改 Prompt 或 Tool 逻辑,跑一遍对比:
| 变化类型 | 处理方式 |
|---|---|
| 结构变了 | 人工确认是否预期变更 |
| 数据源变了 | 自动标记 diff |
| 格式崩了 | 直接报警,禁止合并 |
4.2 CI 流水线
git push → go test ./... → AI 集成测试 → Golden File 对比 → 通过/拒绝集成测试或 Golden File 对比失败 = 不允许合并。
测试分工速查表
| 阶段 | 测试动作 | 工具/方法 | 责任人 |
|---|---|---|---|
| 阶段1 | SSE 连通性 + JSON Schema 校验 | go test + curl | 后端 |
| 阶段2 | Tool 调用追踪 + 输出检查点 + 30 条人工评测 | go test + 打分表 | 后端 + 全员抽检 |
| 阶段3 | RAG 召回率 + Golden File 基线建立 | Chroma 查询日志 | 后端 |
| 阶段5 | 全链路压测 + 真机回归 | wrk/vegeta + 真人走查 | 全员 |
七、运维监控与告警
- 高德 API 调用量监控:Redis 计数器 + 每日定时写入 PostgreSQL,Grafana 面板可视化;接近免费额度(80%)自动告警
- 大模型 API 耗时监控:Gin 中间件记录每次 AI 请求耗时,P99 > 10s 触发告警
- 服务健康检查:
/health端点检查 PG、Redis、Chroma 连通性,Docker healthcheck 自动重启异常容器 - 告警通道:企业微信机器人/邮件通知,告警内容包括:接口名、错误率、发生时间
- 日志方案:Gin 访问日志 + 业务错误日志落盘,按天切割保留 30 天;关键错误额外写入 Redis List 便于实时查询
八、后期迭代拓展功能
- 出行标签筛选:特种兵穷游/亲子游/轻奢度假,AI自动调整住宿、景点搭配
- 行程微调:用户指定修改某天景点,AI局部重新生成方案
- 扩充县域、古镇小众目的地库,覆盖全国小地点规划
九、配套学习&开源资源
- langchaingo开源地址:https://github.com/tmc/langchaingo
- 高德开放平台文档:https://lbs.amap.com/
- 和风天气开发文档:https://dev.qweather.com/
- 参考开源:Travel-Agent-Go(Go语言AI旅行规划项目)
十、项目全周期成本总结
- 开发&内测:API 侧 0 元(各平台免费额度);服务器可选本地 Docker 全模拟(¥0),或阿里云 2核4G 轻量约 ¥80/月
- 日活<500 小规模运营:API 依旧免费(Redis 缓存命中率高);服务器 + 域名 + SSL 约 ¥100/月
- 大批量商用:按需充值高德接口(约 ¥0.015/次),月度 API 成本可控在 ¥500 以内;服务器按需升配
- 总预估:从开发到上线运营前3个月,总现金支出可控制在 ¥300 以内
十一、关键风险与应对策略
| 风险项 | 影响 | 概率 | 应对措施 |
|---|---|---|---|
| 大模型幻觉/杜撰虚假信息 | 用户体验差、信任度下降 | 高 | Prompt 强制标注【暂无精准信息】;RAG 本地知识库优先检索真实数据;人工抽检 + 用户反馈机制 |
| 高德 POI 数据不准确(店铺已关闭、票价过时) | 行程推荐质量下降 | 中 | 页面增加"信息有误?"反馈按钮;优先展示评分≥4.0 的 POI;定期更新热点城市缓存 |
| 微信小程序审核不通过 | 无法上线 | 中 | AI 生成内容不属于 UGC,无需办证;但需添加内容审核 + 用户协议 + 免责声明;建议提前用体验版提交预审 |
| SSE 长连接在实际网络环境下不稳定 | 用户看到断流/卡顿 | 中 | 前端实现断线重连(EventSource reconnect + Last-Event-ID);后端设置合理的超时时间(5min) |
| Chroma 单机性能瓶颈(攻略数据增长) | RAG 检索变慢 | 低 | 前期攻略数据量可控(<1万条);后期可平滑迁移到 Milvus / Qdrant |
| 高德/和风 API 超额或被限流 | 功能不可用 | 低 | Redis 计数器 + 80% 阈值告警;核心城市数据提前缓存在本地 |
| 云服务器被攻击或爬虫恶意调用 | 费用暴增、服务中断 | 低 | API 限流中间件;Nginx IP 黑名单;微信小程序天然隔离部分爬虫 |
附:Go最简Demo(测试调用大模型生成行程)
package main
import (
"context"
"fmt"
"github.com/tmc/langchaingo/llms/openai"
)
func main() {
llm, err := openai.New(
openai.WithBaseURL("你的大模型中转地址"),
openai.WithToken("你的key"),
openai.WithModel("deepseek-chat"),
)
if err != nil {
panic(err)
}
prompt := `你是旅游星推官,深圳出发,云南游玩3天,输出完整行程:交通、每日景点、美食、住宿、预算`
resp, err := llm.Call(context.Background(), prompt)
if err != nil {
panic(err)
}
fmt.Println(resp)
}