上个月接了个需求,某消费品团队想实时盯住自家品牌在几大社交平台上的讨论,尤其担心夜间出现负面内容没人发现。手动刷当然不现实,我就用 OpenClaw 搭了一个 7×24 小时在跑的 Agent。这个 Agent 到现在稳定跑了三周,平均每天处理上万条公开信息,真正需要人工介入的只有几十条。这篇我就把整个搭建过程、稳定性处理和踩过的坑一次性说清楚,如果你也在琢磨“XX平台出了事我要第一时间知道”,这篇文章应该能帮你少走不少弯路。
先说明一下:这个方案里的“监测”只针对公开信息,比如公开帖子、公开评论、搜索结果页,不涉及任何私信、加密群组或需要绕过权限的内容。合规是底线,这一点后面我会单独展开。
无论你是做品牌公关、竞品分析,还是想给自己的产品加一个舆情预警能力,都可以按这篇文章的步骤来。我会从需求边界讲起,一直讲到怎么让它稳定跑几个月不崩。
1. 先想清楚:你要监测的是什么,边界在哪里
1.1 从“监控焦虑”到“监测需求”
很多人找到我说“我要监控全网”,但等我追问“具体监控什么关键词”“发现了之后要做什么动作”的时候,对方往往答不上来。这其实不是一个工具问题,而是需求没拆解清楚。
我习惯把这件事分成四层:
- 品牌层:自己的品牌词、产品词、官方账号名,防止负面发酵或消费者投诉没被响应。
- 竞品层:竞品的新功能发布、促销活动、用户评价变化,用来做动态调整。
- 行业层:行业关键词、监管动态、热门事件,用来判断趋势和借势机会。
- 执行层:监测到之后触发什么动作——通知群里、生成工单、记入报表,还是自动回复。
后面三层,每一层的关键词策略和采集频率都不一样。品牌词可以做到分钟级,竞品词可能分钟级,行业词小时级就够了。如果不分轻重全都每秒跑一遍,既浪费资源,也容易被平台限流。
1.2 合规边界:只做公开数据的“聚合”,不做私域“窃取”
在动手写代码之前,我最想强调的就是合规。很多平台在服务条款里明确写了禁止未经许可的大规模自动化采集,所以我的原则非常保守:
- 只使用开放式搜索接口、公共RSS、以及页面里不需要登录就能看到的公开信息;
- 不破解任何加密参数,不绕过验证码,不伪造登录态;
- 控制请求频率,设置 User-Agent 和合理的间隔,模拟真实用户的浏览节奏;
- 数据使用上只做聚合分析,不存储不必要的个人敏感信息。
为什么要这么较真?因为“社交监测 Agent”听起来很酷,但它本质上是一个自动化数据管道。你永远不知道某个平台的接口哪天会发生什么变化,一旦因为违规采集被封了账号或收到法务函,前面的所有投入都白费了。所以我宁可在功能上做取舍,也要保证整个方案干干净净。
如果你要监测的内容属于私密群聊、需要特定权限才能看,那这个工具不是为那种场景设计的,也不应该这么用。我的建议是:如果你做的监测可能涉及第三方隐私,先把需求拿给法务或熟悉数据合规的同事过一遍,再决定技术怎么落地。
2. OpenClaw 的定位:它是 Agent 编排器,不是传统爬虫
2.1 它解决的核心问题
我自己早期也写过一些零散的采集脚本,命令刷一下,抓完存进数据库,然后设一个 crontab。问题是,这种脚本组合非常脆弱:今天是有效的结果,明天页面结构一改就抓回来一堆空数据;偶尔一个异常没处理,进程挂了,整套链路就静默失效了。
OpenClaw 给我的感觉是,它把“定时抓取、解析清洗、去重过滤、存储通知、失败重试、运行监控”这些事情封装成了一个有状态的 Agent 工作流。你只需要定义任务和规则,框架会负责任务的调度、状态持久化和异常恢复。它不像传统爬虫那样只解决“怎么把网页拉下来”,而是解决“怎么让一条数据管道稳定地长期运转”。
这就好比,普通爬虫是给你一辆车,OpenClaw 是给你一套带司机的车队管理系统——不仅要跑得快,还要知道什么时候加油、什么时候保养、哪辆车坏了怎么让别的车顶上。
2.2 最小安装与环境准备
我的安装方式很简单,直接用包管理器拉起:
pip install openclaw如果你想从源码运行,也可以拉取项目仓库后执行初始化命令:
git clone <你的OpenClaw版本仓库地址> cd openclaw python -m openclaw init social-monitor这里的初始化命令会生成一个social-monitor工作目录,里面包含默认配置文件openclaw.yaml、任务是目录、插件目录和日志目录。装完之后跑一下自检:
openclaw doctor它会告诉你环境变量、Python 版本、依赖包和数据库连接是否都正常。我的经验是,第一次跑doctor大概率会提示缺少 Redis 或 SQLite 驱动之类的,直接补装就行。
2.3 核心抽象:任务、循环、管道
OpenClaw 给我的体感是,它把一套长期运行的 Agent 拆成三个层次:
- 任务(Task):一个可以被调度的最小工作单位,比如“抓取某平台关键词页”“清洗上一步抓到的数据”“把高优先级内容发到群里”。
- 循环(Loop):任务按周期反复执行的调度器,支持 cron 表达式和固定间隔两种模式。真正要做到 7×24,不是只设一个定时任务那么简单,而是需要在循环里处理超时、重试和续跑。
- 管道(Pipeline):多个任务按顺序连接起来,前一个任务的输出作为后一个任务的输入。管道状态会持久化,Agent 中途崩溃重启后,可以从上次中断的位置继续跑,而不是全部重来。
默认的openclaw.yaml长下面这样:
agent: name: social-monitor timezone: Asia/Shanghai loop: tick_interval: 60 retry_interval: 300 max_retries: 5 pipeline: - name: collect type: source - name: parse type: parser - name: filter type: filter - name: store type: sink - name: notify type: messenger看起来很简单,但底层已经把“每 60 秒跑一轮、失败后 300 秒重试、最多 5 次”的机制准备好了。你不需要自己写 while True 循环,也不用担心 while 循环里的一个异常让整个进程退出。这个抽象,是它比裸脚本稳定很多的核心原因。
3. 搭建第一版关键词监测 Agent:四步跑通
3.1 定义监测关键词和检索规则
我执行的第一个版本只盯一个场景:某品牌名 + 产品型号的负面舆情预警。关键词我分了三种:
- 精确词:例如品牌官方名称和产品全称,用于召回最相关的讨论。
- 模糊词:例如常见缩写或错别字变体,因为用户不会每次都打完整品牌名。
- 组合词:例如品牌名 + “投诉/垃圾/避雷/退货”,用逻辑与缩小检索面。
关键词不是越多越好。一开始如果直接塞五十个关键词,Agent 跑起来会发现数据量爆炸且噪音极大。我建议从五个以内开始,跑两天看结果,再逐步扩展。
检索规则在 OpenClaw 里是以配置文件管理的。以自定义搜索源为例:
sources: - name: demo_brand_search type: search endpoint: url: "https://api.example.com/search" method: GET params: q: "{keyword}" count: 20 interval: 300interval: 300表示每 300 秒执行一次。对品牌词来说,5 分钟一轮已经足够快了;如果你真的到了必须秒级响应的程度,那意味着监控成本会非常高,而且大概率会被平台限流。
3.2 写一个源适配器:采集与字段标准化
OpenClaw 的源适配器,说白了就是告诉你“怎么接收外部数据”。它支持两种方式:一种是主动拉取,一种是收到 webhook 后触发。我第一版用的主动拉取,因为简单。
下面是我写的一个极简源适配器,作用是调用搜索接口并把结果转成统一字典:
import hashlib import time import requests from openclaw.sources import BaseSource class DemoSearchSource(BaseSource): def __init__(self, name, endpoint, params, interval=300, **kwargs): super().__init__(name=name, interval=interval, **kwargs) self.endpoint = endpoint self.params = params def fetch(self): session = self.session_with_policy() resp = session.get(self.endpoint["url"], params=self.params, timeout=15) resp.raise_for_status() items = resp.json().get("data", {}).get("items", []) normalized = [] for it in items: link = it.get("url") or it.get("link") title = it.get("title") or "" content = it.get("content") or title published = it.get("publish_time") or int(time.time()) normalized.append({ "source_id": hashlib.md5(link.encode("utf-8")).hexdigest(), "platform": self.name, "title": title, "content": content, "url": link, "published_at": published, "extra": {}, }) return normalized注意source_id我用的是 URL 的 MD5,这是最基础的去重键。同一篇文章在不同平台可能 URL 不同,那要靠后面的内容去重解决,这里先保证同一个链接不会重复入库。
还有一点:session_with_policy()是 OpenClaw 提供的方法,它会自动帮你带上请求间隔、重试和 User-Agent 策略。如果我自己写,十有八九会忘掉请求头,被平台当成机器流量。
3.3 设置调度循环:真·7×24 的启动姿势
我最想强调的是:不要用系统 crontab 直接跑这个 Agent,至少不要只靠 crontab。原因有两个:
- 如果进程因为意外 OOM(内存溢出)挂了,crontab 不会自动把它拉起来,除非额外配置
@reboot,但当时进程也不会重启。 - 如果一次运行时间超过了 cron 的间隔,会产生任务堆叠,两个进程同时跑同一个任务,数据重复、状态错乱。
OpenClaw 自带的运行方式是我比较推荐的:
openclaw run social-monitor --detach--detach会让 Agent 以守护进程方式运行,支持自动重启。你还可以用:
openclaw status social-monitor查看执行周期、上次成功时间、失败次数。我习惯每天早上一上班先看一眼状态页,如果有任务失败,状态页会直接标红。
如果你更信任 systemd,也可以把openclaw run social-monitor写进 service 文件并设置Restart=always。不过需要注意,systemd 强杀进程后,如果 OpenClaw 的任务状态文件没有被正常写入,重启后可能会从较旧的位置续跑。为了安全,我最终选择了 OpenClaw 自带的守护进程模式,它会把任务游标和进度写入数据库,重启后能精准续跑。
3.4 接入通知:结果主动来找你
Agent 如果只是默默存数据,那依然要人工去查,价值就少了一半。我第一版直接把通知接到团队用的即时通讯机器人上,实现了“高优先级的消息自动推群”。
通知配置长这样:
messengers: - type: webhook name: team_bot url: "https://example.com/hooks/your-bot-token" template: | 【社交监测】发现疑似负面内容 平台:{platform} 标题:{title} 链接:{url} 发布时间:{published_at} 关键词命中:{matched_keywords} filters: - type: keyword words: ["投诉", "质量", "售后退款", "曝光"]配置里的filters是我特别推荐加的,别一上来所有内容都推送。否则你会在凌晨三点被几十条“品牌名+正常讨论”的消息吵醒,然后赶紧爬起来看一眼,发现只是个普通用户晒单。我后来把过滤条件收紧到“命中负面词 + 发布 30 分钟内 + 互动量超过阈值”才推消息,噪音一下子少了很多。
4. 进阶一:多源汇聚、去重和热度判断
4.1 多平台字段统一
跑通单一数据源之后,接入第二个平台就顺理成章了。但是每个平台的返回结构都不太一样,有的字段叫content,有的叫desc,有的叫text;时间戳有的是毫秒,有的是秒,还有的是字符串。
我的做法是在每个源适配器里,把数据全部转成统一格式:
| 字段 | 类型 | 说明 |
|---|---|---|
| source_id | string | 内容唯一标识,用于硬去重 |
| platform | string | 来源平台标识 |
| title | string | 标题或首段文字 |
| content | string | 正文内容 |
| author | string | 作者显示名 |
| url | string | 永久链接 |
| published_at | integer | 发布时间,Unix 秒级时间戳 |
| extra | dict | 扩展字段,比如点赞、评论、转发数 |
统一字段的价值在于,后续的过滤器、去重器、通知模板都可以复用同一套逻辑。我后来加了第三个数据源,只写了一个新的源适配器,后面所有流程一行没改。
4.2 相似内容去重
同一篇新闻报道会被不同账号在多个平台复制粘贴;同一条微博被转来转去内容也差不多。如果不去重,通知群里会出现一堆“同一件事的 N 个副本”。
我用的是 OpenClaw 内置的 SimHash 去重组件,实现思路很简单:
from openclaw.deduplicators import SimHashDeduplicator dedup = SimHashDeduplicator( fields=["title", "content"], threshold=4, ) def process(item: dict) -> dict: item["dedup_key"] = dedup.compute(item) return itemthreshold=4意味着两篇内容的汉明距离小于等于 4 时,判定为相同。这个值需要根据数据量调整,设太小会漏重,设太大可能把两篇相关但不相同的讨论误并。我调了几轮,最终在品牌舆情场景下觉得 4 最合适。
去重之后,同一个热点事件只会保留一个代表内容进入后续提醒流程。如果你想观察事件演化,可以把重复内容计数加一,而不是直接丢弃。
4.3 热度评分与优先级排序
如果只是把负面帖子推出来,那运营看到一条就要处理一条,还是不够聪明。我加了一个简单的热度分,让 Agent 只推送真正值得马上响应的内容。
热度分公式大概长这样:
score = log2(comments * 1.5 + shares * 2 + likes * 0.5 + 1) * time_decay_factor其中time_decay_factor按发布时间衰减,规则是:发布 1 小时内衰减系数为 1,1-6 小时降为 0.8,6-24 小时降为 0.5,24 小时以上降为 0.2。
这个公式没什么高级算法,但足够管用:点赞转发多、发布时间又近的内容,分数自然高;一条三年前的旧帖即使突然有人评论,时间衰减也会把它压下去。
我在管道里加了一步排序:
pipeline: - name: score type: scorer rule: hybrid threshold: 5.0 weight: comments: 1.5 shares: 2.0 likes: 0.5只有score大于等于 5 的内容才进入通知模块。这个阈值也要看你们的处理能力,团队人工响应多就调高一点,响应快就可以调低。
5. 进阶二:长期运行的稳定性,比功能更磨人
5.1 内存泄漏和连接池耗尽
Agent 刚跑起来的两天一切正常,但到第三天,OpenClaw 状态页显示内存占用从 300MB 涨到了 1.2GB,再过半天直接 OOM 被系统杀掉。
我排查后定位到两个常见问题:
- 源适配器里的
requests.Session如果反复创建而不关闭,底层连接池会越积越多; - 通知消息模板拼接后没有清理缓存,积累了大量字符串对象。
解决办法也很简单:不要在外面手动创建全局 Session,直接用self.session_with_policy(),它自己会处理连接复用和关闭;另外在循环里定期调用内存回收。
OpenClaw 里可以设置循环内的软重启:
loop: tick_interval: 60 soft_restart_interval: 86400soft_restart_interval: 86400表示每 24 小时让 worker 优雅重启一次,清掉累积状态。这不影响任务游标,因为游标存在数据库里,重启后继续跑即可。跑了两周之后,内存曲线一直很平稳。
5.2 接口变更、字段缺失和解析容错
社交平台的页面结构隔三差五就会改一次。如果解析逻辑太刚性,比如硬编码了某个 CSS 选择器,那平台一改版,这个 Agent 抓回来的就是一堆空值。
我的第一个版本就经历过某平台改版后,返回的 JSON 里desc字段变成了abstract,当时我的解析代码报KeyError,任务直接失败。但因为管道有重试机制,它每 5 分钟重试一次,一直报了二十几次,我才从日志里发现。
后来我给自己定了一条规矩:解析模块必须做多级兜底。
def safe_get(item, keys, default=""): for k in keys: if item.get(k): return item[k] return default取正文时尝试多个字段名:desc、abstract、text、content。取发布时间时同样做归一化处理,兼容秒、毫秒和 ISO 字符串。这样平台改字段名时,最多丢一些辅助信息,核心链路不会挂。
5.3 频率限制一定要当回事
有些数据源会在同一 IP 请求次数过多时返回 429 状态码。第一次遇到时,我还以为是对方故障,后来看日志才发现是我们自己的请求太密了。
我后来在配置文件里统一调低了采集频率:
policy: max_requests_per_minute: 20 backoff: initial: 2 multiplier: 2 max_backoff: 600当收到 429 或特定错误码时,OpenClaw 会按指数退避策略休息,从 2 秒开始,翻倍到最多 10 分钟。这个策略看起来是“慢”,但长期跑下来反而是最稳的。
有一个反直觉的经验:监测 Agent 的采集频率,做到“够用就行”。品牌词 5 分钟一轮,行业词 30 分钟一轮,已经覆盖 99% 的场景了。你不需要秒级,秒级采集只会让你更快被限制,而且数据量暴增之后分析成本也跟着涨。
5.4 给 Agent 本身也装上“监控”
既然是 7×24 的工具,那它自己也会出问题。我不可能 24 小时盯着状态页,于是给 Agent 加了两层自监控:
- 心跳机制:用 OpenClaw 内置的 Heartbeat,每 5 分钟向一个状态数据库上报一次心跳。如果心跳超过 15 分钟没有更新,我就知道 Agent 可能挂了,管理后台会发出告警。
- 日志水位:每天凌晨检查日志大小和磁盘剩余空间,超过阈值就自动轮转压缩。这个比想象中重要,我遇到过日志文件把磁盘写满导致所有任务停摆的尴尬情况。
这层“元监控”听起来像是绕圈子,但非常值得做。因为你搭的 Agent 越是自动化,它对运维的可见性就越重要。你不可能永远在旁边盯着它,所以必须让它把“自己还活着”这件事变成一个可观测的指标。
6. 写在后面:投入与边界
这套 Social Monitor Agent 从第一版到稳定运行,前后大概花了一周。单纯写代码可能三天就够,剩下四天基本都在调关键词、去重阈值、通知过滤条件和稳定性参数。
如果你也打算搭一个,我的建议是:先别追求大而全,选定一个平台 + 一个品牌词 + 一个通知群,用两三天跑通,再逐步加源和加规则。你会很快发现,最花时间的不是 Agent 本身,而是“到底什么样的内容需要通知人工”这个决策逻辑。
另外,OpenClaw 这类工具并不是银弹。它不会主动帮你判断一条内容是正面还是负面,也不会替你处理平台接口的复杂变化。它更像是把“跑数据管道”这件事做扎实的底座,让你能把精力放在数据解释和业务响应上。
我现在的扩展计划是:把热度评分再接一个简单的正负面词表,做成轻量情感倾向判断,出每周趋势报告;同时把竞品词和行业词接入同一套管道,让 Agent 从一个“品牌守护者”变成“行业雷达”。如果你也正在调类似的监测系统,欢迎把自己的踩坑经历和经验拿出来一起聊聊,很多时候别人的一条配置就能救回你一晚上的睡眠。