智能旅行规划助手 — 实习面试问答手册

智能旅行规划助手 --- 实习面试问答手册

本文档基于项目 helloagents-trip-planner 的实际代码整理,供软件开发实习生面试使用。

建议配合项目 README 和本地 Demo 演示一起准备。


一、30 秒电梯演讲(开场必背)

面试官:先简单介绍一下这个项目。

回答示例:

这是一个 AI 驱动的智能旅行规划 Web 应用 。用户在首页填写目的地、日期、预算、偏好等信息后,后端会先调用 高德地图 API 获取真实景点、酒店和天气数据,再把这些结构化信息交给 大语言模型(LLM) 生成多日行程;前端用 Vue 3 展示每日路线、地图标记、预算汇总,并支持行程伴游问答、历史记录和 PDF 导出。

我主要负责(或参与)前后端联调、Agent 行程生成链路、POI 坐标准确性治理、异步任务接口 等工作。项目采用 前后端分离:FastAPI 提供 REST API,Vue 3 + Ant Design Vue 负责交互与可视化。


二、项目背景与目标

Q1:为什么要做这个项目?解决了什么问题?

回答:

传统旅行规划要么靠人工查攻略、拼表格,耗时长;要么纯靠 AI 生成,容易出现 虚构景点、坐标不准、地图无法展示 的问题。

我的项目核心思路是:「真实数据 + AI 编排」------

  1. 用高德地图拿到 真实 POI(景点/酒店)和天气
  2. 用 LLM 负责 行程安排、餐饮建议、预算估算、文字描述
  3. 后端再做 坐标回填与校验,保证前端地图能正确打点。

这样既保留了 AI 的灵活性,又提高了结果的可信度和可执行性。

Q2:项目的用户是谁?核心使用场景是什么?

回答:

面向 有出行计划但不想花大量时间做攻略的用户,典型场景包括:

  • 周末/小长假城市游,快速生成 2~5 日行程;
  • 按偏好(历史文化、美食、自然风光等)筛选景点;
  • 生成后在结果页查看地图路线、调整关注点后导出 PDF;
  • 对已生成行程进行 伴游问答(如「第 2 天下午适合去哪?」)。

三、技术栈说明

Q3:项目用了哪些技术?为什么选它们?

回答:

层级 技术 选型理由
后端框架 FastAPI 异步友好、自动生成 OpenAPI 文档、Pydantic 数据校验成熟
LLM OpenAI 兼容接口(OpenAI / DeepSeek 等) 通过统一 HelloAgentsLLM 封装,便于切换模型和 Base URL
地图 高德 Web 服务 API + JS API 国内 POI、天气、路线数据准确;前后端分别调用 HTTP API 和 JS SDK
HTTP 客户端 httpx(后端)、axios(前端) 异步/拦截器支持好,对接第三方 API 方便
数据模型 Pydantic v2 请求/响应强类型校验,减少接口脏数据
前端 Vue 3 + TypeScript + Vite 组合式 API + 类型安全,开发效率高
UI Ant Design Vue 表单、卡片、步骤条等组件齐全,适合 B 端/工具类产品
路由 Vue Router 首页 / 结果 / 历史 / 探索页分离
PDF 导出 html2canvas + jsPDF 将 DOM 渲染为图片再写入 PDF,实现成本低
图片 Unsplash API(可选) 为景点补充展示图
Agent 框架 本地 hello_agents 兼容层 参考 Datawhale Hello-Agents 教程,轻量封装 LLM 与 MCP 工具

Q4:前后端是如何通信的?

回答:

  • 前端通过 VITE_API_BASE_URL(默认 http://localhost:8000)访问后端;
  • 后端开启 CORS ,允许 localhost:5173 等开发源;
  • 主要接口:
    • POST /api/trip/plan_async --- 提交异步规划任务
    • GET /api/trip/plan_result/{job_id} --- 轮询任务结果
    • POST /api/assistant/chat --- 行程伴游
    • GET /api/map/poi --- POI 搜索
    • POST /api/map/route --- 路线规划
  • 数据格式统一为 JSON,后端用 Pydantic 模型约束字段。

四、系统架构与运行流程

Q5:请描述一下项目的整体架构。

回答:

项目是典型的 三层前后端分离架构

复制代码
┌─────────────────────────────────────────────────────────┐
│  前端 (Vue 3)                                            │
│  Home → 提交表单 │ Result → 地图/导出 │ History/Explore │
└───────────────────────────┬─────────────────────────────┘
                            │ HTTP / JSON
┌───────────────────────────▼─────────────────────────────┐
│  后端 (FastAPI)                                          │
│  API 路由层 → Agent/Service 层 → 外部 API (LLM/高德/Unsplash) │
└─────────────────────────────────────────────────────────┘
  • API 路由层trip.pyassistant.pymap.pypoi.py
  • 业务层MultiAgentTripPlanner(行程规划)、AmapService(地图)、HelloAgentsLLM(大模型)
  • 数据层 :本项目无独立数据库,历史记录存 浏览器 localStorage

Q6:用户点击「生成旅行计划」后,完整流程是什么?

回答(按时间顺序):

前端:

  1. 用户在 Home.vue 填写城市、日期、偏好、预算等,点击提交;
  2. 调用 generateTripPlan()
    • POST /api/trip/plan_async,立即拿到 job_id
    • 每 2 秒轮询 GET /api/trip/plan_result/{job_id},更新进度条;
  3. 成功后把计划写入 sessionStoragelocalStorage 历史,跳转 Result.vue

后端(MultiAgentTripPlanner.plan_trip):

  1. 步骤 1 --- 搜索景点:调用高德 POI 文本搜索,获取真实名称与坐标;
  2. 步骤 2 --- 查询天气:地理编码拿 adcode,再查天气预报;
  3. 步骤 3 --- 搜索酒店:按住宿偏好搜索酒店 POI;
  4. 步骤 4 --- LLM 生成行程:把用户需求 + 景点列表 + 天气 + 酒店列表拼成 Prompt,要求 LLM 输出固定 JSON 结构;
  5. 解析与治理
    • 从 LLM 回复中提取 JSON(支持 markdown 代码块);
    • 坐标回填:用高德搜索结果覆盖/修正景点坐标;
    • 酒店强制对齐:名称无法匹配时按天轮换回填真实酒店;
    • POI 一致性校验:检查坐标是否在中国范围、是否使用模板默认坐标等;
  6. 若任一步失败,走 _create_fallback_plan() 返回兜底行程,避免接口完全不可用。

结果页:

  • 加载高德 JS API,按景点坐标打 Marker、画 Polyline;
  • 可调用伴游 API 问答、导出 PDF。

Q7:你说的「多智能体」具体是怎么协作的?

回答(诚实且准确):

从代码实现上看,当前版本是 「多步骤流水线 + 单一 LLM 规划」,而不是多个独立 Agent 互相对话:

  • 「景点搜索」「天气查询」「酒店搜索」由 AmapService 直接调用
  • 「行程编排」由 一个 LLM 调用 完成,Prompt 里注入了前三步的结构化结果;
  • 项目保留了 hello_agents 里的 SimpleAgentMCPTool 兼容层,便于后续扩展成真正的 Tool Calling Agent。

面试时可以这样说:「当前是 Pipeline 式多阶段协作,架构上预留了 Agent + Tool 扩展能力。」


五、核心模块深入

Q8:TripRequest 里有哪些字段?后端如何校验?

回答:

主要字段包括:citydestinations(多城市)、start_dateend_datetravel_days(1~30)、transportationaccommodationpreferencesbudget_per_persontravel_pacecompanionsdietary_restrictionsfree_text_input

使用 Pydantic 做类型和范围校验,例如 travel_days 必须 ≥1 且 ≤30。FastAPI 会在入参不符合模型时直接返回 422,减少业务层重复校验。

Q9:LLM 返回的不是纯 JSON 怎么办?

回答:

_parse_response() 里做了 多层提取策略

  1. 优先找 ` ```json ... ````代码块;
  2. 否则找普通 ` ```... ````;
  3. 再否则从第一个 { 到最后一个 } 截取;
  4. json.loads() 解析;
  5. 解析失败则记录日志,返回 fallback 计划,保证用户体验不中断。

这是对接 LLM 时的常见工程化处理,因为模型偶尔会加解释性文字或格式不规范。

Q10:为什么要把景点/酒店坐标从 LLM 结果里「强制回填」?

回答:

这是项目里最关键的 工程问题之一

LLM 容易:

  • 改写 POI 名称(如「如家快捷酒店」vs「如家酒店(XX路店)」);
  • 编造或复制模板坐标(代码里专门检测默认北京坐标 116.397128, 39.916527);
  • 名称和坐标 张冠李戴(名字是 A 景点,坐标却是 B 景点)。

解决方案:

  1. Prompt 里明确要求 必须从给定列表逐字复制 name/address/location
  2. 解析后 _enforce_hotels_from_search_results()精确匹配 + 子串模糊匹配 + 按天轮换回填
  3. 景点侧建立 attraction_map,按名称匹配后替换 location
  4. _validate_plan_against_poi_search() 打日志告警,便于排查。

我还写了 diagnose_coordinates.py 脚本,专门验证某城市 POI 坐标范围和名称匹配率。

Q11:前端为什么用异步任务 + 轮询,而不是一次同步请求?

回答:

行程生成链路包含 多次外部 API + 一次长文本 LLM 调用 ,整体可能耗时 1~3 分钟甚至更久

如果只用同步 POST /api/trip/plan

  • 浏览器/网关可能 超时断开
  • 用户看不到真实进度,体验差。

因此前端改为:

  1. plan_async 立即返回 job_id
  2. 后端用 asyncio.create_task + asyncio.to_thread 在后台线程跑同步规划逻辑;
  3. 前端每 2 秒轮询,最多约 10 分钟;
  4. axios 全局 timeout 设为 5 分钟,轮询单次 30 秒。

这是典型的 长任务异步化 方案。生产环境可进一步升级为 WebSocket 或 Redis 任务队列,但实习项目用内存 _job_store 足够演示。

Q12:历史记录存在哪里?有什么限制?

回答:

存在浏览器 localStoragetripPlanHistory),最多保留 50 条;当前激活 ID 在 sessionStorage。

优点:无需后端数据库,部署简单;

缺点:换设备/清缓存会丢失,不支持多用户 ------ 面试时可主动说 「这是 MVP 阶段的权衡,后续可接 SQLite/PostgreSQL + 用户体系」


六、开发过程中遇到的问题与解决方案

这一部分是实习面试的高频考点,建议结合具体例子讲,体现 发现问题 → 定位 → 解决 → 验证 的能力。

问题 1:地图上的景点位置不准确 / 全部打在一个点

现象: 结果页高德地图 Marker 偏移,或多个景点坐标相同。

原因:

  • LLM 自行「编造」经纬度;
  • 景点名与高德搜索结果不一致,导致坐标和名称错配;
  • 高德返回的 location"lng,lat" 字符串,解析错误会导致异常。

解决:

  1. 后端先用高德搜索拿 权威 POI 列表
  2. LLM 只负责选哪些景点、怎么排 day,不负责造坐标;
  3. _parse_response 阶段强制用搜索结果回填 location
  4. 校验中国大陆经纬度范围(经度 73~136,纬度 18~54);
  5. 编写 test_poi_fix.pydiagnose_coordinates.py 做回归测试。

收获: 明白了 「LLM 适合生成语义内容,不适合作为地理数据源」,结构化数据要以 API 为准。


问题 2:LLM 改写酒店名称,导致 POI 对不上

现象: 行程里酒店名不在高德返回列表中,前端无法关联真实位置。

解决:

  1. Prompt 增加 正反示例,强调 hotel.name 必须逐字复制;
  2. 实现 _match_hotel_poi():先精确匹配,再单向子串匹配;
  3. 仍匹配不上则 _enforce_hotels_from_search_results() 按天轮换填入搜索结果;
  4. _validate_plan_against_poi_search() 输出不一致告警。

问题 3:请求超时,前端显示「生成失败」

现象: 同步接口在 LLM 慢时经常失败。

解决:

  • 后端新增 plan_async + plan_result
  • 前端 api.ts 改为提交任务后轮询;
  • 进度条结合后端 stage/progress 与前端模拟进度,提升感知体验。

问题 4:高德 API 返回字段类型不一致

现象: POI 的 tel 有时是字符串,有时是列表,直接赋值导致 Pydantic 校验失败或前端展示异常。

解决:AmapService.search_poi() 里统一处理:列表取第一个,非字符串置 None


问题 5:LLM JSON 解析失败导致 500

解决:

  • 多策略提取 JSON;
  • 解析失败走 _create_fallback_plan() 兜底;
  • 降低 temperature(如 0.4)提高输出稳定性。

问题 6:CORS / 环境变量配置问题

现象: 本地前端调后端跨域失败,或 Key 未加载。

解决:

  • FastAPI 配置 CORSMiddleware,允许 Vite 开发端口;
  • 使用 python-dotenv + pydantic-settings 统一管理 .env
  • 启动时 validate_config() 检查必要 Key 是否存在。

七、面试官可能追问的技术问题

Q13:FastAPI 的异步在这里是怎么用的?

回答:

路由函数是 async def,但 LLM 和 httpx 同步调用较重,所以异步任务通过 asyncio.to_thread()同步规划逻辑放到线程池,避免阻塞事件循环。这是 Python 异步 Web 开发里常见的折中做法。

Q14:如果 LLM API 挂了怎么办?

回答:

当前有 _create_fallback_plan() 返回基础模板行程;生产环境还可以:重试 + 指数退避、切换备用模型、缓存热门城市模板、向用户明确提示「AI 服务暂不可用」。

Q15:如何保证 Prompt 输出稳定?

回答:

  • 提供 完整 JSON Schema 示例 在 system prompt;
  • 约束必须使用的 POI 列表(含正确/错误示例);
  • 较低 temperature;
  • 后端 Pydantic 二次校验;
  • 关键字段(坐标、酒店名)不信任 LLM,以 API 数据为准

Q16:项目有哪些不足?如果继续迭代你会做什么?

回答(展示思考深度):

现状 改进方向
任务队列在内存 接 Redis/Celery,支持重启不丢任务
无用户系统 JWT 登录 + 数据库存行程
Agent 是 Pipeline 引入 Function Calling,让 LLM 自主决定何时查 POI/路线
路线规划 API 已有 可在生成阶段就把相邻景点路线算进日程
缺少自动化测试 为 POI 回填、JSON 解析写单元测试
伴游无上下文记忆 加 session 或多轮对话 history

Q17:你在这个项目里具体负责什么?

回答模板(请按真实情况修改):

我主要负责后端行程规划模块和前后端联调。包括:设计 MultiAgentTripPlanner 的四步流水线;实现 LLM 响应 JSON 解析与 POI 坐标回填;排查并修复地图打点不准的问题;对接异步任务接口,解决长请求超时;前端完成结果页地图展示和历史记录功能。

原则: 只讲自己真正做过的部分,细节要能答上来。

Q18:遇到过最难的 bug 是什么?

回答示例:

最难的是 「景点名称和坐标不匹配」------表面上行程 JSON 合法,Pydantic 也能过,但地图把「鼓浪屿」打到了另一个 POI 的位置。

我通过日志对比 LLM 输出与高德搜索结果,发现模型会轻微改写名称;随后加了名称映射、坐标强制回填和诊断脚本,并补充 POI 校验日志。这个问题让我理解了 AI 应用里「看起来正确」和「事实正确」是两回事


八、行为面试 / 软技能问题

Q19:这个项目是你独立完成的还是团队完成的?

回答模板:

如果是课程/教程延伸:说明基于 Hello-Agents 教程,我在其基础上 扩展了 POI 治理、异步接口、前端完整流程

如果是团队:说明分工,强调自己模块的 owner 意识 和联调沟通。

Q20:开发周期多长?怎么管理进度?

回答模板:

例如 2~3 周:第 1 周打通 MVP(表单 → LLM → 展示);第 2 周接高德地图和坐标修复;第 3 周做历史、PDF、伴游和 UI polish。用 README 和 TODO 列表跟踪,优先保证 主链路可 Demo

Q21:从项目中学到了什么?

回答:

  1. LLM 应用工程化:Prompt 设计、输出解析、兜底策略同样重要;
  2. 第三方 API 集成:要处理超时、字段不一致、Key 配置;
  3. 全栈协作:Pydantic 模型最好与前端 TypeScript 类型对齐;
  4. 用户体验:长任务需要进度反馈和异步化;
  5. 问题定位方法:写诊断脚本、打结构化日志,比盲目改 Prompt 更高效。

九、Demo 演示建议(面试现场加分)

  1. 提前启动 前后端,确认 .env 中 LLM 和高德 Key 有效;
  2. 演示路径:填表单 → 看进度 → 结果页地图 → 问伴游一个问题 → 打开历史记录
  3. 准备 1 个失败案例(如断网)说明 fallback 机制;
  4. 打开 http://localhost:8000/docs 展示 API 文档,体现 FastAPI 优势;
  5. 若被问代码,能快速打开:
    • backend/app/agents/trip_planner_agent.py --- 主流程
    • frontend/src/services/api.ts --- 异步轮询
    • backend/app/services/amap_service.py --- 地图封装

十、快速记忆卡片

关键词 一句话
项目定位 AI + 高德真实数据的旅行规划助手
后端 FastAPI + Pydantic + LLM + 高德 HTTP API
前端 Vue3 + TS + Ant Design Vue + 高德 JS API
核心流程 搜 POI → 查天气 → 搜酒店 → LLM 编排 → 坐标回填 → 返回
最大难点 LLM 幻觉导致 POI/坐标不准
核心解法 API 数据为准,LLM 只编排;解析后强制回填与校验
长任务 plan_async + 轮询 job_id
存储 localStorage 历史,无数据库
亮点 伴游问答、知识图谱、PDF 导出、探索页主题 POI

十一、常见「坑」提醒(避免面试翻车)

  1. 不要说「完全是多个 AI Agent 自主对话」------ 与当前实现不符,除非你真的改了架构;
  2. 不要说 「坐标都是 AI 生成的」------ 恰恰相反,核心是 不信任 AI 的坐标
  3. 准备好 API Key 成本:LLM 和高德都有调用费用,面试官可能问;
  4. 诚实说明数据持久化局限:无后端 DB 是已知 trade-off,不是疏忽;
  5. 能解释 hello_agents 是本地兼容层,参考 Datawhale 教程,避免被问「框架源码在哪」答不上来。

祝你面试顺利。 建议把本文档中标注「请按真实情况修改」的部分,换成你自己的贡献描述,并对着镜子练习 项目介绍 1 分钟版技术难点 2 分钟版 各一遍。

相关推荐
8Qi81 小时前
LeetCode 32:最长有效括号 —— 栈 + 标记法 题解
java·数据结构·算法·leetcode·职场和发展··括号匹配
自由路飞1 小时前
Trellis 从 0 到 1 实战指南:让 AI 从"随便聊聊"变成"项目协作者"
面试
浮午1 小时前
腾讯AI应用开发一面实录:13道硬核面试题全解析
人工智能·面试·职场和发展
AI人工智能+电脑小能手2 小时前
【大白话说Java面试题 第106题】【并发篇】第6题:synchronized 锁的锁对象可以是什么?
java·开发语言·面试
cccyi73 小时前
C++ 面试题整理
c++·面试
uhakadotcom3 小时前
什么是Mass Assignment(批量赋值)风险
后端·面试·github
公考指南针4 小时前
公务员面试怎么准备?2026 结构化面试流程、答题训练和备考工具测评
经验分享·学习·面试
AI人工智能+电脑小能手4 小时前
【大白话说Java面试题 第107题】【并发篇】第7题:说说 Lock 锁?
java·开发语言·面试
焦虑的说说5 小时前
mysql为什么回表会慢
mysql·面试