对话笔记直发:5.5 Cloudflare AI内容流水线部署。分类:网络基建。

Cloudflare AI内容流水线部署

时间

2026-05-05

用户目标

用户先提供了一篇关于用 Cloudflare 免费搭建 AI 内容流水线的教程,希望我阅读后提炼出如何快速上手部署。随后用户说明 Cloudflare 账号已经注册好,并要求我直接负责本地部署和后续推进,不要反复询问。最终目标是搭建一个可运行的 Cloudflare AI 内容聚合流水线,并逐步从最小可用版扩展到可配置多源抓取版本。

背景与上下文

最初读取了用户提供的 Markdown 教程文件: C:\Users\fengx\onedrive\Apps\remotely-save\feng\000_Raw\30_剪藏\2026-05-05\Cloudflare 免费搭了一套 AI 内容流水线.md

对教程做出的判断:

  • 教程更像“架构演示”和 MVP 思路,不是可直接稳定上线的完整部署手册。
  • 建议先做最小闭环:Worker + Cron + Workers AI + D1 + 简单展示页。
  • 第一阶段明确不做 R2、正文抽取、向量检索、邮件推送、多数据源复杂逻辑。

随后进入实际部署阶段,发现本地工作区 D:\Program\0\vps 下没有现成 Cloudflare 项目,因此从零创建了一个新项目并持续迭代。

过程摘要

1. 环境检查与登录

  • 在本地检查 wrangler 状态,确认 npx wrangler --version 可用。
  • 初次执行 npx wrangler whoami 时发现未登录。
  • 指导用户执行 npx wrangler login,用户完成浏览器授权后继续。
  • 再次确认 wrangler whoami 成功,登录身份为 unixcs@qq.com,且输出说明当前使用的是 OAuth Token 登录,而不是手工创建的 API Token。

2. 初始化 Cloudflare Worker 项目

  • 使用 npm create cloudflare@latest ai-content-pipeline -- --type=hello-world --lang=ts --no-deploy 初始化项目。
  • 创建过程中脚手架停在交互式问题(是否添加 AGENTS.md),但项目骨架已生成,因此直接接管现有目录继续修改,而没有重新走交互流程。
  • 项目目录位于:D:\Program\0\vps\ai-content-pipeline

3. 最小版 MVP:HN + Workers AI + D1

第一版主要完成了以下事情:

  • 修正 wrangler.jsonc 中默认的占位字段,设置实际 Worker 名称和兼容日期。
  • 添加 AI binding。
  • 创建 schema.sql,建立 articles 表。
  • 新写 src/index.ts,实现:
    • fetch /run:手动触发抓取并总结
    • fetch /articles:返回 D1 中最近文章
    • fetch /:内嵌一个简易 HTML 首页
    • scheduled:定时执行抓取
  • 数据源使用 Hacker News top stories。
  • 使用 Workers AI 模型 @cf/meta/llama-3.1-8b-instruct-fast 做中文标题、摘要、推荐理由、标签生成。

4. 创建和绑定 D1

  • 使用 npx wrangler d1 create content-db 创建 D1 数据库。
  • 得到数据库信息:
    • database_name: content-db
    • database_id: 4ff4e353-321e-4966-983b-52153de250dd
  • 将 D1 binding 写入 wrangler.jsonc。
  • 使用 npx wrangler d1 execute content-db --remote --file=schema.sql 在远端初始化表结构。

5. AI 返回值兼容处理

在第一次真实触发时,发现 Worker 能抓到 HN 条目,但 AI 返回格式与最初假设不完全一致。

经历的问题:

  • 初期错误:raw.match is not a function
  • 后续发现 Workers AI 返回的是带 choices / response 结构的对象,而非纯字符串 JSON。
  • 某些字段如 summary_zh、why_it_matters 还会是数组。

因此在 src/index.ts 中逐步做了兼容:

  • 提取 response / choices[0].message.content / result.response。
  • 支持 AI 直接返回对象形式。
  • 将数组型摘要、推荐理由拼接为字符串。
  • 对 tags 做裁剪和清洗。

6. UTF-8 响应与“乱码”排查

用户看到的中文乱码不是数据库损坏,而是本地 PowerShell 打印 HTTP body 时的显示编码问题。

验证结论:

  • D1 中的中文内容是正常的。
  • 浏览器访问页面时中文可正常显示。
  • 但某些 PowerShell 读取 HTTP 响应时会显示乱码。

修复动作:

  • 将 /run 和 /articles 的 JSON 响应改为显式返回 application/json; charset=UTF-8。
  • 首页 HTML 已显式返回 text/html; charset=UTF-8。

7. 页面和数据模型增强

在 MVP 跑通后,又做了第二阶段升级:

  • 扩展数据表字段:
    • source_title
    • source
    • fetched_at
  • 增加迁移文件:migrate_add_article_metadata.sql
  • 为旧数据补齐:
    • source_title = title
    • source = hacker-news
    • fetched_at = created_at

同时升级首页:

  • 支持搜索标题、摘要、标签
  • 支持来源筛选
  • 展示文章数量和来源数量
  • 展示抓取时间
  • 展示原始标题
  • 更换了更完整的卡片样式和移动端适配

8. 回退逻辑

为了避免 AI 失败时整条内容丢失,加入了 fallback 策略:

  • 如果 AI 解析失败,仍然会将文章写入 D1
  • title_zh 退回原始标题
  • summary_zh 标记当前为回退摘要
  • why_it_matters 标记为可供后续人工筛选
  • tags 标记为 待复查 / 自动抓取

9. 升级为多源抓取

用户继续确认后,我把单一 Hacker News 升级成了“可配置多源抓取”。

目前配置的 source registry:

  • hacker-news
  • cloudflare-blog
  • vercel-blog

对应来源:

  • Hacker News API
  • https://blog.cloudflare.com/rss/
  • https://vercel.com/atom

实现方式:

  • 仍保持在一个 src/index.ts 中,不拆分过多模块
  • 不增加第三方依赖,直接手写轻量 RSS/Atom 解析逻辑
  • 支持解析:
    • RSS <item>
    • Atom <entry>
    • title / link / guid / pubDate / updated / published

10. 多源抓取中遇到的两个关键问题

问题 A:单源超时导致整个 /run 报 1101

  • 在真实触发多源抓取时,某些 RSS 请求出现 ETIMEDOUT 你的服务器IP(已脱敏):443
  • 最初实现里,单个 source 抛错会直接导致整轮 runPipeline 失败

修复方式:

  • 将 fetchAllSources 改成逐 source try/catch
  • 某个 source 失败时只记录 sourceErrors
  • 其它 source 正常继续抓取
  • 给 RSS 请求加 AbortSignal.timeout(12000)

问题 B:RSS/Atom 条目 ID 是字符串,与 D1 主键冲突

  • 最初多源模式里给 RSS 项目使用字符串 ID,如 source:guid
  • 但 D1 中 articles.id 仍为 INTEGER PRIMARY KEY
  • 这导致 RSS 条目入库时会造成 Worker 运行时失败,从而触发 1101

修复方式:

  • 将多源条目统一使用数值型稳定 ID
  • HN 继续使用原始数值 ID
  • RSS/Atom 条目通过稳定哈希函数 stableNumericId() 从 source + guid/id/link 生成数值 ID

11. 多源版本最终状态

最终多源版本已成功部署并真实验证:

  • 手动触发:https://ai-content-pipeline.unixcs.workers.dev/run?limit=10
  • 结果:
    • ok: true
    • fetched: 10
    • saved: 10
    • skipped: 0
    • errors: []
    • sources: ["hacker-news", "cloudflare-blog", "vercel-blog"]

来源入库状态:

  • hacker-news: 5 条
  • cloudflare-blog: 3 条
  • vercel-blog: 3 条

12. 关于 Cloudflare token 的解释

用户最后追问“刚刚帮我部署 CF 使用的是什么操作?如何获取的 token”。

已经明确解释:

  • 部署依赖的是 Wrangler OAuth 登录,不是手工复制的 API Token
  • 关键流程是:
    • npx wrangler login
    • 浏览器授权
    • Wrangler 在本机保存登录态
  • wrangler whoami 输出明确显示当前是:You are logged in with an OAuth Token
  • 如果需要 API Token,则需要到 Cloudflare 控制台 My Profile -> API Tokens 手工创建,但本次部署不依赖这种方式。

关键结论

  1. 用户的 Cloudflare AI 内容流水线已经从 0 搭建完成,并已部署到线上。
  2. 当前实现不只是 MVP,而是一个可运行的多源内容抓取系统。
  3. 当前线上地址:https://ai-content-pipeline.unixcs.workers.dev
  4. 已实现的接口和页面:
    • /:前端页面
    • /run:手动触发抓取
    • /articles:文章 API
    • /sources:来源 API
  5. 当前数据源包含:
    • Hacker News
    • Cloudflare Blog
    • Vercel Blog
  6. 最大剩余问题不是部署稳定性,而是 AI 输出质量:
    • 某些英文来源生成的中文摘要仍可能出现可读性不稳定或字符显示不理想的问题
    • 基础设施层面目前已基本跑通

执行动作

  1. 读取用户提供的教程并提炼最短部署路径。
  2. 检查工作区,确认无现成 Cloudflare 项目后从零初始化新项目。
  3. 指导用户完成 wrangler login,再继续接管部署。
  4. 创建并绑定 D1 数据库 content-db。
  5. 编写 Worker、AI 摘要逻辑、D1 写入逻辑和基础首页。
  6. 调试 AI 返回值格式差异,修复 JSON 提取与数组字段兼容问题。
  7. 排查中文“乱码”,确认是 PowerShell 显示问题,并补充 UTF-8 响应头。
  8. 扩展表结构与首页能力,增加搜索、筛选、来源与时间元数据。
  9. 升级为多源抓取系统,支持 HN + RSS/Atom。
  10. 修复单源超时和 RSS 数值主键问题,完成多源真实验证。
  11. 向用户解释本次部署使用的是 Wrangler OAuth 登录,而不是手工 API Token。

执行命令记录

  1. npx wrangler --version

    • 目的:检查本机是否可用 Wrangler
    • 结果:可用,初次使用时通过 npx 拉起安装
  2. npx wrangler whoami

    • 目的:检查是否已经登录 Cloudflare
    • 初次结果:未登录,提示执行 wrangler login
    • 登录后结果:显示 You are logged in with an OAuth Token,确认是 OAuth 登录态
  3. npm create cloudflare@latest ai-content-pipeline -- --type=hello-world --lang=ts --no-deploy

    • 目的:初始化 Cloudflare Worker 项目
    • 结果:脚手架过程中卡在交互问题,但项目骨架已生成,可直接接管使用
  4. npx wrangler d1 create content-db

    • 目的:创建远端 D1 数据库
    • 结果:成功创建 content-db,得到 `database_id = 4ff4e353-321e-4966-983b-52153de2

注:本文涉及的服务器公网 IP / Tailnet / 局域网 IP 已脱敏,请替换为你自己的地址。


相关: 00-索引-网络基建索引 4.30 Cloudflare Tunnel 0基础手动安装教程