一起构建超个性化新闻代理吗?🤖📰(一起编码)

发布: (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
数据库 & ORMMongoDB + 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 点安排执行。

最终测试

  1. 通过表单注册电子邮件。
  2. 检查收件箱中是否收到新闻通讯。

下一步

  • 使用 queues(例如:BullMQ)重构编排。
  • 为 Resend 添加对 多受众 的支持。
  • 实现搜索结果的 缓存 以降低成本。

别再只对 ChatGPT 说“嗨”,开始构建真正能够自主提供价值的工具吧。 🚀

Back to Blog

相关文章

阅读更多 »

仓库利用的权威指南

引言 仓库本质上只是一个 3‑D 盒子。利用率只是衡量你实际使用了该盒子多少的指标。虽然物流 c...