停止发送静态简历:我如何构建了一个‘Chat With My Resume’机器人 (Next.js + RAG)
Source: Dev.to
说实话:招聘人员大约只会花 6 秒钟浏览你的作品集。
你花了数周时间打造一个精美的网站,打磨 CSS,优化 Lighthouse 分数,却发现大多数访客只会扫一眼首页横幅就离开。
我想要一个主动的作品集,而不是被动的——一个能够回答以下问题的网站:
- “他在 TypeScript 方面有什么经验?”
- “他有没有使用过 AWS?”
- “我们为什么要雇用他?”
于是我构建了一个 基于 RAG 的 AI 聊天机器人,它“读取”我的简历并实时回答问题。下面是我的实现过程(你也可以照着做)。

架构:保持“纯粹”
当我开始时,我查看了像 LangChain 这样的库。虽然功能强大,但对于一个简单的作品集机器人来说显得有些大材小用。我不想仅仅为了调用一次 API 就引入 500 MB 的依赖。
技术栈
- 前端:Next.js 15(App Router)用于 UI。
- 后端:Node.js(Express)安全地处理 API 密钥。
- AI:OpenAI API(gpt‑4o‑mini)提供智能。
- 逻辑:自定义 RAG(检索增强生成)流水线。
挑战:上下文与流式输出
构建一个聊天机器人很容易。构建一个了解你是谁的聊天机器人则更难。
1. “大脑”(RAG)
你不能每次都把整份简历粘贴到提示中——这会浪费 token 和金钱。相反,我实现了一个简单的 向量搜索 逻辑:
- 应用启动时加载我的作品集数据(经验、技能、简介)。
- 当用户提问时,系统会找出最相关的“文本块”。
- 只把该块发送给 OpenAI,并使用如下系统提示:
“你是 [姓名] 的 AI 助手。请仅使用下面提供的上下文来回答招聘者的问题。”
2. “打字机”效果(流式输出)
没有什么比等待 5 秒才得到回复更破坏体验的了。我想要那种 ChatGPT 的感觉,让文字逐字出现。为此我放弃了标准的 REST 响应,改用 服务器发送事件(SSE)。
// Example SSE endpoint (Node.js + Express)
app.get('/api/chat', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.flushHeaders();
// Stream chunks from OpenAI
openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [{ role: 'system', content: systemPrompt }, ...userMessages],
stream: true,
}).then(stream => {
for await (const part of stream) {
const content = part.choices[0]?.delta?.content;
if (content) {
res.write(`data: ${JSON.stringify({ content })}\n\n`);
}
}
res.write('event: done\n\n');
res.end();
}).catch(err => {
console.error(err);
res.write('event: error\n\n');
res.end();
});
});
这确保用户能够立即看到活动,从而保持参与感。
注意事项(为何耗时数周)
- 安全:OpenAI 密钥绝不能在客户端代码中泄露;需要使用代理服务器。
- 移动响应性:浮动聊天小部件需要能够处理 iPhone 键盘而不破坏布局。
- 上下文窗口:必须谨慎修剪聊天历史,以避免触及 token 限制。
结果
现在,当招聘人员访问我的网站时,他们不再只是滚动——他们会参与互动。他们可以询问我的费用、可用性以及技术栈,将静态的独白转变为动态的面试。
想把它加入你的作品集吗?
如果你想自己动手构建,我强烈建议了解 OpenAI Node SDK 和服务器发送事件(Server‑Sent Events)。这是一次很好的学习体验。
它是一套完整类型、可用于生产的入门套件:
- ✅ 纯 RAG 设置(无复杂库)
- ✅ 预构建流式 UI(Next.js 15)
- ✅ 简易 “Resume” 配置

你可以在本周末获取模板并开始自定义:
🚀 在 Lemon Squeezy 获取 — 结账时使用代码 HOLIDAY2026 可享折扣!
编码愉快!