什么是信息茧房
为什么我们越来越难看到"不同的声音"?BettaFish 又是如何用多智能体协作来打破这面墙的。
你被困在"茧房"里了吗?
想象一下:你每天打开手机,看到的新闻、视频、朋友圈,都是算法精心挑选的——它觉得你喜欢科技,就只推科技;你觉得某个观点对,就只推同类的声音。久而久之,你的世界变成了一间只播放一个频道的房间。
这不是假设,这就是 信息茧房。而你并不孤单——全球数亿互联网用户都面临同样的困境。
BettaFish 的名字来自"斗鱼"(Betta Fish)——一种体型很小但非常好斗、漂亮的鱼。它象征着"小而强大,不畏挑战"。微舆的目标,就是帮你看清信息的全貌,不被单一声音操控。
传统分析工具为什么不够?
市面上的舆情工具大多是"数据看板"——给你一堆图表和数字。但你真正需要的是:洞察和决策依据。BettaFish 的思路完全不同——你只需要像聊天一样提出问题,它就会自动分析国内外 30+ 主流社媒与数百万条评论。
传统看板
你去看数据、做筛选、画图表——但看到的只是表面数字,难以发现深层趋势和跨平台对比。
单一 AI 分析
一个模型从单一角度分析——它有自己的"偏见"和盲区,和被茧房困住的人类一样。
BettaFish 多智能体
多个专业 Agent 各自从不同角度分析,再通过"论坛辩论"碰撞出更高质量的集体智能。
BettaFish 的六大优势
爬虫集群 7x24 小时不间断作业,覆盖微博、小红书、抖音、快手等 10+ 国内外社媒,下钻至海量用户评论
5 类专业 Agent + 微调模型 + 统计模型,多模型协同保证深度与多维度
深度解析短视频内容,精准提取天气、股票等结构化信息卡片
不同 Agent 有独特工具集与思维模式,通过辩论碰撞出集体智能
同时分析公开舆情和企业内部业务数据库,打通数据壁垒
纯 Python 模块化设计,一键部署,开发者可轻松集成自定义模型与业务逻辑
整体架构一瞥
BettaFish 由六大模块组成,每个模块都是一个独立运行的"角色"。点击下方组件,了解它们各自的职责。
数据采集层
分析引擎层(三个 Agent 并行)
协作与输出层
一切从一个问题开始
用户只需在 Web 界面输入一个分析需求(比如"武汉大学的舆情分析"),Flask 主应用就会启动整个流水线。下面是主应用接收请求的关键代码:
# app.py — Flask 主应用入口
from ForumEngine import start_forum_monitoring
from QueryEngine.agent import DeepSearchAgent
from InsightEngine.agent import DeepSearchAgent
from MediaEngine.agent import DeepSearchAgent
@app.route('/analyze', methods=['POST'])
def analyze():
query = request.json['query']
# 启动论坛监控
start_forum_monitoring()
# 三个 Agent 并行启动
run_agents_parallel(query)
引入论坛引擎(让 Agent 们能"讨论")
引入三个分析 Agent(各有专长)
注册一个 HTTP 接口,接收用户问题
拿到用户的分析需求
先启动论坛监控——它会实时监听 Agent 们的发言
然后三个 Agent 同时开始工作,各干各的
三个 Agent 是并行启动的,而不是串行。这意味着它们同时开始搜索和分析,大大加快了整体速度。而 ForumEngine 在后台持续监听它们的进展。
一次完整分析的流程
当用户提出问题后,系统经历以下几个阶段。注意步骤 5 是一个多轮循环——Agent 们不是一次就完成,而是在论坛中反复深入。
检验你的理解
当用户提出一个分析需求后,Insight Agent、Media Agent、Query Agent 是按什么顺序启动的?
ForumEngine 的核心职责是什么?
如果让你向一个非技术朋友解释"信息茧房",你会怎么说?
五大引擎各司其职
深入理解 MindSpider、Insight Agent、Media Agent、Query Agent 和 Report Agent 各自的工具集与内部工作方式。
MindSpider:不知疲倦的数据采集蜘蛛
就像蜘蛛结网一样,MindSpider 在互联网上织起一张覆盖 30+ 社媒的采集网。它有两个核心模块:
每天自动抓取热点新闻,用 LLM 提取关键词,存入数据库
根据关键词下钻到各平台抓取帖子和评论,支持微博、小红书、抖音、快手、B站等七大平台
# MindSpider/main.py — 爬虫主程序入口
class MindSpider:
def __init__(self):
self.broad_topic_path = (
self.project_root / "BroadTopicExtraction")
self.deep_sentiment_path = (
self.project_root / "DeepSentimentCrawling")
MindSpider 主类——整个爬虫系统的总指挥
初始化时设置两个子模块的路径
广域话题提取模块——负责"今天有什么热点"
深度舆情爬取模块——负责"挖掘大众评论"
Insight Agent:私有数据库的深度矿工
Insight Agent 的专长是在本地舆情数据库中挖掘金矿。它拥有 5 种专用查询工具,还有一个秘密武器——情感分析模型。
search_hot_content
查找指定时间范围内综合热度最高的内容——综合点赞、评论、分享、观看的加权评分
search_topic_globally
在整个数据库中全局搜索与特定话题相关的所有内容和评论
search_topic_by_date
在指定历史日期范围内搜索与话题相关的内容
get_comments_for_topic
专门提取公众对某一话题的评论数据——这就是"听到最真实声音"的关键
# InsightEngine/tools/search.py
class MediaCrawlerDB:
# 权重定义
W_LIKE = 1.0
W_COMMENT = 5.0
W_SHARE = 10.0 # 高价值互动
W_VIEW = 0.1
W_DANMAKU = 0.5
本地舆情数据库查询工具集
热度计算的权重配置——不同互动价值不同
点赞权重 1.0——基础的互动指标
评论权重 5.0——评论代表更深度的参与
分享/转发权重 10.0——传播力最强,价值最高
观看权重 0.1——看的人多但价值较低
弹幕权重 0.5——中等互动深度
Insight Agent 集成了多种情感分析模型:BERT 中文微调、GPT-2 LoRA 微调、小参数 Qwen3 微调、多语言情感分析,甚至还有传统的 SVM 机器学习方法。不同模型各有优势,系统可以根据场景灵活选择。
Media Agent:看图看视频的分析师
Media Agent 是整个系统里"眼睛"最好的成员。它使用博查多模态搜索引擎,能理解图片和视频内容。
# MediaEngine/agent.py
class DeepSearchAgent:
def __init__(self, config=None):
self.llm_client = self._initialize_llm()
self.search_agency = (
BochaMultimodalSearch(
api_key=self.config.BOCHA_API_KEY))
Media Agent 的主类
初始化时准备两样东西
1. LLM 客户端——用来理解和分析内容
2. 多模态搜索引擎——能搜图片和视频
使用博查搜索 API 作为多模态搜索工具
Query Agent:精准信息搜索专家
Query Agent 使用 Tavily 搜索工具集,专门负责精准的国内外新闻搜索。它有 6 种搜索模式:
basic_search_news
标准通用新闻搜索——快速获取概况
deep_search_news
最全面的深度分析——适合重要话题
search_news_last_24_hours
24 小时最新动态——时效性最强
search_news_last_week
过去一周主要报道——看趋势
search_images_for_news
搜索新闻相关图片——视觉维度
search_news_by_date
指定历史日期范围搜索——回溯事件
# QueryEngine/agent.py
class DeepSearchAgent:
def __init__(self, config=None):
self.llm_client = self._initialize_llm()
self.search_agency = TavilyNewsAgency(
api_key=self.config.TAVILY_API_KEY)
# 初始化搜索、反思、总结等节点
self._initialize_nodes()
Query Agent 主类——和 Media Agent 结构类似
初始化 LLM 客户端
但搜索工具不同——用 Tavily 新闻搜索
然后初始化内部的处理节点管线
Report Agent:把分析变成精美报告
Report Agent 是整个系统的最后一棒。它把三个 Agent 的分析结果和论坛讨论内容,变成一份精美的交互式 HTML 报告。这个过程有六个步骤:
模板选择
布局设计
篇幅规划
章节生成
IR 装订
HTML 渲染
IR 是 Report Agent 的独创设计。它不直接生成 HTML,而是先生成一个标准化的 JSON 结构(IR),再由渲染器翻译成 HTML。这样做的好处是:同一份 IR 可以渲染成不同格式——HTML 网页、PDF 文档、Markdown 文本。
把引擎和它的专长匹配起来
把左侧的 Agent 名称拖到右侧对应的描述上:
7x24 爬虫集群,覆盖 30+ 社媒平台
私有数据库挖掘 + 情感分析模型
多模态搜索——能理解图片和短视频
Tavily 新闻搜索——6 种精准搜索模式
IR 中间表示 → HTML/PDF/Markdown 渲染
检验你的理解
如果要分析的是企业内部数据库中的客户反馈,哪个 Agent 最适合?
在 Insight Agent 的热度计算中,哪种互动的权重最高?
Report Agent 为什么要用 IR 中间表示,而不是直接生成 HTML?
论坛协作机制
BettaFish 最独特的设计:三个 Agent 不只是各自分析,而是通过"论坛"进行多轮辩论、纠正和融合,催生集体智能。
为什么单个 Agent 不够?
想象你是一个公司老板,要做一个重大决策。你会只问一个部门的意见吗?当然不会——你会召集市场部(看外部趋势)、客服部(听用户声音)、财务部(看数据)。让不同视角碰撞,才能做出更好的决策。
BettaFish 的"论坛"就是这个道理。三个 Agent 各有专长,但单独看都有盲区。通过论坛讨论,它们互相补充、互相纠错,最终产出远超任何一个 Agent 独自能做到的分析质量。
在 AI 系统中,多智能体协作 的核心优势不只是"干得更快",而是"想得更全面"。通过引入不同视角和辩论机制,可以有效减少单一模型的偏见和盲区。
ForumEngine 如何监听 Agent 发言?
ForumEngine 的核心是一个 LogMonitor。它监控三个日志文件,一旦发现 Agent 产出了有价值的分析内容,就把它记录到论坛日志(forum.log)中。
# ForumEngine/monitor.py
class LogMonitor:
def __init__(self, log_dir="logs"):
self.monitored_logs = {
'insight': self.log_dir / 'insight.log',
'media': self.log_dir / 'media.log',
'query': self.log_dir / 'query.log'
}
self.agent_speeches_buffer = []
self.host_speech_threshold = 5
日志监控器——论坛引擎的核心组件
监控三个日志文件——每个 Agent 一个
Insight Agent 的日志
Media Agent 的日志
Query Agent 的日志
Agent 发言缓冲区——收集发言
每收集 5 条发言,触发一次主持人发言
论坛主持人:智能的讨论引导者
每收集 5 条 Agent 发言,ForumEngine 就会触发一个独立的 LLM(论坛主持人)来生成引导性发言。主持人不是简单地总结,而是梳理事件、整合观点、纠正错误、引导方向。
# ForumEngine/llm_host.py
class ForumHost:
def generate_host_speech(self, forum_logs):
parsed = self._parse_forum_logs(forum_logs)
system_prompt = self._build_system_prompt()
user_prompt = self._build_user_prompt(parsed)
response = self._call_qwen_api(
system_prompt, user_prompt)
return response["content"]
论坛主持人类——用一个独立 LLM 来引导讨论
生成主持人发言的流程:
1. 解析论坛日志,提取 Agent 发言
2. 构建系统提示——定义主持人角色
3. 构建用户提示——附上最近的发言内容
4. 调用 LLM API 生成发言
5. 返回主持人的发言内容
注意:主持人使用的是独立的 LLM(可配置为不同于分析 Agent 的模型),这确保了它的视角不会和分析 Agent 完全一致——这是 BettaFish 避免集体偏见的关键设计。
论坛讨论实况模拟
点击"下一条消息",体验一次真实的论坛讨论流程。注意观察:每个 Agent 从不同角度分析同一个话题,主持人如何整合和引导。
Agent 们如何"听到"论坛讨论?
论坛不是单向的——Agent 们也有一个工具叫 forum_reader,可以读取主持人的引导发言和其他 Agent 的分析,然后据此调整自己的研究方向。这就是"交流融合"。
# InsightEngine/nodes/summary_node.py
from utils.forum_reader import (
get_latest_host_speech,
format_host_speech_for_prompt
)
# 在总结节点中读取主持人发言
host_speech = get_latest_host_speech()
if host_speech:
guidance = format_host_speech_for_prompt(
host_speech)
导入论坛读取工具
get_latest_host_speech:获取主持人最新发言
format_host_speech_for_prompt:格式化为提示词
在生成总结前,先读取主持人说了什么
如果有主持人引导
把主持人的引导格式化为提示词的一部分
论坛消息流——数据如何流转
点击"下一步",观察一条消息从 Agent 到论坛再到其他 Agent 的完整流转路径:
找找这段代码的 Bug
下面是 ForumEngine 的日志监控代码,其中有一个微妙的 Bug。点击你认为有问题的那一行:
ForumEngine 日志处理中的 Bug
def _trigger_host_speech(self):
recent_speeches = self.agent_speeches_buffer[:5]
if len(recent_speeches) < 5: return
host_speech = generate_host_speech(recent_speeches)
self.agent_speeches_buffer = self.agent_speeches_buffer[5:]
检验你的理解
ForumEngine 的主持人(ForumHost)使用什么来生成引导发言?
Agent 们如何"听到"论坛中主持人的引导?
论坛主持人每隔多少条 Agent 发言触发一次?
从数据到报告
追踪一条用户提问从输入到最终 HTML 报告生成的完整旅程,深入理解 Agent 内部节点如何协同工作。
Agent 内部的"节点流水线"
三个分析 Agent(Insight、Media、Query)虽然工具集不同,但共享同一套内部处理架构——一套由"节点"组成的流水线。就像工厂的流水线一样,原材料(搜索结果)经过多个工位(节点)加工,最终变成成品(分析报告)。
首次搜索
首次总结
反思搜索
反思总结
格式化输出
# 三个 Agent 共享的节点初始化模式
def _initialize_nodes(self):
self.first_search_node = FirstSearchNode(
self.llm_client)
self.reflection_node = ReflectionNode(
self.llm_client)
self.first_summary_node = FirstSummaryNode(
self.llm_client)
self.reflection_summary_node = (
ReflectionSummaryNode(self.llm_client))
self.report_formatting_node = (
ReportFormattingNode(self.llm_client))
三个 Agent 都用这个方法初始化处理管线
节点 1:首次搜索——用工具集搜索相关信息
节点 2:反思——基于初步结果,思考还需要搜什么
节点 3:首次总结——把搜索结果总结成段落
节点 4:反思总结——结合论坛讨论,更新总结
节点 5:格式化——输出最终 Markdown 报告
"反思"机制:让 Agent 越来越聪明
BettaFish 的 Agent 不是搜索一次就完事。它们遵循一个"搜索→总结→反思→再搜索→再总结"的循环模式。就像写论文一样——初稿之后要反复修改、补充资料、完善论点。
Agent 的反思节点会审视之前的搜索结果,判断是否还有需要补充的信息。如果发现不足,它会生成新的搜索策略,进行下一轮搜索。这个过程可以重复多轮(由 max_reflections 参数控制),确保分析足够深入。
max_reflections = 2
Query Agent 最多反思 2 轮——平衡深度与速度
max_search_results = 15
每次搜索最多返回 15 条结果
max_content_length = 8000
每条结果最大内容长度 8000 字符
总结节点:Agent 与论坛的交汇点
总结节点(SummaryNode)是 Agent 内部与论坛系统的接口。在生成总结之前,它会先读取主持人的最新引导发言,把引导内容融入自己的分析中。
# InsightEngine/nodes/summary_node.py
class FirstSummaryNode(StateMutationNode):
"""根据搜索结果生成段落首次总结"""
def __init__(self, llm_client):
super().__init__(llm_client,
"FirstSummaryNode")
def validate_input(self, input_data):
"""验证输入数据"""
if isinstance(input_data, str):
data = json.loads(input_data)
首次总结节点——流水线的第 2 站
负责把搜索结果总结成分析段落
继承 StateMutationNode(能修改 Agent 状态)
验证输入——把 JSON 字符串解析为对象
Report Agent 的六步生成流程
Report Agent 有自己独特的六步流程。它不是简单地"拼接文本",而是一个精心设计的多阶段生成管线:
从模板库中收集候选模板,让 LLM 根据分析主题选择最合适的报告模板(如"企业品牌声誉分析报告")
设计报告的标题、目录、主题风格——就像装修房子前先画设计图
根据模板和内容量,为每个章节分配字数预算,确保报告结构均衡
逐章节生成 JSON 格式的内容,经过校验后存入章节存储
把所有章节 JSON 装订成一份完整的 Document IR
把 Document IR 渲染成精美的交互式 HTML 报告,包含图表、动画等丰富的可视化元素
IR 中间表示——报告的"蓝图"
Report Agent 的独创设计是 IR(Intermediate Representation)中间表示。它定义了一套标准的 JSON Schema,所有章节内容都遵循这个格式,然后由装订器(Stitcher)组合成完整文档。
# ReportEngine/core/stitcher.py
class DocumentComposer:
"""Document IR 装订器"""
def compose(self, chapters, meta):
doc_ir = {
"meta": meta,
"chapters": chapters,
"anchors": self._build_anchors(),
"toc": self._build_toc(chapters)
}
return doc_ir
文档装订器——把章节组合成完整文档
装订方法:把各部分组装成 IR
meta:报告元数据(标题、日期、主题等)
chapters:所有章节内容
anchors:锚点链接(用于目录跳转)
toc:自动生成的目录结构
返回完整的 IR 文档蓝图
每个章节在生成后都会经过 IRValidator 的校验,确保 JSON 结构符合规范。如果校验失败,会触发重试——保证最终输出的质量。
怎么知道三个 Agent 都分析完了?
Report Agent 需要等三个 Agent 全部完成后才能开始。它使用 FileCountBaseline 来判断输入是否准备完毕。
# ReportEngine/agent.py
class FileCountBaseline:
def initialize_baseline(
self, directories) -> Dict[str, int]:
for name, path in directories.items():
md_files = [f for f in Path(path)
.glob("*.md")]
self.baseline_data[name] = len(
md_files)
self._save_baseline()
文件数量基准管理器
初始化基准:记录当前文件数量
遍历三个引擎的输出目录
统计每个目录中的 Markdown 文件
记录当前数量作为基准
保存基准数据到磁盘
实时进度推送——SSE 流式传输
Report Agent 使用 SSE(Server-Sent Events)来实时推送报告生成进度,让用户在浏览器中看到报告逐步生成的过程。
Report Agent 的 flask_interface.py 管理任务排队和流式事件分发
每个阶段完成时推送事件:模板已选→布局完成→章节生成中→渲染完成
HTML 交互式报告 + PDF 导出(WeasyPrint)+ Markdown 纯文本
端到端数据流追踪
点击"下一步",追踪一条用户提问从输入到最终报告的完整数据流:
检验你的理解
Agent 内部的"反思"机制是如何工作的?
Report Agent 如何判断三个分析 Agent 都已完成工作?
Report Agent 的 IR 中间表示包含哪些核心部分?
动手扩展你的微舆
理解了架构之后,来看看如何把 BettaFish 改造成你自己的分析引擎——接入不同的 LLM、添加自定义工具、甚至变成金融分析系统。
模块化设计:像搭积木一样扩展
BettaFish 的代码结构遵循一个清晰的模块化原则:每个引擎都是独立的 Python 包,有自己的 Agent、LLM 客户端、节点、工具集、状态管理和提示词。你可以替换任何一个模块,而不影响其他部分。
一键切换 LLM 模型
所有 LLM 调用都遵循 OpenAI API 格式,你只需在 .env 文件中修改三个参数就能切换模型。
# .env — 切换 LLM 只需改三个参数
# Insight Agent 的 LLM
INSIGHT_ENGINE_API_KEY=sk-xxx
INSIGHT_ENGINE_BASE_URL=https://api.openai.com/v1
INSIGHT_ENGINE_MODEL_NAME=gpt-4o-mini
# 换成 DeepSeek?只改这三行:
# INSIGHT_ENGINE_API_KEY=sk-deepseek
# INSIGHT_ENGINE_BASE_URL=https://api.deepseek.com
# INSIGHT_ENGINE_MODEL_NAME=deepseek-chat
环境变量配置文件——不用改代码就能换模型
API 密钥——你的账户凭证
API 地址——模型服务的入口
模型名称——你想用哪个模型
想换模型?注释掉旧的,取消注释新的就行
三个 Agent 可以用不同的模型
每个 Agent 独立配置,互不影响
给 Agent 添加自定义工具
每个 Agent 的工具集都是可扩展的。比如,你可以给 Insight Agent 添加一个"企业内部数据库查询工具",让它不只分析公开舆情,还能分析你公司的业务数据。
# InsightEngine/tools/custom_db_tool.py
class CustomBusinessDBTool:
"""自定义业务数据库查询工具"""
def __init__(self):
self.connection_config = {
'host': config.BUSINESS_DB_HOST,
'port': config.BUSINESS_DB_PORT,
'user': config.BUSINESS_DB_USER,
}
def search_business_data(
self, query: str, table: str):
"""查询业务数据"""
# 实现你的业务逻辑
pass
自定义工具文件——你的业务数据接口
类名可以自由命名
描述这个工具的用途
初始化数据库连接配置
从全局配置读取连接参数
定义查询方法——Agent 会调用这个方法
在这里写你的查询逻辑
README 中提到:你只需简单修改 Agent 工具集的 API 参数和 prompt,就可以把它变成一个金融领域的市场分析系统。这就是模块化设计的威力——同一套架构,不同的工具和提示词,就能适应不同的领域。
自定义报告模板
Report Agent 的模板是 Markdown 文件,放在 ReportEngine/report_template/ 目录下。你可以创建自己的模板,Agent 会自动选择最合适的。
企业品牌声誉分析报告
内置模板,包含品牌认知度、美誉度、危机事件等维度
金融市场分析报告(你可以创建)
只需创建一个 Markdown 模板,包含市场概览、趋势分析、风险评估等章节
竞品监测报告(你可以创建)
追踪竞争对手的动态、用户反馈和市场反应
选择你的情感分析模型
BettaFish 集成了多种情感分析方法,从传统机器学习到大模型微调,你可以根据场景选择:
经典 NLP 模型,适合中文微博评论的情感分析
生成式模型微调,能捕获更细腻的情感变化
支持 22 种语言——分析英文、日文评论也不在话下
轻量高效,适合资源有限的环境
# 情感分析配置示例
SENTIMENT_CONFIG = {
'model_type': 'multilingual',
'confidence_threshold': 0.8,
'batch_size': 32,
'max_sequence_length': 512,
}
情感分析器的配置参数
模型类型:multilingual(多语言)——还可选 bert、qwen 等
置信度阈值 0.8——低于 80% 确信的结果会被标记
批处理大小 32——一次分析 32 条评论
最大序列长度 512——每条评论最多 512 个字符
三层架构总览
BettaFish 的架构可以看作三个层次。切换下面的标签,逐层了解:
数据层:所有原始数据的采集和存储
BettaFish 的设计哲学
通过前四个模块的学习,我们可以总结出 BettaFish 背后的设计哲学——这些原则不仅适用于舆情分析,也适用于任何多智能体系统:
并行 + 反思
Agent 并行启动保证速度,内部反思机制保证深度——速度和质量兼得
辩论优于独白
多个 Agent 通过论坛辩论产生的集体智能,远超任何单一模型的输出
工具即身份
每个 Agent 的"性格"由其工具集决定——换工具就换了视角
IR 解耦
中间表示(IR)把内容生成和格式渲染解耦——一份内容,多种输出
最终测验
如果你想把 BettaFish 的 LLM 从 GPT-4o 切换到 DeepSeek,需要修改什么?
如果你想分析企业内部数据库中的客户反馈数据,应该修改哪个 Agent?
BettaFish "始于舆情,而不止于舆情"的关键是什么?
接下来做什么?
恭喜你完成了 BettaFish 的全部课程!现在你已经理解了一个 41K Star 的多智能体系统是如何设计和实现的。以下是你的下一步选择:
阅读源码
克隆仓库,从 app.py 入口开始追踪一次完整运行。现在你能看懂每一行代码的用意了。
动手改造
试试把 Query Agent 的搜索工具换成另一个 API,或者给 Insight Agent 添加一个自定义查询工具。
探索 MiroFish
BettaFish 团队还发布了 MiroFish——一个"群体智能预测引擎"。从分析到预测,数据分析的完整闭环。
如果你刚开始学习 Agent 系统,作者推荐从 Deep Search Agent Demo 开始——一个极简的单 Agent 搜索系统。理解了单 Agent 的搜索-反思模式后,再来看 BettaFish 的多 Agent 协作,会事半功倍。