# From Blood Tests to Meal Plans: Building a Self-Correcting Health Agent with LangGraph

> Source: <https://dev.to/beck_moulton/from-blood-tests-to-meal-plans-building-a-self-correcting-health-agent-with-langgraph-36hb>
> Published: 2026-06-05 00:08:00+00:00

Ever felt like your fitness app is just a fancy spreadsheet? You log a high uric acid result from your latest blood test, yet it still suggests a high-protein steak dinner for "gains."

In the world of **AI Agents**, we are moving past static prompts. Today, we’re building a **Self-Correcting Health Agent** using **LangGraph**, **LangChain**, and **OpenAI**. This agent doesn't just chat; it monitors laboratory biomarkers like cholesterol and uric acid, maintains a long-term memory via **SQLite**, and dynamically rewrites your lifestyle plan using advanced **OpenAI Function Calling**.

If you've been looking to master **autonomous health agents** and complex state management, you're in the right place. Let's dive into the future of personalized wellness.

Unlike a standard linear chain, a health agent needs to "loop" and "reason." If the agent detects an abnormal lab value, it must trigger a specific logic branch to revise existing plans.

Here is how the data flows through our LangGraph system:

``` php
graph TD
    A[User Input/Lab Report] --> B{Analyze Biomarkers}
    B -- Abnormal Found --> C[Tool: Plan Rewriter]
    B -- All Normal --> D[Tool: Maintenance Plan]
    C --> E[Update SQLite Memory]
    D --> E[Update SQLite Memory]
    E --> F[Output Final Recommendation]
    F --> G[Wait for Next Input]
    G -- New Data --> B
```

To follow along, you'll need:

In LangGraph, the `State`

is the source of truth. We need to track the user's current health metrics and their active diet plan.

``` python
from typing import Annotated, TypedDict, List
from langgraph.graph import StateGraph, END
import operator

class HealthState(TypedDict):
    # We use operator.add to keep a history of logs
    logs: Annotated[List[str], operator.add]
    biomarkers: dict
    current_diet_plan: str
    revision_required: bool
```

The magic happens when the LLM decides whether your lab results require a "Protocol Pivot." We use OpenAI's Function Calling to detect high uric acid or cholesterol.

``` python
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage

llm = ChatOpenAI(model="gpt-4o", temperature=0)

def analyze_labs(state: HealthState):
    biomarkers = state['biomarkers']
    # Logic to determine if intervention is needed
    needs_fix = False
    if biomarkers.get("uric_acid", 0) > 420: # Example threshold
        needs_fix = True

    return {"revision_required": needs_fix, "logs": ["Analyzed lab results..."]}

def rewrite_diet_plan(state: HealthState):
    prompt = f"Adjust the following diet plan based on these biomarkers: {state['biomarkers']}. Current Plan: {state['current_diet_plan']}"
    # The LLM generates a new plan avoiding high-purine/high-fat foods
    new_plan = llm.invoke([HumanMessage(content=prompt)])
    return {"current_diet_plan": new_plan.content, "logs": ["Diet plan updated for health safety."]}
```

Now, we connect the nodes. We use a **conditional edge** to decide whether to go to the `rewrite_diet_plan`

node or straight to the end.

```
workflow = StateGraph(HealthState)

workflow.add_node("analyzer", analyze_labs)
workflow.add_node("rewriter", rewrite_diet_plan)

workflow.set_entry_point("analyzer")

# Conditional Logic: If revision_required is True, go to rewriter
workflow.add_conditional_edges(
    "analyzer",
    lambda x: "rewrite" if x["revision_required"] else "end",
    {
        "rewrite": "rewriter",
        "end": END
    }
)

workflow.add_edge("rewriter", END)

# Compile with persistence (SQLite)
from langgraph.checkpoint.sqlite import SqliteSaver
memory = SqliteSaver.from_conn_string(":memory:")
app = workflow.compile(checkpointer=memory)
```

While this tutorial covers the core logic of stateful agents, building medical-grade or production-ready health platforms requires deeper security and more robust validation patterns.

For advanced architectural patterns on deploying AI agents in high-stakes environments, I highly recommend checking out the ** WellAlly Blog**. They provide excellent deep dives into integrating AI with real-world health data and "Agentic Workflows" that go far beyond basic tutorials.

Let's test it with a scenario: A user with a "Keto" plan suddenly uploads a lab report showing high cholesterol.

```
config = {"configurable": {"thread_id": "user_123"}}
initial_input = {
    "biomarkers": {"cholesterol": 280, "uric_acid": 450},
    "current_diet_plan": "High protein, high fat Keto diet.",
    "logs": []
}

for event in app.stream(initial_input, config):
    for value in event.values():
        print(f"Update: {value.get('logs', '')}")
        if 'current_diet_plan' in value:
            print(f"New Plan: {value['current_diet_plan']}")
```

`thread_id`

, the agent remembers the previous state.`analyzer`

node before the LLM even sees the data.Building autonomous health agents with **LangGraph** transforms a simple chatbot into a proactive health companion. By moving the logic into a directed graph, we gain control over the "reasoning loops" that LLMs often struggle with.

**What's next for your agent?**

Happy coding, and stay healthy! 🚀💻🥑

*Have questions about LangGraph or Agent memory? Drop a comment below!*
