agent已上线

Game Market Intelligence Agent

用AI Agent自动生成游戏竞品周报

构建多步骤 Agent,自动抓取竞品数据、生成分析报告并推送至飞书群组

FastAPIReactDashScope/QwenSensorTower API飞书 Webhook

SensorTower 射击品类竞品监控 Agent

项目背景

我在 FunPlus 做 Guns of Glory 海外运营那几年,竞品监控是每周必做的工作。流程很固定:登录 SensorTower 后台,手动查 10-20 款竞品的收入、下载、排名变化,截图粘贴到 PPT 或飞书文档,再写一段分析。一个熟练的运营同学做这件事大概需要 2-3 小时,但产出的信息密度其实不高——大部分时间花在了"搬运数据"上,而不是"分析数据"。

更麻烦的是信息滞后。等你周二把周报整理完发出来,竞品周末的版本更新、突然的收入飙升这些信号已经过了最佳反应窗口。运营团队拿到的是"上周发生了什么",而不是"现在正在发生什么"。

这个项目的出发点很直接:把运营团队从数据搬运中解放出来。用 Agent 自动拉取 SensorTower 数据,检测异动,生成带分析的周报,推送到飞书群——让运营同学的精力回到"该怎么应对"而不是"发生了什么"。

问题定义

把上面的痛点翻译成产品需求,核心是四件事:

自动化数据采集。 18 款射击/战术竞技品类竞品,覆盖收入、下载、DAU、国家分布、版本更新,双平台(iOS + Android),每周自动拉取并对齐到自然周(周一到周日)。这不是简单地调一个 API——SensorTower 有 6 req/s 的限流,数据分散在多个接口,iOS 和 Android 的字段格式不同,收入单位是 cents 需要转换,DAU 接口不支持跨平台聚合。

可读的分析报告。 不是一张 Excel 表,而是一份有结论、有重点、有数据支撑的周报。运营团队需要的是"本周谁涨了、为什么涨了、我们该关注什么",不是 18 款游戏的原始数据罗列。

推送到团队工作流。 我们团队用飞书,报告需要直接推送到飞书群,以消息卡片的形式呈现,不需要额外打开任何工具。

支持探索性查询。 周报是固定产出,但运营过程中随时会有临时问题:"PUBG Mobile 上周在沙特的收入多少?""Blood Strike 最近有版本更新吗?"这些查询不可能提前预设,需要一个能理解自然语言、自主决定调用哪些数据接口的 Agent。

方案设计

这个项目最核心的架构决策是双模式设计:周报走 Rules-based Pipeline,手动查询走 Agentic Function Calling。这不是因为"两个都想做",而是因为两个场景对可靠性的要求完全不同。

周报每周发给整个团队,数字错了会被质疑、会影响决策。所以周报的数据拉取、聚合、排序、对比全部用固定代码实现,LLM(Qwen)只负责最后一步——基于结构化数据写一段分析叙事。这就是 Data Grounding 原则:所有数字来自 API,LLM 只做解读不做计算。 即使 Qwen 服务挂了,周报照样能降级为纯数据版本发送。

手动查询的输入是不确定的——用户可能问收入、问 DAU、问某个国家的明细、问版本更新,甚至可能问一个需要多个数据源交叉分析的复杂问题。这种场景需要 LLM 自主判断"该调哪些工具、传什么参数、要不要追加查询",这才是 Agent 的价值所在。

为什么用原生 OpenAI Function Calling 而不是 LangChain/LangGraph?两个原因。第一,这个 Agent 的工具集只有 5 个,调用链最多 8 轮,不需要复杂的编排框架,原生 Function Calling 循环 50 行代码就够了。第二,面试时我需要能清晰地解释"Agent 内部在做什么"——用框架会把核心逻辑藏在黑盒里,原生实现意味着每一步我都能讲清楚。

技术架构

整体架构分四层:

交互层是飞书 Bot,接收用户的 @消息,路由到不同处理路径——"生成周报"走 Pipeline,"确认发送"走推送,其他自然语言走 Agentic 查询。

编排层是 FastAPI 后端,包含两个核心组件。Report Generator 负责周报的固定流程:拉取本周和上周数据 → 聚合对比 → 找出 Top 3 变化 → 查版本更新 → 传给 Qwen 生成叙事 → 拼装飞书消息卡片。Agent Orchestrator 负责手动查询:将用户问题和工具定义发给 Qwen → Qwen 返回 tool_calls → 执行对应的 SensorTower 查询 → 将结果返回给 Qwen → 重复直到 Qwen 给出最终回答。

数据层是 SensorTower API Client,封装了 sales_report_estimates(收入/下载)、active_users(DAU)、version_history(版本更新)等接口,统一处理了 rate limit 控制(信号量 + 170ms 间隔)、双平台数据合并、cents → USD 转换、国家代码标准化等脏活。

推送层是飞书 Bot API,支持两种模式:Webhook 推送(群消息卡片)和消息回复(对话场景)。周报用 Interactive Card 格式推送,包含报头、执行摘要、Top 3 增长、核心指标明细等结构化板块。

信息流可以用一句话概括:用户指令(或定时触发)→ 数据拉取(SensorTower,5-6 秒)→ 数据聚合与对比(Rules-based)→ LLM 分析(Qwen,叙事生成)→ 飞书卡片推送。

核心功能

1. 竞品观察列表管理

预设 18 款射击/战术竞技品类竞品,包括 PUBG Mobile、Free Fire、Call of Duty Mobile、Delta Force、Arena Breakout 等。列表通过 YAML 配置文件管理,支持热更新。每款游戏自动映射了 SensorTower 的 Unified App ID 和双平台 Platform App ID,覆盖了中国大陆 iOS only 的特殊情况(如和平精英、明日之后的 Android 数据不经 SensorTower 覆盖)。

2. 自动数据采集与聚合

每次生成周报时,系统按平台批量拉取所有竞品的收入、下载、DAU、国家分布数据,对齐到精确的自然周窗口(周一至周日),并自动计算周环比。批量化设计将 API 调用从最初的 80-100 秒优化到 5-6 秒。对收入和下载 Top 3 变化的产品,额外查询版本更新信息用于关联分析。

3. LLM 生成周报分析

Qwen 3.5 Plus 基于结构化数据生成执行摘要——用 2-4 条洞察概括本周最重要的变化。关键设计:LLM 不接触任何数字计算,只接收已经算好的结构化 JSON,所有数字引用必须来自数据。如果 Qwen 服务不可用,系统降级为 Rules-based 纯数据版周报。

4. 飞书消息卡片推送

周报以 Interactive Card 格式推送到飞书群,包含报头(周期、数据口径)、执行摘要、收入/下载 Top 3 增长、版本更新动态、全部 18 款竞品的核心指标明细(收入、下载、DAU、ARPDAU、Top 3 收入国家)。整个流程支持 Human-in-the-loop:先生成预览 → 发送修改意见可重新生成 → 确认后才正式推送到群组。

5. Agentic 自然语言查询

在飞书中用自然语言提问,Agent 自主选择调用 SensorTower 工具并返回分析。例如"PUBG Mobile 上周在沙特收入多少"会触发 get_revenue_by_country 工具,"对比 Free Fire 和 CODM 的 DAU"会触发两次 get_game_dau 调用。Agent 基于 OpenAI Function Calling 协议实现,最多 8 轮工具调用,30 秒超时保护。

Failure Modes 与兜底设计

这是我在这个项目中最重视的部分。大多数 AI demo 只展示 happy path,但一个真正可用的 Agent 系统,80% 的工程量花在处理"出错时怎么办"。

API 限流与配额控制

SensorTower API 限制 6 requests/second,18 款竞品 × 双平台 × 多维度数据意味着每次周报需要几十次 API 调用。解决方案:asyncio Semaphore 控制并发上限为 5(留 1 个 buffer),每次请求后 sleep 170ms,429 状态码指数退避重试。同时从响应 header 中提取 x-api-usage-count / x-api-usage-limit 监控月度配额,接近上限时可降级为缓存数据。

数据缺失的优雅降级

中国大陆安卓市场不走 Google Play,SensorTower 无法覆盖。系统在设计层面接受 android_app_id = null,在报告开头明确标注数据口径"全球 iOS + 海外 Android(不含中国大陆安卓渠道)"。对任何单款游戏数据获取失败,标注"数据暂不可用",不影响其他游戏的报告生成。

LLM 幻觉防护(Data Grounding)

这是整个项目最核心的设计原则。周报中的所有数字——收入、下载、DAU、环比、ARPDAU、国家排名——全部由 Rules-based Pipeline 从 API 原始数据计算得出,LLM 不参与任何数值计算。Qwen 只接收算好的结构化 JSON,prompt 中明确要求"所有数字必须引用自提供的数据,不要编造"。如果 Qwen 在叙事中引入了数据中不存在的数字,那是 prompt 的问题,不是架构的问题——这个边界很清晰。

Agent 无限循环保护

Agentic 查询路径设置了 MAX_TOOL_ROUNDS = 8 的硬上限和 30 秒的全局超时。如果 LLM 反复调用同一个工具或陷入无效循环,会在达到上限时返回友好提示。这个设计参考了 OpenAI 和 Anthropic 自身 Agent 系统的实践。

Qwen 服务不可用降级

如果 DashScope API 超时或返回错误,周报自动降级为纯数据版本——包含所有结构化指标,只是没有 AI 生成的执行摘要。数据的价值不依赖于 LLM 的可用性。这也是为什么选择"LLM 叠加在 Rules-based 之上"而不是"LLM 驱动整个流程"的根本原因。

演示安全网

面试或演示场景下,SensorTower/Qwen 任何一个服务出问题都可能导致尴尬。系统在每次成功生成周报后自动缓存一份快照到本地文件,提供一个独立的推送端点可以直接从缓存发送,完全不依赖外部 API。

PM 复盘

Agent 系统的核心挑战不是让它跑起来

让 Agent 调用工具返回结果,用 Function Calling 写一个循环就行,技术门槛不高。真正的挑战是:当 API 限流了怎么办?数据缺失了怎么办?LLM 编造数据了怎么办?Agent 陷入死循环了怎么办?这些 failure modes 的处理占了整个项目 70% 以上的工程量,也是这个项目最有面试谈资的部分。做 AI PM,不是要证明"我能让 AI 跑起来",而是要证明"我知道 AI 会在哪里出错,以及出错时该怎么办"。

Function Calling vs LangGraph 的取舍

这个项目一开始就决定不用 LangChain/LangGraph,用原生 OpenAI Function Calling 协议。原因有两个。工具集只有 5 个,调用链最深 8 轮,不需要有向图编排。更重要的是,原生实现意味着每一行代码我都能解释清楚——Agent 怎么决定调什么工具、工具结果怎么回传给 LLM、什么时候终止循环。面试时面试官追问 Agent 内部逻辑,我可以直接画出来。如果用了框架,回答就变成了"LangGraph 帮我处理了",这不是 PM 应该有的答案。

双模式架构是产品判断,不是技术妥协

一开始我想让 Agent 驱动整个周报流程——LLM 自己决定调哪些 API、按什么顺序聚合、怎么生成报告。后来发现这在 demo 里很酷,但在实际使用中不可接受:每次生成的周报格式不一致,偶尔会漏掉某些竞品的数据,数字偶尔会对不上。最终选择了"周报走 Pipeline,查询走 Agent"的双模式架构。这不是因为 Agent 能力不够,而是因为周报这个场景的用户预期是"稳定、准确、每次格式一致",而 Agent 的价值在于处理不确定的探索性问题。知道什么时候不用 Agent,和知道什么时候用 Agent,一样重要。

产品化 vs Demo 的边界

这个项目是面试 demo,不是生产系统。我很清楚哪些东西做了(数据准确性、容错降级、真实 API 调用),哪些东西有意识地没做(持久化存储、自动定时推送、多用户支持、完整的监控体系)。做 demo 的诀窍不是"做得多",而是"核心链路做得深"——一条完整的数据拉取 → 分析 → 推送链路,比十个半成品功能有说服力得多。

版本更新

vv0.1最新2025-12

SensorTower API Client 与数据采集基础

搭建 FastAPI 后端骨架,完成 SensorTower API 封装,实现 18 款竞品的收入与下载数据批量拉取

  • ·封装 SensorTower sales_report_estimates / active_users / version_history 接口
  • ·实现 asyncio Semaphore + 170ms 间隔的 rate limit 控制
  • ·完成 YAML 竞品配置文件,映射 Unified App ID 与双平台 Platform App ID
  • ·处理 iOS/Android 字段差异、cents → USD 转换、国家代码标准化