1. 项目概述:一个完全本地的多智能体社会模拟引擎
如果你对AI智能体、社会动力学模拟或者舆情分析感兴趣,但又受限于云服务API的调用成本、网络延迟或数据隐私问题,那么MiroFish-Offline这个项目绝对值得你花时间研究。简单来说,它是一个“沙盒式”的社会模拟引擎。你扔给它一份文档——可以是一份新闻稿、一份政策草案、一份财报——它就能在你的本地电脑上,凭空“创造”出成百上千个拥有不同性格、立场和记忆的AI智能体,并模拟它们在社交媒体上的互动、争论和观点演变。整个过程,从知识图谱构建到智能体推理,再到最终的报告生成,完全在你的硬件上运行,不依赖任何外部云服务。
我最初接触这个项目,是因为在尝试进行一些市场情绪或政策影响的预演分析时,发现现有的工具要么过于简单(只能做简单的情感分析),要么过于复杂和昂贵(需要调用多个云端大模型API,成本高昂且数据流转存在风险)。MiroFish-Offline的出现,完美地解决了这个痛点。它基于原版MiroFish,但做了一次彻底的“本地化”手术:将中文界面全盘英文化,用开源的Neo4j图数据库替代了原版的Zep Cloud记忆服务,并用同样开源的Ollama本地大模型服务,替换了所有需要调用云端API(如DashScope、OpenAI)的环节。这意味着,你只需要一台性能尚可的电脑,就能拥有一个私有的、可控的、持续运行的社会模拟实验室。
这个项目的核心价值在于其“涌现”能力。单个智能体的行为或许可以预测,但当数百个智能体在一个由知识图谱定义的“世界”里持续互动时,会产生许多意想不到的连锁反应和群体动态。这对于危机公关预演、新产品市场接受度测试、甚至是创意写作(比如为小说生成符合角色性格的对话)来说,都是一个极其强大的工具。接下来,我将带你深入这个项目的内部,从设计思路、环境搭建、核心操作到实战避坑,完整地走一遍。
2. 核心设计思路与架构解析
2.1 为何选择“完全本地化”的路线?
原版的MiroFish是一个优秀的设计,但其架构严重依赖特定的中国云服务生态(如阿里云的DashScope、Zep Cloud)。这对于全球其他地区的开发者,或者对数据隐私、网络稳定性有要求的应用场景来说,构成了不小的门槛。MiroFish-Offline的fork者nikmcfly敏锐地抓住了这个痛点,并执行了一次干净利落的技术栈替换。
本地化的核心挑战与解决方案:
- 图存储与记忆:原版使用Zep Cloud,这是一个托管服务。离线版选择了Neo4j Community Edition。Neo4j是图数据库领域的标杆,其Cypher查询语言非常强大,社区版对于个人和小型项目完全免费。更重要的是,Neo4j能完美承载智能体的“长期记忆”和“世界知识图谱”这两个核心概念。
- 大模型推理:原版调用云端LLM API。离线版集成了Ollama。Ollama的伟大之处在于,它让在本地运行Llama、Qwen等主流大模型变得像
ollama pull和ollama run一样简单。它提供了一个与OpenAI API兼容的接口,使得项目后端几乎无需修改就能从GPT切换到本地模型。 - 文本嵌入:知识检索和相似性搜索离不开文本向量。离线版用Ollama同样能拉取的
nomic-embed-text模型替代了原版的云服务,实现了本地化的嵌入生成。 - 用户界面:将整个前端(超过20个文件,1000多处字符串)从中文翻译为英文,这不仅仅是语言转换,更是为了让项目更符合国际开源社区的标准和习惯。
这个替换并非简单的“拔插头”,而是涉及到底层抽象层的设计,这也是本项目架构中最精妙的部分。
2.2 分层架构与抽象设计
项目采用了一种清晰的分层架构,这保证了核心业务逻辑与具体基础设施的解耦。从上到下看:
应用层(Flask API):这是业务的入口,包含了graph.py(图谱构建)、simulation.py(模拟运行)、report.py(报告生成)等核心业务模块。它们不关心数据具体存在哪里。
服务层:这一层包含了EntityReader、GraphToolsService、GraphMemoryUpdater、ReportAgent等。它们负责具体的业务逻辑,如实体识别、图谱更新、报告分析等。它们通过一个统一的storage接口来操作数据。
存储抽象层(GraphStorage):这是架构的关键。它定义了一个抽象的图存储接口,声明了诸如save_entity、search_similar_nodes、get_agent_memory等方法。目前只有一个具体实现:Neo4jStorage。
具体存储实现(Neo4jStorage):这个类实现了GraphStorage接口的所有方法,内部又封装了:
EmbeddingService:调用本地的Ollama服务生成文本向量。NERExtractor:同样调用本地LLM,进行命名实体识别和关系抽取,从文档中构建初始图谱。SearchService:实现混合搜索。这是提升检索质量的核心。它结合了向量相似度搜索(用于语义匹配)和BM25关键词搜索(用于精确术语匹配),并按0.7:0.3的权重进行综合评分。这种设计能同时保证“找到意思相关的”和“找到提到关键字的”内容。
基础设施层:最底层就是Neo4j数据库和Ollama服务。
这种设计带来的巨大优势:假设未来你想把Neo4j换成JanusGraph或TigerGraph,你只需要实现一个新的
GraphStorage子类(例如JanusGraphStorage),并在配置中切换。应用层和服务层的代码几乎不需要改动。这体现了优秀软件设计的“开闭原则”。
2.3 智能体系统的运作机制
理解了存储,我们再来看智能体是如何“活”起来的。
人格生成:系统会根据导入的文档主题,自动生成数百个智能体。每个智能体不是一个简单的字符串,而是一个拥有多项属性的数据对象,包括:
- 基础身份:姓名、职业、背景故事。
- 性格参数:开放性、尽责性、外向性、亲和性、神经质(类似大五人格)。
- 观点偏见:对文档中核心议题的初始立场(强烈支持、中立、强烈反对)。
- 影响力等级:决定了其言论传播的范围和权重。
- 反应速度:模拟其在社交平台上的活跃度。
记忆与认知:每个智能体在Neo4j中都有一个对应的节点,并关联着一个“记忆子图”。这个子图记录了该智能体“知道”的事件、实体以及与其他智能体的互动历史。每次模拟迭代,智能体做出决策(发帖、回复、转评)时,都会查询自己的记忆和全局知识图谱,确保行为符合其认知和历史。
模拟循环:
- 感知:智能体从环境(全局事件流、其他智能体的公开言论)中获取信息。
- 推理:结合自身人格、记忆、当前情绪,使用本地LLM(通过Ollama)生成对该信息的理解和反应意图。
- 行动:将意图转化为具体的社交行为(发布一条帖子、评论、点赞或转发)。
- 学习与记忆更新:行动的结果(如收到的回复、引发的讨论)会被写回该智能体的记忆节点和全局图谱中,影响其未来的行为。
这个过程每小时(或你设定的时间间隔)循环一次,从而动态地模拟出舆论场的演变。
3. 从零开始:本地环境搭建与配置详解
理论讲完了,我们动手把它跑起来。官方提供了Docker一键部署和手动部署两种方式,我强烈推荐Docker方式,它能避免绝大多数环境依赖问题。
3.1 硬件准备与资源评估
在开始之前,请务必评估你的硬件。运行一个拥有数百个智能体的模拟,是对算力和内存的集中考验。下面是我的经验之谈:
- CPU:至少4核,推荐8核或以上。更多的核心能加速Ollama的推理(如果支持多线程)和Neo4j的查询处理。
- 内存(RAM):16GB是绝对底线。这需要同时承载Neo4j(约2-4GB)、Ollama运行大模型(7B模型约需4-6GB,14B模型约需10-12GB)、Python后端、Node.js前端以及操作系统本身。32GB会让你游刃有余,能运行更大的模型或进行更复杂的模拟。
- 显存(VRAM):如果你有NVIDIA GPU,这将极大提升LLM推理速度。
- 运行
qwen2.5:7b模型,需要约8GB显存。 - 运行
qwen2.5:14b模型,需要约14-16GB显存。 - 运行
qwen2.5:32b模型,需要约24GB+显存。 - 如果没有GPU或显存不足:Ollama会自动退回到CPU模式,速度会慢很多,但可以运行。对于7B模型,CPU模式尚可接受;对于更大的模型,等待时间会呈指数增长。
- 运行
- 磁盘空间:预留50GB。其中,Docker镜像和模型文件是大头。一个14B的模型文件大约在7-10GB,32B的模型可能超过20GB。
3.2 Docker Compose一站式部署(推荐)
这是最省心的方法,项目已经提供了完善的docker-compose.yml文件。
# 1. 克隆仓库 git clone https://github.com/nikmcfly/MiroFish-Offline.git cd MiroFish-Offline # 2. 复制环境变量模板 cp .env.example .env # 此时,你可以打开 .env 文件查看配置,但通常默认值即可用于首次启动。 # 关键检查项:LLM_MODEL_NAME 是否与你计划拉的模型一致(默认是qwen2.5:32b,对硬件要求高)。 # 3. 启动所有服务 docker compose up -d这个命令会在后台启动三个服务:
neo4j: 图数据库,运行在localhost:7474(浏览器管理界面) 和localhost:7687(Bolt协议端口)。ollama: 大模型服务,运行在localhost:11434。mirofish-offline: 应用本身,前端运行在localhost:3000,后端API运行在localhost:5000。
启动需要一些时间,特别是第一次需要下载Docker镜像。你可以用docker compose logs -f来跟踪启动日志。
接下来是最关键的一步——拉取模型。Ollama容器内初始是空的,我们需要把模型文件下载进去。
# 进入Ollama容器内部拉取模型(假设容器名是 mirofish-ollama) docker exec mirofish-ollama ollama pull qwen2.5:14b # 根据你的硬件,从7b, 14b, 32b中选择 docker exec mirofish-ollama ollama pull nomic-embed-text重要提示:
qwen2.5:32b模型需要约24GB显存或大量系统内存,对大多数个人电脑不友好。我强烈建议初次尝试使用qwen2.5:14b甚至qwen2.5:7b。你可以在后面的.env配置中指定使用哪个模型。
拉取模型的时间取决于你的网络速度,qwen2.5:14b大约有7-8GB。完成后,访问http://localhost:3000,你应该就能看到MiroFish-Offline的英文界面了。
3.3 手动部署:深入理解各个组件
如果你更喜欢手动控制每个组件,或者想在宿主机上直接调试代码,可以按照以下步骤。这能帮助你更深刻地理解系统是如何连接在一起的。
第一步:启动Neo4j
docker run -d \ --name neo4j \ -p 7474:7474 -p 7687:7687 \ -e NEO4J_AUTH=neo4j/mirofish \ -v neo4j_data:/data \ neo4j:5.15-community-v neo4j_data:/data:将数据持久化到名为neo4j_data的Docker卷,防止容器删除后数据丢失。- 启动后,可以访问
http://localhost:7474,使用用户名neo4j和密码mirofish登录Neo4j Browser,这是一个强大的图数据查询和可视化工具。
第二步:启动Ollama并拉取模型
# 在终端1启动Ollama服务 ollama serve # 服务会运行在 http://localhost:11434 # 在终端2拉取模型 ollama pull qwen2.5:14b ollama pull nomic-embed-text第三步:配置并运行后端
# 1. 进入项目后端目录 cd MiroFish-Offline/backend # 2. 创建Python虚拟环境(推荐) python -m venv venv source venv/bin/activate # Linux/macOS # venv\Scripts\activate # Windows # 3. 安装依赖 pip install -r requirements.txt # 4. 配置环境变量 cp .env.example .env # 编辑 .env 文件,确保以下关键配置正确: # NEO4J_URI=bolt://localhost:7687 # NEO4J_USER=neo4j # NEO4J_PASSWORD=mirofish # LLM_BASE_URL=http://localhost:11434/v1 # LLM_MODEL_NAME=qwen2.5:14b # 与你拉取的模型一致 # EMBEDDING_BASE_URL=http://localhost:11434 # 5. 运行后端服务器 python run.py后端启动后,会监听http://localhost:5000。
第四步:运行前端
# 1. 新开一个终端,进入前端目录 cd MiroFish-Offline/frontend # 2. 安装Node.js依赖 npm install # 3. 启动开发服务器 npm run dev前端启动后,通常会运行在http://localhost:3000。现在,前端(3000端口)会通过配置的代理,请求后端(5000端口)的API。
3.4 环境配置的深度解析与调优
.env文件是这个项目的控制中枢。我们来详细拆解每一个配置项的意义和调优建议。
# ===== LLM 配置 ===== # API密钥,对于本地Ollama,可以设为任意非空字符串,如'ollama' LLM_API_KEY=ollama # Ollama提供的OpenAI兼容端点 LLM_BASE_URL=http://localhost:11434/v1 # 核心:选择你的模型。这直接决定模拟的智能程度和硬件需求。 LLM_MODEL_NAME=qwen2.5:14b # 可选:如果你有多个Ollama实例或使用其他兼容服务,可以修改这里。 # 例如,使用本地部署的LM Studio: LLM_BASE_URL=http://localhost:1234/v1 # ===== Neo4j 配置 ===== # Bolt协议连接地址,如果Neo4j运行在其他机器,请修改主机IP NEO4J_URI=bolt://localhost:7687 NEO4J_USER=neo4j NEO4J_PASSWORD=mirofish # 强烈建议在生产环境中修改此密码! # ===== 嵌入模型配置 ===== # 用于生成文本向量的模型 EMBEDDING_MODEL=nomic-embed-text # 嵌入模型的API地址,通常与LLM相同(都是Ollama) EMBEDDING_BASE_URL=http://localhost:11434 # ===== 模拟参数配置 (高级) ===== # 智能体数量。首次尝试建议调低(如50),稳定后再增加。 SIMULATION_AGENT_COUNT=200 # 模拟的时间步长(单位:秒)。3600代表模拟中每“小时”现实时间走多少秒。 # 调小此值可以更快看到模拟结果,但节奏会变快。 SIMULATION_TIME_STEP=3600 # 每次模拟循环中,每个智能体最大行动次数。限制计算量。 MAX_ACTIONS_PER_AGENT_PER_STEP=3实操心得:模型选择的平衡艺术模型越大,智能体的对话质量、推理能力和一致性越好,模拟结果越可信。但代价是速度慢、资源占用高。我的经验是:
- 探索和功能验证阶段:使用
qwen2.5:7b。它能在大多数消费级GPU(8GB显存)上流畅运行,快速验证你的想法和流程。- 正式模拟运行:使用
qwen2.5:14b。这是性价比之选,在16-24GB显存的卡上能获得质量和速度的良好平衡。- 深度研究与生产:如果硬件允许,使用
qwen2.5:32b或llama3:70b。它们能产生更细腻、更符合人类逻辑的交互。- 一个常被忽略的要点:
nomic-embed-text是专门为生成高质量文本向量而优化的模型,不要用它来替换LLM_MODEL_NAME做对话生成,反之亦然。
4. 核心工作流实战:从文档到模拟报告
环境就绪后,我们进入最激动人心的环节:实际运行一次完整的模拟。我将以一个虚构的“某科技公司发布新款透明手机”新闻稿为例,带你走完全流程。
4.1 第一步:知识图谱构建(Graph Build)
这是模拟的基石。系统需要从你的文档中提取出“世界”的基本要素。
上传文档:在Web界面点击“New Simulation”,将你的文本粘贴进去或上传TXT/PDF文件。例如,我输入了一段约500字的新闻稿,描述“Quantum Glass”手机的发布,包括其特性(透明屏幕、全息投影)、定价(高昂)、以及CEO的发言。
后台发生了什么:
- 文本分块:长文本被切分成语义连贯的段落。
- 实体与关系抽取:
NERExtractor服务调用你配置的本地LLM(如Qwen2.5),识别出文档中的实体(如“Quantum Glass”、“CEO Alex Chen”、“发布会”、“$1999”)和关系(如“Alex Chen” -[发布]-> “Quantum Glass”, “Quantum Glass” -[价格是]-> “$1999”)。 - 图谱构建:这些实体和关系被送入Neo4j,构建成一张初始的知识图谱。你可以在Neo4j Browser (
localhost:7474) 中执行MATCH (n) RETURN n LIMIT 25来可视化这张图。你会看到人物、产品、事件、组织等节点,以及它们之间的连线。
注意事项:文档质量决定图谱质量
- 文档应信息密集:包含具体的人名、组织名、产品名、事件、数字和观点。模糊的散文式描述提取出的实体较少。
- 控制文档长度:过长的文档(如整本书)会导致处理时间极长,且生成的图谱过于庞大,可能影响后续模拟性能。建议初次使用选择500-2000字的精华内容。
- 实体识别(NER)的局限性:完全依赖LLM的NER能力,对于非常小众的专有名词,可能会识别错误或遗漏。如果结果不理想,可以尝试在文档中更显眼地提及关键实体。
4.2 第二步:环境与智能体生成(Env Setup)
基于上一步构建的知识图谱,系统开始“创造人口”。
- 参数设置:在界面上,你可以设定智能体数量(如200个)、模拟的社交平台类型(默认是类似Twitter/X的“Microblog”)。
- 智能体生成过程:
- 系统首先会分析知识图谱中的核心话题和实体。
- 然后,LLM会根据这些话题,为每一个智能体生成一个详细的“人设”。这个人设不仅包括名字、年龄、职业,更重要的是其性格矩阵和初始观点。
- 性格矩阵:基于大五人格模型,每个智能体在开放性、尽责性、外向性、亲和性、神经质五个维度上有一个分数。这会影响其行为模式,例如,高神经质的智能体更容易发布情绪化的言论,高开放性的智能体更愿意接受新观点。
- 初始观点:针对核心议题(如“对Quantum Glass手机的态度”),智能体会被分配一个从-1(强烈反对)到+1(强烈支持)的初始值,并附带一个“立场强度”。一个立场强度高、观点值为-1的智能体,就是一个坚定的“黑粉”。
- 影响力网络:智能体之间会随机生成一个“关注”关系网络,模拟现实社交网络中的影响力结构。大V(高影响力节点)的言论会被更多人看到。
实操心得:智能体数量的权衡
- 数量太少(<50):群体动态不够丰富,容易形成回声室,可能无法涌现出有趣的模式。
- 数量适中(100-300):推荐范围。能在可接受的计算时间内,提供足够复杂的交互。
- 数量太多(>500):对硬件(尤其是内存和LLM推理)压力巨大,模拟速度会非常慢,且可能因为信息过载而难以分析。建议循序渐进,先用100个智能体跑通流程,再根据硬件能力逐步增加。
4.3 第三步:运行模拟(Simulation)
点击“Start Simulation”,沙盘开始转动。模拟会按照你设定的时间步长(默认1模拟小时/1现实秒)推进。
在模拟界面,你可以观察到:
- 时间线:显示模拟的当前日期和时间。
- 活动流:实时滚动显示智能体发布的帖子、评论和转发。帖子内容由LLM生成,会体现该智能体的性格和观点。例如,一个“科技发烧友”性格的智能体可能会发帖:“Just watched the Quantum Glass keynote. The holographic UI is a game-changer! Pre-ordering now!”,而一个“价格敏感型消费者”可能会说:“$1999 for a see-through phone? That's insane. My current phone works just fine.”
- 情绪热图:一个可视化图表,展示整个群体对核心议题的情绪倾向(正面、负面、中性)随时间的变化。
- 话题传播网络图:动态显示哪些话题(关键词)正在被哪些智能体讨论,以及如何通过社交网络传播。
模拟的核心循环在后台不断运行:
- 每个智能体检查自己的“信息流”(关注对象的发言、热点话题)。
- LLM结合该智能体的记忆、性格、当前情绪和接收到的信息,决定是否行动以及如何行动(生成帖子内容)。
- 行动被发布,并更新到全局事件流和该智能体的个人记忆中。
- 其他智能体看到这条新帖子,可能触发新一轮的感知-推理-行动循环。
你可以随时暂停模拟,也可以调整模拟速度。一个完整的模拟周期(例如模拟现实中的一周)可能需要现实世界的几分钟到几小时,取决于智能体数量、模型速度和硬件性能。
4.4 第四步:生成分析报告(Report)
模拟结束后(或暂停在某个关键时刻),点击“Generate Report”。这时,一个特殊的ReportAgent会开始工作。
ReportAgent的工作流程堪称一次微型研究:
- 环境快照:首先,它会获取当前模拟世界的完整状态,包括所有帖子、情绪数据、图谱关系。
- 焦点小组访谈:它会从所有智能体中,有策略地挑选一小部分(如10-15个)作为访谈对象。选择策略包括:观点极端者(强烈支持/反对)、高影响力者、随机抽样者。然后,它会模拟对这些智能体进行“深度访谈”,通过LLM问答,探究他们持某种观点的深层原因。
- 图谱证据检索:结合访谈中得到的关键词和线索,
ReportAgent会在Neo4j知识图谱中进行混合搜索,找出支持或反驳某些观点的“事实依据”。例如,如果很多智能体抱怨价格高,它会搜索图谱中与“价格”、“成本”、“价值”相关的实体和关系。 - 报告撰写:最后,
ReportAgent综合所有信息,生成一份结构化的分析报告。这份报告通常包括:- 执行摘要:整体舆论倾向的概述。
- 关键发现:分点列出最主要的正面和负面观点。
- 观点演化分析:用图表和数据展示情绪随时间的变化趋势。
- 影响力分析:指出哪些智能体或话题在引导舆论。
- 证据引用:直接引用从知识图谱中检索到的具体事实和智能体的访谈原话。
- 潜在风险与机遇:基于模拟动态,提出未来可能的发展方向。
这份报告不再是简单的情绪统计,而是有数据、有引证、有逻辑链的深度分析,极大地提升了模拟结果的可信度和 actionable insight(可操作的见解)。
4.5 第五步:与智能体对话(Interaction)
这是MiroFish最有趣的功能之一。在报告界面或智能体列表里,你可以点击任何一个智能体,进入与它的“一对一聊天”模式。
这不仅仅是简单的问答:
- 记忆上下文:智能体拥有它在整个模拟过程中的完整记忆。你可以问它:“你三小时前为什么发了那条批评电池续航的帖子?”它会结合当时的场景(看到了什么信息、情绪如何)来回答。
- 人格一致性:它的回答风格会严格符合其预设的人格。一个“愤世嫉俗”的智能体会用讽刺的语气,而一个“乐观积极”的智能体则会看到事情好的一面。
- 深度探查:你可以扮演记者、研究员,去深挖某个观点的形成过程,甚至尝试说服它改变观点(这很难,因为其人格和记忆是固化的)。这对于理解群体中极端观点的形成机制非常有帮助。
5. 常见问题、故障排查与性能优化
在实际部署和运行中,你几乎一定会遇到一些问题。下面是我踩过坑后总结的排查指南和优化技巧。
5.1 部署与启动问题
问题1:Docker Compose启动后,前端页面无法访问或报错。
- 排查步骤:
docker compose ps检查所有容器状态是否为 “Up”。docker compose logs mirofish-offline查看应用容器的日志。最常见的问题是后端连接不上Neo4j或Ollama。- 检查
.env文件中的NEO4J_URI、LLM_BASE_URL等配置。在Docker Compose环境下,容器间通信应使用服务名而非localhost。确保配置类似:
在NEO4J_URI=bolt://neo4j:7687 # 注意是服务名‘neo4j’ LLM_BASE_URL=http://ollama:11434/v1 # 注意是服务名‘ollama’docker-compose.yml中,网络已经打通,使用服务名即可互通。 - 分别访问
http://localhost:7474(Neo4j) 和http://localhost:11434(Ollama) 看服务是否独立可用。
问题2:Ollama拉取模型速度极慢或失败。
- 解决方案:
- 配置镜像加速:对于国内用户,这是必选项。在宿主机(不是容器内)创建或修改
~/.ollama/config.json(Linux/macOS)或C:\Users\<你的用户名>\.ollama\config.json(Windows),加入国内镜像源:
然后重启Ollama服务。{ "registry": { "mirrors": { "docker.io": "https://docker.m.daocloud.io", "ghcr.io": "https://ghcr.dockerproxy.com", "registry.ollama.ai": "https://ollama.mirrors.ustc.edu.cn" } } } - 手动下载:如果拉取始终失败,可以尝试在能科学上网的机器上拉取后,通过
ollama save和ollama load命令迁移模型文件。
- 配置镜像加速:对于国内用户,这是必选项。在宿主机(不是容器内)创建或修改
问题3:启动模拟时,后端报错 “LLM connection error” 或 “Embedding model not found”。
- 排查步骤:
- 确认Ollama服务正在运行:
curl http://localhost:11434/api/tags应该返回已拉取的模型列表。 - 确认
.env中的LLM_MODEL_NAME和EMBEDDING_MODEL拼写完全正确,且与Ollama中的模型名一致。可用ollama list命令查看。 - 对于嵌入模型,除了
nomic-embed-text,也可以尝试all-minilm(更小更快,但性能稍逊)。确保也已拉取。
- 确认Ollama服务正在运行:
5.2 运行时性能问题
问题4:模拟运行速度非常慢,每小时(模拟时间)要等很久。
- 原因分析:这是最普遍的问题。速度瓶颈主要在LLM推理。每个智能体每个行动都需要调用一次LLM。
- 优化策略:
- 降低模型尺寸:从32b降到14b或7b,是提升速度最有效的方法。
- 减少智能体数量:将
SIMULATION_AGENT_COUNT从200降到50或100。 - 限制行动次数:调低
.env中的MAX_ACTIONS_PER_AGENT_PER_STEP(如从3降到1或2)。 - 使用GPU加速:确保Ollama正确识别了你的GPU。在Ollama运行日志或通过
ollama ps查看模型是否显示GPU字样。你可能需要为Docker容器配置GPU支持(安装NVIDIA Container Toolkit)。 - 调整Ollama参数:通过Ollama的
Modelfile或启动参数,可以限制模型使用的线程数、批处理大小等。但对于MiroFish这种通过API调用的方式,更直接的是在项目后端寻找是否有并发请求控制。目前版本似乎是顺序请求,未来或许可以优化为批量请求。
问题5:运行一段时间后,内存或显存耗尽,进程崩溃。
- 原因分析:内存泄漏或大模型本身占用过高。
- 解决方案:
- 监控资源:使用
htop、nvidia-smi等工具实时监控。 - 设置资源限制:在
docker-compose.yml中,为ollama和mirofish-offline服务添加资源限制:services: ollama: deploy: resources: limits: memory: 16G cpus: '4.0' - 定期重启:对于长时间运行的模拟,可以规划在模拟自然“间隔”(如每模拟24小时)暂停并重启后端服务,释放内存。
- 清理Neo4j缓存:如果Neo4j占用内存持续增长,可以在Neo4j Browser中执行
CALL db.clearQueryCaches();进行清理(需管理员权限)。
- 监控资源:使用
5.3 功能与逻辑问题
问题6:智能体的行为看起来重复或不够“智能”。
- 可能原因:
- 模型能力不足:7B模型在复杂推理和多样性生成上确实弱于更大模型。升级模型是根本解决办法。
- 人格参数趋同:检查生成智能体时,人格参数的范围是否足够宽。系统默认会生成多样化的参数,但如果文档主题非常单一,可能导致生成的智能体背景差异不大。
- “冷启动”问题:模拟初期,智能体记忆空白,互动少,行为可能比较模板化。让模拟多运行几个时间步,待记忆和互动丰富后,行为会变得更复杂和有趣。
问题7:报告内容空洞,缺乏深度洞察。
- 优化方向:
- 丰富初始文档:确保上传的文档包含多维度的信息,如技术细节、市场数据、不同利益相关方的观点引用(即使是你虚构的)。这能为图谱提供更多“争论点”。
- 调整
ReportAgent的提示词:在后台代码中,ReportAgent的行为由一系列LLM提示词(prompt)控制。你可以尝试修改这些提示词(位于后端相关agent目录下),要求它进行更深入的对比分析、归因分析或预测推断。 - 手动干预焦点小组:在生成报告前,你可以先浏览智能体列表,手动挑选一些有代表性的智能体ID,然后在调用报告生成时指定这些ID作为焦点小组,而非完全随机。
问题8:如何保存和加载模拟进度?
- 当前机制:模拟的状态(智能体属性、记忆、图谱关系)都持久化在Neo4j数据库中。只要Neo4j的数据卷(
neo4j_data)没有删除,模拟状态就会一直存在。 - 操作:暂停模拟后,你可以直接关闭浏览器或停止前端/后端服务。下次启动服务后,进入项目,之前的模拟项目会出现在列表中,你可以点击“Resume”继续。
- 注意:LLM的对话上下文(conversation context)是临时的,不保存在Neo4j中。因此,与智能体的聊天记录在刷新页面后会丢失,但智能体的长期记忆(已保存到图谱中的)不会。
5.4 高级技巧与扩展思路
- 自定义智能体人格模板:你可以修改后端中智能体生成的提示词,引入更复杂的人格模型(如九型人格、MBTI),或者为特定行业(如金融、政治)定制专属的人格维度。
- 接入外部数据源:让模拟世界与真实世界联动。例如,写一个定时任务,每天抓取真实的社交媒体话题或新闻头条,将其作为“外部事件”注入到模拟的知识图谱中,观察智能体们的反应。这需要一定的开发工作,修改后端的事件注入逻辑。
- 多场景对比实验:这是MiroFish的杀手级用法。针对同一份文档,创建两个完全相同的模拟环境(需要复制Neo4j数据库),然后在其中一个环境中注入一个“关键事件”(如一条突发丑闻),另一个作为对照组。并行运行后对比两份报告,可以清晰量化该事件对舆论的潜在影响。
- 使用不同的本地模型:Ollama支持成百上千的模型。除了Qwen,你还可以尝试
llama3、mistral、gemma等系列。只需在.env中修改LLM_MODEL_NAME,并确保Ollama中已拉取对应模型。不同模型可能会产生截然不同的模拟风格,值得探索。
MiroFish-Offline将一个前沿的多智能体模拟概念,变成了一台在个人电脑上就能发动的“舆论模拟器”。它的价值不在于预测绝对准确的未来,而在于提供一个低成本的、可控的沙盒环境,让你能够测试各种假设,观察复杂系统的涌现行为,从而获得在真实世界中难以获得的洞察。从技术角度看,它对开源模型生态(Ollama)、图数据库(Neo4j)和智能体架构的集成,也为开发者提供了一个绝佳的学习范本。