Skip to content

MiroFish:把一份素材变成群体舆论模拟 ​

资料依据:MiroFish 原项目 666ghj/MiroFish、社区本地化 fork tt-a1i/MiroFish-local,以及本地部署实测。本文讲清它的运行逻辑,不把它误写成角色戏剧引擎。

1. 它预测的不是“未来答案”,而是“群体会怎么反应” ​

MiroFish 的基本问题是:

给定一份材料,如果把其中的人、机构、媒体和事件放进一个模拟社交世界,他们接下来会怎样发言、站队、扩散和反应?

它的输入不是一套台词,也不是一个游戏地图,而是一份材料:

text
新闻 / 报告 / 剧本设定 / 事件说明
              ↓
        实体与关系
              ↓
       Agent 人设与记忆
              ↓
     Twitter / Reddit 式互动
              ↓
        舆论演化 + 报告

因此它更像:

系统基本问题
AI Town角色今天在世界里做什么?
MiroFish一群人会如何讨论同一件事?
戏剧工坊角色下一场会如何演?

这个区别决定了后面的所有架构。


2. 原项目的总体管线 ​

每个阶段的产物不同:

阶段主要产物作用
本体生成Entity types / Edge types决定图谱如何理解材料
建图Nodes / Edges / Episodes保存实体、关系、事件
人设生成Agent Profile把实体变成能发言的角色
配置生成时间和平台参数决定模拟如何运行
OASISActions / Posts / Comments产生舆论行为
报告Markdown 报告汇总趋势、风险和可能结果
Interview单 Agent 回答事后追问角色立场

3. 本体生成:先决定“世界里有什么” ​

MiroFish 不直接把全文塞给一群 Agent。第一步会让模型从素材里抽出:

text
实体类型:Person / Organization / MediaOutlet / Event / Location
关系类型:KNOWS / WORKS_FOR / ACCUSES / REPORTS / INVOLVES

例如一份“地铁停运报告”可能变成:

text
实体:
  某市地铁3号线
  地铁运营方
  交通委
  受影响乘客
  信号系统故障
  微博

关系:
  地铁运营方 ──负责──> 某市地铁3号线
  信号系统故障 ──导致──> 地铁停运事件
  受影响乘客 ──发布──> 微博

本体是一个重要的控制点 ​

本体太粗:所有东西都变成 Entity,后续 Agent 类型混乱。 本体太细:图谱变得复杂,Agent 反而抓不住重点。

我们实测过一个坑:DeepSeek 的 json_object 模式没有正确输出 Graphiti 需要的类型标签,导致节点只有 :Entity,人设筛选拿不到角色。最后通过补 Cypher 类型标签解决。

结论:本体不是装饰,它决定了后面的角色生成和过滤能不能工作。


4. 图谱记忆:原项目为什么依赖 Zep ​

原版 MiroFish 的关键依赖是 Zep Cloud。它负责保存:

text
Graph
  ├─ Nodes:人物、机构、事件、物品
  ├─ Edges:关系
  └─ Episodes:按时间写入的材料和 Agent 活动

Agent 不是只看最近几条帖子,而是可以从图谱里检索与当前行为有关的实体、关系和事件。

不过原项目明确依赖 Zep Cloud,ZEP_API_URL 也不是一个真正可替换的本地后端入口。Zep Community Edition 已经废弃,因此我们没有继续围绕 Zep Cloud 配置。


5. 我们的本地化改造 ​

text
原版:MiroFish → Zep Cloud → OASIS

本地版:MiroFish-local
          ├─ Graphiti 适配层
          ├─ Neo4j 5.26(本机)
          ├─ Ollama nomic-embed-text(本机)
          ├─ DeepSeek / OpenAI 兼容网关
          └─ OASIS(本地 Python 环境)

已验证的本地组件 ​

组件用途
Neo4j图节点、关系、Episode 存储
Graphiti图谱写入、实体关系抽取、检索适配
Ollama本地 embedding,nomic-embed-text,768 维
DeepSeek本体、建图、Agent、报告生成
OASISTwitter / Reddit 行为模拟

我们最终放弃了 Graphiti 的 Kuzu 路线:构造阶段补完 _database 后,继续遇到 Table Entity doesn't exist。因此本地方案选 Neo4j,而不是继续修不完整的嵌入式驱动。


6. OASIS:MiroFish 的行为世界 ​

OASIS 不是一个通用剧场,而是社交平台环境。Agent 的主要动作是:

text
Twitter:发帖 / 点赞 / 转发 / 关注 / 引用
Reddit :发帖 / 评论 / 搜索 / 点赞 / 点踩 / 关注

模拟运行大致是:

Twitter 与 Reddit 的价值 ​

同一个 Agent 在两个平台上的表达可能不同:

平台更像什么常见表现
Twitter公开平台口径更谨慎、重视形象
Reddit匿名论坛更容易泄露怀疑、情绪和细节

这能产生“同一个人两套说法”的矛盾,但它仍然是公开舆论矛盾,不是正式审讯。


7. 报告和 Interview 的边界 ​

Report Agent ​

报告不是简单把帖子拼起来。它会:

text
模拟动作
  ↓
图谱检索
  ↓
规划报告大纲
  ↓
逐章节深度检索与撰写
  ↓
完整报告

本地实测中,完整报告会明显慢于模拟,因为它要逐章节做长上下文分析;报告文件会分章节保存,防止中途失败后完全没有产物。

Interview ​

原生 Interview 是:

text
系统 / 外部调用者 → 单个 Agent → 文本回答

它不是 Agent 之间的原生对话。我们后来加了另一个模式:

text
Agent A 生成问题
  ↓
Agent B 按自己的人设回答
  ↓
Agent A 读取回答并决定是否追问

这正是后来戏剧工坊采用的角色交互基础。


8. 它适合和不适合什么 ​

适合 ​

  • 舆情演化;
  • 多方站队;
  • 谣言扩散;
  • 公开讨论中的立场变化;
  • 研究某种回应策略会引发什么反应;
  • 把一份报告变成多个利益相关者的讨论。

不适合直接做 ​

  • 连续场景戏;
  • 角色动作与台词;
  • 复杂审讯;
  • 固定镜头节奏;
  • 长篇剧集的场次管理;
  • 直接导出分镜。

它的基本单位是:

text
一次平台行为

而不是:

text
一次戏剧交锋

9. 我们从 MiroFish 留下什么 ​

最终保留下来的不是 OASIS,而是三种思想:

9.1 事件应该进入长期结构化记忆 ​

不是只留聊天文本,而是记录:

text
谁出现
谁说了什么
谁因此知道了什么
这件事发生在什么时间

9.2 Agent 的知识应该有来源 ​

一个角色知道某件事,应该能追溯到:

text
亲眼看到
别人告诉
从公开材料读到
自己的秘密

9.3 舆情模拟和角色演戏应该分开 ​

MiroFish 继续作为:

text
群体智能预测 / 舆情实验 / 反应模拟器

戏剧工坊负责:

text
场景 / 动作 / 台词 / 旁白 / 剧情推进

两者共享图谱、模型和部分记忆思想,但不应该强行使用同一套行为循环。


10. 一句话总结 ​

MiroFish 把一份材料变成一个会讨论它的群体;它的核心不是“生成答案”,而是让不同 Agent 在图谱记忆和社交平台规则里产生分化反应。

它最值得借鉴的地方是:

先把世界中的实体、关系和事件结构化,再让 Agent 在这个结构上行动。

这篇里有不清楚的地方,或者想聊类似的东西?私信我 →