【OpenClaw】如何让你的龙虾有人味儿
基于OpenClaw的主动消息系统架构思路分享
概述
在 AI 对话系统中,被动应答只能覆盖用户主动触发的场景。如何让 AI 在无用户输入时主动发起有质量的对话,是构建更自然交互体验的关键。
本文介绍一套运行在云服务器上的主动触发回复系统,基于 OpenClaw 的 cron 任务机制,实现「概率触发 → 话题选择 → 内容生成 → 发送+记录」的完整流程。系统具备可配置的权重体系、智能去重和多模式情感适配能力,已在实际生产环境中稳定运行。
系统架构
整体架构分为五个层次:
┌────────────────────────────────────────────────────┐
│ 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 机器人,实现心跳消息的主动发送,以下为大致流程,详情见各平台相关文档:
- 创建 QQ 机器人:在 QQ 开放平台创建应用,选择机器人类型,获得 AppID 和 clientSecret
- 启用 QQ 插件:在 OpenClaw 配置中启用
qqbot插件(plugins.entries.qqbot.enabled: true) - 配置 channel:在
channels.qqbot中填入appId和clientSecret - 配置路由绑定:添加一条
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 # 发送记录
注意事项
- 时段限制:建议将触发时段限制在 9:00-23:00,睡觉的时候不发消息
- 沉默策略:概率未触发时应直接结束,不应发送无意义的"打卡式"消息
- 发送上限:每日同一小类只发一次,避免疲劳轰炸
- 超时处理:cron 任务设置合理的 timeoutSeconds,若使用联网搜索等工具频繁超时,可适当延长超时时间,如 600 s
- 日志清理:按月归档历史日志,避免磁盘占用持续增长
- 配置入口:主动发送消息的 Agent 入口需要配置正确,否则将无法正确接收消息
- 重要:模型使用:此架构后台耗费token可能较多,请选择性价比高的Token Plan后再搭建
扩展方向
当前系统已实现基础的心跳主动交互能力,以下方向可进一步探索:
- 多模型路由:不同话题类型调用不同的模型,提高生成质量
- 上下文记忆:结合更长的对话历史,避免重复提起近期讨论过的话题
- 实时热点:接入新闻 API,让话题选择结合时事动态
- 反馈闭环:统计哪些话题的回复率高,动态调整权重
- Agent 性格塑造:通过长期对话和引导,让 Agent 逐渐形成特定的人格特质
例如设定为「女朋友/男朋友」角色,让她每天主动分享日常、关注你感兴趣的话题、在语气和行为上呈现出连贯的亲密度和情感温度。
情感模式的设置本身也可以作为性格塑造的一部分————比如在「暧昧」模式下语气更温柔、在「冷静」模式下保持克制但不冷漠。
总结
本系统通过概率触发 + 两级话题选择 + 智能去重的设计,在 OpenClaw 平台上实现了一套稳定运行的心跳主动交互系统。核心思路可归纳为三点:
- 概率驱动:用历史数据说话,让触发时机有据可依
- 分层选择:大类保方向,小类保具体,避免随机性和可控性的矛盾
- 去重兜底:宁可少发一条,不发重复一条
系统配置灵活,权重和情感模式均可按需调整
本文章仅分享架构思路及搭建要点,暂不提供详细搭建过程
如有疑问可以评论或私信,博主随缘回复,感谢浏览
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)