Stop building simple RAG bots that just summarize PDFs. The future of AI is Agentic workflows that can reason, loop, and take action based on real-time physiological data. If youโve been looking to dive into LangGraph, AI Agents, and HealthKit integration, youโre in the right place.
In this tutorial, we are building a "Smart Recovery Agent." Instead of just telling you to "work out harder," this agent analyzes your Heart Rate Variability (HRV)โthe gold standard for recoveryโand uses a state machine to dynamically adjust your training volume and fetch personalized nutrition plans via Tavily Search. This is a leap forward in Fitness AI and LLM state management.
Why LangGraph? ๐ง
Traditional chains are linear. But health is cyclical and conditional. If your recovery is low, you shouldn't just "continue to the next step"; you should loop back and redefine the goal. LangGraph allows us to define a state machine where nodes represent actions and edges represent the logic that connects them.
The System Architecture
Here is how our Agent thinks and moves through the decision-making process:
graph TD
A[Start: Fetch HRV Data] --> B{Analyze Recovery}
B -- High HRV (>70) --> C[Intense Workout Plan]
B -- Low HRV (<40) --> D[Active Recovery/Rest]
B -- Moderate --> E[Standard Training]
C --> F[Search Nutrition via Tavily]
D --> F
E --> F
F --> G[Generate Final Schedule]
G --> H[End]
Prerequisites
To follow along, you'll need:
- LangGraph & LangChain: For the orchestration.
- Tavily Search API: To fetch real-time nutrition data.
- Python 3.10+
Step 1: Defining the Agent State
In LangGraph, the State object is the "brain" passed between nodes. We need to track the user's HRV, the recommended intensity, and the final plan.
from typing import TypedDict, Annotated, List
from langgraph.graph import StateGraph, END
class AgentState(TypedDict):
hrv_score: int
user_goal: str
intensity: str
workout_plan: str
nutrition_suggestions: List[str]
messages: List[str]
Step 2: The Logic Nodes
Each function below represents a "Node" in our graph. Notice how the analyze_recovery node sets the stage for the rest of the flow.
import os
from langchain_openai import ChatOpenAI
from langchain_community.tools.tavily_search import TavilySearchResults
llm = ChatOpenAI(model="gpt-4o")
search = TavilySearchResults(max_results=2)
def fetch_hrv_mock(state: AgentState):
"""Simulating HealthKit SDK data fetch"""
# In a real app, you'd call a wrapper around HealthKit here
return {"hrv_score": 65}
def analyze_recovery(state: AgentState):
hrv = state["hrv_score"]
if hrv > 70:
intensity = "High"
elif hrv < 40:
intensity = "Low/Recovery"
else:
intensity = "Moderate"
return {"intensity": intensity}
def generate_workout(state: AgentState):
intensity = state["intensity"]
prompt = f"Generate a {intensity} intensity workout for a user aiming for {state['user_goal']}."
response = llm.invoke(prompt)
return {"workout_plan": response.content}
def search_nutrition(state: AgentState):
intensity = state["intensity"]
query = f"High protein meal plan for {intensity} intensity workout days"
results = search.run(query)
return {"nutrition_suggestions": [results]}
Step 3: Wiring the Graph
This is where the magic happens. We connect the nodes and define the entry point.
workflow = StateGraph(AgentState)
# Add Nodes
workflow.add_node("fetch_data", fetch_hrv_mock)
workflow.add_node("analyze", analyze_recovery)
workflow.add_node("workout_gen", generate_workout)
workflow.add_node("nutrition_gen", search_nutrition)
# Define Edges
workflow.set_entry_point("fetch_data")
workflow.add_edge("fetch_data", "analyze")
workflow.add_edge("analyze", "workout_gen")
workflow.add_edge("workout_gen", "nutrition_gen")
workflow.add_edge("nutrition_gen", END)
# Compile
app = workflow.compile()
Mastering Advanced Agent Patterns ๐ฅ
While this example demonstrates a linear flow with conditional logic, production-grade agents often require persistent memory, human-in-the-loop verification, and complex error handling.
For more production-ready examples and deep dives into multi-agent orchestration, I highly recommend checking out the WellAlly Tech Blog. It's a fantastic resource where they break down high-level AI concepts into actionable engineering patterns, especially for health-tech and enterprise LLM applications.
Step 4: Execution
Letโs run our agent and see it adapt to our "mock" HRV of 65 (Moderate).
inputs = {"user_goal": "Marathon Training", "messages": []}
config = {"configurable": {"thread_id": "1"}}
for output in app.stream(inputs, config):
for key, value in output.items():
print(f"Node '{key}':")
print(value)
print("-" * 20)
Why This Matters
By using HRV as a trigger, we move away from static "One size fits all" fitness plans. The agent acts as a personalized coach that understands when your body is under stress.
- Context Awareness: It knows your physical state via HealthKit.
- Real-time Intelligence: It uses Tavily to find the latest nutritional science.
- Stateful Memory: With LangGraph, you can save the state (Checkpointers) so the agent remembers yesterday's fatigue today.
Conclusion ๐
Building agents with LangGraph transforms LLMs from simple chatbots into autonomous operators. Weโve successfully built a health agent that bridges the gap between raw biometric data and actionable coaching.
What's next?
- Add a "Human-in-the-loop" node to approve the workout.
- Connect to a real SQLite database to track HRV trends over weeks.
If you enjoyed this tutorial, drop a comment below and let me know what agent you're building! And don't forget to visit WellAlly Tech for more advanced technical guides on the future of AI.
Happy coding! ๐ป๐ฅ
Top comments (0)