跳转到内容
快速开始

开始使用

快速开始

克隆 Mirobody,运行 ./deploy.sh,在 localhost:18080 登录,然后填一个 LLM key。

从一个空目录到登录进 Mirobody 的一条路径:克隆、运行 ./deploy.sh、打开浏览器、用演示账号登录,然后填一个 LLM key。全程运行在 Docker 里,本页不需要宿主机上有 Python 或 Node。

要求为什么
Docker + Docker Composedeploy.sh 会构建一个镜像并启动四个容器。
Git用来克隆仓库。
Git LFSmirobody/res/ 下的术语与指标资源是 LFS 对象。未安装 LFS 获得的是指针文件,启动会失败。

在克隆之前装好 Git LFS:apt install git-lfsbrew install git-lfs,Git for Windows 自带。

Terminal window
git lfs install # once per machine
git clone https://github.com/thetahealth/mirobody.git
cd mirobody
Terminal window
./deploy.sh

这个脚本做四件事:

写出 .env

设置 ENV=localdb,并生成一个 32 字符的 CONFIG_ENCRYPTION_KEY。已存在的文件不会被改动。

写出 config.localdb.yaml

你的覆盖文件,预置了一个随机 JWT_KEY、演示登录验证码,以及被注释掉的 LLM key 占位。

构建镜像

一个 Ubuntu 24.04 镜像,内含 Python 虚拟环境与 Node.js。如果 hub.docker.com 不通,脚本会回退到 docker.1ms.run 镜像源,npm 也会指向 registry.npmmirror.com

启动整套服务

docker compose up -d,然后在前台跟踪日志。四个容器会起来:pg(18082)、redis(18089)、mirobody(18080)、mirobody_worker

打开 http://localhost:18080。引擎会把进程旁边 frontend/ 目录里预构建好的 Web 客户端提供出去,它刻意放在 Python 包之外,这样 wheel 装的是引擎,而不是 8 MB 的 JavaScript。

deploy.sh 会在 config.localdb.yaml 里写入三个预置账号。任选一个,用对应的码作为验证码:

demo1@mirobody.ai
777777

只把这段从 config.localdb.yaml 里删除是不够的:config.yaml 模板自己也带一个预置账号(caregiver@mirobody.ai),而且它先加载。正确做法是把这个键覆盖成空值:

config.localdb.yaml
EMAIL_PREDEFINE_CODES:

验证码需要 Mandrill 或 SMTP,而克隆下来试用的部署两者都没有,因此登录页默认落在密码这 一栏,把邮箱验证码留作第三栏。底层接口接收邮箱(或 username)加一个不少于八位的密码:

Terminal window
curl -X POST localhost:18080/password/register -H 'Content-Type: application/json' \
-d '{"email":"you@example.com","password":"at-least-8-chars"}'

它返回 token 并创建账号;用同样的请求体调 POST /password/login 即可再次登录。哈希是 pgcrypto 在 Postgres 内部算的 bcrypt,所以密码不会在 Python 里被哈希、比较或写进日志,仓库 里也不预置任何密码。对已有密码的账号,register 会拒绝而不是覆盖;密码错误与账号不存在 返回完全相同的结果;两条都是刻意为之。

compose.yaml 设了 SEED_DEMO_DATA=true,所以这条路启动完带着数据,而不是一个空库。一位合成 用户 Demo (synthetic) 会被共享进每一个预置账号的关爱圈,带着 2024-04-16 至 2026-04-15 之间 的 244 项指标和五份 agent 可读的文档。用演示账号登录时,你自己没有任何数据,读到的记录属于 另一个人。

先提问,而不是先看数据表。在问答页问:「她最近一次的 LDL 胆固醇是多少,和一年前比怎么样?」 答案来自她预置的历史,而 agent 往往会自己指出最新那次面板已经过去一年多。她的下一次面板被 刻意留在预置数据之外,以文件形式随包发布:mirobody/demo/lab_report_2025-10-15.pdf

在数据页上传它(或用问答页的 +),前两个步骤就会在一份真实文档上运行:十二个分析物带着单位被 读出,各自解析到编码,LDL 序列多出第四个点;再问同一个问题,答案就变了。

所有数值均为合成,PDF 上也印着这一点。fixture 是随包 vendor 进来的,因此灌数据不需要联网、不 需要任何 API key;它是 upsert,重启不会灌重。承载真实数据的部署请设 SEED_DEMO_DATA=false

登录进去了,但 agent 还没有可调用的模型。编辑 config.localdb.yaml,至少设置一个 key:

config.localdb.yaml
# Pick whichever provider you have a key for. One is enough to start.
OPENROUTER_API_KEY: 'sk-or-...'
# GOOGLE_API_KEY: 'AIza...'
# OPENAI_API_KEY: 'sk-...'

然后重启两个应用容器:

Terminal window
docker compose restart mirobody mirobody_worker

每个 agent 各自能用哪些模型,是在 PROVIDERS_DEEPPROVIDERS_BASE 下按 agent 配置的,config.yaml 里的默认值已经引用了上面这些键名。

对话需要的是 LLM key。embedding key 是另一把,而且是可选的,它换来的是自由文本检索指标和 规整的显示名:

config.localdb.yaml
EMBEDDING_PROVIDER: gemini # 默认值
GOOGLE_API_KEY: 'AIza...' # gemini 对应的 embedding key
# EMBEDDING_PROVIDER: qwen # 另一个支持的 provider
# DASHSCOPE_API_KEY: 'sk-...'

不配它也能用:浏览记录、以及按名称查询指标,这两条路径都是纯 SQL。会降级的是模糊关键词 检索:它会退回成列出指标目录,而不是报错;指标名也会保持数据源原本的拼写 (AlanineAminotransferase-ALT),而不是 embedding 那一遍产出的显示名。如果配了 embedding key 但它不工作,失败是静默的,docker compose logs mirobody_worker 是它唯一说话的地方。

Terminal window
# All four containers up?
docker compose ps
# Liveness — returns JSON with the service name, version, and counts of
# tools, resources and agents that were discovered at startup.
curl http://localhost:18080/api/health
# MCP discovery — JSON-RPC 2.0 over POST, lists the registered tools.
curl -X POST http://localhost:18080/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

如果 /api/health 返回 "tools": 0,说明工具目录没扫到,检查 MCP_TOOL_DIRS 和启动日志(docker compose logs mirobody)。