Fitbitデータ × LangGraph で健康アドバイスを自動生成するアプリを作ってみた

# はじめに ~なぜ作ったのか~
私はFitBit2 Senceを数年前から利用しており、常に腕に巻いているので、データが蓄積されてきました。
その健康に関するデータは溜まってきたが、「で、何すればいいの？」というアクションに落とし込むのは意外と難しいなと自分自身がFitbitを使いながら感じていた課題です。

そこで、「日々のFitbitデータから、生活改善アドバイスを自動生成するAIエージェント」を構築し、どれだけ実用的な示唆が得られるかをMVPとして検証してみました。

目的は以下の通りです。
- 自分の健康状態を客観的に可視化し
- 改善アドバイスを自動で生成し
- 最小限の構成でMVPを構築する

# システム概要
構築したアプリでできることは以下の通り：
- Fitbit APIから睡眠・歩数・心拍数などのデータを取得
- LangGraph上に組んだエージェントが、取得データをもとに生活改善のアドバイスを3点提示
- StreamlitでGUI表示、FastAPI経由でトークン認証やデータ取得を行う
- ユーザーのFitbit連携はOAuth2で一度認証すればOK（JWTでセッション管理）

【構成】
以下が構成図です（docker-compose利用）：

```
[ User ] → [ Streamlit ] → [ FastAPI ] → [ LangGraph Agent ]
                          ↘︎認証   ↓↑API取得
                         [ Fitbit API ]
```
### 技術スタック

| コンポーネント | 技術スタック                       |
| ------- | ---------------------------- |
| UI      | Streamlit                    |
| API     | FastAPI + httpx              |
| LLM連携   | LangGraph + Gemini 1.5       |
| 認証      | Fitbit OAuth2.0 + JWT（PyJWT） |
| デプロイ環境  | Docker Compose               |


# Fitbit APIについて
Fitbit APIはOAuth2.0フローでのアクセストークン取得が必要ですが、以下の点に注意しました。
- codeを /callback で受け取り、FastAPIから https://api.fitbit.com/oauth2/token にPOST
- 取得したトークンはJWTに包んで返却し、以降のリクエストに利用
- データ取得の例：
```python
response = await client.get(
    "https://api.fitbit.com/1/user/-/sleep/date/today.json",
    headers={"Authorization": f"Bearer {access_token}"}
)
```

# こだわり
### なぜLangGraphを選んだか？
LLMに処理を任せるだけでなく、「状態遷移を制御したい」というニーズにLangGraphのStateMachineがピッタリでした。たとえば：
- sleep → activity → heartrate の順に解析
- 各処理後に前段の結果を引き継ぎながら次のAgentへ
### FastAPI側での工夫点
JWTのハードコーディングを廃止し、.envからシークレットを読み込むことでセキュリティ性を向上
```
JWT_SECRET = os.getenv("JWT_SECRET", "default-secret")
```
### MVP思考での割り切り
- トークン永続化やリフレッシュは一旦省略（毎回再認証が必要）
- エージェントの精度より「使える形にする」ことを優先
- StreamlitのUIも最低限（説明 + 実行ボタン + 結果表示）

# 検証
実際の出力結果は以下のような形で、十分に“使える”レベルだけど物足りなさも感じるようなアドバイスが返ってきました：
```
〇〇さん、Fitbitデータに基づいた生活改善アドバイスです。

1. 睡眠の質改善:

睡眠時間: 7時間13分と十分な睡眠時間を確保していますが、睡眠中の覚醒時間が75分と比較的長いです (平均よりも多い)。 睡眠の質を向上させるために、就寝前のカフェイン摂取を控え、リラックスできる就寝ルーティンを確立することをお勧めします。 寝る前のスマホやパソコンの使用も控えるようにしましょう。 睡眠の質を改善することで、日中のパフォーマンスが向上します。
睡眠パターン: 過去数日の睡眠データを見ると、睡眠時間や覚醒時間は日によって大きく変動しています。 規則正しい睡眠時間を心がけることで、体内時計を安定させ、睡眠の質を向上させることができます。 毎日同じ時間に寝起きすることを目指しましょう。
2. 運動量の増加:

活動量が少ない: 1日の歩数は2164歩と目標の10000歩を大きく下回っています。 また、中程度以上の運動（fairlyActiveMinutes, veryActiveMinutes）は全くありません。 健康維持のためには、もっと運動量を増やす必要があります。
具体的な目標: まずは目標の10000歩を達成することを目指しましょう。 通勤・通学手段を見直したり、エレベーターではなく階段を使うなど、日常生活の中に積極的に運動を取り入れてみてください。 また、週に3回以上、30分程度の有酸素運動（ジョギング、ウォーキング、水泳など）を取り入れることをお勧めします。 過去のバッジ取得履歴から、高い運動能力は既に持っていることがわかりますので、継続的な運動が重要です。
強度を上げる: 心拍数データによると、脂肪燃焼ゾーン（Fat Burn）の時間がわずか4分しかありません。 より活発な運動を取り入れることで、心血管系の健康を促進し、カロリー消費を増やすことができます。
3. その他のアドバイス:

心拍数の安定: 安静時心拍数は69とやや高めです。 規則正しい生活、十分な睡眠、適度な運動によって、心拍数を下げることができます。
健康診断: 定期的な健康診断を受けることで、健康状態を把握し、必要に応じた医療処置を受けることができます。
総合的に見ると、〇〇さんは既に相当な運動量をこなせるだけの体力をお持ちです（過去に30000歩を達成した実績あり）。しかし、現在の活動量は非常に少なく、健康的な生活を送るには、日々の運動習慣を見直すことが最も重要です。 睡眠の質を改善し、規則正しい生活リズムを心がけることも、健康的な生活を送る上で不可欠です。 体重の記録も開始し、総合的な健康管理に努めてください。
```
このように、ユーザー視点で「次に何をすればいいか」がはっきり可視化される構成になっているが、コメントでもあるように体重やそれ以外のデータを含めて、より良い診断結果などをもらえるよう今後見直ししたいなって思うレベルでした。

# おわりに ~今後の改善方向~
MVPとしては以下の点が今後以下のような改善ができればより良い機能になると考えています。
- トークンのリフレッシュ自動対応（現在は一時的トークンのみ）
- LangGraphでフィードバック精度を評価し、学習ループを設計
- 睡眠・心拍・活動量以外の身体・栄養・食事データなどとの統合
- NotionやLINEとの連携で、日々の通知や記録に発展させる

# 参考
- FitBit APIドキュメント
    - https://dev.fitbit.com/build/reference/
- Github
    - https://github.com/ebasuke226/fitbitAgent