3) Optional PDF RAG Context
SchemaFlow can run with or without retrieval context, so readers can start with the request alone and add reference docs only when the change needs them.
The sample PDF path in the code cell below points to a file included in the cookbook folder under data/, not to bytes embedded inside the notebook. Leave PDF_PATH = None for static article previews or generic runs.
With the default PDF_PATH = None, the notebook uses only the natural-language change request. This is enough to demonstrate the core staged workflow.
Set PDF_PATH to a local PDF when you want the Impact Agent to ground its analysis in reference material, such as:
- interface design documents
- schema specifications
- lineage documentation
- data contracts
- platform architecture notes
- downstream dependency documentation
When a PDF is configured, this section:
- Validates that the file exists and is a PDF.
- Creates an OpenAI vector store with a one-day expiration policy.
- Uploads the PDF to the vector store.
- Lets OpenAI handle parsing, chunking, embedding, and retrieval.
- Stores the vector store ID for the Impact Agent.
- Later summarizes any File Search results returned during impact analysis.
This keeps the cookbook lightweight because it does not require local embedding models, Chroma, Neo4j, LangGraph, or project-specific Python modules.
from pathlib import Path
# Optional PDF RAG example.
# The GitHub repo includes this sample PDF under schemaflow_cookbook/data.
# When running from a repo checkout in the cookbook folder, uncomment the path below to upload it to File Search.
# For meaningful retrieval hits, pair it with the LOYALTY_TIER change request used in this notebook.
PDF_PATH = None
# PDF_PATH = "data/sample_customer_loyalty_ifd.pdf"
RAG_MAX_RESULTS = 6
rag_vector_store = None
rag_vector_store_id = None
rag_vector_store_file = None
rag_file_search_results = []
impact_response = None
def create_pdf_vector_store(pdf_path):
pdf_path = Path(pdf_path).expanduser().resolve()
if not pdf_path.exists():
raise FileNotFoundError(f"PDF not found: {pdf_path}")
if pdf_path.suffix.lower() != ".pdf":
raise ValueError(f"Expected a PDF file, got: {pdf_path}")
with trace("SchemaFlow PDF Vector Store", group_id=SCHEMAFLOW_TRACE_GROUP_ID, metadata={"step": "pdf_vector_store", "pdf_path": str(pdf_path)}):
with custom_span("Create vector store", {"pdf_path": str(pdf_path)}):
vector_store = client.vector_stores.create(name=f"schemaflow-cookbook-{datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ')}", expires_after={"anchor": "last_active_at", "days": 1})
with custom_span("Upload PDF to vector store", {"vector_store_id": vector_store.id, "pdf_path": str(pdf_path)}):
with pdf_path.open("rb") as handle:
vector_store_file = client.vector_stores.files.upload_and_poll(vector_store_id=vector_store.id, file=handle)
trace_function_result("PDF vector store ready", input_obj={"pdf_path": str(pdf_path)}, output_obj={"vector_store_id": vector_store.id, "status": getattr(vector_store_file, "status", "unknown")})
flush_traces()
return vector_store, vector_store_file
if PDF_PATH:
rag_vector_store, rag_vector_store_file = create_pdf_vector_store(PDF_PATH)
rag_vector_store_id = rag_vector_store.id
print("Created vector store:", rag_vector_store_id)
print("Uploaded PDF status:", getattr(rag_vector_store_file, "status", "unknown"))
else:
print("No PDF configured. Leave PDF_PATH as None to run without RAG, or set it to a local PDF path.")