Skip to content

Latest commit

Β 

History

21 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧾 Snowflake Cortex AI

⚑ Quick Summary

This pipeline ingests accounts-payable invoices from four disconnected ERP/AP systems β€” SAP, Oracle, Baan, and Workday β€” and conforms them into a single, always-fresh Silver view of what the business owes. Snowflake Dynamic Tables handle the incremental transformation from bronze landing tables through to a vendor-level rollup, with source-specific quirks (status vocabularies, a known Baan duplicate-extract issue, dropped system-specific columns) handled per a set of documented, finance-approved business rules rather than ad hoc judgment calls.

On top of that pipeline sits a Snowflake Cortex Agent grounded in a native Semantic View: it answers quantitative questions ("which vendors have the most overdue invoices, and how much") via text-to-SQL against governed business metrics. A 15-question evaluation harness β€” covering core questions, rephrasings, edge cases, and deliberately ambiguous questions the agent should push back on β€” runs against the live agent so answer quality is measured, not assumed.

Multi-source AP invoices β†’ Dynamic Tables β†’ Semantic View β†’ Cortex Agent


🏷️ Project Badges

Snowflake SQL Cortex AI Python Status


πŸ“Œ Project Overview

This project implements a governed, agent-queryable accounts-payable data platform entirely inside Snowflake β€” no external orchestrator, no separate vector database, no copy of the data outside the warehouse.

It implements:

  • 4-source bronze ingestion β€” SAP, Oracle, Baan, and Workday AP invoice tables, each keeping its native column shape and loaded with realistic synthetic sample data (50 invoices total, 3 currencies)
  • Rule-driven Silver conformance via Dynamic Tables β€” a single union/normalize layer implementing 9 documented business rules (status normalization, no currency conversion, Baan duplicate handling, dropped system-specific columns, TARGET_LAG = DOWNSTREAM), plus a vendor-level rollup
  • A native Semantic View β€” business-friendly facts, dimensions, and metrics (total_spend, overdue_by_vendor, etc.) that ground natural-language questions in governed SQL instead of ad hoc joins
  • A Cortex Search service β€” semantic search over free-text invoice line descriptions (ap_invoice_search), for fuzzy lookups that don't map cleanly to a WHERE clause
  • A Cortex Agent β€” Cortex Analyst (text-to-SQL over the semantic view) plus Cortex Search, answering both quantitative and free-text AP questions
  • An evaluation harness β€” a 15-question golden set (core / rephrasings / edge cases / deliberately ambiguous / data-validation) scored against the live agent with pass/fail heuristics

βš™οΈ Tech Stack

Layer Tool Purpose
Warehouse / Storage Snowflake Single platform for storage, transformation, and AI serving
Transformation Dynamic Tables Declarative, auto-refreshed incremental pipeline (no dbt/Airflow needed)
Semantic layer Snowflake Semantic View Governed facts/dimensions/metrics grounding the agent's text-to-SQL tool
Structured Q&A Cortex Analyst Text-to-SQL tool bound to the semantic view
Unstructured Q&A Cortex Search Semantic search over free-text invoice line descriptions
Orchestrating agent Cortex Agents (REST API) Wraps the Analyst and Search tools in one conversational interface
Agent client / eval Python 3.11, requests, pyyaml Calls the Agents REST API and scores answers
Deployment Bash + Snowflake CLI (snow sql) Applies all SQL in order against a target account

🎯 Business Problem

AP teams routinely receive invoices through four or more disconnected ERP/AP systems, each with its own vendor ID scheme, status vocabulary, GL account format, and payment-terms notation. Answering "what do we currently owe, and to whom, and is any of it overdue" means manually reconciling across systems that don't share a common schema β€” and doing it consistently enough that finance trusts the answer.

Can accounts-payable invoice data from four disconnected ERP/AP systems be unified into a single governed view β€” one that a non-technical user can query in plain English and trust the answer to?


πŸ—οΈ Architecture

   [SAP]         [Oracle]         [Baan]          [Workday]
     β”‚               β”‚               β”‚                β”‚
     β–Ό               β–Ό               β–Ό                β–Ό
bronze.sap_ap_   bronze.oracle_   bronze.baan_    bronze.workday_
  invoices       ap_invoices      ap_invoices      ap_invoices
     β”‚               β”‚               β”‚                β”‚
     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β–Ό
              silver.dt_silver_ap_invoices   (Dynamic Table β€” union + BR-001..BR-009)
                              β”‚
                              β–Ό
                 silver.dt_vendor_invoice_summary   (Dynamic Table β€” vendor rollup)
                              β”‚
                 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                 β–Ό                          β–Ό
     semantic.sv_ap_analytics    agent.ap_invoice_search
     (native Semantic View)      (Cortex Search service)
                 β”‚                          β”‚
                 β–Ό                          β–Ό
     Cortex Analyst (text-to-SQL)   Cortex Search (semantic lookup)
                 β”‚                          β”‚
                 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β–Ό
                   Cortex Agent β€” ap_invoice_agent
                              β”‚
                              β–Ό
                eval/ harness (15-question golden set)
Component Role
bronze.*_ap_invoices One landing table per source system (SAP, Oracle, Baan, Workday), native column shapes preserved
dt_silver_ap_invoices Dynamic Table unioning all 4 sources into one invoice-header shape, per BR-001..BR-009
dt_vendor_invoice_summary Dynamic Table rolling invoices up to one row per vendor, incl. pending/overdue exposure
sv_ap_analytics Semantic View exposing facts/dimensions/metrics to Cortex Analyst
ap_invoice_search Cortex Search service over line_description, for fuzzy/semantic invoice lookup
ap_invoice_agent Cortex Agent wrapping the Analyst and Search tools behind one conversational interface

πŸ“ Repository Structure

snowflake-cortex-ai/
β”‚
β”œβ”€β”€ sql/
β”‚   β”œβ”€β”€ 00_setup/
β”‚   β”‚   β”œβ”€β”€ 00_database_schema_warehouse.sql   ← warehouse, bronze/silver/semantic schema creation + grants
β”‚   β”‚   └── 01_github_git_integration.sql      ← optional: SECRET + API INTEGRATION + GIT REPOSITORY for Snowflake Workspaces
β”‚   β”œβ”€β”€ 01_bronze_sources/
β”‚   β”‚   β”œβ”€β”€ 01_sap_ap_invoices.sql             ← bronze SAP table + 15 sample invoices
β”‚   β”‚   β”œβ”€β”€ 02_oracle_ap_invoices.sql          ← bronze Oracle table + 15 sample invoices
β”‚   β”‚   β”œβ”€β”€ 03_baan_ap_invoices.sql            ← bronze Baan table + 10 sample invoices
β”‚   β”‚   └── 04_workday_ap_invoices.sql         ← bronze Workday table + 10 sample invoices
β”‚   β”œβ”€β”€ 02_silver/
β”‚   β”‚   β”œβ”€β”€ 01_dt_silver_ap_invoices.sql       ← unions all 4 sources per BR-001..BR-009
β”‚   β”‚   └── 02_dt_vendor_invoice_summary.sql   ← vendor-level rollup + pending/overdue calc
β”‚   └── 03_semantic_view/
β”‚       β”œβ”€β”€ 01_sv_ap_analytics.sql             ← semantic view grounding Cortex Analyst
β”‚       └── 02_cs_ap_invoice_search.sql        ← Cortex Search service grounding free-text lookup
β”‚
β”œβ”€β”€ cortex_agent/
β”‚   β”œβ”€β”€ agent_spec.yaml                        ← agent tool spec (Cortex Analyst + Cortex Search)
β”‚   └── run_agent.py                           ← REST client to run the agent interactively
β”‚
β”œβ”€β”€ eval/
β”‚   β”œβ”€β”€ golden_dataset.jsonl                   ← 15-question golden set (core/variation/edge/ambiguous/validation)
β”‚   β”œβ”€β”€ run_eval.py                            ← runs the golden set through the agent + scores it
β”‚   β”œβ”€β”€ metrics.py                             ← scoring heuristics per question type
β”‚   └── results/                               ← timestamped eval run outputs (gitignored)
β”‚
β”œβ”€β”€ docs/
β”‚   β”œβ”€β”€ business_requirements/                 ← source CSVs behind the Silver DT's design decisions
β”‚   β”‚   β”œβ”€β”€ README.md                          ← BR-### β†’ implementation cross-reference
β”‚   β”‚   β”œβ”€β”€ sample_business_requirements_source_onboarding.csv
β”‚   β”‚   β”œβ”€β”€ sample_business_requirements_column_mapping.csv
β”‚   β”‚   └── sample_business_requirements_business_rules.csv
β”‚   └── dynamic-tables-reference/              ← Dynamic Tables best-practice reference material (plain docs)
β”‚
β”œβ”€β”€ labs/                                       ← Snowflake Northstar badge lab materials (separate from the pipeline above)
β”‚   β”œβ”€β”€ coco-foundations/                       ← CoCo Foundations lab assets + how-to-run README
β”‚   β”œβ”€β”€ from-zero-to-agents/                    ← From Zero to Agents lab assets + how-to-run README
β”‚   β”œβ”€β”€ northstar-data-engineering/             ← Data Engineering with Snowflake lab assets + how-to-run README
β”‚   └── declarative-dynamic-tables/             ← Declarative Data Pipelines with Dynamic Tables lab assets + how-to-run README
β”‚
β”œβ”€β”€ cortex_project/                              ← Snowflake CLI declarative project definition, auto-generated by Snowsight Agent Studio
β”‚   β”œβ”€β”€ cortex-project.yaml                      ← project manifest (artifact β†’ deployment target)
β”‚   └── ap_invoice_agent.agent.yaml              ← CLI-deployable equivalent of cortex_agent/agent_spec.yaml
β”‚
β”œβ”€β”€ config/
β”‚   └── connection.example.toml                ← Snowflake connection template (copy β†’ connection.toml)
β”‚
β”œβ”€β”€ scripts/
β”‚   └── deploy.sh                               ← applies all sql/ files in order via the Snowflake CLI
β”‚
β”œβ”€β”€ requirements.txt                            ← Python deps for the agent client + eval harness
└── .gitignore

▢️ How to Run

πŸ“Œ Option 1 β€” Local

1. Clone the repository

git clone https://github.com/deepan-mehta-analytics/snowflake-cortex-ai.git
cd snowflake-cortex-ai

2. Create and activate a virtual environment

python -m venv .venv
.venv\Scripts\activate      # Windows
source .venv/bin/activate    # macOS/Linux

3. Install Python dependencies

pip install -r requirements.txt

4. Configure your Snowflake connection

copy config\connection.example.toml config\connection.toml   # Windows
cp config/connection.example.toml config/connection.toml      # macOS/Linux
# then edit config/connection.toml with your account/user

5. Deploy the pipeline

bash scripts/deploy.sh

This applies, in order: warehouse/database/schema setup β†’ the 4 bronze source tables (with sample data) β†’ the 2 Silver Dynamic Tables β†’ the semantic view β†’ the Cortex Search service.

6. Set your Snowflake REST API credentials

run_agent.py calls the Cortex Agents and SQL APIs directly with a Personal Access Token β€” it does not require registering a saved agent object first.

# PowerShell
$env:SNOWFLAKE_ACCOUNT = "<org>-<account>"     # e.g. from your Snowsight URL: app.snowflake.com/<org>/<account>/...
$env:SNOWFLAKE_PAT = "<your PAT>"              # generate via ALTER USER <you> ADD PROGRAMMATIC ACCESS TOKEN ...

Note: PATs require PROGRAMMATIC_ACCESS_TOKEN to be listed in your account's authentication policy, and a network policy must be attached to the user (Snowflake enforces this for PATs even with an unrestricted 0.0.0.0/0 policy) β€” see ALTER AUTHENTICATION POLICY / ALTER USER ... SET NETWORK_POLICY if token creation is rejected.

7. Ask the agent a question

python cortex_agent/run_agent.py "Which vendors have the most overdue invoices?"

The cortex_analyst_text_to_sql tool returns governed SQL rather than executed results, so run_agent.py runs that SQL itself via the SQL API and prints the interpretation plus real rows.

8. Run the evaluation harness

python eval/run_eval.py

πŸ§ͺ Tests

No automated unit/integration test suite yet β€” see Roadmap. Correctness today is checked via eval/run_eval.py, which runs the 15-question golden set (eval/golden_dataset.jsonl) against the live agent and applies heuristic pass/fail checks per question (eval/metrics.py).


πŸ“Š Results / Performance

Deployed and evaluated end-to-end against a live Snowflake trial account (2026-07-16).

Pipeline row counts (bronze β†’ silver, all verified via SHOW/SELECT after each step, not just a bare success message):

Table Rows
bronze.sap_ap_invoices 15
bronze.oracle_ap_invoices 15
bronze.baan_ap_invoices 10
bronze.workday_ap_invoices 10
silver.dt_silver_ap_invoices 50 (union of all 4 sources)

Evaluation harness β€” 13/15 checks passed (eval/run_eval.py against the live agent):

Category Result
Core (6 questions) 6/6 passed
Rephrasings/variation (4 questions) 4/4 passed
Edge cases (2 questions) 2/2 passed
Deliberately ambiguous (2 questions) 0/2 passed
Data validation (1 question) 1/1 passed

The 2 ambiguous-category failures are heuristic-scoring gaps, not agent defects: one question ("Which vendors are problematic?") correctly triggered a refusal for a subjective/discriminatory framing, and the other ("Show me recent invoices") got a reasonable default interpretation β€” eval/metrics.py's keyword-based grounding check just doesn't recognize either phrasing style. See Known Limitations.

Sample query, run live via python cortex_agent/run_agent.py "Which vendors have the most overdue invoices?":

This is our interpretation of your question:

Which vendors have the most overdue invoices, ranked by total overdue amount in descending order?

VENDOR_NAME, VENDOR_TOTAL_OVERDUE_AMOUNT
Summit Energy Corp, 197600.00
National Insurance Brokers, 133500.00
Apex Staffing Solutions, 100000.00
...

⚠️ Known Limitations

  • Payment-terms formats differ per source (NET30 vs N30 vs Net 30) and are intentionally left unnormalized at Silver β€” an open decision per BR-005, deferred to a future Gold layer
  • GL account codes are not cross-mapped across sources (BR-006) β€” a unified chart of accounts is a Phase 2 concern, not implemented here
  • The source data has no paid/unpaid flag β€” "overdue" is approximated as due_date < CURRENT_DATE() β€” since the sample data is dated 2025, this approximation drifts further from reality the longer the demo sits unrefreshed
  • eval/metrics.py checks are heuristic (keyword/shape-based), not semantic β€” a good answer can fail a check and vice versa; the 2 failing "ambiguous" checks in the results above are scorer gaps, not agent defects
  • No CI pipeline runs eval/run_eval.py automatically on change
  • Snowsight's Agent Studio UI and the DATA_AGENT_RUN SQL function were both unreliable for testing the registered agent object during development (hung/incomplete tool configuration); cortex_agent/run_agent.py's direct REST client sidesteps this by embedding the full tool spec in each call rather than depending on the registered agent object, and is the supported path for this repo
  • The cortex_analyst_text_to_sql tool returns governed SQL, not executed results β€” run_agent.py executes that SQL itself via the SQL API rather than relying on the orchestration model to do so
  • ap_invoice_search (Cortex Search over line_description) is wired into agent_spec.yaml, but run_agent.py's result formatting has only been exercised against cortex_analyst_text_to_sql responses β€” its cortex_search result handling is an untested generic JSON fallback, not a confirmed-working formatter, until it's actually run live

πŸ”œ Roadmap

  • v0.2.0 β€” BR-004 data-quality guardrail: flag invoices > $500K USD-equivalent via a Data Metric Function
  • v0.3.0 β€” GitHub Actions workflow running eval/run_eval.py on every push
  • v1.0.0 β€” Documented, reproducible end-to-end demo with CI-verified eval results

πŸ“‚ Dataset

Synthetic AP invoice data (50 invoices across SAP, Oracle, Baan, and Workday; USD/EUR/GBP) plus the accompanying business-requirements CSVs and 15-question evaluation set are sourced from Snowflake's official Cortex Code Foundations workshop β€” a hands-on lab for Snowflake's Cortex Code (CoCo) AI coding agent. This repo implements the pipeline that workshop describes (Dynamic Tables β†’ Semantic View β†’ Cortex Agent β†’ evaluation framework) as a standalone, version-controlled project. See docs/business_requirements/README.md for the rule-by-rule mapping from that workshop's requirements to this repo's SQL, and docs/dynamic-tables-reference/README.md for the Dynamic Tables best-practice reference the Silver layer's design follows.


πŸ‘€ Author

Deepan Mehta

  • Data Analytics β†’ Data Engineering β†’ AI/ML Engineering
  • Focused on building end-to-end data and ML systems combining analytics, automation, and deployment
  • Experience in ETL pipelines, predictive modelling, and analytical databases

πŸ”— GitHub: deepan-mehta-analytics

About

A multi-source AP invoice pipeline using Dynamic Tables and A Cortex Agent grounded on a semantic view, with an evaluation framework

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages