研究
做一份销售团队能直接用的竞品拆解
收集竞品自己的页面、围绕它的报道,以及买家在 X 上的说法,再拼成一份拆解:每条主张都有来源、日期和状态。
复制 prompt
把方括号里的字段替换掉,然后粘贴到 Claude Code、Codex 或任何能访问终端的 AI。它会安装 Felo skill、在花额度前询问,并执行这套 workflow。
为[我们的产品]制作一份针对[竞品名称]的竞品拆解。 范围:[细分市场]、[地区]、[语言]。时间范围:[过去 90 天 / 过去 12 个月]。它支持的决策:[调价 / 发布定位 / 异议处理]。 起始来源:[竞品域名]、[定价页 URL]、[更新日志 URL]。 输出一份 Markdown 拆解,包含: 1. 他们如何定位自己,用他们自己的话。 2. 证据表:主张、来源标题、URL、日期、状态(Verified / Vendor claim / Third-party / Signal / Inference / Not verified)。 3. 定价:页面写了什么,附链接和核对日期。没有页面和日期,绝不把价格写进正文。 4. 买家在哪些地方反弹,附 X 账号和日期,并标注为信号。 5. 我们下一步该做什么,标注为建议。 6. 完整来源列表。 规则: - 引用他们的定位,不要改写成更强的说法。 - 区分厂商主张、第三方报道和你自己的推断,每一行都加标签。 - 不要编造价格、指标、客户名称或基准。数据缺失时写“暂无数据”。 - 把时间范围和地区落实为明确值。 - 消耗额度前,先展示计划执行的 API 调用并等待我批准。 - 不要发布、发送、排期,或写入任何 CRM。 - 将结果写入 ./competitor-teardown.md,并在对话中总结。
复制的内容也包含安装步骤和安全规则。
你会得到什么
一次运行的示例输出,不是实时生成。
竞品拆解 — [竞品],2026-10-30 核对
他们如何定位自己
首页标题:“为成长中的支持团队打造的平台。” 分类页:“支持团队需要的一切。” 两者都是厂商主张,按原文引用。
证据表
| 主张 | 来源 | 日期 | 状态 |
|---|---|---|---|
| 定位为平台而非单点工具 | https://example.com/competitor/home | 2026-10-30 | Verified |
| 每周发布变更 | https://example.com/competitor/changelog | 2026-10-28 | Verified |
| 被独立评测收录 | https://example.com/roundup | 2026-10-27 | Third-party |
| 买家提到上手慢 | 下文引用的 X 帖子 | 2026-10-14 | Signal |
| 企业是他们最大的细分 | 暂无数据 | — | Not verified |
定价
定价页列出分层方案和按量方案。这里不重复费率;查看实时页面和日期:https://example.com/competitor/pricing(2026-10-30)。
买家反弹的地方
@example_dev,2026-10-14:“安装比演示说的更久。” 一条带日期的帖子,是投诉,不是普遍性估计。
建议
在对比页上突出“到第一个结果的时间”。这是我们的推断,不是竞品主张。
来源
- https://example.com/competitor/home
- https://example.com/competitor/pricing
- https://example.com/competitor/changelog
实际调用
给开发者:同一套 workflow 的可复制代码,按执行顺序排列。
展开实际 API 调用
从有来源的基线开始
Chat 会返回答案和它用过的页面,相当于给你一张“竞品在哪里被讨论”的地图。把答案当成线索而不是来源:真正要保留的是链接,它们提供证据表里的第三方行。下面的 helper 只发送一次 Key,非 2xx 响应会抛错。
competitor.ts const BASE = "https://openapi.felo.ai"; const headers = { Authorization: `Bearer ${process.env.FELO_API_KEY}`, "Content-Type": "application/json", }; async function felo<T>(path: string, body?: unknown): Promise<T> { const res = await fetch(`${BASE}${path}`, { method: body ? "POST" : "GET", headers, body: body ? JSON.stringify(body) : undefined, }); if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`); return res.json() as Promise<T>; } type ChatData = { data: { answer: string; resources: { link: string; title: string; snippet: string }[]; }; }; const competitor = "Example Competitor"; const segment = "mid-market support teams"; const baseline = await felo<ChatData>("/v2/chat", { query: `How does ${competitor} position itself for ${segment}? Include pricing and recent launches.`, }); const seedSources = baseline.data.resources.slice(0, 5);示例输出
{ "answer": "The competitor positions itself as …", "sources": [ { "link": "https://example.com/competitor", "title": "…", "snippet": "…" } ] }抓取他们自己控制的页面
第三方报道告诉你别人怎么想,竞品自己的页面告诉你他们怎么宣称。用 readability 把首页、定价页和 changelog 抽成 Markdown,并给每个页面盖上抓取日期——没有日期的定价页是个陷阱。
competitor.ts type ExtractData = { data: { content: string } }; const ownedPages = [ { url: "https://example.com/competitor/home", title: "Homepage" }, { url: "https://example.com/competitor/pricing", title: "Pricing" }, { url: "https://example.com/competitor/changelog", title: "Changelog" }, ]; const fetched = await Promise.all( ownedPages.map(async (page) => { const res = await felo<ExtractData>("/v2/web/extract", { url: page.url, output_format: "markdown", with_readability: true, with_cache: true, }); const checkedAt = new Date().toISOString().slice(0, 10); return { ...page, checkedAt, content: res.data.content }; }), );示例输出
{ "url": "https://example.com/competitor/pricing", "checkedAt": "2026-10-30", "content": "# Pricing\n\nExtracted page text…" }看看买家在 X 上怎么说
在 X 搜索人们对竞品的异议和绕行方案。保留每个帖子的账号和日期;一条带日期的引语只是“有人抱怨过”的证据,不是“有多普遍”的证据,所以拆解把它标为信号,绝不把几条帖子变成百分比。
competitor.ts type XData = { data: { tweets: { content: string; author: { username: string }; created_at: string; metrics: { retweet_count: number; favorite_count: number }; }[]; }; }; const since = Math.floor((Date.now() - 90 * 24 * 60 * 60 * 1000) / 1000); const buyerSignal = await felo<XData>("/v2/x/tweet/search", { query: `"${competitor}" (pricing OR onboarding OR migration)`, limit: 25, since_time: since, }); const objections = buyerSignal.data.tweets.slice(0, 5);示例输出
{ "data": { "tweets": [ { "content": "setup took longer than the demo suggested", "author": { "username": "example_dev" }, "created_at": "2026-10-14T09:20:00Z", "metrics": { "retweet_count": 3, "favorite_count": 24 } } ] } }用证据表组装拆解
这是编辑步骤:把抓到的页面和 X 帖子变成一条条主张,再给每条主张配来源、日期和状态。状态列让文档保持诚实——页面原文是
Verified,厂商营销是Vendor claim,外部报道是Third-party,带日期帖子是Signal,你的解读是Inference,缺证据是Not verified。competitor.ts const today = new Date().toISOString().slice(0, 10); const row = (claim: string, source: string, date: string, status: string) => `| ${claim} | ${source} | ${date} | ${status} |`; const teardown = [ `# Competitor teardown — ${competitor}`, `Scope: ${segment}. Checked ${today}.`, "", "| Claim | Source | Date | Status |", "| --- | --- | --- | --- |", row("Free tier listed on the pricing page", ownedPages[1].url, fetched[1].checkedAt, "Verified"), row("Positions as a platform, not a point tool", ownedPages[0].url, fetched[0].checkedAt, "Vendor claim"), row("Discussed in independent coverage", seedSources[0]?.link ?? "Not available", today, "Third-party"), row("Buyers report onboarding friction", "X post, quoted below", today, "Signal"), row("Most revenue comes from enterprise", "Not available", "—", "Not verified"), "", "## Recommendation", "Lead with time-to-first-result on the comparison page. Inference, not a competitor claim.", ].join("\n"); console.log(teardown);示例输出
| Free tier listed on the pricing page | https://example.com/competitor/pricing | 2026-10-30 | Verified |
存进 LiveDoc,供下次刷新
每个竞品建一个 LiveDoc,把抓到的页面作为 URL 资源加进去,再把拆解本身作为文档资源加进去。重复添加 URL 会自动去重,下一季度只需要抓变化的部分,上一季度的拆解仍和新内容放在同一个归档里。
competitor.ts type LiveDocData = { data: { short_id: string } }; const teardownDoc = await felo<LiveDocData>("/v2/livedocs", { name: `Teardown: ${competitor}`, description: `Sources and teardown checked ${today}`, }); await felo(`/v2/livedocs/${teardownDoc.data.short_id}/resources/urls`, { urls: fetched.map((page) => ({ url: page.url, title: page.title })), }); await felo(`/v2/livedocs/${teardownDoc.data.short_id}/resources/doc`, { title: `Teardown ${today}`, content: teardown, }); console.log(teardownDoc.data.short_id); // the next refresh reuses this LiveDoc示例输出
{ "short_id": "PvyKouzJirXjFdst4uKRK3" }
包含什么
- 来自 Chat API 的有来源基线,以及答案背后的页面
- 竞品首页、定价页和 changelog 的 Markdown 提取
- X 上带日期的买家评论,标记为信号而不是证据
- 把已核实事实、厂商声明和推断分开的证据表
- 保存来源的 LiveDoc,下一次刷新不用从零开始
不做什么
- 只覆盖公开来源;不做赢单/输单访谈、CRM 备注或私有看板
- 价格只做链接和日期,不把费率冻结进没有检查日期的表格
- X 覆盖不完整,不代表买家的有代表性样本
- 它不会替你决定定位;建议会明确标为推断
- 它不会发布拆解,也不会写进 battlecard 工具
常见问题
证据从哪里来?
Chat API 返回有来源的基线及其用过的页面,Web Fetch 把竞品自己的页面转成 Markdown,X Search 补充带日期的买家帖子。每一行都保留来源和日期,推断单独有状态。
可以同时覆盖多个竞品吗?
可以。每个竞品跑一次同样的 prompt,并为每家公司保留一个 LiveDoc。做对比页时只拼接标记为“已验证”的行,不要把两次运行的证据混在一起。
可以直接引用竞品价格吗?
workflow 会记录定价页上写了什么,并附上链接和检查日期。它不会把费率写死成文字,因为厂商价格会变,过时的数字比没有数字更糟。
我们自己的赢单/输单笔记能用吗?
它只读公开来源。把内部笔记作为单独的文档资源加进 LiveDoc,并标记为内部;这些内容不会出现在面向客户的材料里。
应该多久刷新一次?
按触发条件刷新,而不是按日历:价格变化、产品发布或销售周期开始时。对同一个 LiveDoc 重跑 workflow,让上一季度的拆解留在新拆解旁边方便对比。
一份拆解要花多少?
每次 chat、抽取和 X 搜索都会消耗按量计费的额度;当前费率在价格页面。prompt 会在花额度之前请求确认。
相关 workflow
改成你的版本
同一套配方,按你实际的交付方式调整。
按触发条件刷新,而不是按日历
竞品改价、发布重要版本或大型销售周期开始前,重跑同一套 workflow。每份拆解都作为带日期的文档资源留在同一个 LiveDoc 里,下一季度和上一季度并排,而不是覆盖。
把拆解变成 battlecard
用同一张证据表,按角色各写一页——经济买家、拥护者和技术评审——只使用 `Verified` 行,并保留链接。任何面向客户的材料都不要放 `Inference`。
把两个竞品并排比较
每个竞品各跑一次,使用独立的 LiveDoc;然后做一张只拼接两次运行都标记为 `Verified` 的对比页。没有状态列时,绝不把两次运行合并成一张证据表。
继续深入
这套配方背后的参考页面,以及下一步可以看什么。