Sitemap
Press enter or click to view image in full size

Knowledge Engineering in Snowflake: Building the Enterprise Context Layer for Governed AI

--

How Semantic Views, AI_EXTRACT, Cortex Search, RelationalAI and Horizon Context turn your Snowflake account into the place where AI learns what your business actually means.

Press enter or click to view image in full size
Snowflake as the enterprise context layer

You have probably seen this happen.

A business user asks an AI assistant, “What was our revenue last quarter?” The model writes valid SQL in under a second. A number comes back. And it is wrong.

The SQL wasn’t broken. The model just didn’t know that “revenue” in your finance team means recognized revenue, not gross billings. It didn’t know that inventory is a daily snapshot you can’t add up across days. It never saw the penalty clause sitting in a supplier contract PDF on a stage.

That is the real bottleneck now. Moving data is a solved problem. Meaning is the hard part.

Knowledge engineering is the work of writing that meaning down, in a form both people and AI can use. And Snowflake has become one of the best places to do it. Over the last two years, the pieces landed one after another: native Semantic Views, AI_EXTRACT for documents, Cortex Search for hybrid retrieval, RelationalAI for graph reasoning, Horizon Context for cross-platform metadata, and Cortex Agents to tie it all together.

In this article I’ll walk you through each layer, show you the code I actually use, and share the design habits that make the difference once you hit production.

Where things stand in October 2026

Snowflake spent the last eighteen months consolidating its AI stack into a small set of native, governed objects. Four changes are worth knowing before you design anything.

Document AI has graduated to AI_EXTRACT. The Document AI UI and the !PREDICT method were retired on 16 March 2026. What used to be a three-step model-build workflow is now a single SQL function, powered by the Arctic-Extract vision model.

Cortex Agents is the recommended front door. On 28 August 2026 Snowflake recommended moving from standalone Cortex Analyst calls to Cortex Agents. The good news: your semantic views and verified queries carry over unchanged. You change how you invoke Analyst, not what you built.

Semantic modeling became a team workflow. Semantic View Autopilot went GA in February 2026. Semantic Studio (Git-backed authoring in Workspaces) and DEFINE SEMANTIC VIEW in DCM Projects both went GA on 30 September 2026.

Here is the toolkit at a glance.

Press enter or click to view image in full size

Pillar 1: Write your business meaning down with Semantic Views

A semantic view is where “revenue” stops being a guess. It is a schema-level database object, so you grant it, share it and audit it like any other object. It replaces the older pattern of uploading YAML files to a stage. Existing staged YAML still works with Cortex Analyst, but semantic views add direct SQL querying, native sharing through listings and the Marketplace, and visibility in Information Schema and Account Usage.

Every semantic view is built from five pieces:

  • Logical tables: your business entities, mapped to physical tables or views.
  • Relationships: the join paths you allow. An agent will only join along paths you declare.
  • Facts: row-level numeric values, such as net price after discount.
  • Dimensions: what you group and filter by, such as segment or order year.
  • Metrics: reusable aggregations, such as realized net revenue.
Press enter or click to view image in full size
Anatomy of a semantic view

Three ways to build one

You don’t have to start from a blank file.

  • Semantic View Autopilot proposes a view from your query history and existing BI assets. Hand it a Tableau workbook or a Power BI .pbix file (Power BI ingestion went GA in August 2026) and it pulls relationships, measures and descriptions across for you to review.
  • Semantic Studio gives you a Git-backed authoring surface in Workspaces, with CoCo helping you refine the definitions conversationally.
  • SQL or DCM Projects let you manage the view as code, either with CREATE SEMANTIC VIEW or declaratively with DEFINE SEMANTIC VIEW alongside the rest of your objects.

The code

When you write the DDL by hand, keep the clause order: TABLES, RELATIONSHIPS, FACTS, DIMENSIONS, METRICS. Notice the AI_SQL_GENERATION and AI_QUESTION_CATEGORIZATION clauses at the end. They let you give Cortex plain-language rules without touching your prompts.

-- Roles for modeling and consumption
USE ROLE ACCOUNTADMIN;
CREATE ROLE IF NOT EXISTS semantic_engineer_role;
GRANT DATABASE ROLE SNOWFLAKE.CORTEX_USER TO ROLE semantic_engineer_role;
GRANT CREATE SEMANTIC VIEW ON SCHEMA sales_db.analytics TO ROLE semantic_engineer_role;

-- A governed semantic view over a classic orders star schema
CREATE OR REPLACE SEMANTIC VIEW sales_db.analytics.enterprise_revenue_sv
TABLES (
orders AS sales_db.raw.orders
PRIMARY KEY (o_orderkey)
COMMENT = 'One row per sales order header',
customers AS sales_db.raw.customer
PRIMARY KEY (c_custkey)
UNIQUE (c_email)
COMMENT = 'Customer master with market segment',
lineitem AS sales_db.raw.lineitem
PRIMARY KEY (l_orderkey, l_linenumber)
COMMENT = 'One row per order line, with price and discount'
)
RELATIONSHIPS (
orders_to_customers AS orders (o_custkey) REFERENCES customers (c_custkey),
lineitems_to_orders AS lineitem (l_orderkey) REFERENCES orders (o_orderkey)
)
FACTS (
orders.o_totalprice AS o_totalprice
COMMENT = 'Gross order total before line-level returns',
lineitem.net_extended_price AS l_extendedprice * (1 - l_discount)
COMMENT = 'Line revenue after the contractual discount'
)
DIMENSIONS (
customers.customer_segment AS c_mktsegment
COMMENT = 'Commercial market segment of the customer',
orders.order_date AS o_orderdate
COMMENT = 'Date the order was booked',
orders.order_year AS YEAR(o_orderdate)
COMMENT = 'Year the order was booked'
)
METRICS (
customers.active_customer_count AS COUNT(DISTINCT c_custkey)
COMMENT = 'Distinct customers with recorded activity',
orders.average_order_value AS AVG(orders.o_totalprice)
WITH SYNONYMS ('AOV')
COMMENT = 'Average gross value across booked orders',
lineitem.realized_net_revenue AS SUM(lineitem.net_extended_price)
WITH SYNONYMS ('turnover')
COMMENT = 'Total revenue net of line-item discounts'
)
COMMENT = 'Governed semantic view for commercial revenue analytics'
AI_SQL_GENERATION 'Round currency values to two decimals. If no date range is given, use the current calendar year.'
AI_QUESTION_CATEGORIZATION 'If a user asks about revenue without naming a segment or a year, ask which one they mean.';

A quick word on synonyms. Snowflake’s current modeling guidance says frontier models gain little from generic synonyms, so I keep them for genuine house jargon like “AOV” or “turnover” and let good comments do the rest.

Once the view exists, anyone with access can query it deterministically in plain SQL:

SELECT *
FROM SEMANTIC_VIEW(
sales_db.analytics.enterprise_revenue_sv
DIMENSIONS customers.customer_segment, orders.order_year
METRICS lineitem.realized_net_revenue, orders.average_order_value
)
WHERE order_year >= 2025
ORDER BY realized_net_revenue DESC;

Evolving the view

ALTER SEMANTIC VIEW handles renames and comments. For everything else, such as a new metric or a new dimension, you replace the definition. Add COPY GRANTS so existing access survives the change:

CREATE OR REPLACE SEMANTIC VIEW sales_db.analytics.enterprise_revenue_sv
-- ...full updated definition...
COPY GRANTS;

In practice I keep the definition in Git through Semantic Studio or a DCM Project, so every change is reviewed, versioned and deployed like the rest of the platform.

Design habits that pay off

  • Start with 5 to 10 tables. A simple star schema is the best first proof of concept. Grow from there.
  • Stay under about 100,000 tokens per view. There is no hard limit any more, but smaller views mean less pruning and sharper answers.
  • Split by business domain, not by source system. “Sales performance” and “Support metrics” beat “All CRM tables”. Each semantic view is queried on its own, so group things that are joined together.
  • Declare every join you need. If a relationship isn’t declared, the agent won’t invent it. That is a feature: no surprise joins.
  • Know the query rules. SEMANTIC_VIEW() needs at least one of METRICS, DIMENSIONS or FACTS, and you don't mix FACTS with METRICS in the same query. SHOW SEMANTIC DIMENSIONS FOR METRIC tells you which dimensions are valid for a given metric.
  • Add verified queries last. Once tables, columns and descriptions are solid, verified queries cover the edge cases and speed up common questions.
  • Pair high-cardinality text columns with Cortex Search. It lets “iPhone 13” match “Apple iPhone 13 128GB Blue” without anyone typing the exact product name.

Protect the grain under your semantic view

A semantic view is a governed vocabulary. It describes your data faithfully, so the quality of the answer depends on the grain of the tables you point it at. This one habit separates good semantic layers from great ones.

Let’s make it concrete. Say you track which servers were active each day. Server A ran Monday to Wednesday. Server B ran Monday and Tuesday. Server C ran Tuesday and Wednesday. Someone asks: how many servers were active this week?

Press enter or click to view image in full size
Keep atomic grain under your semantic view

The right answer is 3. You get it by running COUNT(DISTINCT server_id) over the event table, one row per server per active day.

Now imagine an upstream dbt job already rolled that up into a daily table: Monday 2, Tuesday 3, Wednesday 2. The server IDs are gone. From here you can only get two answers, and neither is 3:

  • Sum the daily counts and you get 7, because servers active on several days are counted several times.
  • Take the last snapshot and you get 2, which is Wednesday’s count.

That last option is exactly what NON ADDITIVE BY is designed for, and it's a feature many semantic layers outside Snowflake still don't have. You declare that a metric should not be summed across a dimension such as date, and Snowflake picks the right snapshot at query time. It is perfect for account balances and inventory on hand. It is simply the wrong tool for distinct entities, because no declaration can recover IDs a rollup has already thrown away.

Get Abhishek Mittal’s stories in your inbox

Join Medium for free to get updates from this writer.

The fix is easy: anchor your logical tables on atomic fact grain, declare the star-schema relationships, and let the metric do the counting. Keep NON ADDITIVE BY for genuine snapshots. Remember it's an assertion you author, so document why you chose it in the metric's comment.

Pillar 2: Turn documents into knowledge with AI_EXTRACT and Cortex Search

A lot of your most important business context isn’t in tables at all. It’s in indemnification clauses, inspection reports, rate schedules and emails. Snowflake handles this in two native steps, with no external OCR service or separate vector database to run.

  1. AI_EXTRACT pulls structured entities, lists and tables out of each file.
  2. Cortex Search makes the text searchable with hybrid retrieval, ready for agents.
Press enter or click to view image in full size
From PDF to agent-ready knowledge

What AI_EXTRACT gives you

AI_EXTRACT runs on Arctic-Extract, Snowflake’s vision-based extraction model. Because it reads the page visually, it copes with multi-column layouts, checkboxes and nested tables, on both digital and scanned documents. A few facts worth knowing:

  • It accepts PDF, Word, PowerPoint, images (PNG, JPEG, TIFF and more), email, HTML, Markdown and plain text, up to 100 MB and 125 pages per document.
  • One call can ask up to 100 entity questions and up to 10 table questions.
  • scores => TRUE returns a confidence score for every extracted field at no extra cost. This is what makes human-in-the-loop routing easy.
  • config => {'scale_factor': 2.0} upscales pages for small print or dense layouts.
  • It works with client-side and server-side encrypted stages, including accounts behind PrivateLink.
  • Billing is token-based, with each page counted as 970 tokens. Snowflake recommends a warehouse no larger than MEDIUM, because bigger ones don’t make it faster.

When your layouts are very domain-specific, Arctic-Extract fine-tuning (GA since April 2026) trains a custom model from your own labeled documents, and it stays in your account’s Model Registry. On a domain-specific test set, Snowflake’s engineering team reported a fine-tuned model reaching 93.8% mean ANLS*, with 89% of extractions scoring a perfect match.

The pipeline

AI_EXTRACT is inference, so you run it once per new file in a pipeline and store the result. A stream on the stage’s directory table plus a task does exactly that.

-- 1. A stage with a directory table, and a stream that sees new files
CREATE STAGE IF NOT EXISTS legal_db.contracts.vendor_agreements_stage
DIRECTORY = (ENABLE = TRUE)
ENCRYPTION = (TYPE = 'SNOWFLAKE_SSE');

CREATE STREAM IF NOT EXISTS legal_db.contracts.agreements_stream
ON STAGE legal_db.contracts.vendor_agreements_stage;

CREATE TABLE IF NOT EXISTS legal_db.contracts.extracted_vendor_metadata (
file_name STRING,
last_modified TIMESTAMP_TZ,
extraction_payload VARIANT
);

-- 2. A task that extracts only new files, with confidence scores
CREATE OR REPLACE TASK legal_db.contracts.extract_new_contracts
WAREHOUSE = extract_wh
SCHEDULE = '60 MINUTE'
WHEN SYSTEM$STREAM_HAS_DATA('legal_db.contracts.agreements_stream')
AS
INSERT INTO legal_db.contracts.extracted_vendor_metadata
SELECT
relative_path,
last_modified,
AI_EXTRACT(
file => TO_FILE('@legal_db.contracts.vendor_agreements_stage', relative_path),
responseFormat => {
'schema': {
'type': 'object',
'properties': {
'vendor_name': {'description': 'What is the legal name of the supplier?', 'type': 'string'},
'governing_region': {'description': 'Which region governs this agreement?', 'type': 'string'},
'is_signed': {'description': 'Is the contract signed by both parties? Answer yes or no.', 'type': 'string'},
'covered_skus': {'description': 'List every product SKU code covered.', 'type': 'array'},
'rate_schedule': {
'description': 'Pricing tier table in Section 4',
'type': 'object',
'column_ordering': ['Item Category', 'Unit Price', 'Penalty Rate'],
'properties': {
'Item Category': {'description': 'Item Category', 'type': 'array'},
'Unit Price': {'description': 'Unit Price', 'type': 'array'},
'Penalty Rate': {'description': 'Penalty Rate', 'type': 'array'}
}
}
}
}
},
scores => TRUE
)
FROM legal_db.contracts.agreements_stream
WHERE METADATA$ACTION = 'INSERT';

ALTER TASK legal_db.contracts.extract_new_contracts RESUME;

Now flatten the JSON into typed columns and use the scores to decide what goes straight through and what a data steward checks first. Pick the threshold from a sample of your own documents.

-- 3. Typed columns plus a routing decision based on confidence
CREATE OR REPLACE VIEW legal_db.contracts.contract_extractions AS
SELECT
file_name,
extraction_payload:response:vendor_name::STRING AS vendor_name,
extraction_payload:response:governing_region::STRING AS region,
LOWER(extraction_payload:response:is_signed::STRING) AS signature_status,
TO_VARCHAR(extraction_payload:response:rate_schedule) AS rate_schedule_text,
extraction_payload:scoring:scores:vendor_name:score::FLOAT AS vendor_name_score,
extraction_payload:scoring:scores:rate_schedule:score::FLOAT AS rate_schedule_score,
IFF(LEAST(vendor_name_score, rate_schedule_score) >= 0.85,
'AUTO_APPROVED', 'STEWARD_REVIEW') AS review_route
FROM legal_db.contracts.extracted_vendor_metadata
WHERE extraction_payload:error IS NULL;

Hybrid retrieval with Cortex Search

Cortex Search takes care of the hard parts of retrieval for you. It embeds your text, builds a keyword index alongside the vectors, runs both in parallel with semantic reranking, and refreshes incrementally within the TARGET_LAG you set. Two newer options are worth switching on: AUTO_SUSPEND (public preview since May 2026, minimum 1,800 seconds) pauses serving compute when nobody is querying, and REQUEST_LOGGING records search requests for monitoring.

-- 4. A search service over the approved extractions
CREATE OR REPLACE CORTEX SEARCH SERVICE legal_db.contracts.vendor_contract_search_svc
ON rate_schedule_text
PRIMARY KEY (file_name)
ATTRIBUTES vendor_name, region, signature_status
WAREHOUSE = search_wh
TARGET_LAG = '1 hour'
EMBEDDING_MODEL = 'snowflake-arctic-embed-l-v2.0'
REFRESH_MODE = INCREMENTAL
INITIALIZE = ON_CREATE
AUTO_SUSPEND = 1800
REQUEST_LOGGING = TRUE
AS (
SELECT file_name, rate_schedule_text, vendor_name, region, signature_status
FROM legal_db.contracts.contract_extractions
WHERE review_route = 'AUTO_APPROVED'
);

In this example I index the extracted rate schedules. For full-text question answering over whole contracts, parse each file with AI_PARSE_DOCUMENT, chunk the text, and index the chunks in the same way.

For big offline jobs such as entity resolution or matching thousands of disputed invoices to contracts, use the CORTEX_SEARCH_BATCH table function. It runs on separate compute, so it never slows your interactive users. For fewer than about 2,000 queries, the interactive API is usually faster.

-- 5. Match every disputed invoice to its most relevant signed contracts
SELECT q.disputed_item_query, s.*
FROM legal_db.audits.disputed_invoices AS q,
LATERAL CORTEX_SEARCH_BATCH(
service_name => 'legal_db.contracts.vendor_contract_search_svc',
query => q.disputed_item_query,
filter => OBJECT_CONSTRUCT('@eq', OBJECT_CONSTRUCT('signature_status', 'yes')),
limit => 3
) AS s;

One more option to know about: Cortex Knowledge Extensions package Cortex Search services as Snowflake Marketplace listings. Your agents can ground answers in a publisher’s corpus, such as research or technical documentation, without copying the data, while the publisher keeps control of their content.

Pillar 3: Reason over relationships with RelationalAI

Semantic views are brilliant at governed aggregations. Cortex Search is brilliant at finding the right passage. Some questions need a third skill: following chains of relationships and applying rules along the way.

You’ll know you’ve hit this point when you catch yourself writing a recursive CTE to walk a bill of materials. Or when your team maintains thousands of lines of business rules that change every week.

That’s where RelationalAI comes in. It is a Snowflake Native App that runs on Snowpark Container Services, inside your own account. Your data never leaves Snowflake, and your RBAC still applies. You describe your domain as an ontology in Python (concepts, relationships, properties), write declarative rules, and RelationalAI derives new facts you can query or write back to Snowflake tables.

Here is a supply chain example in the current PyRel v1 syntax. The rule flags any low-stock product whose supplier is currently disrupted.

from relationalai.semantics import Integer, Model, String

m = Model("supply_chain_kg")

# 1. The ontology: concepts, properties and relationships
Supplier = m.Concept("Supplier", identify_by={"id": Integer})
Product = m.Concept("Product", identify_by={"sku": String})

Supplier.status = m.Property(f"{Supplier} has status {String:status}")
Product.stock_level = m.Property(f"{Product} has stock level {Integer:stock_level}")
Product.reorder_threshold = m.Property(f"{Product} reorders below {Integer:reorder_threshold}")
Supplier.supplies = m.Relationship(f"{Supplier} supplies {Product:product}")
Product.needs_expedited_reorder = m.Relationship(f"{Product} needs an expedited reorder")

# 2. Base facts straight from Snowflake tables
suppliers = m.Table("SCM.CORE.SUPPLIERS") # id, status
products = m.Table("SCM.CORE.PRODUCTS") # sku, stock_level, reorder_threshold
supply_map = m.Table("SCM.CORE.SUPPLY_MAP") # supplier_id, product_sku

m.define(
Supplier.new(suppliers.to_schema()),
Product.new(products.to_schema()),
)
m.define(
Supplier.lookup(id=supply_map.supplier_id).supplies(
Product.lookup(sku=supply_map.product_sku)
)
)

# 3. A declarative rule: low stock + disrupted supplier = expedite
s, p = Supplier.ref(), Product.ref()
m.where(
s.supplies(p),
s.status == "DISRUPTED",
p.stock_level < p.reorder_threshold,
).define(p.needs_expedited_reorder())

# 4. Query the derived facts
print(m.select(Product.sku).where(Product.needs_expedited_reorder()).to_df())

Notice what changes when the business changes. A new threshold or a new risk condition is one edit to one rule. No pipeline refactor. RelationalAI reports that Blue Yonder used this approach to cut its legacy rule code by 90%.

Pair it with Cortex and you get GraphRAG: an LLM turns a question into a graph query and retrieves multi-hop connections that vector similarity alone would miss. RelationalAI also integrates with Snowflake Semantic Views, so the meaning you defined in Pillar 1 carries across into the graph. Snowflake’s GraphRAG quickstart is a great place to try it end to end.

Pin your relationalai package version, as the PyRel API evolves quickly.

Pillar 4: Govern, trace and activate

All of this knowledge only pays off when people and agents can use it safely, and when you can prove where every answer came from. Snowflake gives you two layers for this: Horizon for context and lineage, and Cortex Agents for reasoning and action.

Context and lineage across your whole estate

An agent needs to tell an authoritative production table from a stale sandbox copy. Three recent releases help with exactly that.

  • Horizon Context (public preview since 12 October 2026) extends Horizon Catalog with metadata from outside Snowflake. Metadata connectors cover 18 sources, including Power BI, Tableau, dbt, SQL Server, Oracle, Databricks, BigQuery, MySQL and PostgreSQL. You can browse external assets, explore cross-platform lineage, and curate tags and descriptions in one place. A new metadata-only editing access lets stewards curate descriptions without being able to read the data itself.
  • External lineage (GA since 3 September 2026) accepts OpenLineage events from tools such as dbt and Apache Airflow at the /api/v2/lineage/external-lineage endpoint, and stitches them into Snowflake's native lineage graph. It needs Enterprise Edition and the INGEST LINEAGE privilege.
  • Cortex Agent lineage (since 2 September 2026) records the semantic views and Cortex Search services each agent’s tools reference. Snowflake captures this when you create an agent or commit a new version, which is one more good reason to standardize on native semantic views.

That gives you a single path from raw table to semantic view to agent. Before you change a schema, check the blast radius in SQL:

-- Everything downstream of LINEITEM: semantic views at distance 1, agents at distance 2
SELECT distance,
source_object_domain, source_object_name,
target_object_domain, target_object_name
FROM TABLE(
SNOWFLAKE.CORE.GET_LINEAGE('SALES_DB.RAW.LINEITEM', 'TABLE', 'DOWNSTREAM', 3)
);

Bringing it together with a Cortex Agent

Now register your knowledge assets as tools on one agent. Take a real question: “Which market segments saw realized net revenue fall this year, and do our signed vendor contracts in those regions include penalty-rate protections?”

Press enter or click to view image in full size
One question, two knowledge sources, one cited answer

The agent plans the steps. It sends the revenue part to the Cortex Analyst tool over enterprise_revenue_sv, sends the contract part to the Cortex Search tool over vendor_contract_search_svc, keeps the conversation in a thread, and answers with citations. Every user only sees the rows and documents their role allows.

CREATE OR REPLACE AGENT sales_db.analytics.revenue_contracts_agent
COMMENT = 'Revenue trends plus vendor contract terms'
FROM SPECIFICATION
$$
models:
orchestration: auto
instructions:
orchestration: "Use RevenueAnalyst for revenue, segments and trends. Use ContractSearch for contract terms, clauses and penalty rates."
response: "Be concise. Cite the source contract for every clause you quote."
sample_questions:
- question: "Which segments saw realized net revenue fall this year?"
tools:
- tool_spec:
type: "cortex_analyst_text_to_sql"
name: "RevenueAnalyst"
description: "Governed revenue metrics by segment and year"
- tool_spec:
type: "cortex_search"
name: "ContractSearch"
description: "Rate schedules and penalty terms from signed vendor contracts"
tool_resources:
RevenueAnalyst:
semantic_view: "SALES_DB.ANALYTICS.ENTERPRISE_REVENUE_SV"
ContractSearch:
name: "LEGAL_DB.CONTRACTS.VENDOR_CONTRACT_SEARCH_SVC"
max_results: "5"
filter:
"@eq":
signature_status: "yes"
$$;

One agent, every surface

Once the agent exists, you can put it in front of every kind of user without rebuilding anything:

  • Snowflake CoWork (formerly Snowflake Intelligence) gives business users a governed chat and work agent.
  • Snowflake CoCo (formerly Cortex Code) lets engineers build pipelines, dbt models and semantic views grounded in the same definitions, from the desktop app, CLI or VS Code.
  • The Cortex Agent SDK (public preview since 13 October 2026) embeds agents in your own Python or TypeScript applications.
  • The Snowflake-managed MCP server exposes semantic views, search services, agents and UDFs as MCP tools to external clients such as Claude Desktop or Cursor. Access is controlled per tool with standard grants, and the data stays inside Snowflake.
CREATE OR REPLACE MCP SERVER sales_db.analytics.knowledge_mcp
FROM SPECIFICATION $$
tools:
- name: "revenue-analyst"
type: "CORTEX_ANALYST_MESSAGE"
identifier: "SALES_DB.ANALYTICS.ENTERPRISE_REVENUE_SV"
title: "Revenue analyst"
description: "Governed revenue metrics by segment and year"
- name: "contract-search"
type: "CORTEX_SEARCH_SERVICE_QUERY"
identifier: "LEGAL_DB.CONTRACTS.VENDOR_CONTRACT_SEARCH_SVC"
title: "Contract search"
description: "Clauses and rate schedules from signed vendor contracts"
$$;

A checklist to take back to your team

If you only do five things after reading this, make it these.

  1. Move to native objects. Migrate staged YAML semantic models to semantic views, and move any remaining Document AI pipelines to AI_EXTRACT. You get SQL querying, sharing, RBAC and lineage for free.
  2. Defend atomic grain. Point logical tables at event-level fact tables. Keep NON ADDITIVE BY for real snapshots such as balances and inventory.
  3. Match the primitive to the question. Semantic views for governed numbers. AI_EXTRACT plus Cortex Search for documents. RelationalAI for multi-hop reasoning and fast-changing rules.
  4. Put Cortex Agents in front. One agent, many surfaces: CoWork, CoCo, the Agent SDK and MCP clients all read the same definitions.
  5. Turn on lineage everywhere. External lineage, agent lineage and Horizon Context together tell you where every answer came from, and what breaks if you change a table.

The edge is your context, not your model

Language models are getting better and cheaper every quarter. The thing that sets your AI apart is the layer of meaning underneath it: your definitions, your documents, your rules, your lineage.

What I like most about building that layer in Snowflake is where it lives. It sits right next to your data, under the same governance, and every consumer reads from it, from a dashboard to an agent to an engineer’s IDE.

Your data team’s job is changing. We aren’t just pipeline builders any more. We’re curators of what the business means. That’s a much more interesting job, and Snowflake has given us an excellent toolkit to do it well.

If you’re building a context layer on Snowflake, I’d love to hear what’s working for you. Drop a comment or find me on LinkedIn.

--

--

Abhishek Mittal
Abhishek Mittal