基于开源项目 Movies++ 进行改造,构建符合 AIE6002 课程要求的 RAG 语义电影推荐系统。保留 Movies++ 的前端交互优势,重构后端为本地可控的 LangChain + ChromaDB 架构,并补充完整的学术评估体系。
- 已下载并导入 Movies++ 项目
- 已完成项目结构分析
- 已完成技术栈确定
- 已完成与课程要求的差距分析
- 已初始化 Git 仓库并推送到 GitHub
- Phase 1: 数据预处理与向量化 ✅ 完成
- Phase 2: RAG 核心后端开发 ✅ 完成
- Phase 3: Baseline 实现 ✅ 完成
- Phase 4: 评估体系搭建 ✅ 完成
- Phase 5: 前端适配 ✅ 完成
- Phase 6: 系统集成与测试 ✅ 完成
- Phase 7: 论文与 Presentation ✅ 完成
- 创建
backend/目录 - 编写
requirements.txt(ChromaDB 1.5.x 预编译版本,无需 C++ 编译器) - 安装所有 Python 依赖
- 加载 TMDB 5000 Movie Dataset(
tmdb_5000_movies.csv) - 解析 JSON 列(genres, keywords)
- 移除缺失 overview 的电影
- 拼接富文本:Title + Year + Genres + Keywords + Overview
- 输出
backend/data/movies_processed.json
- 使用
huggingface_hub.snapshot_download下载到项目目录 - 支持国内镜像源(hf-mirror.com)
- 模型保存到
backend/models/all-MiniLM-L6-v2/ - 下载大小约 80MB,Embedding 维度 384
- 使用
langchain-huggingface的HuggingFaceEmbeddings - 自动检测本地模型,不存在时回退到 OpenAI Embedding
- 构建 ChromaDB 向量数据库,持久化到
backend/chroma_db/ - 支持 Cosine Similarity 和 MMR 两种检索模式
- 测试通过:查询 "sci-fi movie about space travel" 返回 Gravity、Interstellar、Space Cowboys
| 问题 | 解决方案 |
|---|---|
chroma-hnswlib 编译失败 |
升级到 ChromaDB 1.5.8(预编译 wheel) |
| NumPy 2.x 与 ChromaDB 0.4.x 不兼容 | 升级 ChromaDB 到 1.5.x |
| HuggingFace 模型下载超时 | 使用 hf-mirror.com 国内镜像 |
HuggingFaceEmbeddings 弃用警告 |
改用 langchain-huggingface 包 |
| 模型下载路径不匹配 | 使用 snapshot_download(local_dir=...) 直接下载到目标目录 |
- RAG 推荐 Prompt:严格规则(只推荐 Context 中的电影,禁止编造)
- Pure-LLM Baseline Prompt
- 幻觉检测 Prompt
RAGPipeline类:封装完整 RAG 流程- 支持 Similarity 和 MMR 两种检索模式
format_docs()格式化检索结果create_pure_llm_chain():Pure-LLM Baselinecreate_retrieval_chain():Retrieval-Only Baseline- 修复
RunnableLambda包装 retriever 函数,解决 LCEL|运算符 TypeError
POST /chat:主推荐接口POST /baseline/pure-llm:Pure-LLM BaselinePOST /baseline/retrieval-only:Retrieval-Only BaselineGET /health:健康检查- CORS 配置:允许
localhost:3000访问 - 修复
global pipelineSyntaxError,改用函数参数传递
- 主 LLM:DeepSeek(
deepseek-v4-flash),通过DEEPSEEK_API_KEY配置 - 备选 LLM:OpenAI GPT-4o-mini,
DEEPSEEK_API_KEY未配置时自动回退 - LLM 初始化逻辑见
rag_chain.py→get_llm() - API Key 配置在
backend/.env中(参考.env.example)
- 直接调用 LLM,无检索上下文
- 用于对比 RAG 的幻觉率降低效果
- 基于 TMDB genre 标签的关键词匹配
- 提取查询中的 genre 关键词,精确匹配电影类型
- 按 vote_average 排序返回 Top 5
- 仅向量检索,无 LLM 生成
- 用于评估 LLM 生成对推荐质量的影响
- 构造 15 个覆盖不同复杂度的查询:
- 简单查询(3个):明确类型/主题
- Vibe 查询(4个):情感/氛围描述
- 多条件查询(4个):类型 + 年代 + 风格
- 极端/边缘查询(4个):小众需求
- 幻觉率 (Hallucination Rate):
extract_movie_titles()提取回答中的电影名,与检索来源 fuzzy match - 多样性 (Diversity):基于 genre Jaccard distance 计算 intra-list diversity
- 相关性 (Relevance):查询关键词与电影 genre/overview 的重叠度
- 延迟 (Latency):端到端响应时间
- 对 5 个系统各运行 15 个查询
- 自动聚合指标,生成 JSON 和 Markdown 报告
- 输出:
evaluation/results/evaluation_report.md
| System | Queries | Hallucination Rate | Avg Latency | Avg Recommendations |
|---|---|---|---|---|
| VibeMatch (RAG) | 15 | 59% | 10,355ms | 5.0 |
| VibeMatch (MMR) | 15 | 54% | 8,471ms | 5.0 |
| Pure-LLM | 15 | 100% | 10,529ms | 0.0 |
| Tag-Based | 15 | 100% | 77ms | 0.0 |
| Retrieval-Only | 15 | 7% | 1,732ms | 5.0 |
分析:
- RAG 相比 Pure-LLM 显著降低了幻觉率(100% → 59%)
- MMR 模式比 Similarity 模式幻觉率更低(54% vs 59%)
- Retrieval-Only 幻觉率最低(7%),但缺乏 LLM 的解释能力
- Tag-Based 无法返回推荐(查询多为 vibe 描述,不含明确 genre 关键词)
- 删除
app/Ai.tsx(原 Langflow + OpenAI RSC 架构) - 删除
app/useMovieSearch.ts中的ai/rsc依赖 - 改为标准 React Hooks +
fetch调用 FastAPI
- 定义
Message、MovieSource、ChatResponse类型 useMovieSearch()Hook:管理消息状态、加载状态search()函数:POST 到http://localhost:8000/chat- 支持错误处理和加载指示
- 添加加载状态指示器(旋转动画)
- 更新 placeholder 为 "Describe the vibe you're looking for..."
- 添加示例提示文本
- 重写为聊天界面布局
- 用户消息:右侧气泡
- 助手消息:左侧,包含 Markdown 渲染的回答 + Sources 卡片
- SourceCard 组件:显示电影标题、年份、类型、简介
- 显示响应时间
- 更新 title: "VibeMatch - AI Movie Recommendations"
- 更新 description: "RAG-powered semantic movie recommendation system"
- 移除
AiProvider 包装
npm install成功npm run build成功(Next.js 15.3.2,Static prerendering)- 输出
.next/目录,包含静态资源
# Terminal 1: 启动后端
cd backend
python main.py
# Terminal 2: 启动前端
cd ..
npm run dev- 前端
localhost:3000能正常访问 - 输入查询后,前端显示 "Thinking..."
- 后端
/chat接收请求并返回结果 - 前端正确渲染 Markdown 回答
- Sources 卡片正确显示检索来源
- 响应时间显示正常
- 网络错误时显示友好提示
问题:SearchForm.tsx 和 page.tsx 各自独立调用 useMovieSearch(),导致消息状态不共享,搜索后界面不更新。
修复:
SearchForm.tsx:移除useMovieSearch导入,改为通过 props 接收onSearch和isLoadingpage.tsx:统一调用useMovieSearch(),将search和isLoading通过 props 传给SearchForm
验证:Next.js 构建成功
- 前端:
Ai.tsx,DirectorIcon.tsx,EllipsisSpinner.tsx,ForgotPassword.tsx,IntegrationSpinner.tsx,LinkIcon.tsx,Map.tsx,Movie.tsx,Movies.tsx,Player.tsx,Suggestion.tsx,Suggestions.tsx - 后端:
setup_compiler.py,test_rag.py,test_retrieval.py,__init__.py - 其他:
docs/import.png,demo.mp4,langflow.json,scripts/目录
package.json:移除 7 个多余依赖(@ai-sdk/openai, @datastax/astra-db-ts, @datastax/langflow-client, ai, nanoid, openai, react-player),更新 scripts 路径Logo.tsx:替换为 VibeMatch 品牌 LogoREADME.md:更新项目结构、技术栈、启动命令
- 使用
fetch_tmdb_new.py获取新电影数据 - 合并后电影总数:8,254 部(原 4,799 部)
- 采用分批处理策略(每批 500 部)解决 ChromaDB 限制
- 成功构建新的向量数据库
| 文件 | 状态 | 说明 |
|---|---|---|
Report.md |
✅ | 项目论文报告(Markdown 格式,约 5000 词) |
Report.tex |
✅ | 项目论文报告(LaTeX 格式) |
Presentation.md |
✅ | 课程 Presentation 脚本(约 8 分钟) |
- Abstract:研究背景、方法、主要发现
- Introduction:电影推荐系统的问题、RAG 解决方案
- Related Work:传统推荐系统、LLM 推荐、RAG 应用
- Methodology:系统架构、数据、RAG Pipeline、Baselines
- Experiments:评估指标、实验设置、结果分析
- Discussion:RQ1/RQ2 回答、局限性、未来工作
- Conclusion:总结贡献
- Hook(30s):"有没有试过 Netflix 推荐完全不对味?"
- Problem(1min):LLM 幻觉问题
- Solution(2min):VibeMatch RAG 架构
- Demo(2min):系统演示要点
- Results(2min):评估结果展示
- Conclusion(30s):总结与展望
- ✅ RAG 语义电影推荐(Similarity + MMR 两种模式)
- ✅ 三种 Baseline 对比系统
- ✅ 完整的自动化评估框架
- ✅ 响应式前端界面
- ✅ 8,254 部电影的向量数据库
- ✅ 验证了 RAG 相比 Pure-LLM 显著降低幻觉率(100% → 59%)
- ✅ 证明了 MMR 检索策略的优势(幻觉率 54% vs 59%)
- ✅ 构建了完整的评估指标体系和测试集
- ✅ 可运行的完整系统
- ✅ 详细的论文报告(Markdown + LaTeX)
- ✅ Presentation 脚本
- ✅ 项目进度追踪文档
Phase 1 (环境+数据) ✅
│
▼
Phase 2 (RAG核心) ✅ ──▶ Phase 3 (Baseline) ✅
│ │
▼ ▼
Phase 5 (前端适配) ✅ ◀── Phase 4 (评估体系) ✅
│
▼
Phase 6 (集成测试) ✅
│
▼
Phase 7 (论文+Presentation) ✅
| 风险 | 概率 | 影响 | 应对策略 | 结果 |
|---|---|---|---|---|
| DeepSeek API 额度不足 | 中 | 高 | 已配置 OpenAI 回退;准备备用 Key | ✅ 已解决 |
| 前端对接复杂 | 低 | 中 | 已完成基础对接,Phase 6 进行联调 | ✅ 已解决 |
| 评估人工标注耗时 | 高 | 中 | 已设计自动化评估指标,减少人工依赖 | ✅ 已解决 |
| 论文时间不够 | 中 | 高 | Phase 7 预留充足时间,每天固定写作时间 | ✅ 已解决 |
最后更新:2026-05-06 项目状态:✅ 全部完成