做投研的人,大概率都经历过这种时刻:手机震到发烫,微信群一晚上刷了两千条消息,你真正常看的可能不到二十条,而真正影响判断的,也许就一句话。更气人的是,那句话往往不是正儿八经的逻辑推演,而是一条带着自嘲或者反讽意味的“卖方段子”。
我在投研系统这块已经有几年经验,一直觉得机构交流群是一座没被好好利用的金矿。群里的卖方分析师们嘴上说的是段子,实际传递的是行业冷暖的变化、产业链景气度的拐点、机构情绪的转向。这些内容天然是非结构化的、带有情绪的、高度依赖上下文的,指望人工一条条盯不现实,但放任不管又可惜。所以我搭了一个小系统:用微信API把群聊消息实时接进来,用OpenClaw智能体作为调度核心,先把每条消息做清洗和情绪预判,再让大模型把“段子”还原成“事件”,最后输出成一条条带时间戳、带置信度、可以直接进数据库回测的投研信号。
这个系统不复杂,但拆开看每一层都有值得说的细节。下面我把完整的技术方案、踩过的坑、还有合规边界一起写清楚。
1. 从“段子”到“信号”:这个项目到底在解决什么问题
1.1 卖方段子为什么值得被程序化处理
先说说我理解的“卖方段子”。卖方分析师每天的工作之一是维护市场沟通,但合规约束下,很多真实判断不能直接用“强烈看好”“注意风险”这样的字眼来说。于是圈内形成了一套隐语文化:用段子表达观点,用自嘲对冲风险,用嘲讽转移焦点。比如某行业连续涨了几天,群里开始有人发“这次真的不一样”或者“永远滴神”,这往往意味着情绪处于高位;反过来,一个常年冷门的细分行业突然有人开始编段子,很可能说明这个方向的关注度正在升温。
这种表达方式表面上是娱乐,实质上是观点的高密度压缩。一条合格的卖方段子至少包含三层信息:情绪方向(看多还是看空、兴奋还是悲观)、涉及的主体(公司、行业、产业链环节)、以及时效性(讨论的是当下事件还是存量话题)。如果能把这三层信息自动化提取出来,它就不是段子,而是高频的、带情绪的投研灰度数据。
但想用程序处理段子,难点也非常具体:一是上下文依赖极重,“XXYYDS”这类话单独拎出来没有任何信息量;二是反讽和隐喻频出,字面意思和真实含义经常相反;三是时效窗口短,一个梗的生命周期可能只有两三天。这些特征决定了,简单关键词匹配和常规情感词典都不会有好效果,需要一套上下文感知的处理链路。
1.2 人工盯群的三个痛点
我在开发之前,先用人工方式连续盯了两周的群,把痛点记了下来。
第一个痛点是信息过载。一个活跃的机构交流群,工作日的信息量大约在每天800到3000条之间,其中真正有增量信息的比例可能不到5%。让研究员把时间耗在爬楼上,是巨大的浪费。
第二个痛点是语境断裂。段子这种东西,单看一条没什么意义,得知道前面讨论了什么、谁在说、当时的市场环境如何。人工一旦中途有十分钟没看手机,再回来大概率已经“看不懂梗”了。
第三个痛点是情绪误判。同一句话,在不同人嘴里可能是完全相反的意思。今天群里那种“行业完了”的调侃,过两天可能被证明是底部信号。人的情绪在不同时段状态不一样,判断稳定性远不如一套设计良好的模板加模型组合。
这三个痛点,其实是所有非结构化信息处理场景的共性问题。机构群只是其中一个典型载体。所以这个项目的价值不只停留在“盯群”本身,它更像是把一种多人实时对话流,改造成一个结构化、可检索、可计算的数据库的过程。
1.3 项目的最终定位
整个项目的定位非常明确:不是去替代投研人员做判断,而是做一个“信号助理”。它负责在正确的时间,把正确的问题,以正确的形式递到研究员面前。最终输出物是三类东西:实时异动提醒、结构化Signal记录、每日情绪日报。这套东西如果放在传统投研流程里,相当于给研究团队加了一个不睡觉的盯盘实习生。
2. 整体架构设计:四层流水线把微信群变成数据源
2.1 四层架构总览
整个系统按“采集、解析、理解、编排”四层来设计。我一开始也想过更复杂的微服务方案,但实际跑下来发现,对一个最多同时监控几十个群、每天几万条消息的系统来说,四层流水线是最清晰也最容易维护的形态。
先给一张分层对照表,方便理解每一层的职责:
| 层级 | 核心组件 | 输入 | 输出 |
|---|---|---|---|
| 采集层 | 微信API / 企业微信回调 | 群聊消息流 | 原始消息JSON |
| 解析层 | 清洗节点 + 身份映射 | 原始消息JSON | 标准化消息记录 |
| 理解层 | 大模型抽取 + 规则校验 | 标准化消息记录 | 候选信号 |
| 编排层 | OpenClaw智能体 | 候选信号 | 结构化Signal、通知、日报 |
采集层做的事情是“把群聊变成可处理的字节流”。这里要特别强调合规姿势,后面第3章我会专门展开。解析层负责去掉杂讯,比如表情包、小程序卡片、红包提示、过长的刷屏,同时把微信昵称映射到内部人员档案。理解层是核心,它需要把“卖方段子”这种高语境文本转化为结构化的“事件”。编排层则负责决定“这条信号要不要发出去、发给谁、怎么归档”。
2.2 为什么选“轻规则 + 大模型 + 智能体”而不是纯模型
设计理解层时,我纠结过两种方案:纯大模型端到端方案,以及“规则粗筛 + 大模型精析”的组合方案。最终选了后者,原因是纯大模型方案在实际场景下有三个硬伤。
第一是成本不可控。消息流是持续涌入的,如果每条消息都调用一次大模型接口,一天下来成本很可观。加入规则初筛之后,只有不到15%的消息会进入大模型处理,成本大概能压到原来的六分之一。
第二是幻觉问题。大模型在无人约束的情况下,倾向于把“看起来相关”的信息强行拓展成完整逻辑链。而这在投研场景是致命的,因为一条幻觉信号可能被研究员当真,直接进入决策流程。规则层至少能保证标记对象在已知标的池内,主题在关注列表内。
第三是可控性。合规审计要求我们能够解释“这条信号为什么出现”。纯大模型黑箱很难讲清楚,而“规则过滤 + 模型打分 + 规则复盘”的组合,每一步都有据可查。
2.3 数据回放与Label设计
既然是投研信号,就必须考虑回测,所以数据怎么落库从一开始就要设计好。我用了两套存储:一套是PostgreSQL,存信号记录、消息原文和人工标注;另一套是向量数据库,用来做语义检索、上下文召回。这样既支持结构化查询,也支持“找到历史上说过类似话的所有消息”。
信号本身的Label我设计了这样一组字段:
- signal_id:唯一标识
- ts:消息时间戳
- source_group:来源群标识
- target_type:标的类型(行业、公司、大类资产)
- target_entity:标的名称(使用内部标准化名称,不直接用外部简称)
- signal_type:信号类型(情绪升温、关注转向、基本面提示等)
- direction:方向(正向、负向、中立)
- confidence:置信度(0到1)
- raw_msg_id:关联的原始消息
- stage:当前状态(候选、已确认、已过时、已证伪)
这套Label设计不是一次定稿的。早期版本里我没有加stage字段,结果出现过时信号反复提醒的问题,后来才补上。这个经验我在第6章还会讲到。
3. 数据采集与合规准入:微信侧信息接入的可行路径
3.1 合规优先:能走接口就不走Hook
数据采集是整个项目最敏感的部分。微信端的接入方式我认真研究过:个人号Hook类方案,以及官方接口方案。
个人号相关的非官方方案,确实存在一些开源的模拟登录或Hook工具,能拿到个人微信群的实时消息。我在技术验证阶段测试过,稳定性尚可,但心里一直不踏实。这类方案存在两个无法回避的问题:一是违反平台使用协议,账号随时可能被限制,群和好友都可能受到影响;二是数据性质太敏感,群聊中有大量第三方个人信息,如果管道出现泄漏,责任完全在我。所以最终我把个人号方案定位为“实验室研究用途”,没有用于生产环境。
生产环境我推荐大家优先考虑企业微信官方接口,或者自建一个合规的“群服务机器人”账号。以企业微信为例,应用可以配置接收群消息回调,消息以JSON形式推送,官方支持加密解密,权限边界清晰。这个方案有一个额外的好处:消息带一个稳定的发言人ID,不需要额外做昵称到身份的模糊匹配。
如果你所在团队当前只有个人微信群,没法立刻切到企业微信,也有一个折中方案:安排一位团队成员作为群内“记录机器人”,用机器人账号在群里接收消息,然后走官方接口去读。本质上还是“账号自己把数据交给你”,而不是你去窃取别人的数据。
3.2 消息解析与去噪
拿到原始消息JSON后,解析层的工作非常琐碎。我总结了几类高频干扰,需要重点处理。
第一类是系统消息。红包、转账、拍一拍、撤回提示、新人入群提示,这些在JSON里都有明显的类型标识,直接过滤。
第二类是媒体消息。图片、视频、语音、小程序卡片、文件等。这些消息多模态信息量大,但解析成本高,我在MVP阶段先跳过,只保留文本和“引用回复对象”。
第三类是被@的海量无关内容。群里经常有几十上百人的消息,一次@多人的消息会带来大量转发,需要做去重。我的策略是消息摘要窗口内去重:同一发言人在30秒内的重复内容视为一条。
第四类是个人信息清洗。消息里出现的手机号、邮箱、身份证号,用正则做脱敏。这是个很基本的合规动作,但很多开发者容易漏掉。
phone_re = re.compile(r'1[3-9]\d{9}') email_re = re.compile(r'[\w.+-]+@[\w-]+\.[\w.-]+') msg = phone_re.sub('[手机号]', msg) msg = email_re.sub('[邮箱]', msg)3.3 群管理与权限边界
还有一个容易忽略的点:不是所有信号都需要监控所有群。我维护了一张群白名单,只有研究团队确认过、成员构成清楚、内容定位明确的群才会接入采集。准入标准有三条:成员以机构从业者为主、历史消息密度足够、话题集中在投研相关领域。
对于不在白名单内的群,系统直接不做任何处理。处理过程中的数据也要遵循最小化原则:只保存与信号生产相关的字段,不保存聊天背景、个人备注、地理位置等无关信息。存储周期也做了限制,原始消息保留30天,结构化信号保留更久。
这个群管理机制帮我避开了很多麻烦。有一次,一个群被加入了非预期成员,导致消息质量明显下降,我就用群名单快照做了对比,很快定位到问题,及时把该群从白名单中移出。
4. 智能体检索引擎:从文本到投研信号的五步管道
4.1 第一步:情绪基调识别
理解层是整个项目的核心。我把它拆成了五个步骤,这里一个一个说。
第一步是情绪基调识别。对于通过粗筛的消息,我要判断这条消息整体的情绪方向:正面、负面、中性还是“反讽/隐喻”。之所以把“反讽/隐喻”单列出来,是因为在卖方段子场景里,它出现的比例相当高,而且情绪方向往往与字面完全相反。
我用两个手段叠加:先用一个轻量情绪词表做快速预判,得到初步方向;然后交给大模型做上下文感知的二次判断。所谓上下文感知,就是不光看当前消息,还要把这个消息之前的5到10条相关记录一起送进去。
一个典型的例子:“本轮周期确定见底了,大约是在2018年吧。”单看字面是偏正面的,但如果群里的上下文是“大家疯狂看空某行业”,那这句话就是典型的反讽。大模型的判断在这里通常会带上“表面正向、隐含负向”的双向标签,同时给出原始置信度。
4.2 第二步:主体识别与话题聚类
识别了情绪还不够,还要知道“在说谁”。主体识别做的是两件事:第一,从消息里抽取可能关注的行业、公司、产品、宏观指标;第二,把这些抽取结果映射到内部维护的标准实体库。
标准实体库很重要。群聊里的叫法是五花八门的:“保险”“保险茅”“那个卖保险的”可能指向同一个实体。如果不做标准化,后续的信号聚合会非常散。我用近义别名表加向量匹配的方式维护这个实体库,新增一个实体时,系统会自动扫描历史消息,建立别名关联。
话题聚类是下一步。我会把一条消息归类到一组预设话题上,例如:产业链景气度、公司经营变化、资金面情绪、监管政策预期等。这个分类决定了信号后续进入哪条下游工作流。
4.3 第三步:反话与隐喻消解
这是整个管道里最有趣也最难的环节。规则匹配基本搞不定反讽,比如“好起来了”这句话,在不同上下文里可能是完全相反的信号。
我采用的方法是“情绪偏离检测”。具体说,大模型会先判断消息字面情绪,再判断消息在上下文环境里相对“正常水平”的情绪偏离度。如果一条消息的字面情绪是“极度正面”,但群里的近期情绪基调在“负面”区间,且消息发出者的历史情绪也是偏负面的,系统就会标记该消息为“疑似反转”,置信度加一个特殊权重。
隐喻消解则依赖领域知识库。比如“水泥又双叒涨价了”,表面上在调侃涨价新闻重复,实际指向的是基建回暖的预期。这种知识很难从通用文本里得到,我会把卖方研究员的解读沉淀成“领域常识库”,定期人工更新,每次大模型判断隐喻时会带着这个知识库去推理。
4.4 第四步:信号打分与阈值过滤
做完前三步,每条消息已经有了实体、情绪、方向、话题等标签。此时还不能直接输出信号,因为真正值得发出的“信号”必须满足两个条件:有信息增量、有决策价值。
我给每条候选信号打一个分,综合四个维度:
- 新颖度:当前消息与最近N天内同实体消息的语义差异度。越新鲜分数越高。
- 热度:关注标的池内最近一小时提及该实体的次数,用于判断“是不是在被集体讨论”。
- 情绪强度:情绪方向与置信度的乘积,权重由研究员预先设定。
- 上下文可信度:发言人的历史信号命中率、消息类型的可信权重。
综合分大致是:score = 0.4 × 新颖度 + 0.3 × 热度 + 0.2 × 情绪强度 + 0.1 × 上下文可信度。分数超过阈值才允许进入下一步。阈值的设定不是拍脑袋:我先用历史两周的数据离线计算,找到“人工判定有价值的信号”的最低分,再留出30%的余量作为线上阈值。
4.5 第五步:输出结构化Signal
最后一步把候选信号变成标准结构。一个典型的输出长这样:
{ "signal_id": "sig_20250117_0032", "ts": "2025-01-17T10:24:33+08:00", "source_group": "某产业链交流群", "target_type": "行业", "target_entity": "工业母机", "signal_type": "情绪升温", "direction": "positive", "confidence": 0.78, "evidence": { "msg_id": "msg_86823", "excerpt": "以前说这行是夕阳产业,现在群里全是‘国产替代YYDS’,看不懂了。" }, "stage": "candidate" }这条JSON会进入PostgreSQL,同时触发编排层的动作:如果confidence大于0.75且信号类型属于“情绪升温”,OpenClaw智能体会把消息推送到研究员的工作面板,并附带同实体的历史信号做对比。
5. OpenClaw智能体的实际编排:怎么让流程自动跑起来
5.1 智能体在项目里的角色划分
OpenClaw在这个系统里不是单打独斗的一个“大模型”,而是多个职责明确的子Agent协作编排的框架。我分了四个角色:
采集Agent负责监听采集层的消息队列,做基本去重和时间戳记录。清洗Agent负责解析层的事情,包括脱敏、过滤和身份映射。分析师Agent是核心,它负责理解层的五步管道,也就是情绪、实体、反讽、打分、输出。通知Agent负责最终触达:把信号推送给人、生成日报、归档到知识库。
这些Agent之间通过消息队列解耦。采集Agent产出原始消息,清洗Agent消费后产出标准化消息,分析师Agent再消费,通知Agent在最末端。这样任何一个环节挂了,其他环节还能继续跑,消息不会丢失。
5.2 触发-执行-反馈闭环
整个系统的运行逻辑是事件驱动的。群里有新消息,采集Agent被触发;清洗完成,分析师Agent被触发;信号确认,通知Agent触发。这样一个“触发-执行-反馈”的闭环,保证系统对外界变化能做到分钟级响应。
这里有个细节值得说:合并窗口。如果每来一条消息就做一次完整推理,既贵又吵。我在分析师Agent前面加了一个30秒的合并窗口,窗口内的消息先聚合成一个批,再一次性做理解。这样不仅成本降下来了,而且大模型在分析时能看到更完整的上下文,判断质量反而更高。
5.3 定时任务与人工复核的交接
除了实时链路,OpenClaw还负责三个定时任务:每天早上9点生成昨日信号复盘;每周一上午生成上周关注热度变化表;每月底把信号命中情况回灌进实体库打分,反向调整上下文可信度权重。
人工复核是这套系统很关键的一环。分析师Agent产出的所有“高置信度信号”并不是直接发给研究员,而是先进入一个轻量的复核队列。研究员用工作面板对信号做一次性确认:接受、拒绝、调整方向。这个反馈会被记录,并作为后续“上下文可信度”维度的训练数据。用了三周之后,高频发言人的可信度排序开始稳定,信号质量有了明显提升。
6. 测试效果与典型案例复盘
6.1 三个典型案例
跑了一段时间后,我复盘了三个比较有代表性的案例。
案例一:字面利空、真实利多的“自嘲段子”。某天群里有人转了一个段子:“公司今年业绩要靠卖楼保壳,明年估计卖无可卖。”字面上看是极度负面的。但大模型结合历史上下文发现,这个“卖楼”的说法在当地已经流传很久,这次换了一种新说法,而且说话人是某位长期看空该公司的分析师,情绪反而没有进一步恶化。系统给出了“负面转中性、关注底部信号”的结论。几天后传出公司获得新订单的消息,群里风向立刻变了。这个案例证明,情绪变化的方向比绝对情绪水平更有参考价值。
案例二:冷门行业的“谐音梗”触发关注。群里有条消息用谐音梗调侃一个非常冷门的细分行业,看起来像闲聊。但系统在实体库识别后发现,这个谐音指向的实体近一周被提及频率涨了六倍,且都是日常活跃的分析师在聊。系统把这条消息记为“关注转向”信号,置信度0.72。一周后,这个细分行业出现在多家机构的研究目录里。这个案例说明了实体标准库和频率变化的价值。
案例三:过时信号的重复提醒。这是早期的一个失败案例。系统第一天在一个段子里捕获了“某行业产能过剩”的情绪信号,但第二天群聊又开始大量讨论同样的旧梗,导致系统连续三天发同样的提醒,研究员开始忽略所有信号。我后来加上了stage字段:如果同一实体、同一信号类型、同一方向的信号在48小时内重复出现,只保留新颖度最高的一条,其余标记为“已过时”。这个问题解决后,系统提醒的有效性大幅提升。
6.2 评估指标怎么设定
对这类系统,指标不能只盯准确率。我用了四个指标组合评估:
准确率:信号最终被研究员确认的比例,跑了一个月稳定在62%到70%之间。这个数字看起来不高,但投研类信号只要能保持在60%以上,配合置信度排序,实用性就很强。
时效性:系统触发信号与人工发现自己意识到该信息之间的时间差。统计下来,系统的平均时间领先在1.5小时左右,最高能领先到前一天晚上市场没有异动的时候。
覆盖率:系统能捕获的信号中,研究员事后确认“确实有价值”的比例,方向上无法人工监测,所以只能用抽查方式评估,大约在50%左右。
稳定性:系统在无人工干预情况下连续运行120小时的故障次数。经过调优后,稳定在0到1次之间。
6.3 踩坑清单
这里集中分享几个实操中踩过的坑,都是常规文档里不会写的。
第一个坑是微信接口的限流。企业微信回调接口有每天调用次数上限,如果不做本地聚合,直接在回调里逐条处理,很容易把配额耗尽。解决办法是在入口加一层缓冲队列,批量消费。
第二个坑是LLM幻觉信号。有一次大模型把“某公司商标纠纷”脑补成了“该公司经营风险升高”,置信度给了0.8。我后来在提示词里加了三条硬性约束:不允许添加消息中不存在的实体、不允许主动关联历史事件、必须输出消息原文摘录。幻觉概率大幅下降。
第三个坑是群成员的昵称变化。微信群里昵称一变,身份映射就失效了。我在解析层维护了一个“昵称快照”表,每次发言时更新最近昵称和时间戳,遇到陌生昵称先进入待确认区,不直接丢弃消息。
7. 风险边界与合规底线
7.1 数据最小化与个人信息保护
这类系统踩在个人数据与业务数据的交界处,合规意识必须放在第一优先级。我的原则是数据最小化:只保存与“信号生产”有直接关系的字段,包括消息文本、发送人ID、发送时间、所在群ID。不保存与业务无关的隐私信息,不分析聊天中的私人话题。
原始消息数据库设了30天自动清理任务,每周跑一次全量脱敏检查。同时,所有涉及个人信息的字段在写入数据库前都会经过脱敏处理。这些细节虽然不起眼,但能在审计的时候保护团队。
7.2 输出定位:是“信号”不是“建议”
必须说清楚:这个系统输出的“信号”是信息层面的事实,比如“某行业关注度上升”“某实体被频繁提及”,它不输出买卖方向,更不构成任何形式的投资建议。
在Signal结构里,方向字段只表示消息情绪方向,不代表操作方向。系统里不出现仓位、价格、买入卖出等词汇。如果模型意外生成了这类内容,规则层会直接拦截。
7.3 技术实现的安全底线
最后说几个技术安全细节。所有API密钥和Token都放在独立的密钥管理服务里,不写进代码仓库。服务之间的通信走内网加密,生产环境的日志不输出任何消息原文。OpenClaw的Agent文件也做了分层权限,采集Agent只有读消息队列的权限,没有数据库写权限,分析师Agent只能写信号表,不能碰原始消息表。这套权限隔离保证了就算某个Agent被绕过,数据也不能被一锅端。
8. 一些可以直接上手的建议
写到这里,我把整个项目的技术链路、设计思路、踩坑经验都讲完了。最后给想复现类似系统的朋友几点建议。
第一,从小范围开始。不要一上来就接几十个群,建议先接三个群跑两周,把实体库和阈值调稳了再扩容。
第二,把提示词当成代码来治理。大模型输出的质量高度依赖提示词,建议用独立文件保存每一版提示词,配合测试数据做回归比较。
第三,人工反馈闭环一定要早做。没有人工标注的信号系统,效果会随着时间漂移。我后来每周末花30分钟批量复核一周信号,整个系统的质量都稳下来了。
第四,别忘了时效管理。信号是有生命周期的,同一个事件在48小时后就不再是新鲜信号。给信号加状态字段,定时把旧信号标记为过时,比什么都重要。
我个人调这套系统最大的体会是:真正的投研信息差,往往藏在那些没人当回事的“段子”里。技术能做的,是把捕捉这种信息差的能力,从“几个老研究员的心法”变成“一套可复制、可审计的数据管道”。这个方向还有很大的空间可以挖,如果你也在做类似的事情,欢迎一起交流。