Felo API PlatformFelo API Platform

研究

做一份销售团队能直接用的竞品拆解

收集竞品自己的页面、围绕它的报道,以及买家在 X 上的说法,再拼成一份拆解:每条主张都有来源、日期和状态。

构建时间30 分钟难度进阶更新于2026-10-30
适合谁产品市场竞争情报销售赋能

复制 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/home2026-10-30Verified
每周发布变更https://example.com/competitor/changelog2026-10-28Verified
被独立评测收录https://example.com/roundup2026-10-27Third-party
买家提到上手慢下文引用的 X 帖子2026-10-14Signal
企业是他们最大的细分暂无数据—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 调用
  1. 从有来源的基线开始

    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": "…" }
      ]
    }
  2. 抓取他们自己控制的页面

    第三方报道告诉你别人怎么想,竞品自己的页面告诉你他们怎么宣称。用 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…"
    }
  3. 看看买家在 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 }
      }
    ] } }
  4. 用证据表组装拆解

    这是编辑步骤:把抓到的页面和 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 |
  5. 存进 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` 的对比页。没有状态列时,绝不把两次运行合并成一张证据表。

这套配方背后的参考页面,以及下一步可以看什么。