跳转到主要内容
Mirobody 是一套 C++11 引擎。它可以在桌面/服务器上独立运行,也可以在 Android / iOS 应用内端侧运行,因此健康数据无需离开手机。它用 CMake 构建(Windows 上外加 vcpkg),由五个可以独立扩展的部分组成。
Mirobody architecture overview

五个部分

部分路径说明
LLM 客户端src/llm/每个 provider 一个流式 llm::ClientOpenAIChatClientGeminiClientMiroThinkerClient,外加 EmbeddingClient 以及实时的 OpenAIRealtimeClient / GeminiLiveClient(WebSocket 上的音频)。
MCP 工具src/mcp/ + res/mcp_tools/通过 /mcp 端点(JSON-RPC 2.0)暴露的服务端工具。九个内置工具是在编译时自注册的 C++ 文件。
Agentsrc/chat/ + res/agents/base.cpp一个 Agent(“Base”):按 provider 选择一个 LLM 客户端,构建 system prompt,把这一轮流式返回,其间调用 MCP 工具。
健康 vendorsrc/health/vendor/每个数据源一个 vendor::Vendor,置于 authorize / fetch / webhook 契约之后,通过注册表按 id 解析。
FHIR R4src/fhir/内嵌的 RESTful FHIR R4 端点 + 术语(单位归一化为 UCUM)。
Agent 和工具都在编译时自注册:把一个 .cpp 丢进相应的 res/ 目录并重新构建 —— CMakeLists.txt 会用 CONFIGURE_DEPENDS glob res/mcp_tools/*.cpp(以及 res/agents/)。

Agent

Mirobody 运行一个简单的 Agent —— res/agents/base.cpp。它没有 Agent 循环,没有 planner,也没有中间件。每一轮它按 provider 名称选择一个 LLM 客户端,构建一段固定的内联 system prompt(当前时间、回复语言,以及使用文件 / 健康工具的引导),并把 provider 的事件直接流式返回,让模型调用内置的 MCP 工具。
该 Agent 刻意保持轻量:它选择一个 provider,构建提示词,流式返回一轮,并按需调用 MCP 工具。你选择的是一个 模型provider),而不是 Agent 类型。

支持的提供商

该 Agent 注册最多四个 provider 客户端,以 /api/providers 选择器展示的模型名为键:
  • gemini-2.5-flash —— Google Gemini 2.5 Flash(默认 provider),GeminiClient
  • gpt-5-nano —— OpenAI GPT-5 nano,OpenAIChatClient
  • mirothinker-1.7 —— MiroThinker(MiroMind),MiroThinkerClient
  • gemma-4-e2b —— 端侧 Gemma 4 E2B,通过本地 OpenAI 兼容端点提供服务(仅在设置了 base URL 时才注册)。
原生应用还会在端侧运行 Gemma 4 E2B(Android/iOS 上用 LiteRT-LM,Electron 上用 llama.cpp)—— 完全离线、无需 API 密钥。工具执行因 provider 而异: OpenAI 和 Gemini 把工具作为 function-call 描述符接收,引擎以已认证用户的身份在本地进程内执行每次调用;MiroThinker 则在 provider 侧运行工具 —— MiroMind 通过公网在 MCP_PUBLIC_URL 反向访问你的 /mcp 端点。实时音频聊天可通过 WebSocket 经 OpenAI Realtime 和 Gemini Live 使用。 配置见 工具与 Agent 概览

MCP 工具

工具是 res/mcp_tools/ 中的 C++ 文件。每个声明一个 Tool —— 名称、描述、一个 auth 标志、一张 Param 表以及一个 handler —— 并通过 MIROBODY_REGISTER_TOOL(...) 自注册。C++11 没有运行时反射,因此参数显式声明,注册表会把它们展开成 MCP 的 inputSchema 以及 OpenAI / Gemini 的 function 描述符。
// res/mcp_tools/echo.cpp — the smallest complete tool
const Tool kEcho = {
    "echo",
    "Echo back the provided text.",
    false,                                                    // auth
    { Param("text", Type::String, Required, "Text to echo back") },
    &echo,
};
MIROBODY_REGISTER_TOOL(kEcho);
默认提供九个工具:list_filesread_filefamily_healthwhoamirecall_memoryrememberrender_chartsummarize_conversationecho。一个 auth 工具以 UserInfo 接收调用者身份;它需要的其它后端(缓存、对象存储、数据库、记忆)通过 ToolContext 送达。参见 内置工具添加自定义工具

健康 vendor

每个数据源是 src/health/vendor/ 中的一个 vendor::Vendor,置于同一份 authorize / fetch / webhook 契约之后,并通过注册表按 id 解析。分桶如下:
分桶路径数据源
Platformsplatform/15 个 B2B 聚合器 —— Terra、Validic、Human API、Junction、Metriport……
Phonephone/Huawei
Devicedevice/Fitbit、Garmin、Withings、Oura、Polar
EHRehr/SMART on FHIR —— 面向 ONC 认证 EHR(Epic、Oracle Health / Cerner、athenahealth)的一个通用客户端,通过 ONC Lantern 发现
仅端侧的存储(Apple Health、Samsung Health、Google Health Connect、Xiaomi)没有服务端客户端 —— 由宿主应用在端侧读取并 POST FHIR Observation。要添加一个数据源,实现一个 vendor::Vendor;参见 Provider 集成

FHIR R4 与术语

src/fhir/ 内嵌了一个 RESTful FHIR R4 端点(/fhir/*)。单位归一化为 UCUM。上传的文档会被解析成指标和数值。把指标映射到 SNOMED CT / LOINC / RxNorm,以及完整的文档→指标术语流水线,部分仍在进行中 —— UCUM 已交付;更广的术语映射仍在落地。(verify:以当前构建为准确认确切状态。)

存储与基础设施

  • 数据库 —— 在构建期通过 CMake -DMIROBODY_DATABASE_BACKEND= 选定:SQLITE(移动端默认)、POSTGRESQL(桌面端默认)、MYSQLDUCKDBCLICKHOUSE。SQL schema 位于 res/sql/
  • 文件存储 —— S3 / S3 兼容(MinIO、R2)、阿里云 OSS、Azure Blob 或本地文件系统(默认),在运行时选定。
  • 缓存 —— 默认是一个进程内的内存 KV 存储,或在设置了 REDIS_HOST 时使用 Redis。
  • 配置 —— config.yml(源自 config.example.yml);优先级为 环境变量 > config.yml > 远程配置 > config.example.yml。键名包含 _KEY / _PASSWORD / _SECRET / _TOKEN(及类似)的值会用 CONFIG_ENCRYPTION_KEY 自动加密(Fernet)。参见 配置
  • 认证 —— 多用户 JWT;一个带 OIDC discovery + PKCE 的 OAuth 2.0 授权服务器(以便 MCP 客户端为 /mcp 获取 token);通过邮箱一次性验证码,以及 Google / Apple / WeChat / GitHub(Firebase)外加 Tanka QR 登录。
  • Web 客户端 —— htdoc/ 中的一个静态 SPA,构建进 res/htdocHTTP_ROOT)并在 HTTP 根路径提供服务。

部署:一个核心,三种形态

同一个核心以三种方式交付:
  1. 独立二进制 —— ./build.shbuild/mirobody,在 HTTP_HOST:HTTP_PORT(默认 0.0.0.0:8080)上提供 HTTP + WebSocket 服务,并读取 ./config.yml
  2. Android —— libmirobody.so 通过 JNI 加载进宿主应用(Gradle + NDK)。
  3. iOS —— libmirobody.a / mirobody.xcframework 通过 src/mirobody.h 中的 C API 链接。
那个 extern "C" C API 还让 Java、Go、C#、Rust、Swift 或 Python 得以直接嵌入该核心。

HTTP 路由

路由用途
/api/health健康检查
/api/chat聊天 —— POST 流式返回 Server-Sent Events;GET 升级为 WebSocket(实时)
/api/providers列出可用 provider
/api/history对话历史
/api/files文件上传 / 列表
/fhir/*内嵌的 FHIR R4 端点
/mcp, /mcp/{secret}MCP 端点(JSON-RPC 2.0)
/oauth/*OAuth 2.0 授权服务器

端到端请求流程

已登录用户在 Web UI 里发出*“我最近睡得怎么样?“*时,会发生什么:
1. Browser POSTs to /api/chat (Server-Sent Events).
2. JWT middleware resolves the caller → user_id.
3. The chat service seeds/uses a conversation and persists the user message.
4. The Base agent is created: it detects the response language, builds the
   system prompt, and resolves the LLM client for the requested provider
   (default gemini-2.5-flash).
5. The client streams the turn. When the model calls a tool:
   - OpenAI / Gemini → the engine runs it locally in-process as the user
     (e.g. family_health → recent FHIR Observations; render_chart → a chart
     event the frontend draws with ECharts).
   - MiroThinker → the tool runs provider-side over MCP_PUBLIC_URL.
6. Reply chunks stream back over SSE; the response is persisted.
7. summarize_conversation may set a short title for the chat-history list.
会话分享(无需登录的只读路径)见 会话分享

下一步去哪

Providers

设备和 EHR 如何接入

数据流

从厂商原始 payload 到归一化的 FHIR

文件处理

多格式文件的接入与解析

工具与 Agent

跨 MCP 生态构建并暴露工具