MiroFish-Offline Skill
MiroFish-Offline Skill
Skill by
ara.so — Daily 2026 Skills collection.
MiroFish-Offline is a fully local multi-agent swarm intelligence engine. Feed it any document (press release, policy draft, financial report) and it generates hundreds of AI agents with unique personalities that simulate public reaction on social media — posts, arguments, opinion shifts — hour by hour. No cloud APIs required: Neo4j CE 5.15 handles graph memory, Ollama serves the LLMs.
由
ara.so开发的Skill — 属于Daily 2026 Skills合集。
MiroFish-Offline是一款全本地化的多智能体群体智能引擎。向其输入任意文档(新闻稿、政策草案、财务报告),它就能生成数百个具有独特人格的AI Agent,逐小时模拟公众在社交媒体上的反应——包括发帖、争论、观点转变等全过程。无需调用云端API:Neo4j CE 5.15负责图内存存储,Ollama提供大语言模型支持。
Architecture Overview
架构概述
Document Input
│
▼
Graph Build (NER + relationship extraction via Ollama LLM)
│
▼
Neo4j Knowledge Graph (entities, relations, embeddings via nomic-embed-text)
│
▼
Env Setup (generate hundreds of agent personas with personalities + memory)
│
▼
Simulation (agents post, reply, argue, shift opinions on simulated platforms)
│
▼
Report (ReportAgent interviews focus group, queries graph, generates analysis)
│
▼
Interaction (chat with any individual agent, full memory persists)
Backend: Flask + Python 3.11
Frontend: Vue 3 + Node 18
Graph DB: Neo4j CE 5.15 (bolt protocol)
LLM: Ollama (OpenAI-compatible
endpoint)
Embeddings:
(768-dimensional, via Ollama)
Search: Hybrid — 0.7 × vector similarity + 0.3 × BM25
文档输入
│
▼
图构建(通过Ollama LLM实现命名实体识别+关系提取)
│
▼
Neo4j知识图谱(实体、关系、基于nomic-embed-text的嵌入向量)
│
▼
环境搭建(生成数百个带有人格与记忆的Agent角色)
│
▼
仿真模拟(Agent在模拟平台上发帖、回复、争论、转变观点)
│
▼
报告生成(ReportAgent访谈焦点群体、查询图谱、生成分析报告)
│
▼
交互功能(与任意单个Agent对话,完整记忆持久化存储)
后端:Flask + Python 3.11
前端:Vue 3 + Node 18
图数据库:Neo4j CE 5.15(bolt协议)
大语言模型:Ollama(兼容OpenAI的
端点)
嵌入模型:
(768维,通过Ollama提供)
搜索方式:混合搜索 — 0.7×向量相似度 + 0.3×BM25
Option A: Docker (Recommended)
选项A:Docker(推荐)
bash
git clone https://github.com/nikmcfly/MiroFish-Offline.git
cd MiroFish-Offline
cp .env.example .env
bash
git clone https://github.com/nikmcfly/MiroFish-Offline.git
cd MiroFish-Offline
cp .env.example .env
Start Neo4j + Ollama + MiroFish backend + frontend
启动Neo4j + Ollama + MiroFish后端 + 前端
Pull required models into the Ollama container
拉取所需模型到Ollama容器中
docker exec mirofish-ollama ollama pull qwen2.5:32b
docker exec mirofish-ollama ollama pull nomic-embed-text
docker exec mirofish-ollama ollama pull qwen2.5:32b
docker exec mirofish-ollama ollama pull nomic-embed-text
Check all services are healthy
检查所有服务是否健康运行
docker compose ps
Open `http://localhost:3000`.
docker compose ps
打开`http://localhost:3000`即可访问。
Option B: Manual Setup
选项B:手动安装
1. Neo4j
bash
docker run -d --name neo4j \
-p 7474:7474 -p 7687:7687 \
-e NEO4J_AUTH=neo4j/mirofish \
neo4j:5.15-community
2. Ollama
bash
ollama serve &
ollama pull qwen2.5:32b # Main LLM (~20GB, requires 24GB VRAM)
ollama pull qwen2.5:14b # Lighter option (~10GB VRAM)
ollama pull nomic-embed-text # Embeddings (small, fast)
3. Backend
1. 安装Neo4j
bash
docker run -d --name neo4j \
-p 7474:7474 -p 7687:7687 \
-e NEO4J_AUTH=neo4j/mirofish \
neo4j:5.15-community
2. 安装Ollama
bash
ollama serve &
ollama pull qwen2.5:32b # 主LLM(约20GB,需要24GB显存)
ollama pull qwen2.5:14b # 轻量化选项(约10GB显存)
ollama pull nomic-embed-text # 嵌入模型(体积小、速度快)
3. 安装后端
Edit .env (see Configuration section)
编辑.env文件(参考配置章节)
cd backend
pip install -r requirements.txt
python run.py
cd backend
pip install -r requirements.txt
python run.py
**4. Frontend**
```bash
cd frontend
npm install
npm run dev
**4. 安装前端**
```bash
cd frontend
npm install
npm run dev
── LLM (Ollama OpenAI-compatible endpoint) ──────────────────────────
── LLM(Ollama兼容OpenAI端点) ──────────────────────────
── Neo4j ─────────────────────────────────────────────────────────────
── Neo4j ─────────────────────────────────────────────────────────────
NEO4J_URI=bolt://localhost:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=mirofish
NEO4J_URI=bolt://localhost:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=mirofish
── Embeddings (Ollama) ───────────────────────────────────────────────
── 嵌入模型(Ollama) ───────────────────────────────────────────────
── Optional: swap Ollama for any OpenAI-compatible provider ─────────
── 可选:替换Ollama为任意兼容OpenAI的服务商 ─────────
LLM_API_KEY=$OPENAI_API_KEY
LLM_API_KEY=$OPENAI_API_KEY
LLM_MODEL_NAME=gpt-4o
LLM_MODEL_NAME=gpt-4o
Core Python API
核心Python API
GraphStorage Interface
GraphStorage接口
The abstraction layer between MiroFish and the graph database:
python
from backend.storage.base import GraphStorage
from backend.storage.neo4j_storage import Neo4jStorage
MiroFish与图数据库之间的抽象层:
python
from backend.storage.base import GraphStorage
from backend.storage.neo4j_storage import Neo4jStorage
Initialize storage (typically done via Flask app.extensions)
初始化存储(通常通过Flask app.extensions完成)
storage = Neo4jStorage(
uri=os.environ["NEO4J_URI"],
user=os.environ["NEO4J_USER"],
password=os.environ["NEO4J_PASSWORD"],
embedding_model=os.environ["EMBEDDING_MODEL"],
embedding_base_url=os.environ["EMBEDDING_BASE_URL"],
llm_base_url=os.environ["LLM_BASE_URL"],
llm_api_key=os.environ["LLM_API_KEY"],
llm_model=os.environ["LLM_MODEL_NAME"],
)
storage = Neo4jStorage(
uri=os.environ["NEO4J_URI"],
user=os.environ["NEO4J_USER"],
password=os.environ["NEO4J_PASSWORD"],
embedding_model=os.environ["EMBEDDING_MODEL"],
embedding_base_url=os.environ["EMBEDDING_BASE_URL"],
llm_base_url=os.environ["LLM_BASE_URL"],
llm_api_key=os.environ["LLM_API_KEY"],
llm_model=os.environ["LLM_MODEL_NAME"],
)
Building a Knowledge Graph from a Document
从文档构建知识图谱
python
from backend.services.graph_builder import GraphBuilder
builder = GraphBuilder(storage=storage)
python
from backend.services.graph_builder import GraphBuilder
builder = GraphBuilder(storage=storage)
Feed a document string
读取文档字符串
with open("press_release.txt", "r") as f:
document_text = f.read()
with open("press_release.txt", "r") as f:
document_text = f.read()
Extract entities + relationships, store in Neo4j
提取实体+关系,存储到Neo4j
graph_id = builder.build(
content=document_text,
title="Q4 Earnings Report",
source_type="financial_report",
)
print(f"Graph built: {graph_id}")
graph_id = builder.build(
content=document_text,
title="Q4 Earnings Report",
source_type="financial_report",
)
print(f"图谱构建完成: {graph_id}")
Returns a graph_id used for subsequent simulation runs
返回的graph_id用于后续的仿真运行
Creating and Running a Simulation
创建并运行仿真
python
from backend.services.simulation import SimulationService
sim = SimulationService(storage=storage)
python
from backend.services.simulation import SimulationService
sim = SimulationService(storage=storage)
Create a simulation environment from an existing graph
从现有图谱创建仿真环境
sim_id = sim.create_environment(
graph_id=graph_id,
agent_count=200, # Number of agents to generate
simulation_hours=24, # Simulated time span
platform="twitter", # "twitter" | "reddit" | "weibo"
)
sim_id = sim.create_environment(
graph_id=graph_id,
agent_count=200, # 要生成的Agent数量
simulation_hours=24, # 仿真时间跨度
platform="twitter", # 可选值:"twitter" | "reddit" | "weibo"
)
Run the simulation (blocking — use async wrapper for production)
运行仿真(阻塞式——生产环境请使用异步封装)
result = sim.run(sim_id=sim_id)
print(f"Simulation complete. Posts generated: {result['post_count']}")
print(f"Sentiment trajectory: {result['sentiment_over_time']}")
result = sim.run(sim_id=sim_id)
print(f"仿真完成。生成帖子数量: {result['post_count']}")
print(f"情绪变化轨迹: {result['sentiment_over_time']}")
Querying Simulation Results
查询仿真结果
python
from backend.services.report import ReportAgent
report_agent = ReportAgent(storage=storage)
python
from backend.services.report import ReportAgent
report_agent = ReportAgent(storage=storage)
Generate a structured analysis report
生成结构化分析报告
report = report_agent.generate(
sim_id=sim_id,
focus_group_size=10, # Number of agents to interview
include_graph_search=True,
)
print(report["summary"])
print(report["key_narratives"])
print(report["sentiment_shift"])
print(report["influential_agents"])
report = report_agent.generate(
sim_id=sim_id,
focus_group_size=10, # 要访谈的Agent数量
include_graph_search=True,
)
print(report["summary"])
print(report["key_narratives"])
print(report["sentiment_shift"])
print(report["influential_agents"])
Chatting with a Simulated Agent
与仿真Agent对话
python
from backend.services.agent_chat import AgentChatService
chat = AgentChatService(storage=storage)
python
from backend.services.agent_chat import AgentChatService
chat = AgentChatService(storage=storage)
List agents from a completed simulation
列出已完成仿真中的Agent
agents = chat.list_agents(sim_id=sim_id, limit=10)
agent_id = agents[0]["id"]
print(f"Chatting with: {agents[0]['persona']['name']}")
print(f"Personality: {agents[0]['persona']['traits']}")
agents = chat.list_agents(sim_id=sim_id, limit=10)
agent_id = agents[0]["id"]
print(f"正在与以下Agent对话: {agents[0]['persona']['name']}")
print(f"人格特质: {agents[0]['persona']['traits']}")
Send a message — agent responds in-character with full memory
发送消息——Agent会结合完整记忆以符合其人格的方式回复
response = chat.send(
agent_id=agent_id,
message="Why did you post that criticism about the earnings report?",
)
print(response["reply"])
response = chat.send(
agent_id=agent_id,
message="你为什么要发布那篇批评收益报告的帖子?",
)
print(response["reply"])
→ Agent responds using its personality, opinion bias, and post history
→ Agent会结合自身人格、观点倾向及发帖历史进行回复
Hybrid Search on the Knowledge Graph
知识图谱混合搜索
python
from backend.services.search import SearchService
search = SearchService(storage=storage)
python
from backend.services.search import SearchService
search = SearchService(storage=storage)
Hybrid search: 0.7 * vector similarity + 0.3 * BM25
混合搜索:0.7×向量相似度 + 0.3×BM25
results = search.query(
text="executive compensation controversy",
graph_id=graph_id,
top_k=5,
vector_weight=0.7,
bm25_weight=0.3,
)
for r in results:
print(r["entity"], r["relationship"], r["score"])
results = search.query(
text="高管薪酬争议",
graph_id=graph_id,
top_k=5,
vector_weight=0.7,
bm25_weight=0.3,
)
for r in results:
print(r["entity"], r["relationship"], r["score"])
Implementing a Custom GraphStorage Backend
自定义GraphStorage后端实现
python
from backend.storage.base import GraphStorage
from typing import List, Dict, Any
class MyCustomStorage(GraphStorage):
"""
Swap Neo4j for any graph DB by implementing this interface.
Register via Flask app.extensions['neo4j_storage'] = MyCustomStorage(...)
"""
def store_entity(self, entity: Dict[str, Any]) -> str:
# Store entity, return entity_id
raise NotImplementedError
def store_relationship(
self,
source_id: str,
target_id: str,
relation_type: str,
properties: Dict[str, Any],
) -> str:
raise NotImplementedError
def vector_search(
self, embedding: List[float], top_k: int = 5
) -> List[Dict[str, Any]]:
raise NotImplementedError
def keyword_search(
self, query: str, top_k: int = 5
) -> List[Dict[str, Any]]:
raise NotImplementedError
def get_agent_memory(self, agent_id: str) -> Dict[str, Any]:
raise NotImplementedError
def update_agent_memory(
self, agent_id: str, memory_update: Dict[str, Any]
) -> None:
raise NotImplementedError
python
from backend.storage.base import GraphStorage
from typing import List, Dict, Any
class MyCustomStorage(GraphStorage):
"""
通过实现此接口,可将Neo4j替换为任意图数据库。
通过Flask app.extensions['neo4j_storage'] = MyCustomStorage(...)完成注册。
"""
def store_entity(self, entity: Dict[str, Any]) -> str:
# 存储实体,返回entity_id
raise NotImplementedError
def store_relationship(
self,
source_id: str,
target_id: str,
relation_type: str,
properties: Dict[str, Any],
) -> str:
raise NotImplementedError
def vector_search(
self, embedding: List[float], top_k: int = 5
) -> List[Dict[str, Any]]:
raise NotImplementedError
def keyword_search(
self, query: str, top_k: int = 5
) -> List[Dict[str, Any]]:
raise NotImplementedError
def get_agent_memory(self, agent_id: str) -> Dict[str, Any]:
raise NotImplementedError
def update_agent_memory(
self, agent_id: str, memory_update: Dict[str, Any]
) -> None:
raise NotImplementedError
Flask App Integration Pattern
Flask应用集成模式
backend/app.py — how storage is wired via dependency injection
backend/app.py — 如何通过依赖注入实现存储组件的连接
from flask import Flask
from backend.storage.neo4j_storage import Neo4jStorage
import os
def create_app():
app = Flask(name)
# Single storage instance, injected everywhere via app.extensions
storage = Neo4jStorage(
uri=os.environ["NEO4J_URI"],
user=os.environ["NEO4J_USER"],
password=os.environ["NEO4J_PASSWORD"],
embedding_model=os.environ["EMBEDDING_MODEL"],
embedding_base_url=os.environ["EMBEDDING_BASE_URL"],
llm_base_url=os.environ["LLM_BASE_URL"],
llm_api_key=os.environ["LLM_API_KEY"],
llm_model=os.environ["LLM_MODEL_NAME"],
)
app.extensions["neo4j_storage"] = storage
from backend.routes import graph_bp, simulation_bp, report_bp
app.register_blueprint(graph_bp)
app.register_blueprint(simulation_bp)
app.register_blueprint(report_bp)
return app
from flask import Flask
from backend.storage.neo4j_storage import Neo4jStorage
import os
def create_app():
app = Flask(name)
# 单例存储实例,通过app.extensions注入到所有模块
storage = Neo4jStorage(
uri=os.environ["NEO4J_URI"],
user=os.environ["NEO4J_USER"],
password=os.environ["NEO4J_PASSWORD"],
embedding_model=os.environ["EMBEDDING_MODEL"],
embedding_base_url=os.environ["EMBEDDING_BASE_URL"],
llm_base_url=os.environ["LLM_BASE_URL"],
llm_api_key=os.environ["LLM_API_KEY"],
llm_model=os.environ["LLM_MODEL_NAME"],
)
app.extensions["neo4j_storage"] = storage
from backend.routes import graph_bp, simulation_bp, report_bp
app.register_blueprint(graph_bp)
app.register_blueprint(simulation_bp)
app.register_blueprint(report_bp)
return app
Accessing Storage in a Flask Route
在Flask路由中访问存储组件
python
from flask import Blueprint, current_app, request, jsonify
simulation_bp = Blueprint("simulation", __name__)
@simulation_bp.route("/api/simulation/run", methods=["POST"])
def run_simulation():
storage = current_app.extensions["neo4j_storage"]
data = request.json
sim = SimulationService(storage=storage)
sim_id = sim.create_environment(
graph_id=data["graph_id"],
agent_count=data.get("agent_count", 200),
simulation_hours=data.get("simulation_hours", 24),
)
result = sim.run(sim_id=sim_id)
return jsonify(result)
python
from flask import Blueprint, current_app, request, jsonify
simulation_bp = Blueprint("simulation", __name__)
@simulation_bp.route("/api/simulation/run", methods=["POST"])
def run_simulation():
storage = current_app.extensions["neo4j_storage"]
data = request.json
sim = SimulationService(storage=storage)
sim_id = sim.create_environment(
graph_id=data["graph_id"],
agent_count=data.get("agent_count", 200),
simulation_hours=data.get("simulation_hours", 24),
)
result = sim.run(sim_id=sim_id)
return jsonify(result)
REST API Reference
REST API参考
| Method | Endpoint | Description |
|---|
| | Upload document, build knowledge graph |
| | Get graph entities and relationships |
| | Create simulation environment |
| | Execute simulation |
| /api/simulation/:id/results
| Get posts, sentiment, metrics |
| /api/simulation/:id/agents
| List generated agents |
| | Generate ReportAgent analysis |
| | Chat with a specific agent |
| | Hybrid search the knowledge graph |
Example: Build graph from document
bash
curl -X POST http://localhost:5000/api/graph/build \
-H "Content-Type: application/json" \
-d '{
"content": "Acme Corp announces record Q4 earnings, CFO resigns...",
"title": "Q4 Press Release",
"source_type": "press_release"
}'
| 方法 | 端点 | 描述 |
|---|
| | 上传文档,构建知识图谱 |
| | 获取图谱的实体与关系 |
| | 创建仿真环境 |
| | 执行仿真 |
| /api/simulation/:id/results
| 获取帖子、情绪数据及指标 |
| /api/simulation/:id/agents
| 列出生成的Agent |
| | 生成ReportAgent分析报告 |
| | 与指定Agent对话 |
| | 对知识图谱执行混合搜索 |
示例:从文档构建图谱
bash
curl -X POST http://localhost:5000/api/graph/build \
-H "Content-Type: application/json" \
-d '{
"content": "Acme Corp宣布第四季度收益创新高,首席财务官辞职...",
"title": "Q4新闻稿",
"source_type": "press_release"
}'
→ {"graph_id": "g_abc123", "entities": 47, "relationships": 89}
→ {"graph_id": "g_abc123", "entities": 47, "relationships": 89}
**Example: Run a simulation**
```bash
curl -X POST http://localhost:5000/api/simulation/run \
-H "Content-Type: application/json" \
-d '{
"graph_id": "g_abc123",
"agent_count": 150,
"simulation_hours": 12,
"platform": "twitter"
}'
**示例:运行仿真**
```bash
curl -X POST http://localhost:5000/api/simulation/run \
-H "Content-Type: application/json" \
-d '{
"graph_id": "g_abc123",
"agent_count": 150,
"simulation_hours": 12,
"platform": "twitter"
}'
→ {"sim_id": "s_xyz789", "status": "running"}
→ {"sim_id": "s_xyz789", "status": "running"}
Hardware Selection Guide
硬件选型指南
| Use Case | Model | VRAM | RAM |
|---|
| Quick test / dev | | 6 GB | 16 GB |
| Balanced quality | | 10 GB | 16 GB |
| Production quality | | 24 GB | 32 GB |
| CPU-only (slow) | | None | 16 GB |
Switch model by editing
:
bash
LLM_MODEL_NAME=qwen2.5:14b
Then restart the backend — no other changes needed.
| 使用场景 | 模型 | 显存 | 内存 |
|---|
| 快速测试/开发 | | 6 GB | 16 GB |
| 平衡性能与质量 | | 10 GB | 16 GB |
| 生产环境质量 | | 24 GB | 32 GB |
| 仅CPU运行(速度慢) | | 无 | 16 GB |
bash
LLM_MODEL_NAME=qwen2.5:14b
然后重启后端即可,无需其他修改。
PR Crisis Test Pipeline
公关危机测试流水线
python
import os
from backend.storage.neo4j_storage import Neo4jStorage
from backend.services.graph_builder import GraphBuilder
from backend.services.simulation import SimulationService
from backend.services.report import ReportAgent
storage = Neo4jStorage(
uri=os.environ["NEO4J_URI"],
user=os.environ["NEO4J_USER"],
password=os.environ["NEO4J_PASSWORD"],
embedding_model=os.environ["EMBEDDING_MODEL"],
embedding_base_url=os.environ["EMBEDDING_BASE_URL"],
llm_base_url=os.environ["LLM_BASE_URL"],
llm_api_key=os.environ["LLM_API_KEY"],
llm_model=os.environ["LLM_MODEL_NAME"],
)
def test_press_release(text: str) -> dict:
# 1. Build knowledge graph
builder = GraphBuilder(storage=storage)
graph_id = builder.build(content=text, title="Draft PR", source_type="press_release")
# 2. Simulate public reaction
sim = SimulationService(storage=storage)
sim_id = sim.create_environment(graph_id=graph_id, agent_count=300, simulation_hours=48)
sim.run(sim_id=sim_id)
# 3. Generate report
report = ReportAgent(storage=storage).generate(sim_id=sim_id, focus_group_size=15)
return {
"sentiment_peak": report["sentiment_over_time"][0],
"key_narratives": report["key_narratives"],
"risk_score": report["risk_score"],
"recommended_edits": report["recommendations"],
}
python
import os
from backend.storage.neo4j_storage import Neo4jStorage
from backend.services.graph_builder import GraphBuilder
from backend.services.simulation import SimulationService
from backend.services.report import ReportAgent
storage = Neo4jStorage(
uri=os.environ["NEO4J_URI"],
user=os.environ["NEO4J_USER"],
password=os.environ["NEO4J_PASSWORD"],
embedding_model=os.environ["EMBEDDING_MODEL"],
embedding_base_url=os.environ["EMBEDDING_BASE_URL"],
llm_base_url=os.environ["LLM_BASE_URL"],
llm_api_key=os.environ["LLM_API_KEY"],
llm_model=os.environ["LLM_MODEL_NAME"],
)
def test_press_release(text: str) -> dict:
# 1. 构建知识图谱
builder = GraphBuilder(storage=storage)
graph_id = builder.build(content=text, title="Draft PR", source_type="press_release")
# 2. 模拟公众反应
sim = SimulationService(storage=storage)
sim_id = sim.create_environment(graph_id=graph_id, agent_count=300, simulation_hours=48)
sim.run(sim_id=sim_id)
# 3. 生成分析报告
report = ReportAgent(storage=storage).generate(sim_id=sim_id, focus_group_size=15)
return {
"sentiment_peak": report["sentiment_over_time"][0],
"key_narratives": report["key_narratives"],
"risk_score": report["risk_score"],
"recommended_edits": report["recommendations"],
}
with open("draft_announcement.txt") as f:
result = test_press_release(f.read())
print(f"Risk score: {result['risk_score']}/10")
print(f"Top narrative: {result['key_narratives'][0]}")
with open("draft_announcement.txt") as f:
result = test_press_release(f.read())
print(f"风险评分: {result['risk_score']}/10")
print(f"核心舆论倾向: {result['key_narratives'][0]}")
Use Any OpenAI-Compatible Provider
使用任意兼容OpenAI的服务商
Claude via Anthropic (or any proxy)
通过Anthropic使用Claude(或任意代理)
Local LM Studio
本地LM Studio
Neo4j connection refused
Neo4j连接被拒绝
Check Neo4j is running
检查Neo4j是否在运行
docker logs neo4j --tail 50
docker logs neo4j --tail 50
Ollama model not found
Ollama模型未找到
List available models
列出可用模型
Pull missing models
拉取缺失的模型
ollama pull qwen2.5:32b
ollama pull nomic-embed-text
ollama pull qwen2.5:32b
ollama pull nomic-embed-text
Check Ollama is serving
检查Ollama是否正常提供服务
Switch to smaller model in .env
在.env中切换为更小的模型
LLM_MODEL_NAME=qwen2.5:14b # or qwen2.5:7b
LLM_MODEL_NAME=qwen2.5:14b # 或qwen2.5:7b
cd backend && python run.py
cd backend && python run.py
Embeddings dimension mismatch
嵌入向量维度不匹配
nomic-embed-text produces 768-dim vectors
nomic-embed-text生成768维向量
If you switch embedding models, drop and recreate the Neo4j vector index:
若切换嵌入模型,需删除并重新创建Neo4j向量索引:
DROP INDEX entity_embedding IF EXISTS;
DROP INDEX entity_embedding IF EXISTS;
Then restart MiroFish — it recreates the index with correct dimensions.
然后重启MiroFish——它会自动以正确维度重建索引。
Docker Compose: Ollama container can't access GPU
Docker Compose:Ollama容器无法访问GPU
docker-compose.yml — add GPU reservation:
docker-compose.yml — 添加GPU资源预留:
services:
ollama:
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
services:
ollama:
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
Slow simulation on CPU
CPU运行仿真速度慢
- Use for faster (lower quality) inference
- Reduce to 50–100 for testing
- Reduce to 6–12
- CPU inference with 7b model: expect ~5–10 tokens/sec
- 使用模型以获得更快(质量稍低)的推理速度
- 测试时将减少到50–100
- 将减少到6–12
- 7b模型的CPU推理速度:预计约5–10 tokens/秒
Frontend can't reach backend
前端无法连接后端
Check VITE_API_BASE_URL in frontend/.env
检查frontend/.env中的VITE_API_BASE_URL
Verify backend is up
验证后端是否正常运行
MiroFish-Offline/
├── backend/
│ ├── run.py # Entry point
│ ├── app.py # Flask factory, DI wiring
│ ├── storage/
│ │ ├── base.py # GraphStorage abstract interface
│ │ └── neo4j_storage.py # Neo4j implementation
│ ├── services/
│ │ ├── graph_builder.py # NER + relationship extraction
│ │ ├── simulation.py # Agent simulation engine
│ │ ├── report.py # ReportAgent + focus group
│ │ ├── agent_chat.py # Per-agent chat interface
│ │ └── search.py # Hybrid vector + BM25 search
│ └── routes/
│ ├── graph.py
│ ├── simulation.py
│ └── report.py
├── frontend/ # Vue 3 (fully English UI)
├── docker-compose.yml
├── .env.example
└── README.md
MiroFish-Offline/
├── backend/
│ ├── run.py # 项目入口
│ ├── app.py # Flask工厂、依赖注入配置
│ ├── storage/
│ │ ├── base.py # GraphStorage抽象接口
│ │ └── neo4j_storage.py # Neo4j实现
│ ├── services/
│ │ ├── graph_builder.py # 命名实体识别+关系提取服务
│ │ ├── simulation.py # Agent仿真引擎
│ │ ├── report.py # ReportAgent+焦点群体分析服务
│ │ ├── agent_chat.py # 单Agent对话接口
│ │ └── search.py # 混合向量+BM25搜索服务
│ └── routes/
│ ├── graph.py
│ ├── simulation.py
│ └── report.py
├── frontend/ # Vue 3实现(全英文UI)
├── docker-compose.yml
├── .env.example
└── README.md