You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<reasoning>user is venting about matchmaking, should empathize</reasoning>
<reply>yeah matchmaking is just rigged</reply>
然后正则抠 <reply> 里的内容发出去。
这套 XML 协议有个致命问题: 模型偶尔会拼错标签、截断、或吐出厂商内部 token。一旦 <reply> 没闭合或没出现, 正则的兜底分支会把整条文本(包括 reasoning 里的内部独白)发到群里。社死现场。
改成 JSON 之后:
{
"reasoning": "user is venting about matchmaking, should empathize",
"intent": "vent",
"reply": "matchmaker decided you needed character development today",
"mem": ""
}
也就是说 bot 不会说 "the cat in this image"、"your art style is..."、"this sticker shows..."。因为这是 AI 最大的 tell —— 真人在群里看到表情包不会复述图里画了啥, 只会反应"对方发表情"这个动作, 或者顺着情绪接话。
举个例子:
Friend: (sends a reaction sticker, no text)
❌ "that cat looks just like me right now" ← 念图了, AI 腔
✅ "stickers as a substitute for words. classic. [STICKER:eyeroll]" ← 反应动作本身
四、"旁观者位" 处理
群聊上下文每条消息会带 [name|qq=xxx] text 前缀。当群里 A 在和 B 说话, bot 是旁观者, 这种情况要禁用 "我/你" 代入双方任何一边, 默认 PASS 不接话。
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
大家好,分享一个基于 OneBot v11 的项目:onebot-llm-agent
Repo: https://github.com/qiankangwang/onebot-llm-agent
这是个 LLM agent 设计模式的研究模板。OneBot 协议端 (NapCat / LLOneBot / Lagrange 等) 在这里只是演示载体——repo 本身不含任何 IM 协议代码, 接哪个协议端都行。
想解决什么问题
之前在朋友几个群里跑过几版 LLM bot, 最大的痛点不是接不通协议端 —— OneBot 生态把这层封装得非常好 —— 而是接通之后 bot 说话总是一眼假: 礼貌、热心、有问必答、动不动列点分析, 群里人三句话就能看出是 AI。
这套模板从几个角度治这个病。下面挑几个不那么显然的设计聊一下, 希望和也在跑类似东西的人交流。
一、输出协议: JSON 而不是 XML
主流做法是让模型先 reasoning 再 reply, 结构通常是这样:
然后正则抠
<reply>里的内容发出去。这套 XML 协议有个致命问题: 模型偶尔会拼错标签、截断、或吐出厂商内部 token。一旦
<reply>没闭合或没出现, 正则的兜底分支会把整条文本(包括 reasoning 里的内部独白)发到群里。社死现场。改成 JSON 之后:
{ "reasoning": "user is venting about matchmaking, should empathize", "intent": "vent", "reply": "matchmaker decided you needed character development today", "mem": "" }模型截断/字段拼错/吐出 token 时
json.loads()直接抛异常, 整条丢弃不发。fail-closed, 宁可这一轮不回也绝不漏 reasoning。二、字符白名单 validator
JSON 协议挡住"完全错误"的输出, 但还有一类部分错误 —— reply 字段里混进英文系统提示词残片、markdown 表格、子词 token (
▁/<|eot_id|>这种)。JSON 解析不出错, 字段也齐全, 但发出去就出戏。第二道防线是发送前过字符白名单: 剥掉允许的标记 (
[STICKER:xx]/[AT:qq]) 后, 只放行 CJK + 中文标点 + 全角 + 安全 ASCII。出现 XML 残片 / JSON 大括号 / 英文长句 / 子词 marker, 整条丢。关键是反过来定义什么是允许的, 而不是去追新出现的漏出形态打地鼠。未来模型出现新形式的输出污染, 这条防线自动挡住, 不用追加规则。
三、"看图不念图"
表情包和图片喂给视觉模型生成 caption 后, 这个 caption 只能进 reasoning, 严禁出现在 reply 里。
也就是说 bot 不会说 "the cat in this image"、"your art style is..."、"this sticker shows..."。因为这是 AI 最大的 tell —— 真人在群里看到表情包不会复述图里画了啥, 只会反应"对方发表情"这个动作, 或者顺着情绪接话。
举个例子:
❌ "that cat looks just like me right now" ← 念图了, AI 腔
✅ "stickers as a substitute for words. classic. [STICKER:eyeroll]" ← 反应动作本身
四、"旁观者位" 处理
群聊上下文每条消息会带
[name|qq=xxx] text前缀。当群里 A 在和 B 说话, bot 是旁观者, 这种情况要禁用 "我/你" 代入双方任何一边, 默认 PASS 不接话。直觉是"被 @ 才回, 没被 @ 不回"够用了, 但实际场景里有大量没 @ 但 bot 觉得自己被点名了的情况 —— 比如群友提到某个话题 bot 觉得自己能聊, 一插嘴就破坏了别人原本的对话节奏。
这条历来在 eval 里掉分最多, 是 bot 最容易出戏的地方。
五、register fatigue (语气疲劳检测)
LLM 写段子很容易陷入一个模式: 连续几条回复都是 反问句式 + 对仗调侃。一开始挺有趣, 第三条之后群友就反应过来"这是个会写段子的 AI"。
所以连续 2 条都是这种"反弹句式"时, 第 3 条强制切换到平淡型 / 顺着演 / 只发 sticker。让 bot 像真人一样有时候没那么会聊。
本质是反 LLM 的优势 —— 大多数场景我们都希望模型"更聪明、更有趣", 但在装人这件事上, 笨一点反而更像人。
六、表情包多重过滤管线
表情包不能让 LLM 临时编 (每次推理烧 token), 得有本地库。但群里偷来的表情参差不齐, 需要分层过滤:
两个关键设计:
两个版本号
PERSONA_PROMPT_VERSION/VISUAL_AESTHETIC_VERSION一 bump, 全库重判。七、热加载迭代闭环
最常用的迭代路径:
output_filter.json(语义级 pre-send 正则) 和lorebook.json(关键词触发 prompt 注入, 致敬 SillyTavern World Info) 都是热加载, 改完不用重启。dynamic few-shot 用 2-char 中文 ngram + scenario tag + recency decay 检索, 5-10 条样本就能起效。技术栈
部署
python quickstart.py自动建 venv、装依赖、复制配置模板。填完.env和persona.txt就能跑。OneBot 协议端配置里把 webhook 指向http://127.0.0.1:8080/webhook/qq即可。想和大家交流的
教育/研究用途, 详见 repo 里的 DISCLAIMER。欢迎拍砖、提 issue、提 PR 🙏
All reactions