DEV Community

Beck_Moulton
Beck_Moulton

Posted on

Quantified Self: Transform Your Medical PDFs into a Personal Health Oracle with RAG & PubMed

Have you ever looked at a 10-page medical lab report and felt like you were reading ancient hieroglyphics? You’re not alone. In the era of the Quantified Self, we are collecting more health data than ever, yet most of it sits rotting in unstructured PDF files.

In this tutorial, we are going to build a Medical RAG (Retrieval-Augmented Generation) system. We will use Unstructured.io to parse messy medical reports, Pinecone as our high-performance Vector Database, and LangChain to orchestrate a dual-retrieval strategy that links your personal data with real-time clinical research from the PubMed API.

By the end of this guide, you’ll have a pipeline that doesn't just "read" your files but understands them in the context of global medical literature.


The Architecture: Personal Data meets Global Knowledge

To build a reliable medical assistant, we can't rely on the LLM's internal knowledge alone (hallucinations are dangerous here!). We need a "Ground Truth" pipeline.

graph TD
    A[Medical PDF/Report] --> B[Unstructured.io Partitioning]
    B --> C[LangChain Text Splitter]
    C --> D[OpenAI Embeddings]
    D --> E[(Pinecone Vector DB)]

    F[User Query: 'Why is my Ferritin high?'] --> G[Vector Search - Personal History]
    F --> H[PubMed API Search - Clinical Papers]

    G --> I[Context Injection]
    H --> I

    I --> J[GPT-4o Medical Reasoning]
    J --> K[Actionable Health Insight]
Enter fullscreen mode Exit fullscreen mode

Prerequisites

Before we dive into the code, ensure you have your tech_stack ready:

  • Unstructured.io: For handling complex PDF layouts.
  • Pinecone: Our managed Vector Database.
  • LangChain: The glue for our LLM chain.
  • PubMed API: To fetch peer-reviewed biomedical literature.

Step 1: Parsing Messy Medical PDFs

Medical reports are notoriously difficult to parse because they contain tables, checkboxes, and multi-column layouts. We'll use unstructured to clean the noise.

from unstructured.partition.pdf import partition_pdf

# Extracting elements from a medical lab report
elements = partition_pdf(
    filename="my_blood_work_2023.pdf",
    infer_table_structure=True,
    strategy="hi_res"
)

# Filter for relevant text and tables
clean_content = [str(el) for el in elements if el.category in ["NarrativeText", "Table"]]
full_text = "\n".join(clean_content)
print(f"✅ Successfully extracted {len(clean_content)} medical data points.")
Enter fullscreen mode Exit fullscreen mode

Step 2: Vectorizing the Quantified Self

Now that we have clean text, we need to store it in Pinecone. This allows us to perform semantic searches—finding "Iron levels" even if the query is about "anemia."

Pro-Tip: For production-ready RAG patterns and advanced data engineering workflows, I highly recommend checking out the deep dives at wellally.tech/blog. Their guides on vector indexing were a huge inspiration for this architecture! 🥑

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Pinecone
from langchain_text_splitters import RecursiveCharacterTextSplitter
import pinecone

# Split text into chunks that preserve medical context
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
docs = text_splitter.create_documents([full_text])

# Initialize Pinecone and upload
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Pinecone.from_documents(
    docs, 
    embeddings, 
    index_name="medical-rag-index"
)
Enter fullscreen mode Exit fullscreen mode

Step 3: Integrating the PubMed Knowledge Graph

The magic happens when we cross-reference your data with PubMed. If your report shows high "CRP" (C-Reactive Protein), our system will fetch the latest research on what that means.

from langchain_community.tools.pubmed.tool import PubmedQueryRun

pubmed = PubmedQueryRun()

def medical_context_retriever(query):
    # 1. Get personal history from Pinecone
    personal_docs = vectorstore.similarity_search(query, k=2)
    personal_context = "\n".join([d.page_content for d in personal_docs])

    # 2. Get clinical context from PubMed
    clinical_research = pubmed.run(query)

    return personal_context, clinical_research
Enter fullscreen mode Exit fullscreen mode

Step 4: The Reasoning Engine

Finally, we wrap everything in a LangChain Chain to generate a response that is both personal and scientifically grounded.

from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate

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

template = """
You are a medical data assistant. Use the personal health records and the clinical research provided below to answer the user's question.

Personal Records:
{personal_context}

Clinical Research (PubMed):
{clinical_research}

User Question: {question}

Assistant Instruction: Provide a clear summary. If the data suggests a risk, advise consulting a professional.
"""

prompt = ChatPromptTemplate.from_template(template)
chain = prompt | llm

# Execute the query
p_context, c_research = medical_context_retriever("Analyze my cholesterol trends and heart health.")
response = chain.invoke({
    "personal_context": p_context,
    "clinical_research": c_research,
    "question": "What do my recent results suggest about my cardiovascular risk?"
})

print(response.content)
Enter fullscreen mode Exit fullscreen mode

Conclusion: Taking Control of Your Data 🚀

Building a personal health RAG system isn't just a fun coding project—it's about data agency. By combining Unstructured.io with Pinecone and PubMed, we’ve moved from static pixels on a PDF to a dynamic, searchable knowledge graph.

Key Takeaways:

  1. Unstructured Data is the biggest hurdle in health tech; tools like unstructured are lifesavers.
  2. Hybrid Retrieval (Personal + Clinical) reduces hallucinations significantly.
  3. Privacy First: Always ensure your medical data stays encrypted and within secure environments!

If you're looking to scale this into a production environment or want to learn about handling multi-modal medical data (like X-rays), definitely head over to wellally.tech/blog for more advanced tutorials.

What's next for your health stack? Drop a comment below or share your thoughts on Twitter!

Top comments (0)