一起构建超个性化新闻代理吗?🤖📰(一起编码)
发布: (2025年12月20日 GMT+8 10:37)
5 min read
原文: Dev.to
Source: Dev.to
想法: 不要再使用千篇一律的新闻简报了!
你是否注意到大多数科技简报要么太通用,要么只报道硅谷的动态?我决定改变这一现状,打造一个 软件代理,为你量身定制内容,并邀请你一起编码。
这不仅仅是一个聊天机器人。它是一个自主代理,能够:
- 使用 Tavily 实时爬取网络。
- 按国家和语言过滤:想要日本发布的 AI 新闻,却以葡萄牙语呈现?代理可以搞定。
- 通过 Gemini 1.5 Pro 进行合成——这“大脑”负责翻译、摘要和格式化。
- 通过 Resend 发送——直接自动化推送到你的收件箱(或整个受众)。
主要功能
- 实时搜索 在网络 (Tavily)。
- 过滤 按国家和语言。
- 摘要 和 翻译 使用 Gemini 1.5 Pro。
- 自动发送电子邮件 (Resend + MJML)。
技术栈
| 层级 | 技术 |
|---|---|
| 框架 | Next.js (Vercel) |
| 智能 | Gemini SDK + Tavily API |
| 数据库 & ORM | MongoDB + Prisma |
| 电子邮件 | Resend(用于可扩展性的受众) |
| 电子邮件设计 | MJML(响应式) |
路线图(任务)
- 定义架构(Prisma + Mongo)。
- 创建偏好捕获表单(主题、国家、语言)。
- 编排代理循环:搜索 → 摘要 → 翻译。
- 在 Vercel 上配置 Cron Job,实现每周自动发送。
如何一起参与
- 评论:你会为新闻代理添加什么功能?
- 选择你最感兴趣的技术栈(Prompt Engineering、API 集成或 Next.js 前端)。
- GitHub:仓库将提供完整的应用程序。
初始目标:让项目在本地运行,并准备好数据库以接收注册用户。
快速设置
# Crie a aplicação Next.js
npx create-next-app@latest ai-newsletter
安装依赖:
npm install @prisma/client @google/generative-ai @tavily/core resend zod mjml
使用 Subscriber 模型配置 schema.prisma(见下例)。
实现
用户界面
- 表单包括:
- Input 电子邮件。
- Selects 国家和语言。
- Checkboxes 兴趣主题。
API
- 路由
/api/subscribe通过 Prisma 将注册信息保存到 MongoDB。
// pages/api/subscribe.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { prisma } from '../../lib/prisma';
import { z } from 'zod';
const schema = z.object({
email: z.string().email(),
country: z.string(),
language: z.string(),
topics: z.array(z.string()),
});
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') return res.status(405).end();
const result = schema.safeParse(req.body);
if (!result.success) return res.status(400).json(result.error.format());
await prisma.subscriber.create({ data: result.data });
return res.status(200).json({ message: 'Inscrição salva com sucesso!' });
}
搜索与摘要(“代理的魔法”)
// lib/agent.ts
import { Tavily } from '@tavily/core';
import { Gemini } from '@google/generative-ai';
export async function generateNewsletter(preferences) {
const searchResults = await Tavily.search({
query: preferences.topics.join(', '),
region: preferences.country,
language: preferences.language,
});
const prompt = `
Você é um assistente que deve:
1. Resumir as notícias encontradas.
2. Traduzir o resumo para ${preferences.language}.
3. Formatar o conteúdo como e‑mail (HTML).
`;
const gemini = new Gemini({ model: 'gemini-1.5-pro' });
const response = await gemini.generate({
prompt,
documents: searchResults,
});
return response.text; // HTML pronto para MJML
}
Prompt 工程
- 上面的提示指示 Gemini 专门 为用户语言进行格式化,并生成适用于 MJML 的 HTML。
MJML 集成
// lib/mjml.ts
import mjml2html from 'mjml';
export function renderEmail(htmlContent) {
const mjmlTemplate = `
<mjml>
<mj-body>
<mj-section>
<mj-column>
${htmlContent}
</mj-column>
</mj-section>
</mj-body>
</mjml>
`;
const { html } = mjml2html(mjmlTemplate);
return html;
}
批处理逻辑(发送)
// pages/api/send-newsletter.ts
import { prisma } from '../../lib/prisma';
import { generateNewsletter } from '../../lib/agent';
import { renderEmail } from '../../lib/mjml';
import { resend } from '../../lib/resend';
export default async function handler(req, res) {
const subscribers = await prisma.subscriber.findMany();
for (const sub of subscribers) {
const content = await generateNewsletter(sub);
const html = renderEmail(content);
await resend.sendEmail({
from: 'news@yourdomain.com',
to: sub.email,
subject: 'Sua newsletter personalizada',
html,
});
}
res.status(200).json({ message: 'Newsletters enviadas' });
}
Vercel 定时任务
创建文件 vercel.json:
{
"crons": [
{
"path": "/api/send-newsletter",
"schedule": "0 9 * * MON"
}
]
}
这将在每周一上午 9 点安排执行。
最终测试
- 通过表单注册电子邮件。
- 检查收件箱中是否收到新闻通讯。
下一步
- 使用 queues(例如:BullMQ)重构编排。
- 为 Resend 添加对 多受众 的支持。
- 实现搜索结果的 缓存 以降低成本。
别再只对 ChatGPT 说“嗨”,开始构建真正能够自主提供价值的工具吧。 🚀