[硬核实战] 从零构建全栈 AI 简历助手:复刻 DeepSeek 交互与长期记忆实现
摘要:如何将一个简单的 LangChain Demo 进化为生产级的 AI SaaS 应用?本文记录了
JD_Agent项目的里程碑式更新。我们引入了 Next.js 复刻 DeepSeek 的丝滑 UI,基于 SQLModel 实现了完整的用户鉴权与会话管理,并利用 RAG 技术 实现了“简历解析与长期记忆”功能,让 AI 真正拥有了“记住用户”的能力。
1. 项目演进:从 Script 到 Product
在之前的版本中,我们的 JD_Agent 只是一个无状态的 API 接口:用户发 JD,AI 返回分析。
但一个真正的 AI 产品需要具备:
- 用户系统:数据隔离,每个人只能看自己的历史。
- 交互体验:流式输出、Markdown 渲染、历史记录回溯。
- 长期记忆:记住用户的简历背景,不需要每次 Prompt 都重复“我是 Python 开发…”。
今天,我们完成了这次全栈重构。
2. 技术栈全景
- Frontend: Next.js 14 (App Router) + Tailwind CSS + Lucide React
- Backend: FastAPI + Uvicorn
- Database: SQLModel (SQLite) + Alembic
- Auth: JWT (OAuth2PasswordBearer) + Passlib (Bcrypt)
- AI Core: LangChain + OpenAI/DeepSeek + FAISS (RAG)
3. 核心功能实现
3.1 完美复刻 DeepSeek 的交互界面
我们抛弃了简陋的 HTML,采用 Next.js + Tailwind 打造了现代化的 Chat UI。
- 布局攻坚:为了实现“顶部固定、侧边栏独立滚动、输入框底部悬浮且不遮挡内容”,我们采用了
fixed inset-0锁死视口高度,并配合pb-[200px]的底部内边距策略。 - Markdown 渲染:后端返回的结构化 JSON 报告,在前端被动态组装成 Markdown,并通过
react-markdown渲染出漂亮的排版。
1 | // 前端布局核心 Trick |
3.2 长期记忆:简历解析与用户画像 (LTM)
这是本次更新的灵魂功能。我们不希望 AI 聊完就忘,而是构建了一个长期记忆系统 (Long-Term Memory)。
实现流程:
- 上传:用户上传 PDF/Word 简历。
- 解析:后端使用
pdfplumber提取纯文本。 - ETL:利用 LangChain 的
resume_extractor链,从杂乱的简历中提取出结构化画像(如:tech_stack: ["Python", "FastAPI"],experience: "5年")。 - 存储:存入
UserProfile数据库表。 - 回想:下次用户发送 JD 时,系统自动读取
UserProfile,注入到 System Prompt 中。
后端代码片段 (Service Layer):
1 | # app/services/interview_service.py |
3.3 数据闭环:会话历史管理
为了实现侧边栏的“历史记录”功能,我们引入了 SQLModel。
-
表结构设计:
User: 存储用户名、加密密码。ChatSession: 代表一次对话(如“神州邦邦面试准备”)。ChatMessage: 存储具体的 User/Assistant 消息内容。
-
难点处理:Pydantic 对象无法直接存入数据库,我们在存库前将其序列化为 JSON 字符串,在读取时再反序列化,确保前端能拿到结构化的
meta数据进行渲染。
4. 工程化踩坑实录
在开发过程中,我们解决了一系列真实的工程问题:
坑位 1:Tailwind CSS 样式失效
- 现象:页面元素堆叠在左上角,样式全无。
- 原因:Next.js 初始化时
tailwind.config.js路径配置错误,且误装了不兼容的 Tailwind v4 版本。 - 解决:降级至
tailwindcss@3.4.17,并手动修正content路径覆盖src/目录。
坑位 2:Bcrypt 版本冲突
- 现象:注册时报错
AttributeError: module 'bcrypt' has no attribute '__about__'。 - 原因:
passlib库与最新版bcrypt 4.0+不兼容。 - 解决:强制锁定版本
pip install "bcrypt==3.2.2"。
坑位 3:LangChain 参数丢失
- 现象:
KeyError: "Input to ChatPromptTemplate is missing variables {'user_profile'}"。 - 原因:在 Prompt 模板中定义了
{user_profile}占位符,但在 Chain 调用 (ainvoke) 时忘记传入该参数。 - 解决:在 Service 层获取记忆后,显式传递给 Chain。
5. 总结与展望
通过今天的迭代,JD_Agent 已经具备了一个商业化 AI 产品的雏形:
- 好看:媲美 DeepSeek 的 UI。
- 好用:支持简历一键解析,AI 越用越懂你。
- 稳健:完整的鉴权与日志系统。
下一步计划:
- 多智能体模拟面试:引入两个 Agent 互相对话,用户旁观“模拟面试”过程(基于 SSE 流式输出)。
- 语音交互:接入 TTS/ASR,实现真正的语音模拟面试。
技术改变生活,AI 赋能求职。如果你对这个项目感兴趣,欢迎关注我的 GitHub!