生物T传感器助手(LLM_App)
BioT Speech IoT项目的Python后端。主持人:
- A. FastAPI服务器 这暴露了
POST /chat对于Android应用程序。 - 一 LLM代理 (提供者不可知——Anthropic、OpenAI、DeepSeek、Gemini)。
- A. 正确的MCP服务器 (
FastMCP,流式HTTP,端口8002),暴露
传感器查询工具。
- 一 MQTT用户 将实时传感器读数镜像到SQLite中
代理可以查询的数据库。
系统角色: 这是BioT拆分的服务器端。 Android应用程序是客户端,它拥有手机上的Room数据库 实时图表。服务器的SQLite是一个单独的并行视图 相同的MQTT数据,仅由LLM使用。看 数据库架构.
______________________________________________________________________
目录
______________________________________________________________________
建筑
┌──────────────────────────────┐
│ Android app (BioT_Speech_IoT_App)
│ - Voice → VoiceCommandResolver
│ - QUERY_* + UNKNOWN → LlmQueryHandler
│ │
└──────┼───────────────────────┘
│ POST /chat { "message": "..." }
▼
┌────────────────────────────────────────┐
│ app/main.py (FastAPI, port 8001) │
│ ├── /health │
│ └── /chat ─► SensorAgent.run() │
│ │ │
│ ▼ │
│ app/agent.py │
│ (provider-agnostic) │
└──────┬─────────────────────┬────────────┘
│ HTTP │ tool calls
▼ ▼
┌───────────────────────────┐ ┌───────────────────────────┐
│ Anthropic / OpenAI / │ │ mcp_server/ │
│ DeepSeek / Gemini API │ │ sensor_mcp_server.py │
│ (chosen by LLM_PROVIDER) │ │ FastMCP, port 8002 │
└───────────────────────────┘ └────────────┬───────────────┘
│ SELECT
▼
┌────────────────────────────┐
│ data/sensor_database.db │
│ (SQLite, read-only by MCP)│
└────────────▲───────────────┘
│ INSERT
┌─────────────────────┴─────────────────┐
│ mcp_server/mqtt_subscriber.py │
│ (background thread inside FastAPI) │
└─────────────────▲─────────────────────┘
│ subscribes Sensor/*
│
┌─────────────────┴─────────────────────┐
│ Mosquitto MQTT broker │
└─────────────────▲─────────────────────┘
│ publishes Sensor/*
┌─────────────────┴─────────────────────┐
│ ESP8266 + MPU-6050 + A3144 │
└───────────────────────────────────────┘MCP服务器作为 子进程 FastAPI服务器-- app/main.py 在FastAPI生命周期启动期间生成它。代理通过HTTP到达它 上 localhost:8002。要公开部署,请更改 MCP_SERVER_URL 在 .env 而无需更改任何代码。
______________________________________________________________________
数据库架构
BioT系统具有 两个SQLite数据库。这是故意的 记录在这里,所以看起来不像是bug。
| 数据库 | 位置 | 编写人 | 读取人 | 目的 |
|---|---|---|---|---|
| 房间(电话) | /data/data/com.fhdw.biot.speech.iot/databases/sensor_database | 安卓 MainActivity 从MQTT消息 | 所有图表活动通过 LiveData | 反应式UI、离线图表、日期过滤器 |
| 服务器SQLite | LLM_App/data/sensor_database.db | mqtt_subscriber.py 从MQTT消息 | MCP工具(只读) | LLM历史查询、异常分析 |
两个数据库都使用 相同的模式 (参见 mqtt_subscriber._ensure_db_schema) 因此,代理的SQL查询对任何一个都以相同的方式工作。他们都订阅了 对于相同的MQTT主题,它们只是写入不同的文件。
为什么没有一个DB?
- Room位于Android应用沙箱中。MCP服务器无法访问它
没有 adb pull.
- 将Room从Android应用程序中删除意味着重写每个图表
活动(AccelActivity, GyroActivity, MagnetActivity, MainGraphActivity)从HTTP端点获取数据,并会破坏离线图表。
- 两个DB的“额外”成本是一个后台线程(
mqtt_subscriber)那个
不管怎样,他一直在跑步。与MQTT相比,磁盘开销可以忽略不计 系统处理的消息量。
______________________________________________________________________
先决条件
- Python 3.10+https://www.python.org/downloads/
uv(Astral的软件包管理器)。通过PowerShell安装:
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"- Mosquitto MQTT代理在同一台机器上运行(或可在局域网上访问)
- API密钥来自其中之一:Anthropic/OpenAI/DeepSeek/Gemini
______________________________________________________________________
快速开始
# 1. Clone and enter the project
cd C:\Users\Arun\Documents\School\BioT_Speech_IoT_LLM_App
# 2. Create a virtualenv and install dependencies
uv venv
.venv\Scripts\Activate.ps1
uv sync
# 3. Configure
copy .env.example .env
# … edit .env and set LLM_API_KEY
# 4. Make sure Mosquitto is running
net start mosquitto
# 5. Start the FastAPI server (which launches the MCP server + MQTT subscriber)
uv run python -m app.main您应该看到以下日志行:
INFO | biot.app.main | Starting MCP sensor server on port 8002
INFO | biot.app.main | MCP server ready at http://localhost:8002/mcp
INFO | biot.app.main | Agent ready (provider=anthropic, model=claude-sonnet-4-6, mcp=http://localhost:8002/mcp)
INFO | biot.app.main | MQTT subscriber running (broker=127.0.0.1:1883)
INFO | uvicorn.error | Application startup complete.快速烟雾测试:
curl.exe -X POST http://127.0.0.1:8001/chat `
-H "Content-Type: application/json" `
-d '{ "message": "How many gyro readings are in the database?" }'______________________________________________________________________
端点
| 方法 | 路径 | 目的 |
|---|---|---|
GET | /health | 活体检查-退货 { "status": "ok" } |
POST | /chat | 发送自然语言查询,返回结构化JSON操作 |
/chat 请求
{ "message": "What is the latest gyro Y value?" }/chat 回应
代理始终返回以下操作类型之一(请参见 docs/LLM_USE_CASES.md 对于完整模式):
{
"reply": "{ \"action\": \"answer\", \"tts\": \"Gyro axis Y is 0.45 degrees per second, 2 seconds ago.\" }"
}Android应用程序的 LlmQueryHandler 解析内部JSON并分派操作。
______________________________________________________________________
项目布局
LLM_App/
├── app/
│ ├── main.py # FastAPI entry point + lifespan that starts MCP + MQTT
│ ├── agent.py # SensorAgent — provider-agnostic LLM orchestration
│ ├── database.py # Direct SQLite access helpers (used outside MCP)
│ ├── logger.py # Centralised rotating-file + console logger
│ └── providers/
│ ├── base.py # Abstract LLMProvider interface
│ ├── anthropic.py # Claude implementation
│ ├── openai.py # GPT implementation
│ ├── deepseek.py # DeepSeek implementation
│ ├── gemini.py # Gemini implementation
│ └── __init__.py # create_provider() factory
├── mcp_server/
│ ├── sensor_mcp_server.py # FastMCP server exposing 7 sensor tools
│ └── mqtt_subscriber.py # Background MQTT → SQLite writer
├── config/
│ └── settings.py # Settings class — reads from .env
├── docs/
│ └── LLM_USE_CASES.md # Source of truth for what the LLM must handle
├── data/
│ └── sensor_database.db # Server-side SQLite (created on first MQTT message)
├── logs/
│ └── biot.log # Rotating log file (5 MB × 3)
├── .env # Real credentials (gitignored)
├── .env.example # Safe template (committed)
├── pyproject.toml
└── README.md # ← you are here______________________________________________________________________
环境变量
看 .env.example 对于规范列表。关键问题:
| 变量 | 必填 | 默认 | 备注 |
|---|---|---|---|
LLM_PROVIDER | 是的 | anthropic | 其中之一:人择、openai、deepseek、双子座 |
LLM_API_KEY | yes | -- | 所选提供程序的密钥 |
LLM_MODEL | 否 | 每个提供者默认值 | 例如。 claude-sonnet-4-6 |
SQLITE_DB_PATH | 没有 | data/sensor_database.db | 服务器端数据库路径 |
SERVER_PORT | 没有 | 8001 | FastAPI端口 |
MCP_SERVER_PORT | 没有 | 8002 | MCP子进程端口 |
MQTT_BROKER_HOST | 没有 | 127.0.0.1 | 蚊子宿主 |
MQTT_BROKER_PORT | 没有 | 1883 | 莫斯基托港 |
______________________________________________________________________
切换LLM提供者
更改一行 .env:
LLM_PROVIDER=openai
LLM_API_KEY=sk-...无需更改代码。工厂在 app/providers/__init__.py 解决 启动时正确执行。每个提供者都实现相同的 LLMProvider 抽象类,因此代理代码永远不知道使用的是哪一个。
要添加新的提供者(例如Mistral):
- 创建
app/providers/mistral.py子类化LLMProvider. - 添加
mistral到_SUPPORTED在app/providers/__init__.py. - 在中添加导入+返回分支
create_provider(). - 在中添加默认模型
config/settings.py.
______________________________________________________________________
添加新的MCP工具
- 添加一个
@mcp.tool()功能在mcp_server/sensor_mcp_server.py. - 添加相应
_TOOLS进入app/agent.py所以法学硕士知道
存在。
- 重新启动FastAPI服务器——MCP子进程随之重新启动。
该工具从以下位置调用 SensorAgent._dispatch_tool 通过HTTP,所以没有 SDK设置或注册模板超出了这两个文件。
______________________________________________________________________
故障排除
| 症状 | 可能原因 | 修复 |
|---|---|---|
MCP server unreachable at http://localhost:8002/mcp 在代理日志中 | 子进程在启动过程中崩溃 | 检查上面的终端输出是否有Python回溯——通常是缺少模块或端口冲突 |
Database file does not exist 从工具调用 | MQTT订阅者尚未收到任何消息 | 确认Mosquitto正在运行,ESP8266正在发布,以及 MQTT_BROKER_HOST 匹配代理的IP |
FastAPI启动,但 /chat 总是返回“代理未就绪” | LLM_API_KEY 为空或无效 | 在中设置密钥 .env 并重新启动 |
日志显示代理呼叫 execute_query 重复使用奇怪的SQL | 模型产生了列名幻觉 | 使用以下命令手动运行查询 sqlite3 要查看模式,请改进系统提示以明确提及列 |
| 端口8001正在使用 | 绑定到FastAPI端口的另一个进程 | 更改 SERVER_PORT 在 .env |
______________________________________________________________________
*BioT语音物联网——LLM_App | FHDW汉诺威物联网2025-26*
