基于OpenClaw的主动消息系统架构思路分享

概述

在 AI 对话系统中,被动应答只能覆盖用户主动触发的场景。如何让 AI 在无用户输入时主动发起有质量的对话,是构建更自然交互体验的关键。

本文介绍一套运行在云服务器上的主动触发回复系统,基于 OpenClawcron 任务机制,实现「概率触发 → 话题选择 → 内容生成 → 发送+记录」的完整流程。系统具备可配置的权重体系、智能去重和多模式情感适配能力,已在实际生产环境中稳定运行。


系统架构

整体架构分为五个层次:

┌────────────────────────────────────────────────────┐
│                    Cron 触发层                      │
│         每天 9:00-22:00,每隔 30 分钟触发一次          │
└─────────────────────┬──────────────────────────────┘
                      │
┌─────────────────────▼──────────────────────────────┐
│                   概率决策层                         │
│         heartbeat_prob.py                          │
│         读上下文 → 推断情感模式 → 查表掷骰决定是否发送     │
└─────────────────────┬──────────────────────────────┘
                      │ 触发
┌─────────────────────▼──────────────────────────────┐
│                   话题选择层                         │
│         heartbeat_topic_roulette.py                │
│         两级掷骰:大类权重 → 小类权重                   │
└─────────────────────┬──────────────────────────────┘
                      │
┌─────────────────────▼──────────────────────────────┐
│                   内容生成层                         │
│         Web 搜索 → 格式化为自然语言 → 发送             │
└─────────────────────┬──────────────────────────────┘
                      │
┌─────────────────────▼──────────────────────────────┐
│                   日志记录层                         │
│         heartbeat_msg_sent.py                      │
│         记录已发内容,供去重检查和后续分析               │
└────────────────────────────────────────────────────┘

核心模块设计

1. 概率决策模块

核心思路:每次心跳触发时,先由 AI 阅读近期的对话上下文(最近的聊天记录或记忆文件),推断当前应使用哪种情感模式,再根据该模式查询对应时间桶的概率并掷骰决定是否发送。情感模式不只是概率,还影响后续的语气风格。

数据格式:每个情感模式配一个 JSON,time_buckets 用区间节点表示,只需填每个区间起点的概率。

{
  "mode_name": "默认",
  "time_buckets": {
    "09:00": 0.1,
    "12:00": 0.4,
    "17:00": 0.7,
    "21:00": 0.7
  }
}

含义:09:00 起概率 0.1 → 12:00 起概率 0.4 → 17:00 起概率 0.7 → 21:00 起概率 0.7,程序自动将每个值向下延伸覆盖对应区间。

多情感模式示例

[
  {
    "mode_name": "默认",
    "time_buckets": { "09:00": 0.1, "12:00": 0.4, "17:00": 0.7, "21:00": 0.7 }
  },
  {
    "mode_name": "热情",
    "time_buckets": { "09:00": 0.5, "13:00": 0.5, "17:00": 0.8, "21:00": 0.8 }
  },
  {
    "mode_name": "冷静",
    "time_buckets": { "09:00": 0.05, "12:00": 0.1, "17:00": 0.4, "21:00": 0.3 }
  }
]

说明:只需在区间起点填写概率,程序自动向下延伸至下一个节点之前。

代码实现

# heartbeat_prob.py

import random
from datetime import datetime

EMOTION_MODES_CONFIG = [
    {"mode_name": "默认", "time_buckets": {"09:00": 0.1, "12:00": 0.4, "17:00": 0.7, "21:00": 0.7}},
    {"mode_name": "热情", "time_buckets": {"09:00": 0.5, "13:00": 0.5, "17:00": 0.8, "21:00": 0.8}},
    {"mode_name": "冷静", "time_buckets": {"09:00": 0.05, "12:00": 0.1, "17:00": 0.4, "21:00": 0.3}},
]

def get_prob_for_bucket(bucket_str, time_buckets):
    """找到所有 <= 当前时间桶的节点,返回最近一个的值"""
    h, m = map(int, bucket_str.split(":"))
    target_minutes = h * 60 + m
    last_prob = 0.0
    for key, prob in time_buckets.items():
        h2, m2 = map(int, key.split(":"))
        if h2 * 60 + m2 <= target_minutes:
            last_prob = prob
    return last_prob

def should_trigger(emotion_mode):
    bucket = f"{datetime.now().hour:02d}:{(datetime.now().minute // 30) * 30:02d}"
    for cfg in EMOTION_MODES_CONFIG:
        if cfg["mode_name"] == emotion_mode:
            prob = get_prob_for_bucket(bucket, cfg["time_buckets"])
            roll = random.random()
            return roll < prob, roll, prob
    return False, 0.0, 0.0

概率日志

{
  "timestamp": "2026-05-18 11:15:00",
  "weekday": "周一",
  "time_bucket": "11:00",
  "emotion_mode": "默认",
  "probability": 0.5,
  "random_roll": 0.32,
  "triggered": true,
  "message_sent": true
}

情感模式影响概率和语气:每个模式对应不同的概率分布,AI 在生成内容时也会选择相匹配的语气——比如「默认」偏日常随意,「热情」更主动温暖,「冷静」则克制简洁。

2. 两级话题选择器

传统方案用单一权重表选择话题,容易出现两个问题:

  • 话题分布不均匀,高权重话题持续占主导
  • 相近话题反复出现,用户容易感到重复

本系统采用两级掷骰机制:

第一次掷骰:按大类权重选方向

大类 权重
游戏 20
新闻 20
体育 15
文化 15
日常 10

第二次掷骰:在同一大类内按相对权重选具体小类

# heartbeat_topic_roulette.py

SUB_WEIGHTS = {
    "游戏": [
        ("明日方舟", 20), ("终末地", 20),
        ("Steam游戏库", 15),
        ("Steam促销", 10), ("Steam新游戏", 10),
        ("Steam近期榜单", 10), ("游戏二创", 10),
    ],
    "新闻": [
        ("科技新闻", 20), ("奇闻轶事", 20),
        ("AI新闻", 15), ("数码产品新闻", 15),
        ("游戏开发新闻", 15),
        ("园林行业新闻", 10), ("游戏行业新闻", 10),
    ],
    # ... 其他大类
}

def roll_major():
    return weighted_choice(MAJOR_WEIGHTS)  # 第一次掷骰

def roll_sub(major):
    subs = SUB_WEIGHTS.get(major)
    return weighted_choice(subs)  # 第二次掷骰

同时掷出互动方式:提问 30% / 分享 70%,确保对话不是一边倒的访问式问答。

3. 智能去重机制

去重逻辑需精确到"大类+小类"的组合,而不仅是日期匹配。使用专用脚本检查:

# heartbeat_dedup_check.py

def main():
    major = sys.argv[1]
    sub = sys.argv[2]
    today = datetime.now().strftime("%Y-%m-%d")

    with open(LOG_FILE, "r") as f:
        for line in f:
            m = re.match(
                r"\[(\d{4}-\d{2}-\d{2})\] \[.*?\] \[.*?\] \[([^\]]+)\] \[([^\]]+)\] ",
                line
            )
            if m and m.group(1) == today:
                if m.group(2) == major and m.group(3) == sub:
                    print(f"DUPLICATE: {major} {sub}")
                    sys.exit(1)  # 重复,不发送

    print(f"OK: {major} {sub}")
    sys.exit(0)  # 不重复,继续

Cron 任务中通过 exit code 判断是否继续:

python3 heartbeat_dedup_check.py 游戏 Steam新游戏
# exit 1 → 结束任务,不发消息
# exit 0 → 进入内容生成步骤

4. OpenClaw Cron 配置

整个系统在 OpenClaw 的 cron 任务中编排:

{
  "schedule": {
    "kind": "cron",
    "expr": "15,45 9-22 * * *",
    "tz": "Asia/Shanghai"
  },
  "sessionTarget": "session:agent:<user-id>:qqbot:direct:...",
  "payload": {
    "kind": "agentTurn",
    "message": "【心跳主动聊天任务】\n\n第一步:读取近期对话上下文,由 AI 推断当前情感模式(如默认/热情/冷静)\n第二步:python3 heartbeat_prob.py <情感模式>\n第三步:两级掷骰选话题\n第四步:python3 heartbeat_dedup_check.py <大类> <小类>\n第五步:搜索相关信息\n第六步:按该情感模式的语气生成内容并发送\n第七步:记录日志",
    "timeoutSeconds": 600,
    "toolsAllow": ["exec", "message", "sessions_history", "web_search"]
  }
}

关键步骤

触发时间配置

Cron 表达式决定何时触发心跳任务,例如每小时的 15 分和 45 分触发(9:15 ~ 22:45 活跃时段),读者可按需自定义触发间隔和时段范围。示例:

15,45 9-22 * * *

全局概率系数

各时间桶的概率值填好后,还可以通过全局系数 PROB_COEFFICIENT 统一调节整体触发频率。该系数与时间桶概率相乘后再掷骰决定是否触发,初始值 1.0,效果不佳时可往下调(比如 0.5、0.3),不同情感模式也可配置不同的系数实现个性化平衡。

PROB_COEFFICIENT = 1.0  # 可按情感模式独立配置

# should_trigger 中:
final_prob = base_prob * PROB_COEFFICIENT
triggered = roll < final_prob

日志格式设计

发送记录日志采用可读格式,便于人工核查和脚本解析:

[2026-05-18 11:30] [默认] [11:30] [游戏] [Steam游戏库] 最近Steam夏促快到了,你有想买的吗?

概率日志采用 JSONL 格式,便于程序处理和后续分析。

话题权重配置

两级权重的设计使得话题分布既可控又具有一定随机性。大类权重决定长期趋势,小类权重决定每次选择的具体范围。调整时只需修改对应的列表,无需改动核心逻辑。


部署要点

环境要求

  • OpenClaw Gateway 已正常运行
  • Python 3 已安装,所需标准库(random、json、sys、pathlib 等)
  • 足够的磁盘空间存储日志文件

例:QQ Bot 接入

将 OpenClaw 对接到 QQ 机器人,实现心跳消息的主动发送,以下为大致流程,详情见各平台相关文档:

  1. 创建 QQ 机器人:在 QQ 开放平台创建应用,选择机器人类型,获得 AppID 和 clientSecret
  2. 启用 QQ 插件:在 OpenClaw 配置中启用 qqbot 插件(plugins.entries.qqbot.enabled: true
  3. 配置 channel:在 channels.qqbot 中填入 appIdclientSecret
  4. 配置路由绑定:添加一条 bindings 规则,将 qqbot 渠道的消息路由到指定的 Agent
{
  "channels": {
    "qqbot": {
      "enabled": true,
      "appId": "你的 AppID",
      "clientSecret": "你的 clientSecret"
    }
  },
  "bindings": [
    {
      "type": "route",
      "agentId": "<agent-id>",
      "match": { "channel": "qqbot" }
    }
  ]
}
搭建并接入QQ的效果

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
如果你有支持生成语音的模型:
在这里插入图片描述

目录结构建议

workspace/
└── heartbeat-agent/
    ├── scripts/
    │   ├── heartbeat_prob.py          # 概率决策
    │   ├── heartbeat_topic_roulette.py # 话题选择
    │   ├── heartbeat_dedup_check.py   # 去重检查
    │   └── heartbeat_msg_sent.py      # 发送记录
    └── logs/
        ├── heartbeat_probability_YYYY-MM.log  # 概率日志
        └── heartbeat_sent_content_YYYY-MM.log  # 发送记录

注意事项

  1. 时段限制:建议将触发时段限制在 9:00-23:00,睡觉的时候不发消息
  2. 沉默策略:概率未触发时应直接结束,不应发送无意义的"打卡式"消息
  3. 发送上限:每日同一小类只发一次,避免疲劳轰炸
  4. 超时处理:cron 任务设置合理的 timeoutSeconds,若使用联网搜索等工具频繁超时,可适当延长超时时间,如 600 s
  5. 日志清理:按月归档历史日志,避免磁盘占用持续增长
  6. 配置入口:主动发送消息的 Agent 入口需要配置正确,否则将无法正确接收消息
  7. 重要:模型使用:此架构后台耗费token可能较多,请选择性价比高的Token Plan后再搭建

扩展方向

当前系统已实现基础的心跳主动交互能力,以下方向可进一步探索:

  • 多模型路由:不同话题类型调用不同的模型,提高生成质量
  • 上下文记忆:结合更长的对话历史,避免重复提起近期讨论过的话题
  • 实时热点:接入新闻 API,让话题选择结合时事动态
  • 反馈闭环:统计哪些话题的回复率高,动态调整权重
  • Agent 性格塑造:通过长期对话和引导,让 Agent 逐渐形成特定的人格特质
    例如设定为「女朋友/男朋友」角色,让她每天主动分享日常、关注你感兴趣的话题、在语气和行为上呈现出连贯的亲密度和情感温度。
    情感模式的设置本身也可以作为性格塑造的一部分————比如在「暧昧」模式下语气更温柔、在「冷静」模式下保持克制但不冷漠。

总结

本系统通过概率触发 + 两级话题选择 + 智能去重的设计,在 OpenClaw 平台上实现了一套稳定运行的心跳主动交互系统。核心思路可归纳为三点:

  1. 概率驱动:用历史数据说话,让触发时机有据可依
  2. 分层选择:大类保方向,小类保具体,避免随机性和可控性的矛盾
  3. 去重兜底:宁可少发一条,不发重复一条

系统配置灵活,权重和情感模式均可按需调整

本文章仅分享架构思路及搭建要点,暂不提供详细搭建过程
如有疑问可以评论或私信,博主随缘回复,感谢浏览

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐