LeeBoonstra.dev
AI ArchitectureKnowledge GraphsAgents

Reimagining the Supply Chain: Why Vector RAG Fails in Physical Operations (And How Agentic Knowledge Graphs Fix It)

Picture this: it’s 2:00 AM at a global ocean shipping division, and a critical support alert escalates to the night desk. A customer support coordinator opens a newly deployed Gemini AI assistant and types a simple question: “Why is container SHP-10005 delayed?”

“The container is blocked at the terminal due to a severe weight discrepancy,” the assistant replies. “Local documentation shows a gross weight of 45,000, whereas the verified tare weight is 20,000.”

The customer panics and files a cargo-tampering claim. Down at the port, the terminal system flags the box and halts loading before the crane can touch it.

When the on-call engineering team digs through the execution logs at dawn, they uncover a costly data mismatch. The steel seal on the container stayed intact, and the cargo weight matched the manifest to the pound. The AI agent had pulled a raw number from a legacy database column named gross_weight_lbs (measured in pounds) and compared it against a standardized column named tare_weight_kg (measured in kilograms). Because the vector embeddings for “weight” cluster tightly in logistics documentation, cosine similarity projected gross_weight_lbs right next to tare_weight_kg in vector space. The probabilistic Retrieval-Augmented Generation (RAG) pipeline matched the two fields, treated pounds and kilograms as identical units, calculated a phantom discrepancy, and froze a live shipment.

By the time engineers clear the false flag, container SHP-10005 has missed its flatbed truck pickup. The box sits on the pier concrete for five days, racking up $15,000 in terminal demurrage fees.

In the Google Cloud Office of the CTO (OCTO), I spend my time working shoulder-to-shoulder with engineering teams at the world’s largest logistics and enterprise organizations to co-build proofs for problems like this. When you work with global carriers moving millions of containers across oceans, you learn fast that enterprise AI requires more than a clever prompt and a vector index. Relying on vector math to bridge structured physical operations is a fast way to gamble with your supply chain.

Reimagining the Supply Chain with Agentic Knowledge Graphs and Cloud Spanner

In this post, I’ll walk you through the Universal Data Adapter—an architecture we engineered in OCTO to reimagine supply chain data interoperability. We’ll look at how combining Gemini 4 Argon on the Gemini Enterprise Agent Platform, BigQuery Graph, Cloud Spanner Graph, and the Agent Development Kit (ADK) lets enterprises adopt global industry standards while preserving the proprietary data that gives them their competitive edge.

RAG vs. GraphRAG: Why Similarity Search Breaks in Logistics

Traditional vector RAG treats your enterprise systems of record like a flat heap of text. It slices schemas, PDFs, and transaction logs into chunks, calculates high-dimensional embeddings, and retrieves context based on cosine similarity.

Global logistics operates as a physical network. Every shipment moves across a strict, multi-hop chain of dependencies:

Booking → Shipment → CargoItem → Equipment → TransportCall → Location

When a model lacks database-level schema enforcement or foreign-key constraints, it guesses connections across disconnected systems. Solving this requires shifting the operational retrieval layer to GraphRAG.

What Is GraphRAG (And What Does Google Cloud Offer for It)?

Graph Retrieval-Augmented Generation (GraphRAG) grounds an LLM in a structured Knowledge Graph where domain entities live as typed nodes (such as a shipment, a piece of equipment, or a customer_request) and their relationships live as explicit, directional edges (such as references_shipment). When a user asks a question, the AI agent translates the request into a formal graph query—using ISO-standard Graph Query Language (GQL)—to traverse those multi-hop relationships deterministically before synthesizing a response.

GraphRAG establishes an immutable “Ground Truth” map inside a Knowledge Graph. During live operations, the LLM walks explicit physical graph nodes and edges. If no physical path connects two entities in the database, the query fails cleanly before the model can invent an answer.

On Google Cloud, you can build and run enterprise GraphRAG architectures directly on top of your existing relational and analytical tables—preserving strict ACID governance and unified SQL/GQL interoperability:

  • Cloud Spanner Graph (Operational GraphRAG): Embeds a native Property Graph engine (CREATE PROPERTY GRAPH and ISO GQL) directly inside Cloud Spanner. You declare graph nodes and edges over your operational relational tables, combining sub-second transactional consistency, SQL, vector search, and multi-hop graph traversal in a single database.
  • BigQuery Graph (Analytical & Semantic GraphRAG): Brings native property graphs, GRAPH_TABLE SQL integration, and semantic graphs to petabyte-scale data warehousing in BigQuery—allowing teams to curate enterprise schemas, run multi-hop analytical traversals, and combine VECTOR_SEARCH with graph pattern matching at scale.
  • Gemini Enterprise Agent Platform (Gemini 4 Argon) & Agent Development Kit (ADK): Provide the agentic reasoning and tool-orchestration layer—translating natural language questions into schema-validated GQL statements, executing deterministic graph lookups, and returning auditable lineage proofs.
RAG vs. GraphRAG Architecture

Metric / Capability Traditional Vector RAG GraphRAG (Spanner Graph)
Relationship Mapping Probabilistic / Semantic similarity Deterministic / Strict physical edges
Schema Enforcement None (relies on prompt context) Strict database-level DDL enforcement
Multi-hop Traversal Poor (suffers from context dilution) Excellent (handles N-hop walks natively)
Hallucination Risk High (creates logical shortcuts) Zero (verifies edge paths before execution)
Operational Cost Expensive (large prompts, high token cost) Optimized (GQL compiled to structured query)

Why Industries Need Standards (And Why Companies Resist Them)

To make a cross-enterprise Knowledge Graph work, every system needs to speak a common language. In ocean shipping, the Digital Container Shipping Association (DCSA) defines that language. Establishing shared definitions for core entities—such as a shipment, a piece of equipment (a container), or a transport_call (a vessel journey)—removes semantic ambiguity across carriers, ports, and freight forwarders.

Here lies the enterprise paradox: a shared language solves communication across companies, yet threatens the differentiation that helps those companies compete.

Shipping carriers win contracts on proprietary edge cases. Standard DCSA schemas omit attributes like polar ice-ratings for Arctic routes, custom carbon-offset indices, or bespoke client SLA penalties. Forcing all operational data into a rigid industry-standard schema strips away the intellectual property that differentiates a carrier’s service. At the same time, enterprise database administrators guard legacy columns fiercely. During classical migrations, teams often dump unmatched legacy fields into raw JSON blobs, destroying their downstream query utility.

Mapping thousands of cryptic legacy columns to an industry standard by hand takes years. Large Language Models, however, excel at solving the schema-mapping bottleneck during build time.

The “Old” Is New Again: For decades, global data standards sat trapped in thousand-page PDFs because legacy migrations were too expensive and destructive to justify. Generative AI changes that equation. Acting as a dynamic adapter, an LLM can overlay the committee-vetted industry standard as an interoperable skeleton while stitching your proprietary IP directly alongside it.

The Universal Adapter Concept

The Universal Adapter & n-Tier Data Architecture

To preserve proprietary data while enforcing global standards, we designed the Universal Data Adapter. The architecture separates data onboarding and querying into three decoupled lifecycles:

  1. Schema Mapping (Offline Build Loop): A Gemini agent analyzes both the legacy system schemas and the DCSA standard specification, proposing a tiered hierarchy in a Mapping Manifesto. A human data architect reviews and approves this manifesto once; the pipeline only re-runs when legacy schemas drift or the standard updates.
  2. Knowledge Graph Generation (Materialization Loop): Using the approved Mapping Manifesto, a data pipeline populates the Knowledge Graph and listens for incremental changes in the legacy systems to keep the graph synchronized.
  3. The Inference Loop (Online Runtime): When a support coordinator or operational system asks a question in natural language, an ADK agent translates the request into Graph Query Language (GQL) and executes it against the graph.
Figure 1: Generation of Mapping Manifesto & Graph

The n-Tier Logical Layout

Squeezing messy legacy tables into a single schema destroys context. We isolate data into decoupled logical tiers based on operational purpose, security boundaries, and business value:

  • Tier 1: Standard (Core DCSA): Clean, compliant tables containing the exact fields defined by the DCSA OpenAPI specification (shipment, equipment, cargoitem).
  • Tier 2: Extension (1:1 Sidecars): Dedicated tables holding proprietary attributes (polar ratings, carbon indices) that share the exact primary key of their Tier 1 parent. This keeps the core schema compliant while attaching competitive differentiators side-by-side.
  • Tier 3: Proprietary (Stitched Graphs): Standalone internal operational tables (customer_requests, custom port-routing logs) linked to Tier 1 nodes through explicit edges in Cloud Spanner Graph.

NOTE: Because this is an n-tier logical architecture, you can compile additional layers as governance requires:

  • Tier 4: Confidential / PII: An isolated tier housing customer contact records, pricing contracts, and customs clearance data behind fine-grained IAM controls.
  • Tier 5: High-Velocity Cache: A real-time indexed layer built for sub-second status lookups.
  • Tier 6: Immutable Compliance Ledger: An append-only audit layer tracking physical chain-of-custody events.

This layout gives enterprises a strict guardrail for AI inference, keeps every legacy attribute intact during ingestion, and lets teams expose public Tier 1 sub-graphs to partners while locking down internal tiers.

Phase 1: Schema Mapping & Constructing the Truth Engine

Building a tiered Knowledge Graph follows an orchestrated lifecycle that ingests rigid standards, profiles legacy Systems of Record (SoRs), compiles tiered schemas, and materializes an operational property graph.

The Six-Step Truth Engine Lifecycle

Step 1: Ingesting and Extracting Rigid Standards

Industry bodies like DCSA publish their standards as massive PDF specifications spanning hundreds of pages of taxonomies, state flows, and OpenAPI definitions.

To extract these definitions into executable database blueprints, we used NotebookLM. By feeding the DCSA specification PDFs into NotebookLM, we synthesized the target DDL definitions, turning static industry documentation into structured target schemas.

Step 2: Legacy Profiling and Context Enrichment

Next, we extract the DDL schema dumps from the legacy Systems of Record alongside a few representative sample data rows per table.

Legacy enterprise tables are notorious for cryptic column headers like google-octo_t_w_ind or sh_pr_cd. Passing live sample rows alongside the DDL allows the LLM to inspect actual values—recognizing that google-octo_t_w_ind holds 'lbs' or 'kg'—and infer the true semantic meaning behind opaque naming conventions.

Step 3: Compiling the Mapping Manifesto

With the target DCSA schemas and enriched legacy profiles ready, we run the semantic mapping agent to produce the Mapping Manifesto—a deterministic JSON specification defining every field alignment, tier classification, and unit transformation.

Because enterprise estates span hundreds of tables, we run this mapping workload as an asynchronous batch pipeline on Google Cloud Dataflow with Apache Beam. Scaling this analysis in the background keeps heavy metadata processing off live transactional databases.

TIP: Never let an LLM auto-migrate production schemas without human sign-off. In global logistics, a unit mismatch carries real financial liability. We enforce a strict two-stage Human-in-the-Loop (HiL) workflow:

  1. AI Synthesis: A mapping agent powered by Gemini 4 Argon analyzes the legacy schemas and sample rows, proposing translation rules, tier splits, and confidence scores.
  2. Human Governance: Data engineers and subject matter experts inspect, adjust, and approve the generated Mapping Manifesto before a single record moves.

Here is the prompt template we use to generate the baseline Mapping Manifesto for human review:

You are a Senior Principal Data Architect specializing in global logistics data standards and semantic schema alignment.

GIVEN the target DCSA standard entity schema:
-----
{dcsa_target_schema}
-----

AND the available legacy Systems of Record (SOR) schemas with representative sample data rows:
-----
{sor_schemas_with_samples}
-----

AND the strict architectural classification rules for the "Standards-Plus-Tiers" model:
1. **Tier 1 (Standard):** Direct or close semantic match to a target DCSA standard field.
2. **Tier 2 (Extension):** Crucial proprietary attributes that logically extend a standard entity but are missing in the DCSA spec. These MUST map to a 1:1 primary key sidecar table.
3. **Tier 3 (Proprietary):** Independent entities, system metadata, or internal auditing fields with no standard anchor.

WHEN we analyze the structural metadata, data types, constraints, and sample values to identify semantic alignments and required transformations:

THEN generate a deterministic JSON Mapping Manifesto specifying the optimal cherry-picking strategy to construct this standard entity.

CRITICAL ALIGNMENT & MAPPING RULES:
[Additional alignment, cryptic name resolution, and mapping rules go here...]

Output ONLY a valid JSON object matching the following schema format. Do not include markdown formatting wrappers (e.g. do not wrap the JSON in ```json).

{
"target_entity": "dcsa_entity_name",
"required_source_tables": [
"legacy_table_1",
"legacy_table_2"
],
"field_level_mapping": [
{
"target_field": "dcsa_field_name",
"source_table": "legacy_table_name",
"source_field": "legacy_field_name",
"classification": "Standard | Extension | Proprietary",
"transformation_rule": "Direct 1:1 mapping | Convert lb to kg | Concatenate [field1] and [field2] | Map to Tier 2 sidecar [sidecar_table_name]",
"confidence": 0.95,
"reasoning": "Detailed business and technical explanation for this mapping decision."
}
]
}

Step 4: Tiered Schema Compilation and Cherry-Picked Ingestion

Once data architects approve the Mapping Manifesto, orchestration scripts provision the target dataset inside BigQuery under the standards_plus_tiers namespace.

A Google Cloud Dataflow ingestion pipeline then reads raw transactional records from the legacy databases, executes the transformation rules (such as converting pounds to kilograms), and routes every attribute to its designated tier—populating Tier 1 DCSA tables, Tier 2 extension sidecars, and Tier 3 proprietary tables.

Phase 2: Knowledge Graph Generation

Step 1: Operationalizing Data in Cloud Spanner

To serve real-time operational queries with strict consistency, we synchronize the curated BigQuery tables into Cloud Spanner. Spanner acts as our horizontally scalable relational core and physical “hallucination floor” for live agent queries.

Here is how a Python migration script reads curated tables from BigQuery and writes them in transactional batches into Spanner node tables:

import pandas as pd
from google.cloud import bigquery, spanner

# Initialize Google Cloud clients
bq_client = bigquery.Client()
spanner_client = spanner.Client(project="google-project-id")
database = spanner_client.instance("dcsa-instance-ent").database("dcsa-all")

# Fetch curated DCSA data from BigQuery
query = "SELECT * FROM `google-project-id.standards_plus_tiers.shipment`"
df = bq_client.query(query).to_dataframe()
df = df.where(pd.notnull(df), None)

# Stream in transactional batches directly into Spanner Node Tables
with database.batch() as batch:
batch.insert_or_update(
table="shipment",
columns=df.columns.tolist(),
values=df.values.tolist()
)

Step 2: Compiling the Spanner Property Graph

With the physical tables loaded in Cloud Spanner, we compile the logical property graph. We declare node tables, primary keys, and explicit edge tables that define how entities connect across tiers.

The Spanner Graph DDL below links standard DCSA operational tables (Tiers 1 and 2) to custom proprietary tables (Tier 3) via explicit property graph edges:

-- Spanner Graph DDL: Structuring Tiers 1, 2, and 3

-- Tier 3 Proprietary Node: Custom Requests Table
CREATE TABLE customer_requests (
request_id STRING(MAX) NOT NULL,
customer_id STRING(MAX) NOT NULL,
shipment_id STRING(MAX) NOT NULL,
request_datetime TIMESTAMP,
issue_category STRING(MAX),
) PRIMARY KEY(request_id);

-- Edge Bridge Table: Links customer request to shipment
CREATE TABLE CUSTOMERREQUEST_TO_SHIPMENT (
request_id STRING(MAX) NOT NULL,
shipment_id STRING(MAX) NOT NULL,
) PRIMARY KEY(request_id, shipment_id);

-- Building the Logical Property Graph
CREATE PROPERTY GRAPH LogisticsGraph
NODE TABLES(
shipment KEY(shipment_id),
equipment KEY(equipment_reference),
customer_requests KEY(request_id),
shipmentequipment KEY(shipment_equipment_id)
)
EDGE TABLES(
CUSTOMERREQUEST_TO_SHIPMENT
SOURCE KEY(request_id) REFERENCES customer_requests(request_id)
DESTINATION KEY(shipment_id) REFERENCES shipment(shipment_id)
LABEL references_shipment,
SHIPMENTEQUIPMENT_VIA_SHIPMENT_ID_REFERENCES_SHIPMENT
SOURCE KEY(shipment_equipment_id) REFERENCES shipmentequipment(shipment_equipment_id)
DESTINATION KEY(shipment_id) REFERENCES shipment(shipment_id)
LABEL SHIPMENTEQUIPMENT_VIA_SHIPMENT_ID_REFERENCES_SHIPMENT,
SHIPMENTEQUIPMENT_VIA_EQUIPMENT_REFERENCE_REFERENCES_EQUIPMENT
SOURCE KEY(shipment_equipment_id) REFERENCES shipmentequipment(shipment_equipment_id)
DESTINATION KEY(equipment_reference) REFERENCES equipment(equipment_reference)
LABEL SHIPMENTEQUIPMENT_VIA_EQUIPMENT_REFERENCE_REFERENCES_EQUIPMENT
);

Phase 3: The Inference Loop & The Truth Engine

Building the Knowledge Graph sets the foundation; the Inference Loop puts it to work in production.

In our architecture, BigQuery serves as the analytical muscle for batch curation, while Cloud Spanner Graph serves as the logical brain for real-time agent traversal.

The Five Steps of the Truth Engine

How the Truth Engine Answers a Query

  1. Natural Language Query Ingestion: A support coordinator asks: “What is the gross weight and tare weight for the container associated with customer request REQ-99281?”
  2. Graph Query (GQL) Translation: The Inference Agent—powered by Gemini 4 Argon—reads the question. Grounded in the explicit LogisticsGraph schema, it compiles a deterministic GQL statement.
  3. Deterministic Graph Traversal & Path Verification: Spanner executes the GQL statement across the verified path:
    customer_requests (Tier 3) —[references_shipment]→ shipment (Tier 1) ←[shipmentequipment]— equipment (Tier 2)
    If a query attempts to bridge disconnected nodes or compare incompatible columns outside defined edges, the Spanner GQL compiler throws an exception and halts execution before bad data can reach the user.
  4. Answer Synthesis & Lineage Trace Proof: Gemini formats the verified database rows into a clear response and attaches an Immutable Lineage Trace Proof—surfacing the exact GQL path, source tables, columns, and verification hashes for compliance teams.

Here is how we implement this grounded inference agent using the Google Agent Development Kit (ADK):

import asyncio
from google.cloud import spanner
from google.adk.agents import LlmAgent, InvocationContext, RunConfig
from google.adk.models.google_llm import Gemini
from google.adk.sessions.in_memory_session_service import InMemorySessionService

# 1. Define the Spanner Graph Traversal Tool
def query_spanner_graph(gql_query: str) -> list:
"""Executes a GQL query on the Spanner property graph to retrieve validated logistics data.

Args:
gql_query (str): The syntactically correct GQL query matching the LogisticsGraph schema.

Returns:
list: The list of raw verified matching rows.
"""
spanner_client = spanner.Client(project="google-project-id")
instance = spanner_client.instance("dcsa-instance-ent")
database = instance.database("dcsa-all")

with database.snapshot() as snapshot:
result = snapshot.execute_sql(gql_query)
return [list(row) for row in result]

# 2. Configure the Grounded ADK Inference Agent
def create_inference_agent() -> LlmAgent:
"""Configures and returns the ADK LLM Agent grounded in LogisticsGraph rules."""

# Anchor to Gemini 4 Argon on Gemini Enterprise Agent Platform (global endpoint)
model = Gemini(
model="gemini-4-argon",
project="google-project-id",
location="global"
)

# Define schema-grounding guidelines in system instructions
instruction_text = """
You are an expert logistics coordinator. Your job is to answer support queries using the
'query_spanner_graph' tool.

You MUST translate natural language questions into GQL queries matching this strict graph schema:

Graph Name: LogisticsGraph
Nodes:
- shipment (shipment_id, carrier_booking_reference, collection_datetime, delivery_datetime)
- equipment (equipment_reference, tare_weight_kg)
- customer_requests (request_id, customer_id, request_datetime, issue_category)
- shipmentequipment (shipment_equipment_id, cargo_gross_weight)

Edges:
- (customer_requests)-[:references_shipment]->(shipment)
- (shipmentequipment)-[:SHIPMENTEQUIPMENT_VIA_SHIPMENT_ID_REFERENCES_SHIPMENT]->(shipment)
- (shipmentequipment)-[:SHIPMENTEQUIPMENT_VIA_EQUIPMENT_REFERENCE_REFERENCES_EQUIPMENT]->(equipment)

CRITICAL RULES:
1. You MUST walk physical edges in the graph. Do not invent direct links (e.g. do not link requests straight to equipment).
2. Call the 'query_spanner_graph' tool to fetch verified ground truth.
3. Answer based ONLY on returned data. If the tool returns nothing, explain that no records match the verified path.
"""

agent = LlmAgent(
name="TruthEngineAgent",
instruction=instruction_text,
model=model,
tools=[query_spanner_graph]
)

return agent

# 3. Async Execution Handler
async def handle_customer_inquiry(question: str) -> str:
"""Runs the ADK agent to process the inquiry."""
agent = create_inference_agent()
session_service = InMemorySessionService()

# Establish standard ADK Session & Invocation contexts
session = await session_service.create_session(app_name="LogisticsApp", user_id="support_agent")
context = InvocationContext(
session_service=session_service,
invocation_id="inv-verified-001",
agent=agent,
run_config=RunConfig(),
session=session
)

# Run agent and aggregate events
response_text = ""
async for event in agent.run_async(context, input=question):
if hasattr(event, "text") and event.text:
response_text += event.text
return response_text

Think back to that 2:00 AM weight-discrepancy alert that left container SHP-10005 stranded on the pier. Wrapping our operational agent in a deterministic GQL compiler eliminates that failure mode at the root. Any attempt to skip graph edges or compare unaligned units gets rejected by the compiler before a query ever touches transactional data.

TruthEngine Console: GraphSQL Chatbot and Traversed Spanner Graph Nodes

Resilient Schema Drift Handling

Enterprise databases evolve constantly. Next quarter, a legacy team might rename gross_weight_lbs or add a column for iot_humidity_reading. In standard RAG or brittle text-to-SQL pipelines, schema changes break queries or pollute the vector index.

Anchoring your AI agent’s tools to the abstracted Spanner Property Graph shields the runtime agent from physical schema drift. The ADK agent continues executing multi-hop traversals against stable logical nodes and edges, while the offline Mapping Manifesto pipeline recompiles the physical BigQuery and Dataflow plumbing underneath.

Wrapping Up: Deterministic Truth at Scale

Large context windows and multimodal tools like NotebookLM shine when you need to digest hundred-page industry PDFs or generate baseline schema mappings during build time. Once a container is sitting on a terminal pier and every hour of delay costs real money, your runtime AI needs deterministic guardrails.

Pairing BigQuery for tiered data curation with Cloud Spanner Graph and ADK for grounded graph traversal gives you both: global DCSA interoperability on the outside, proprietary differentiation on the inside, and a zero-hallucination floor underneath your supply chain.

Lee Boonstra

About the Author

Lee Boonstra is a Staff AI Software Engineer & Advocate in the Google Cloud Office of the CTO (Applied Innovation Factory). They specialize in secure multi-agent systems, frontier LLMs, and voice technology. Lee is the author of reference books for O'Reilly and Apress, and the viral Kaggle/Google Prompt Engineering whitepaper.

Disclaimer: The opinions stated here are my own, not those of my company. • 2026 ® Lee Boonstra • Hexo Blog Design by Lee Boonstra