📚 离职知识库

AI 产品教学向长文自动生成 SOP

#这份文档是干嘛的

固化这样一条流水线:给一个 AI 产品的官网链接 → 自动抓官网 + 全网调研 → 出一篇 3000-7000 字的上手教程长文 → 自动配「产品真实界面截图」(不是图库意境图)。

把本文件拖进新的 Claude Code 会话,就能照着复现整条链路——无论是在现有项目里加功能,还是从零搭一个独立网站(本文最后一节专门讲迁出与扩展到视频脚本)。

沉淀自 2026-08-05~/personal/media-studio 上的实践:功能已上线 https://studio.saveme505.help/teach,首篇成品是 Gemini Notebook(原 NotebookLM)教程,线上实测调研 64 秒、出稿+配图 67 秒、6971 字、4 张真实截图、零告警。


#环境与前置条件

要求 说明
运行时 Node.js 20+ / Next.js 16 / React 19 Vercel serverless(Node runtime,非 Edge)
抓取与搜索 Firecrawl API Key 一把 key 通吃「抓网页 + 全网搜索 + 图片搜索 + 网页截图」四件事。key 从 ~/Desktop/配置信息/firecrawl-api-key.md 读取
文案引擎 云雾中转(yunwu.ai)等 OpenAI 兼容接口 配置从 ~/Desktop/配置信息/云雾API-中转/README.md 读取。模型能力是本流水线的质量瓶颈,见「踩过的坑」第 4 条
图片存储 Vercel Blob(BLOB_READ_WRITE_TOKEN 必需,不是可选项,原因见「踩过的坑」第 5 条
SDK ai (Vercel AI SDK v5)、@ai-sdk/openai-compatible@vercel/blob Firecrawl 不装 SDK,直接 fetch REST v2
数据库 任意(本例 Supabase Postgres) 不是必需——纯生成链路可以完全不落库

Vercel 计划限制:Hobby 免费版单函数 maxDuration 上限 300 秒。这个数字直接决定了架构必须拆成两步,见「踩过的坑」第 1 条。


#正确流程(照着做)

#第 0 步:验证 Firecrawl 的四个能力

在写任何代码之前先用 curl 打通,确认 key 有效、返回结构符合预期。以下四条命令都是本轮真实跑通的。

KEY=$(grep -oE 'fc-[A-Za-z0-9]+' ~/Desktop/配置信息/firecrawl-api-key.md | head -1)

# ① 抓正文 + 首屏截图(一次请求同时拿到)
curl -s -X POST https://api.firecrawl.dev/v2/scrape \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"url":"https://notebooklm.google/","formats":["markdown",{"type":"screenshot","fullPage":false,"quality":85,"viewport":{"width":1440,"height":900}}],"onlyMainContent":true,"waitFor":2500}' \
  | python3 -c "import json,sys;d=json.load(sys.stdin)['data'];print(list(d.keys()));print(str(d.get('screenshot'))[:100])"

# ② 全网搜索(web 源)
curl -s -X POST https://api.firecrawl.dev/v2/search \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"query":"NotebookLM review 2026","sources":[{"type":"web"}],"limit":5}'

# ③ 图片搜索(images 源)—— 这就是「谷歌图片」的平替
curl -s -X POST https://api.firecrawl.dev/v2/search \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"query":"NotebookLM audio overview interface","sources":[{"type":"images"}],"limit":8}'

成功判据:① 返回 data.screenshot 是一个 storage.googleapis.com/firecrawl-scrape-media/... 的签名 URL,data.metadata.ogImage 有值;② data.web[] 每条含 url/title/description;③ data.images[] 每条含 imageUrl/url/imageWidth/imageHeight,且 creditsUsed: 2

#第 1 步:调研(四小步,约 60 秒)

① 抓官网正文        scrapePage(url) → markdown(截 14000 字)
② 规划搜索方向      模型读官网正文 → 产品名 + 一句话定位 + 5-6 条搜索式
③ 并发搜 + 抓正文   searchWeb(每条搜索式, limit 5) → 去重、排除官网自身域名
                    → 取前 8 条 → scrapePage 并发抓回正文(并发数 4)
④ 提炼底稿          官网正文 + 7-8 篇第三方正文 → 模型提炼成十节结构、逐条带出处的底稿

搜索式规划的提示词要点(这条决定了调研广度,是整条链路质量的第一道阀门):

  • 强制覆盖六个互不重复的角度:官方公告 / 第三方评测 / 上手教程 / 竞品对比 / 真实吐槽(Reddit 等社区)/ 定价与配额
  • 英文为主,至少一条中文(覆盖中文社区的用法与「国内能不能用」)
  • 每条带年份,避免搜到过时资料
  • 用「产品名 + 角度词」,不要写成整句问句

提炼底稿的提示词要点(第二道阀门,防幻觉全靠它):

  • 明确告知模型:下游写作环节只能看到这份底稿,看不到原始资料
  • 十节结构:是什么 / 时间线与改名 / 功能清单 / 定价与配额 / 上手步骤 / 使用场景 / 进阶技巧 / 限制与坑 / 竞品对比 / 可信度备注
  • 每条结尾括号标来源 URL;官方来源与第三方来源分开标注
  • 只写资料里有的,不许"合理推断"
  • 价格/配额这类会过期的数字,逐条标注来源与查询日期;不同来源打架时如实写出冲突("官网写 A,第三方评测写 B"),不许自己拍板

#第 2 步:出稿(约 40 秒)

把底稿 + 来源清单 + 用户附加指令喂给模型,按固定骨架写长文。骨架八段:

开头(用读者天天遇到的场景切入,不许铺垫行业趋势)
→ 它到底是什么(核心机制 + 所以对你意味着什么)
→ 核心功能逐项拆解(全文主体,每项写:干什么 / 效果如何 / 免费还是付费,并明确哪些是噱头)
→ 上手步骤(从零到第一个结果,能写到界面元素名就写)
→ 进阶技巧(5-8 条,每条写清怎么做 + 什么时候用得上)
→ 限制、坑与风险(必须写实,教学文的信任感全在这里)
→ 竞品对比(给判断,不要只罗列)
→ 适合谁 / 不适合谁(明确选型建议收尾,不许喊口号)

三条硬约束写进提示词:① 事实全部来自底稿,没有的不写;② 不许编造第一人称体验(不许"我实测了三天",要转述就写"据官方文档");③ 会过期的数字必须写「截至 X 年 X 月」+ 提醒以官网为准

#第 3 步:配产品真实截图(约 25 秒)

① 模型挑 2-4 个插图点 → 每个点给一条英文图片搜索式 + 中文图注
② 第 1 个点优先用官网首屏现截(Firecrawl screenshot 1440×900),失败退 og:image
③ 其余点走 searchImages,按来源域名分级择优
④ 每张图立刻下载 → 转存 Vercel Blob → 用 Blob 的长期 URL 插回正文

来源分级(决定采不采用,也决定图注怎么标出处):

等级 判定 图注标注
official_site 图片直链或来源页在产品自己的域名下 图片来源:产品官网
official_blog 命中 blog.google / gweb-uniblog-publish-prod / support.google.com / openai.com / anthropic.com 等官方渠道 图片来源:官方渠道 xxx
tech_media 命中 The Verge / TechCrunch / XDA / 9to5Google / Android Police / MakeUseOf / ZDNet / Engadget / Ars Technica / TestingCatalog 图片来源:xxx
other 其余 图片来源:xxx

候选图过滤:宽度 < 600px 丢弃;宽高比 < 0.8 或 > 3.2 丢弃(横幅/图标);文件名含 logo|icon|favicon|avatar|sprite 丢弃。

#第 4 步:验证

# 本地预览(不落库,只出 md 看效果)
npm run teach:preview -- "https://产品官网/" "附加指令"

# 线上端到端(需要先登录拿 cookie)
curl -s -c /tmp/c.txt -X POST https://studio.saveme505.help/api/auth/login \
  -H 'Content-Type: application/json' -d '{"password":"<从 .env.local 的 ACCESS_PASSWORD 读取>"}'

curl -s -m 300 -b /tmp/c.txt -X POST https://studio.saveme505.help/api/teach/research \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://notebooklm.google/","extra":"写给中文 AI 重度用户"}' -o /tmp/r.json

curl -s -m 300 -b /tmp/c.txt -X POST https://studio.saveme505.help/api/teach/write \
  -H 'Content-Type: application/json' \
  -d "{\"topicId\":\"$(python3 -c "import json;print(json.load(open('/tmp/r.json'))['topicId'])")\"}"

成功判据:research 返回 stats: {queries: 6, pagesFetched: 5-8}sources 有 6-9 条;write 返回 draft.content 长度 > 3000、draft.meta.shots 有 2-4 张且 origin 里有 official_siteofficial_blogwarnings 为空数组。


#踩过的坑

#1. 单个 serverless 函数塞不下整条链路

  • 现象:调研要抓十几个页面(约 60 秒),出稿要写四五千字(约 40 秒),配图还要搜图+下载+转存(约 25 秒)。串在一个函数里稳稳撞 Vercel Hobby 的 300 秒上限。
  • 原因:抓取和长文生成都是分钟级操作,叠加后没有余量。
  • 正确做法拆成两个 API/research/write),前端顺序调用,中间把调研结果落库(或存 KV)。附带收益:调研底稿可以先给用户过目,不满意直接换链接重来,不用白烧出稿的 token。两个函数各自 export const maxDuration = 300

#2. Firecrawl 会直接拒绝抓某些站点

  • 现象Firecrawl /scrape 失败:We apologize for the inconvenience but we do not support this site.
  • 原因:Firecrawl 对部分站点(含某些大厂站点)有黑名单,付费也抓不了。
  • 正确做法单点失败绝不能阻断整条链路。用并发池逐项 try/catch,失败的返回 null 后过滤掉;只有「官网都抓不到」才抛错终止(那种情况下写出来的必然是编的)。实测每次调研有 1-3 篇会失败,属正常。

#3. Kimi 新模型强制 temperature = 1

  • 现象invalid temperature: only 1 is allowed for this model(kimi-k2.5 / k2.6 / k3 全部如此)。
  • 原因:月之暗面新模型不再支持自定义 temperature。
  • 正确做法:要么改用支持 temperature 的老模型(moonshot-v1-128k),要么在 provider 元信息里加「强制 temperature」的字段。本轮选择直接换引擎。

#4. ⚠️ 隐性坑:弱模型会把官网的营销标题当功能名照抄

  • 现象不报错,链路全绿,但产出的稿子完全没有信息量。用 moonshot-v1-128k 跑出来的正文,"核心功能"一节列的是 Upload your sourcesInstant insightsSpark new ideas——这些全是官网首页的营销 slogan,不是功能名;每条下面写"实际效果:它能够提供即时的洞见和摘要"这种同义反复;Audio Overview / Video Overview / Mind Map / Deep Research 这些真正的功能一个没提。
  • 原因:官网正文里营销标题的视觉权重最高,弱模型抓不住"哪些是功能、哪些是广告词"的区别,也不会去调研底稿里找第三方补充的真实功能清单。
  • 正确做法deepseek-v4 级别以上的模型出稿。同一条链路、同一份提示词,换成云雾的 deepseek-v4-flash 后,正文自动变成「按实用价值排序、标注免费/付费、明说哪些是噱头」的结构,长度从 3221 字涨到 5000-7000 字。这条是全流水线最贵的坑——它不报错,容易让人以为功能做完了。

#5. ⚠️ 隐性坑:Firecrawl 的截图 URL 会过期

  • 现象:截图接口返回的是 storage.googleapis.com/firecrawl-scrape-media/...?GoogleAccessId=...&Expires=1786520926&Signature=... 这样的签名链接。当场访问一切正常,直接写进稿子几天后全部变成裂图。
  • 原因:Google 云存储签名 URL 有过期时间(Expires 参数是 Unix 时间戳,实测约 7 天;官方文档另有 24 小时的口径,以更短的为准)。
  • 正确做法:拿到 URL 后立刻下载并转存到自己的存储(Vercel Blob / R2 / S3),入库存转存后的长期 URL。第三方媒体的图直链同理——随时可能防盗链或改版失效。

#6. 转存图片不带浏览器 UA,Google 的 CDN 返回 HTML 拦截页

  • 现象转存 Blob 失败:目标不是图片,URL 是 storage.googleapis.com/gweb-uniblog-publish-prod/images/xxx.webp(Google 官方博客的图床)。
  • 原因:裸 fetch 没有 UA/Referer,被当成爬虫,返回的是 HTML 而不是图片字节。
  • 正确做法:下载图片时带上完整的浏览器请求头:
const res = await fetch(imageUrl, {
  signal: AbortSignal.timeout(30_000),
  cache: "no-store",
  headers: {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0 Safari/537.36",
    Accept: "image/avif,image/webp,image/apng,image/*,*/*;q=0.8",
    Referer: new URL(imageUrl).origin + "/",
  },
});

顺带把报错信息改成带 content-type 的(目标不是图片(content-type: text/html)),否则这个坑根本定位不到。

#7. ⚠️ 隐性坑:产品名带括号补充,会把图片搜索结果搅烂

  • 现象:模型把产品名识别成 Gemini Notebook (formerly NotebookLM),这串拼进图片搜索词后,4 个插图点只配上 2 张。
  • 原因:搜索引擎把括号里的内容也当关键词,命中率骤降。
  • 正确做法:产品名字段做清洗——剥掉括号补充、按 | | - – — : : 切第一段。新旧名的说明交给调研底稿和正文去写,不要塞进这个字段。
const productName = String(plan.productName ?? official.title ?? "")
  .replace(/[((].*?[))]/g, "")
  .split(/[||\-–—::]/)[0]
  .trim() || official.title;

#8. ⚠️ 隐性坑:模型把标题重复写进正文首行

  • 现象:schema 里 titlecontent 是两个字段,模型仍然在 content 第一行又写一遍 # 标题。发到公众号就是标题出现两遍。
  • 原因:模型的 markdown 写作惯性。
  • 正确做法:出稿后确定性剥掉正文首行的一级标题(分节标题一律从 ## 起):
function stripLeadingTitle(content: string): string {
  const trimmed = content.trimStart();
  const m = trimmed.match(/^#\s+[^\n]+\n+/);
  return m ? trimmed.slice(m[0].length) : content;
}

#9. 中转通道对 json_schema 的顶层键名约束不严

  • 现象:schema 里要求返回 { images: [...] },经聚合中转(云雾等)的模型有时返回 { illustrations: [...] }。内容是对的,只是键名漂了,代码取 object.images 拿到 undefined,整轮配图白跑。
  • 原因:中转层对 response_format: json_schema 的转译不严格。
  • 正确做法:取不到目标键时,退而找对象里第一个数组值;数字字段一律 Number() 收编(模型可能给 "12" 字符串):
const raw = object as Record<string, unknown>;
const rawList = Array.isArray(raw.images)
  ? raw.images
  : ((Object.values(raw).find(Array.isArray) as unknown[]) ?? []);

#10. DeepSeek 官方 key 失效,与「欠费」不是一回事

  • 现象Authentication Fails, Your api key: ****3ae5 is invalid(HTTP 401)。
  • 原因:这是 key 本身失效(被吊销/重置),不是余额耗尽——余额耗尽报的是 Insufficient Balance
  • 正确做法:先用 curl https://api.deepseek.com/user/balance 区分两种情况。本轮的解法是继续用云雾中转(线上引擎本来就是云雾,未受影响)。~/Desktop/配置信息/deepseek-api-key.md 里那把已作废。

#11. 本地 DATABASE_URL 是占位值,本地跑不了任何落库流程

  • 现象Client network socket disconnected before secure TLS connection was established
  • 原因~/personal/media-studio/.env.localDATABASE_URLpostgresql://placeholder:***@127.0.0.1:5432/placeholder,只够本地 npm run build 通过。
  • 正确做法本地只做「不落库的纯生成预览」(写个 teach-preview.ts 脚本直接调 lib 函数,产出 md 文件);正式产出一律打生产站 API。注意配置读取函数(getStoredConfig / getPromptOverrides)都要对 DB 失败做 .catch() 兜底退回默认值,否则本地预览也会被 DB 拖死。

#已知限制 / 死路

方向 结论 原因
Google Custom Search JSON API(图片搜索) ❌ 别走 已不对新用户开放,且官方公告将于 2027-01-01 完全下线。老账号能用也是等死。
Bing Image Search API ❌ 已死 微软全系列 Search API 于 2025-08-11 彻底退役,不接受新签约,现有实例已下线。迁到 Azure AI Agents 的 Grounding with Bing 成本高 40%~483%。
自建 Puppeteer 截 SaaS 内部界面 ❌ 基本不可行 需要登录态的产品(NotebookLM/ChatGPT 这类)会触发验证码与风控;Vercel serverless 上跑无头浏览器比本地慢 4-8 倍,单次约 50 秒,容易超时。
直接搬运图片搜索里的第三方博客截图 ⚠️ 风险中高 授权状态不明,公众号被投诉会限流/删文。只采官方渠道与认可的科技媒体,且必须标出处。
Serper.dev / SerpAPI 🟡 可作三级兜底 能用、便宜(约 $1/1000 起),但既然 Firecrawl 的 images 源已经够用,没必要多接一家、多管一把 key。
本流水线覆盖不了的场景 ① 需要登录才能看到的产品内部界面(只能用官网宣传图代替);② 官网是纯 SPA 且 Firecrawl 抓不到正文的产品;③ 太新、全网没有第三方评测的产品(底稿会很薄,写出来必然空洞)。

#可复用的代码/脚本

现有实现全部在 ~/personal/media-studio,文档见该项目的 docs/teach-article.md

路径 作用
lib/firecrawl.ts Firecrawl REST v2 封装:scrapePage / searchWeb / searchImages迁出时这个文件可以整个复制,零项目耦合
lib/teach-research.ts 调研四步编排(抓官网 → 规划搜索式 → 并发搜抓 → 提炼底稿),含并发池 mapWithLimit
lib/teach-generate.ts 出稿(schema + 骨架提示词 + 剥重复标题)
lib/teach-shots.ts 产品真实截图配图(来源分级 / 候选过滤 / 转存 Blob / 插回正文)
app/api/teach/{research,write,ping}/route.ts 两步 API + 连通性测试
app/teach/page.tsx 两步式前端页面
scripts/teach-preview.ts 本地预览,不落库,产出 预览-*.md
prompts/system/teach/*.mdprompts/pipeline/teach-article.md 四条提示词(调研方向规划 / 调研提炼 / 长文骨架 / 截图选点)

#Firecrawl 封装核心(迁出时直接抄这段)

const API_BASE = "https://api.firecrawl.dev/v2";

async function callFirecrawl(path: string, body: Record<string, unknown>, timeout: number) {
  const res = await fetch(`${API_BASE}${path}`, {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.FIRECRAWL_API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify(body),
    signal: AbortSignal.timeout(timeout),
    cache: "no-store",
  });
  const json = await res.json().catch(() => null);
  if (!res.ok || !json?.success) throw new Error(`Firecrawl ${path} 失败:${json?.error || `HTTP ${res.status}`}`);
  return json.data ?? {};
}

// 抓正文(+ 可选首屏截图)
scrapePage: callFirecrawl("/scrape", {
  url,
  formats: withScreenshot
    ? ["markdown", { type: "screenshot", fullPage: false, quality: 85, viewport: { width: 1440, height: 900 } }]
    : ["markdown"],
  onlyMainContent: true,
  waitFor: withScreenshot ? 3000 : 1500,   // SPA 不等一下截出来是白屏
}, 60_000)

// 全网搜索
searchWeb: callFirecrawl("/search", { query, sources: [{ type: "web" }], limit: 6 }, 45_000)
// → data.web[]: { url, title, description }

// 图片搜索(「谷歌图片」平替)
searchImages: callFirecrawl("/search", { query, sources: [{ type: "images" }], limit: 10 }, 45_000)
// → data.images[]: { imageUrl, url, imageWidth, imageHeight, title }

#并发池(Firecrawl 限流友好,也避免 serverless 内存尖峰)

async function mapWithLimit<T, R>(items: T[], limit: number, fn: (item: T) => Promise<R>): Promise<(R | null)[]> {
  const out: (R | null)[] = new Array(items.length).fill(null);
  let cursor = 0;
  const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
    while (cursor < items.length) {
      const i = cursor++;
      try { out[i] = await fn(items[i]); } catch (e) { console.error("单项失败(跳过)", e); }
    }
  });
  await Promise.all(workers);
  return out;
}
// 并发 4 是实测舒适值

#成本与耗时(实测)

Firecrawl creditsscrape 1 credit/页,search 2 credits/次):

阶段 消耗
抓官网 1
6 条搜索式 × search 12
抓 8 篇第三方正文 ≤ 8
官网首屏截图 1
3 次图片搜索 6
单篇合计 约 28 credits

模型调用:4 次(规划搜索式 / 提炼底稿 / 写正文 / 挑配图点)。其中提炼底稿的输入最大(官网 14k 字 + 7 篇各 8k 字),是 token 大头。

耗时(线上实测):调研 64 秒,出稿 + 配图 67 秒。

存储:每篇 2-4 张图进 Vercel Blob,单张约 100-500KB。


#迁出成独立网站 / 扩展到视频脚本的建议

如果后续要把这条链路从 media-studio 里拆出来做成独立站,按下面这个顺序最省事。

#依赖梳理:哪些能直接搬,哪些要重写

模块 迁出难度 说明
lib/firecrawl.ts ⭐ 直接复制 只依赖 fetch 和一个环境变量,零耦合
lib/teach-research.ts ⭐⭐ 改两行 getPrompt(id) 换成读本地 md 文件或常量,把 getLlmModel() 换成新项目的模型构造函数
lib/teach-generate.ts ⭐⭐⭐ 需要拆 现在走的是 media-studio 的 styledGenerateObject(风格注入 + 成稿净化 + 输出契约兜底)。这套「防跑偏」机制值得一起搬——尤其是「模型把正文塞进别的键」的兜底逻辑(salvageContent),DeepSeek 系模型在长 system 下确实会跑偏
lib/teach-shots.ts ⭐⭐ 改存储层 只有 persistToBlob 绑了 Vercel Blob,换 R2/S3 只改这一个函数
提示词 ⭐ 直接复制 四个 md 文件
落库 独立站建议直接建自己的表:products(产品/链接/产品名)、researches(底稿/来源清单/统计)、articles(正文/配图清单/类型)

强烈建议保留的两个设计:① 两步式(调研与出稿分离、底稿给用户过目)——这不只是为了绕超时,更是产品逻辑上的正确切分;② 提示词与代码分离、可在网页热改——教学文的调性要反复调,改代码重新部署一次成本太高。

#扩展到视频文案脚本

调研阶段(第 1 步)完全不用改——底稿是中立的事实资料,喂给什么下游都行。要改的只有出稿阶段,按输出形态分叉:

                          ┌→ 公众号教学长文(现有)
调研底稿(十节结构,共用)─┼→ 口播视频脚本(新增)
                          ├→ 分镜脚本 / 逐镜表(新增)
                          └→ 短视频钩子 + 三段式脚本(新增)

具体做法:新增一份 schema + 一份骨架提示词即可,其余全部复用。

  • 口播脚本的 schema 建议:{ title, hook, sections: [{ heading, narration, duration_sec, b_roll_hint }], cta }
  • b_roll_hint(这一段配什么画面)字段是关键——它天然对接现有的 teach-shots.ts:把每段的 b_roll_hint 当图片搜索式,就能自动配出「这段口播配哪张产品截图」的素材清单
  • 视频脚本对时长敏感,schema 的 description 里要写死「每段 narration 控制在 X 字,对应约 Y 秒口播」,并在最后做一次总时长校验

#再往后:生成视频

这一步本 SOP 未验证,只给已知的接口线索:

  • 静态图 + 口播 TTS + 转场 是最省的路径:现有 teach-shots.ts 出的产品截图正好当画面,配 TTS 音轨用 ffmpeg 合成。注意 ffmpeg 在 Vercel 上有坑(见 project_gifmoji 的记录),这一步建议放本地或独立的容器服务,不要塞进 serverless
  • 家里已有的相关能力:阶跃/可灵的图生视频(见 ~/Desktop/配置信息/)、gpt-image-2 生图(生图API-gpt-image-2.md)、scribe-studio 的白板手绘渲染(后端已随东京 VPS 下线,需要重建
  • 建议的推进顺序:先把「口播脚本 + 配图素材清单」做扎实并人工验证几期,再考虑自动合成——脚本质量不过关的话,自动合成只是把废稿变成废视频

#下次可以直接从这里开始

当前进度:功能已在 media-studio 上线并跑通端到端。

  • 线上入口:https://studio.saveme505.help/teach(顶部导航「教学向」)
  • 首篇成品稿件:https://studio.saveme505.help/drafts/7f569186-68f2-4037-a825-904c310d4097
  • 本地成品副本:~/Desktop/Gemini Notebook(原 NotebookLM)上手教程-media-studio生成.md
  • 调研底稿副本:~/Desktop/Gemini Notebook-调研底稿.md
  • 代码:~/personal/media-studio,commit 69429e1,项目内文档 docs/teach-article.md
  • Firecrawl key 已写进线上 DB 配置(设置页「网页抓取」卡片,source=db),无需再配 env

下一步可选方向(按投入产出排序):

  1. 再跑几个产品验证稳定性——换不同形态的官网试(纯 SPA 的、中文产品的、小众工具的),看调研底稿会不会变薄。这是决定要不要迁出的前提。
  2. 加「批量」入口——一次贴 5 个链接排队跑,晚上跑完早上看。现有两步 API 直接串就行。
  3. 接口化——把 /api/teach/* 加上 token 鉴权对外,方便未来独立站或自动化流程调用。
  4. 扩展视频脚本——按上一节做法,新增一份 schema + 骨架提示词,调研阶段零改动。
  5. 迁出独立站——建议等 1 和 4 都验证过再动,那时需求边界才清楚。

来源:沉淀/AI产品教学向长文自动生成-SOP.md(整理于 2026-08-18)