如果你可以在凌晨 2 点启动一场焦点小组讨论,让 50 个“很有主见”的 AI 智能体围绕你提供的任意文档展开辩论,并且在第二天早晨喝咖啡之前就得到一份按优先级排序的异议清单,会怎样?
这正是 MiroFish 的核心想法。它是一个开源多智能体仿真引擎,会生成具备不同 persona 的 LLM 智能体,给它们一份“种子文档”作为反应对象,然后让它们在一个模拟社交平台上进行多轮互动。最终得到的不是预测,而是一种合成公众意见仿真。把它理解为数字民族志,而不是预测工具。
在你兴奋之前,有几件事必须先说明白:
- 许可证是 AGPL v3.0,不是 MIT。 如果你把它嵌入到封闭式商业 SaaS 中,你就必须开源你的修改版本。若是内部工具、研究用途或咨询工作流,通常没有问题。
- 它是场景模拟器,不是神谕。 它不会告诉你下个季度的流失率,但它会告诉你哪些 persona 类型最反感你的定价页面。
- Token 成本并不低。 50 个智能体 × 20 轮 = 大量 LLM 调用。建议先用 Ollama 本地跑,或者用像 DeepInfra 这样较便宜的接口(约 0.20 美元 / 100 万 tokens)。
安装方面,README 已经写得很完整:github.com/666ghj/MiroFish。你需要 Node.js 18+、Python 3.11–3.12、uv 和一个 LLM API Key。如果你不想手动折腾环境,也可以直接使用 Docker Compose。
它实际上是如何工作的(系统架构)
当你点击 Launch 时,底层会发生什么?这里有三个参与者:你的浏览器、MiroFish 技术栈(运行在 :3000 的 React 前端和运行在 :5001 的 Python/OASIS 后端),以及你接入的 LLM API。
browser { # 你的浏览器
n1: circle label="Start"
n2: rectangle label="粘贴种子文档\n并配置智能体"
n3: rectangle label="Launch"
n10: rectangle label="查看讨论日志\n与洞察"
n11: circle label="Done"
n1.handle(right) -> n2.handle(left)
n2.handle(right) -> n3.handle(left)
n3.handle(bottom) -> mirofish.n4.handle(top) [label="POST /simulation/start"]
n10.handle(right) -> n11.handle(left)
}
mirofish { # MiroFish 技术栈 (:3000 / :5001)
n4: rectangle label="生成 N 个带 persona\n的智能体"
n5: rectangle label="把种子文档\n分发给每个智能体"
n6: rectangle label="编排互动轮次"
n9: rectangle label="汇总日志并\n准备结果"
n4.handle(right) -> n5.handle(left)
n5.handle(right) -> n6.handle(left)
n6.handle(bottom) -> llm.n7.handle(top) [label="并行智能体\nprompts"]
n9.handle(top) -> browser.n10.handle(bottom) [label="结果 JSON"]
}
llm { # LLM API (OpenAI / Ollama / DeepInfra)
n7: rectangle label="为每个智能体\n执行推理"
n8: rectangle label="返回智能体响应"
n7.handle(right) -> n8.handle(left)
loop [每轮] n7 n8
n8.handle(top) -> mirofish.n9.handle(bottom) [label="智能体输出"]
}
注意 LLM 这一条 lane:它是按每个智能体、每一轮、并行调用的。若你设置 50 个智能体、10 轮互动,那一次仿真就是 500 次 LLM 调用。现在你就能明白,为什么 token 成本是真正需要被认真管理的问题。
场景 1:上线前文案验证
你的 landing page 写好了。你觉得它不错。MiroFish 让你可以先用 50 个合成版 ICP 去“折磨测试”这份文案,再决定是否花钱投广告。
这里同样有三个参与者:你自己、负责管理仿真的 MiroFish 引擎,以及真正去阅读、争论、更新观点的智能体群体。
builder { # Builder
n1: circle label="Start"
n2: rectangle label="撰写文案草稿\n+ 定义 personas"
n3: rectangle label="提交到\nMiroFish"
n12: rectangle label="阅读异议\n报告"
n13: circle label="迭代优化"
n1.handle(right) -> n2.handle(left)
n2.handle(right) -> n3.handle(left)
n3.handle(bottom) -> engine.n4.handle(top) [label="POST /simulation/start"]
n12.handle(right) -> n13.handle(left)
}
engine { # MiroFish 引擎
n4: rectangle label="初始化仿真\n并生成智能体"
n5: rectangle label="分发种子文档\n+ persona 配置"
n10: rectangle label="收集并排序\n主要异议"
n11: rectangle label="生成报告"
n4.handle(right) -> n5.handle(left)
n5.handle(bottom) -> agents.n6.handle(top) [label="种子文档 + persona"]
n10.handle(right) -> n11.handle(left)
n11.handle(top) -> builder.n12.handle(bottom) [label="Top 3 异议"]
}
agents { # 智能体群体(50 个 LLM 智能体)
n6: rectangle label="阅读文案\n并形成观点"
n7: rectangle label="发布到模拟\n社交平台"
n8: rectangle label="阅读其他智能体\n的反应"
n9: rectangle label="更新记忆\n与立场"
n6.handle(right) -> n7.handle(left)
n7.handle(right) -> n8.handle(left)
n8.handle(right) -> n9.handle(left)
loop [10 轮] n6 n7 n8 n9
n9.handle(top) -> engine.n10.handle(bottom) [label="每轮输出"]
}
智能体循环是整个系统的核心:智能体发布意见、阅读彼此的反应,并在每一轮之后更新自己的立场。到了第 10 轮,主导性的观点簇会逐渐形成。引擎再对这些观点进行排序,并把最值得你关注的异议返回给你。
一个 B2B SaaS 产品的 persona 配置示例:
{
"seed_document": "你的 landing page 文案...",
"agent_count": 50,
"personas": [
{ "type": "skeptical_cto", "weight": 0.2 },
{ "type": "budget_conscious_pm", "weight": 0.3 },
{ "type": "early_adopter", "weight": 0.2 },
{ "type": "enterprise_buyer", "weight": 0.3 }
],
"max_rounds": 10
}
如何后处理输出: 原始输出通常是一份 JSON 讨论日志。你可以再交给另一个 LLM,用类似这样的提示词进行总结:请从这份讨论日志中提炼出最常见的 3 个定价异议、最受赞赏的功能,以及最常被要求补充的能力。
场景 2:仿真中途注入危机变量
这才是 MiroFish 真正有意思的地方。你可以在仿真运行到任意一轮时暂停它,注入一个新变量——新闻事件、竞争对手公告、政策变化——然后观察智能体如何基于新的背景重新评估它们此前相信的一切。
下面这个流程展示了完整的三方链路:你触发注入,引擎广播事件,智能体把新的上下文写入记忆后重新展开辩论。
builder { # Builder
n1: circle label="Start"
n2: rectangle label="定义基线场景\n+ 种子文档"
n3: rectangle label="启动基线仿真"
n9: rectangle label="注入危机事件"
n15: rectangle label="比较变化:\n前 vs 后"
n16: circle label="End"
n1.handle(right) -> n2.handle(left)
n2.handle(right) -> n3.handle(left)
n3.handle(bottom) -> engine.n4.handle(top) [label="POST /simulation/start"]
n9.handle(bottom) -> engine.n10.handle(top) [label="POST /simulation/{id}/inject"]
n15.handle(right) -> n16.handle(left)
}
engine { # MiroFish 引擎
n4: rectangle label="初始化基线仿真"
n5: rectangle label="调度智能体执行\n第 1–5 轮"
n8: rectangle label="基线已捕获\n— 通知 builder"
n10: rectangle label="接收危机变量"
n11: rectangle label="向智能体广播\n该事件"
n14: rectangle label="汇总危机后的\n日志"
n4.handle(right) -> n5.handle(left)
n5.handle(bottom) -> agents.n6.handle(top) [label="运行 5 轮"]
n8.handle(top) -> builder.n9.handle(bottom) [label="基线准备完成——现在注入"]
n10.handle(right) -> n11.handle(left)
n11.handle(bottom) -> agents.n12.handle(top) [label="注入:危机上下文"]
n14.handle(top) -> builder.n15.handle(bottom) [label="危机后讨论日志"]
}
agents { # 智能体群体
n6: rectangle label="运行基线\n第 1–5 轮"
n7: rectangle label="基线完成"
n12: rectangle label="吸收危机上下文"
n13: rectangle label="带着新信息\n重新辩论"
n6.handle(right) -> n7.handle(left)
n7.handle(top) -> engine.n8.handle(bottom) [label="基线输出"]
n12.handle(right) -> n13.handle(left)
n13.handle(top) -> engine.n14.handle(bottom) [label="危机后输出"]
}
危机注入 payload 示例:
{
"event_type": "market_event",
"content": "突发:一家主要竞争对手刚刚推出了一个完全免费的替代方案,并且功能覆盖率达到 80%。",
"inject_at_round": 5
}
通过比较注入前后的情绪变化,你可以看出哪些 persona 类型最脆弱,以及脆弱到什么程度。这就是你的竞争风险地图。
场景 3:A/B 提案测试
两个会员机制。两次仿真。一个赢家。无需等待 4 周真实 A/B 测试结果。
pm { # Product Manager
n1: circle label="Start"
n2: rectangle label="定义变体 A\n和变体 B"
n3: rectangle label="提交变体 A\n进行仿真"
n7: rectangle label="提交变体 B\n进行仿真"
n11: rectangle label="比较结果:\n选出赢家"
n12: circle label="Ship it"
n1.handle(right) -> n2.handle(left)
n2.handle(right) -> n3.handle(left)
n3.handle(bottom) -> mirofish.n4.handle(top) [label="POST /simulation/start (A)"]
n7.handle(bottom) -> mirofish.n8.handle(top) [label="POST /simulation/start (B)"]
n11.handle(right) -> n12.handle(left)
}
mirofish { # MiroFish 引擎
n4: rectangle label="仿真变体 A:\n50 个智能体响应"
n5: rectangle label="智能体评估\n感知价值"
n6: rectangle label="汇总:\n变体 A 得分"
n8: rectangle label="仿真变体 B:\n50 个智能体响应"
n9: rectangle label="智能体评估\n感知价值"
n10: rectangle label="汇总:\n变体 B 得分"
n4.handle(right) -> n5.handle(left)
n5.handle(right) -> n6.handle(left)
n6.handle(top) -> pm.n7.handle(bottom) [label="变体 A:情绪 + 意图"]
n8.handle(right) -> n9.handle(left)
n9.handle(right) -> n10.handle(left)
n10.handle(top) -> pm.n11.handle(bottom) [label="变体 B:情绪 + 意图"]
}
在这两次运行中,你主要对比的是:激活意图分数、感知价值评分,以及流失风险信号。如果变体 A 在激活意图上更高,而变体 B 在感知价值上更强,那么你面对的是一个细分决策问题,而不是掷硬币。
在真正投入使用之前
| 检查项 | 为什么重要 |
|---|---|
| Seed 质量 | 越密集、越具体的输入文案,智能体输出越有价值。模糊的 seed 只会得到模糊的结果。 |
| Persona 权重 | 尽量贴近真实用户分布,否则模拟结果会偏离现实。 |
| 从小规模开始 | 先跑 5–10 轮,确认输出逻辑通顺之后再扩大规模。 |
| 模型选择 | 开发阶段可以用本地 7B 或 GPT-4o-mini。最终验证再切换到更强模型。 |
| 后处理 | 一定要把日志交给另一个 LLM 做聚合总结。原始 JSON 本身不是洞察。 |
| 先跑中性基线 | 先用中性 seed 建立情绪基准线,再做对比更有意义。 |
| AGPL | 内部工具通常没问题;如果你把它包装成 SaaS,就需要开源相关代码。 |
如何把这些流程图可视化
把上面的任意一个 FlowZap Code 代码块,或把它保存成 .fz 文件,然后导入到 你的 FlowZap 项目 中,就可以把它渲染成可分享给团队的可视化图表。
别再手动拖拽箭头了。用 FlowZap 设计系统。
