news 2026/9/14 8:05:16

OpenSEO Onboarding Agent 实现方案:无 Agent 框架的引导式 SEO 激活管线

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenSEO Onboarding Agent 实现方案:无 Agent 框架的引导式 SEO 激活管线

OpenSEO Onboarding Agent 实现方案:无 Agent 框架的引导式 SEO 激活管线

【免费下载链接】open-seoOpen source alternative to Semrush and Ahrefs项目地址: https://gitcode.com/GitHub_Trending/op/open-seo

导读

本文基于 OpenSEO 仓库中的技术设计文档 specs/0006-onboarding-agent-implementation.md,详细拆解「Onboarding Agent」的落地实现:一个确定性 seed 函数负责分析新用户真实网站并生成首份 SEO 策略,配合普通流式聊天让用户在线打磨这份策略,最终沉淀为项目可复用的Project Context。读完本文,你将理解 OpenSEO 如何在不引入任何 Agent 框架、不做持久化执行的前提下,用fetch抓取、Browser Rendering 抓取、两次 DataForSEO 付费调用和一次 OpenRouter 合成调用,把注册用户转化为激活用户,并掌握其数据模型、计量护栏、MCP 暴露方式与分阶段构建顺序。

文档状态说明:本文主体是 0006 号规格书描述的原始技术方案(Status: Accepted, June 2026),该文档自身标注了「shipped implementation diverged from the plan」的更新说明;文末会结合仓库当前源码,单独对比实际交付形态与原始计划的差异。

一、为什么需要 Onboarding Agent

Onboarding Agent 是 OpenSEO 的最高激活优先级功能。产品规格 specs/0005-onboarding-agent.md 开宗明义:把注册变成激活。当新用户完成注册后,一个「agent」实时分析他们真实的网站,随后产出一份量身定制的 SEO 策略。

关键设计理念是:策略本身免费且自洽,付费墙落在「执行策略」上——排名追踪、内容简报、持续 coach 都是付费面。这份策略会成为项目持久的「Project Context」,既能在应用内阅读,也能通过 MCP 暴露给用户的 Claude/Codex 等客户端读取。

规格文档特别澄清了「agent」一词的含义:它不是 LLM agent 循环,而是一条实时旁白式引导管线。步骤大多是确定性的(抓取、拉取关键词数据),只在最后用一次 LLM 调用合成策略叙事。所谓「agent 感」来自两步:实时流式播报各阶段进度(「正在读取你的首页……你看起来像 Notion 的竞品……有 4 个关键词在排名,30 个值得瞄准……」),以及最终报告逐 token 流出。v1 不需要 Anthropic SDK 或任何 agent 基础设施。

二、总体架构:两个简单部件,零 Agent 框架

实现计划(TL;DR)将系统收敛为两个互不依赖的部件:

  1. seed 函数(普通 async 函数):发现 sitemap → 用 Browser Rendering 把 3–5 个页面抓成 markdown → 2 次付费 DataForSEO 调用 → 1 次 OpenRouter 合成调用 → 把结果保存为项目的第一个Project Context版本。在 onboarding 启动时只运行一次。
  2. 普通流式聊天(Vercel AI SDKstreamText走 OpenRouter):用户提问/打磨;update_project_context工具写入新版本。由一条基于现有 better-auth session 的普通 API 路由承载。

Project Context 是版本化的:不可变 markdown blob 存 R2,D1 里存 append-only 日志。回滚复用先前 blob 的 key。通过 MCP 的get_project_context暴露。

三、为什么不用 Cloudflare Think / Workflows(以及为什么保留 agents 包)

方案演进过程中,作者曾提出用 Cloudflare Project Think + Durable Objects + Workflow 的草案,最终全部放弃,理由在文档中有三条硬核论证:

  • 不需要持久化执行。付费的 DataForSEO 服务是 cache-first 的——getCached先于createDataforseoClient/metering 执行,所以同一域名崩溃后重试会重新命中 12 小时 R2 缓存,不会重复扣费。这直接消除了引入 fibers/Workflows 的唯一理由。
  • 不需要 agent 宿主。想要的能力(流式回答、未来的 docs 工具、保存/更新产物)都是普通的streamText({ tools })就能覆盖。Think 的差异化价值(durable DO sessions、scheduled turns、sub-agents)在这里一个都用不上。
  • agents包保留,但用途不是 agent 运行时:它被 MCP handler 使用——agents/mcpcreateMcpHandler(见 src/server/mcp/transport.ts)。不做版本升级。

方案留有「毕业」路径:只有当某个能力确实需要 durable sessions、schedule(如每周排名追踪)或 sub-agents(按竞品)时,才考虑迁移;seed 函数和聊天路由可以直接平移过去。

四、数据模型:projects 扩展 + append-only 版本日志

4.1projects表新增列

类型默认值/说明
location_codeint默认2840(美国)
language_codetext默认'en'
onboarding_run_statustext 可空running\|complete\|failed
onboarding_run_attext 可空运行时间戳

新增 location 相关默认值并非孤例:仓库中 src/shared/keyword-locations.ts 及其厂商默认值测试 src/shared/keyword-locations.vendor-defaults.test.ts 也维护了位置/语言默认逻辑。产品规格要求从 Stage 0 的表单收集国家,写入projects复用于此后所有 DataForSEO 调用

4.2project_context_versions(新增,append-only 日志)

说明
id主键
project_id外键
r2_key指向 R2 中的 markdown blob
authoronboarding\|chat\|user
note可空,记录该版本变更说明
reverted_from_id可空,回滚来源
created_at创建时间

当前版本 = 每个项目最新一行;索引建在(project_id, created_at)上。

4.3 R2 不可变 blob + 写序约束

  • 每个版本对应 R2 中一个不可变 markdown blob:project-context/{projectId}/{versionId}.md
  • 必须先写 R2、再写 D1 行:失败只会留下一个无害的孤儿 blob,绝不会出现指向空内容的行。
  • 回滚时插入新行复用目标版本的r2_key,不产生新 blob。

五、seed 函数逐阶段拆解

runOnboardingSeed({ projectId, organizationId, userId, userEmail, domain })是一条六阶段的确定性管线:

  1. 准入标记(Admission marker)——原子更新UPDATE projects SET onboarding_run_status = 'running' WHERE id = ? AND onboarding_run_status IS NULL;仅当恰有一行受影响才继续(否则说明已有 run 在途)。这是至多一次(at-most-once)的并发护栏。
  2. 发现(Discover)——fetch()robots.txt + sitemap.xml;抓不到时降级为浅层爬取。产品规格强调:多发现 URL(便宜)、少抓取页面。
  3. 读取(Read)——通过BROWSERbinding 顺序抓取 3–5 个关键页面(首页 + 核心产品/导航页)转成 markdown。失败只打标记,绝不中断整个 run。这是全案唯一真正新增的能力:页面 → markdown(Cloudflare Browser Rendering)。规格要求诚实的「我们读不了你的站」提示 + 手动「告诉我们你做什么」兜底,保证流程永不卡死。
  4. 信号(Signal)——DomainService.getOverview(总是调用,对应仓库中的 src/server/features/domain/services/DomainService.ts)+ 以抓取主题为种子做关键词研究,两者都带creditFeature: 'onboarding'getSuggestedKeywords仅当 overview 显示真实排名时才调用。这与产品规格中的 Stage 3 数据矩阵一致(见下节)。
  5. 合成(Synthesize)——一次 OpenRoutergenerateText/streamText,输入 {profile + markdown + signal},输出策略 markdown:定位陈述、3–5 个主题簇、起始关键词表(量/难度)、按优先级排序的「下一步行动」清单。规格强调:冷启动(零排名)是独立开发者 ICP 的默认场景而非边缘情况,必须能产出可信策略。
  6. 持久化(Persist)——写入 v1 版本(authoronboarding),并把onboarding_run_status置为'complete'。任何异常抛出则置为'failed'可重跑,重试受缓存保护且廉价)。

Stage 3 信号数据(v1 保持最小)

Stage 3 是原型条件式的:廉价探测站点类型,据此调整叙事目标——v1 中原型只影响「旁白」,不放大 API 调用矩阵。基线两次调用:

调用端点用途时机
domain_rank_overview/v3/dataforseo_labs/google/domain_rank_overview/live流量 + 排名关键词数;原型探测器总是
keyword_ideas/v3/dataforseo_labs/google/keyword_ideas/live起始关键词表,以抓取主题为种子总是
ranked_keywords/v3/dataforseo_labs/google/ranked_keywords/live当前已排名关键词仅 overview 显示真实排名时(新站通常跳过)

原型(v1 仅影响叙事):new/pre-traffic(新站/无流量)、established content site(成熟内容站)、local business(本地商家)、SaaS/product(核心 ICP)

六、计量与护栏:'onboarding' CreditFeature 与 skipBalanceAssert

方案的关键约束:整个 run 免费(付费墙在其后),因此每次免费 onboarding 的成本必须封顶。文档给出预算:

  • DataForSEO:约 $0.04–0.08(2 次 Labs live 调用;按响应信封中的真实cost字段计量,可硬性封顶)。
  • Browser Rendering 抓取:可忽略。
  • LLM 合成:约 $0.05–0.15(一次调用,输入几页 markdown)。
  • 合计约 $0.10–0.25 / 次 onboarding。

计量机制在原计划中保持不变:付费调用仍走现有createDataforseoClientseam(对应仓库 src/server/lib/dataforseo/client.ts),新增'onboarding'CreditFeature 为支出打标签;计量特征清单集中在 src/shared/billing-credit-features.ts,被研究、排名追踪、反链、域服务等共享。关键设计:

  • skipBalanceAssert标志:让零余额的新注册用户在 Signal 阶段不因INSUFFICIENT_CREDITS死掉,但仍调用trackDataforseoCost——支出被计量、但不被余额门禁拦截
  • 自托管已完全跳过 Autumn(计费服务),故该逻辑对 self-host 无影响。

配套护栏(产品规格):每人一次 run、结果硬缓存、邮箱验证门禁 Stage 3(挡住 DataForSEO 花销的滥用攻击)。

七、聊天:POST /api/onboarding/chat

POST /api/onboarding/chat由 TanStackcreateFileRoute服务端 handler 承载:

  • 认证:从请求解析 better-auth session;断言用户拥有projectId(通过ProjectRepository.getProjectForOrganization做组织作用域,对应仓库 src/server/features/projects/repositories/ProjectRepository.ts)。不加新传输层,因此不增加认证攻击面
  • 流式响应streamText({ model: openrouter(MODEL), system: seededWithContext, messages, tools: { update_project_context } }),以 UI 消息流形式返回。
  • update_project_context({ markdown, note })写入新版本(authorchat)。v1 直接应用;append-only 日志保证任何不满意的改动都「一个 revert 之遥」。

客户端:AI SDKuseChat({ api: '/api/onboarding/chat' })。策略渲染在聊天上方;升级 CTA 是 UI 状态,在 v1 存在后出现。这也对应产品规格的付费墙设计:免费给完整策略(定位、主题、封顶约 15–20 个起始关键词、「下一步」清单);执行层面(追踪建议关键词的排名、完整关键词扩展、按主题的内容简报、持续的seo-coach)才被门禁。GSC 留在付费墙后,onboarding 期间提示连接 GSC,避免「连完就撞付费墙」的诱饵式体验。

八、认证与邮箱验证

  • EnsuredUserContext上暴露emailVerified(来源session.user.emailVerified);自托管视为已验证。
  • seed 在付费的「Signal」阶段之前断言emailVerified;Discover + Read(免费)允许未验证用户运行。

九、MCP 暴露:get_project_context

get_project_context(projectId)—— 只读工具(readOnlyHint: true),走withMcpProjectAuth(见 src/server/mcp/project-auth.ts);解析最新版本 → R2 get → 返回 markdown。list_project_context_versions是 fast-follow。

值得注意的是,当前仓库已经实现了这一工具的成熟形态:src/server/mcp/tools/project-context.ts 中的get_project_context并非按「R2 markdown blob 版本」实现,而是基于分节式 Project Contextbusiness_overview(业务概览)、current_goal(当前目标)、positioning(定位)、writing_preferences(写作偏好)四个类型化 section,外加 custom sections、competitors(竞品)、key pages(关键页面)与 research log(研究日志),schema 定义在 src/types/schemas/projectContext.ts,作者枚举为user|sam|mcp。服务层 src/server/features/project-context/services/ProjectContextService.ts 负责读取、批量应用补丁(applyContextUpdates,经 src/db/runBatch.ts 原子批处理)以及渲染统一 markdown digest(renderProjectContextMarkdown)。从该实现看,MCP 工具返回的text字段承载渲染好的 markdown,structuredContent提供结构数据,并带项目页跳转 meta。

产品规格中还规划了更进一步的 MCPresource(自动载入 agent 上下文),v1 只做 tool。

十、本地测试:真实服务商,无 fixture 系统

本地测试策略刻意不用 fixture provider,而是直接打真实服务商

  • 新增唯一一个 key:OPENROUTER_API_KEY写入.env.localwrangler login获取BROWSERbinding 权限(dev 下remote: true)。
  • DataForSEO 凭据沿用现有账号;缓存让重复运行免费(12h R2 缓存)。
  • 用 Playwriter skill 驱动真实 onboarding UI,逐步截图。测试域名:openseo.so

十一、构建顺序(stacked PRs)

  1. Foundation(基础)——schema + 迁移(projects新列、project_context_versions);emailVerified上 context;'onboarding'CreditFeature + 标签 +skipBalanceAssert标志;国家 →location_code映射。无行为变更。
  2. Stage 0 表单——域 + 国家合并为一步,写入projects
  3. Project Context 存储——R2 blob helper + versions 仓库 +get_project_contextMCP 工具。
  4. 抓取 + seed + 合成——BROWSERbinding、scrape-to-markdown、seed 函数、OpenRouter 依赖、「生成中 → 策略」UI。
  5. 聊天——/api/onboarding/chat+update_project_context工具 +useChatUI + revert。

(没有 fixture-provider PR——直接对真实服务商测试。)

十二、实际交付 vs 原始计划

文档顶部的 Update 注释(June 2026)明确记录了计划与交付的分歧,仓库源码可以印证最终形态:

  • 交付形态:不再有确定性的 seed + 合成管线,也没有claimRun运行状态护栏与skipBalanceAssert绕过;取而代之的是按需聊天——Sam 调用read_websiteget_seo_metrics两个工具、在流中亲自撰写策略。Sam 的实现集中在 src/server/features/sam/SamChatAgent.ts、工具注册在 src/server/features/sam/samChatTools.ts、技能清单在 src/server/features/sam/samSkills.ts。
  • 持久化与 MCP 工具:计划中的project_context_versions存储 + R2 版本化,以及get_project_contextMCP 工具,曾被推迟到后续 PR——但从仓库现状看,get_project_context/update_project_context已作为分节式 Project Context 落地(见第九节)。
  • 计量:onboarding 花销(DataForSEOLLM tokens)通过正常余额门禁从组织的 onboarding-plan trial credits 中扣减。
  • 产品侧:0005 号规格同样标注交付偏移——策略展示在聊天中,Sam 使用read_website+get_seo_metrics按需分析,而非分阶段「synthesize → persist」管线。

十三、Out of scope(v1)

原计划明确排除:Think/DO/Workflows、sub-agents、计划性排名追踪、GSC 增强策略、多语言、自动内容生成、MCP contextresource(仅 tool)。产品规格的 v1 排除项还包括:会话式/迭代式 agent 循环、竞品与本地商家分析、多语言策略、自动内容生成——这些将作为核心激活循环验证后的增量改进。

参考路径速查

  • 技术实现计划:specs/0006-onboarding-agent-implementation.md|产品规格:specs/0005-onboarding-agent.md
  • Sam 聊天实现:src/server/features/sam/SamChatAgent.ts、src/server/features/sam/samChatTools.ts
  • MCP Project Context 工具:src/server/mcp/tools/project-context.ts、src/server/mcp/project-auth.ts
  • Project Context 服务与 schema:src/server/features/project-context/services/ProjectContextService.ts、src/types/schemas/projectContext.ts
  • 计量与 DataForSEO:src/shared/billing-credit-features.ts、src/server/lib/dataforseo/client.ts
  • 位置/语言默认值:src/shared/keyword-locations.ts

【免费下载链接】open-seoOpen source alternative to Semrush and Ahrefs项目地址: https://gitcode.com/GitHub_Trending/op/open-seo

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 8:02:45

Netty不是Java必修课,却是高并发架构分水岭:线程模型与实战避坑

做Java这么久,不管是在技术群还是面试现场,“要不要深入学Netty”这个问题我听了不下几十遍。有人觉得Netty就是搞网络编程的框架,业务开发根本碰不到;也有人一头扎进Netty源码,结果被Reactor模型和堆外内存折腾得怀疑…

作者头像 李华
网站建设 2026/9/14 8:02:35

工业视觉云边协同架构设计与落地实践:从固化困境到持续进化

前阵子跟一个做汽车零部件视觉检测的朋友吃饭,他说了一句话让我印象深刻:“我们那套视觉系统,验收那天就是它最好用的一天,之后每天都在走下坡路。”三年前上线的设备,当时节拍、准确率全部达标,可如今客户…

作者头像 李华
网站建设 2026/9/14 7:59:20

Rocky 9.4 下 ELK 日志分析系统部署实战与性能优化

1. 项目概述与整体方案设计1.1 为什么要在Rocky 9.4上搭ELK日志分析这件事,只要是跑业务的服务器,基本都绕不开。服务器一多,靠着tail -f逐个翻日志的日子就过不下去了。ELK这套组合——Elasticsearch负责存储和检索,Logstash负责…

作者头像 李华
网站建设 2026/9/14 7:56:57

ESP32-S3 N16R8开发实战:Flash+PSRAM精准适配指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 7:56:52

大模型训练数据的时间边界:2024年现象解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华