What you will be able to do
- Generate embeddings with AI_EMBED and store them in a VECTOR column
- Choose among similarity, manipulation and aggregate vector functions
- Assemble a semantic-search and RAG query from AI_EMBED, VECTOR_COSINE_SIMILARITY and AI_COMPLETE
- Estimate input tokens with AI_COUNT_TOKENS and explain what its result does and doesn't include
- Use TRY_COMPLETE, SPLIT_TEXT_RECURSIVE_CHARACTER and SPLIT_TEXT_MARKDOWN_HEADER appropriately
1.AI_EMBED: turning text into vectors
An embedding converts unstructured data such as text into a numeric vector, so that semantic similarity becomes geometric closeness. A help desk, for example, can find already-resolved cases that resemble a new one even when they share no keywords, because the search goes beyond keyword matching to semantic similarity.
AI_EMBED generates an embedding vector for text or image input. The vector can be used for similarity search, clustering and classification. AI_EMBED is a Cortex AI Function, so the same access controls apply as for the others. Older material uses EMBED_TEXT_768 and EMBED_TEXT_1024, where the number is the output dimension. The model you choose determines the dimension, so it has to match the VECTOR column you store into.
| Model | Output dimensions | Context window | Language support |
|---|---|---|---|
| snowflake-arctic-embed-m-v1.5 | 768 | 512 | English-only |
| snowflake-arctic-embed-m | 768 | 512 | English-only |
| e5-base-v2 | 768 | 512 | English-only |
| snowflake-arctic-embed-l-v2.0 | 1024 | 512 | Multilingual |
| voyage-multilingual-2 | 1024 | 32000 | Multilingual |
| nv-embed-qa-4 | 1024 | 512 | English-only |
ALTER TABLE issues ADD COLUMN issue_vec VECTOR(FLOAT, 768);
UPDATE issues
SET issue_vec = AI_EMBED('snowflake-arctic-embed-m', issue_text);If you only need a similarity score between two inputs and don't want to store vectors, AI_SIMILARITY calculates the embedding similarity between two inputs in a single call.
Checkpoint 1 of 7· Check yourself
You embed multilingual product reviews with snowflake-arctic-embed-l-v2.0. What must the target column be?
snowflake-arctic-embed-l-v2.0 produces 1024-dimension vectors. 512 is its context window, not its output size.
“Snowflake Cortex offers the EMBED_TEXT_768 and EMBED_TEXT_1024 functions and several Vector functions to compare them for various applications.”Source: docs.snowflake.com
2.Vector functions: similarity, manipulation and aggregation
Once you have vectors, SQL vector functions work with them. They fall into three families:
- Similarity: VECTOR_INNER_PRODUCT, VECTOR_L1_DISTANCE, VECTOR_L2_DISTANCE and VECTOR_COSINE_SIMILARITY. Each takes two VECTOR arguments of equal element type and dimension and returns a metric. - Manipulation: VECTOR_TRUNCATE and VECTOR_NORMALIZE. Each takes one vector and returns a new vector, for example a truncated or normalized one. - Aggregation: VECTOR_SUM, VECTOR_MIN, VECTOR_MAX and VECTOR_AVG. These work element-wise down a column of vectors within a group.
Two details are worth remembering. The functions are optimized in a way that can reduce floating-point precision, with a margin of error up to 1e-4. And VECTOR_COSINE_SIMILARITY isn't supported in the Snowpark API, so Snowpark Python examples use functions such as vector_l2_distance instead.
A little more detail on each family. VECTOR_INNER_PRODUCT, VECTOR_L1_DISTANCE and VECTOR_L2_DISTANCE compute the inner product, the L1 distance and the L2 distance of two vectors. VECTOR_COSINE_SIMILARITY computes their cosine similarity, which is why the search examples rank it with ORDER BY ... DESC. The Snowpark example that uses vector_l2_distance sorts by the distance to put the nearest vector first.
On the manipulation side, VECTOR_TRUNCATE truncates a VECTOR to a smaller dimension. VECTOR_NORMALIZE normalizes a VECTOR in the L2 vector space so that it has a magnitude of 1. On the aggregation side, VECTOR_SUM, VECTOR_MIN, VECTOR_MAX and VECTOR_AVG compute the element-wise sum, minimum, maximum and average of the vectors in an aggregate, for example VECTOR_AVG over a group of embeddings.
Checkpoint 2 of 7· Fill the gap
Which function completes this query that finds the vector closest to [1,2,3]? (Higher values mean more similar.)
SELECT a, ? (a, [1,2,3]::VECTOR(FLOAT, 3)) AS similarity
FROM vectors
ORDER BY similarity DESC
LIMIT 1;Cosine similarity rises as vectors align, so ORDER BY ... DESC returns the closest one first. A distance would need ascending order. VECTOR_NORMALIZE and VECTOR_AVG don't compare two vectors.
Source: docs.snowflake.comCheckpoint 3 of 7· Exam question
A data engineer needs every completion returned by an LLM call to conform to a fixed JSON schema so downstream ETL code can parse fields without try/catch logic. Which capability should they configure?
Correct answer: A — Pass a response_format JSON schema object in the options argument of AI_COMPLETE
- A. This is correct: the structured outputs feature accepts a JSON schema in the options object and constrains the model's response to that schema, giving predictable, parseable fields.
- B. This is incorrect: the NULL-on-error wrapper only changes what happens when the call fails outright; it does not constrain the shape of a successful completion.
- C. This is incorrect: the boolean row-filtering function decides whether a row passes a predicate, it has no mechanism for shaping a completion's JSON structure.
- D. This is incorrect: raising the token budget only prevents truncation; it does not force the response into a specific schema.
3.From vectors to answers: semantic search and RAG
Semantic search combines the pieces. First store embeddings for the documents and keep them up to date as documents change. Then embed the search term, compare it with the stored vectors using a similarity function, and use ORDER BY and LIMIT to keep the top k matches.
One performance rule: put the similarity call in the SELECT clause, not the WHERE clause. That way it runs only on rows that survive other filters, such as a date range. To filter on similarity, give the call a column alias in SELECT and test the alias in WHERE.
Retrieval-augmented generation (RAG) adds one more step. The best-matching document goes to an LLM together with the user's question, which gives the model context for its answer.
WITH result AS (
SELECT
w.content,
$query AS query_text,
VECTOR_COSINE_SIMILARITY(w.vec, q.query_vec) AS similarity
FROM wiki w, query_table q
ORDER BY similarity DESC
LIMIT 1
)
-- Pass to large language model as context
SELECT AI_COMPLETE('mistral-7b',
CONCAT('Answer this question: ', query_text, ' using this text: ', content)) FROM result;Checkpoint 4 of 7· Put it in order
Put the RAG steps in order
- 1.Pass the query and the retrieved text to AI_COMPLETE
- 2.Rank documents by VECTOR_COSINE_SIMILARITY and keep the top match
- 3.Embed the incoming query with the same embedding model
- 4.Store AI_EMBED vectors for the documents in a VECTOR column
Document embeddings must exist first. Then the query is embedded, compared and ranked, and the best match becomes context for the completion.
“create an embedding of the search term or target document, and then use a vector similarity function to locate documents with similar embeddings”Source: docs.snowflake.com
Sources2
4.AI_COUNT_TOKENS: estimating input before you spend
AI_COUNT_TOKENS takes a function name and, where relevant, a model name, the input text, and options that affect the count, such as AI_CLASSIFY categories. It returns an INTEGER estimate of the *input* tokens. Rules to know:
- Write function and model names in lowercase. The function name must start with ai_. It doesn't work with functions in the SNOWFLAKE.CORTEX namespace or with fine-tuned models.
- It accepts text only, not images, audio or video.
- It incurs compute cost only and isn't billed per token. It is available in all regions, even for models that aren't available there.
- For actual billed input and output tokens, use the CORTEX_FUNCTIONS_QUERY_USAGE_HISTORY view.
- With AI_COMPLETE structured output on Anthropic Claude models, billed input tokens can be materially higher than the estimate.
SELECT AI_COUNT_TOKENS('ai_sentiment',
'This place makes the best truffle pizza in the world! Too bad I cannot afford it');| Model | Token count accuracy |
|---|---|
| Anthropic Claude | Estimate; relative error under 3% |
| Google Gemini | Estimate; relative error under 3% |
| OpenAI | Near-exact |
| All other models | Exact |
Checkpoint 5 of 7· Check yourself
Which AI_COUNT_TOKENS call is valid?
The function name must be lowercase and start with ai_, and the input must be text. SNOWFLAKE.CORTEX functions, uppercase names and file inputs don't work.
“AI_COUNT_TOKENS does not work with LLM functions in the SNOWFLAKE.CORTEX namespace or with fine-tuned models.”Source: docs.snowflake.com
Checkpoint 6 of 7· Exam question
A product feedback table has millions of rows and support tickets can belong to more than one issue type at once (e.g. both 'Shipping Delay' and 'Damaged Item'). Which AI_CLASSIFY configuration is required to return more than one label per row?
Correct answer: A — Set 'output_mode': 'multi' in the config object argument
- A. This is correct: multi-label output is enabled by setting the output_mode field to multi in the optional config object; the default single-label mode returns exactly one category.
- B. This is incorrect: duplicating the categories array does not change the function's labeling mode and would just create redundant category entries.
- C. This is incorrect: this works but requires N separate LLM calls and manual result merging, which is unnecessary given the built-in multi-label mode.
- D. This is incorrect: task_description clarifies the classification task in natural language but does not toggle the structural single-vs-multi label behavior.
Sources5
5.TRY_COMPLETE and the text-splitting helpers
TRY_COMPLETE (SNOWFLAKE.CORTEX) does the same thing as COMPLETE, but returns NULL instead of raising an error when the operation can't be performed. That made it the safe choice for long batch jobs that use the legacy function. It is now a legacy function that will be deprecated by the end of 2026. Snowflake directs new work to AI_COMPLETE, which already returns NULL for failed rows by default.
One syntax difference matters when you migrate. In the legacy TRY_COMPLETE and COMPLETE, response_format (structured output) is a key inside the options object. In AI_COMPLETE it moves out into its own named argument, response_format, and the hyperparameters go in model_parameters. If you leave response_format inside model_parameters, it isn't recognized and the response comes back as an unstructured string.
For RAG, long documents must be split into chunks before embedding. Two helpers do this.
SPLIT_TEXT_RECURSIVE_CHARACTER splits text recursively and returns an array of chunks. It tries its separators in order: the defaults for the chosen format, or those you pass in separators. Any chunk still longer than chunk_size is split again with the next separator. overlap is optional.
SPLIT_TEXT_MARKDOWN_HEADER first splits a Markdown document on the header levels you list in headers_to_split_on, such as # and ##, then splits each section to chunk_size characters. Each chunk it returns is an object with the chunk text and the headers it falls under, so chunk boundaries follow the document's sections.
SNOWFLAKE.CORTEX.SPLIT_TEXT_RECURSIVE_CHARACTER (
'<text_to_split>',
'<format>',
<chunk_size>,
[ <overlap> ],
[ <separators> ]
)Checkpoint 7 of 7· Check yourself
A knowledge base of Markdown articles uses #, ## and ### headers. Each embedded chunk should stay within one section and carry its section titles. Which helper fits?
SPLIT_TEXT_MARKDOWN_HEADER splits on the header levels you specify and returns each chunk together with its headers.
“The function returns an array of objects, where each object contains the text chunk and the associated headers under which that chunk falls.”Source: docs.snowflake.com
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.AI_COUNT_TOKENS predicts the full token bill for a batch.Why is that wrong?
It estimates input tokens only. Output tokens are billed on top, and the CORTEX_FUNCTIONS_QUERY_USAGE_HISTORY view shows the actual billed counts.
Covered in AI_COUNT_TOKENS: estimating input before you spend
2.Every SQL vector function, including VECTOR_COSINE_SIMILARITY, is also available in the Snowpark Python API.Why is that wrong?
VECTOR_COSINE_SIMILARITY isn't supported in Snowpark. Use SQL, or another metric such as vector_l2_distance, in Snowpark code.
Covered in Vector functions: similarity, manipulation and aggregation
3.TRY_COMPLETE is the recommended long-term way to make completions error-tolerant.Why is that wrong?
TRY_COMPLETE is a legacy function that will be deprecated by the end of 2026. New work should use AI_COMPLETE.
Covered in TRY_COMPLETE and the text-splitting helpers
Practise it for real
Build a small semantic search and RAG flow over a support-issues table using AI_EMBED, VECTOR_COSINE_SIMILARITY and AI_COMPLETE
1.Run ALTER TABLE issues ADD COLUMN issue_vec VECTOR(FLOAT, 768); then UPDATE issues SET issue_vec = AI_EMBED('snowflake-arctic-embed-m', issue_text);
Why: Stored document embeddings are the index that semantic search compares against.
You should see: Every row has a 768-element vector in issue_vec.
2.Run AI_COUNT_TOKENS('ai_embed', 'snowflake-arctic-embed-m', <a sample issue_text>) on a few representative rows.
Why: This checks input size against the model's 512-token context window before you embed at scale.
You should see: An INTEGER per row. It is an input-only estimate.
3.SELECT issue_text and VECTOR_COSINE_SIMILARITY(issue_vec, AI_EMBED('snowflake-arctic-embed-m', 'User could not install Facebook app on his phone')) AS similarity, ORDER BY similarity DESC, LIMIT 5.
Why: Embed the query with the same model, then rank by cosine similarity to get the top k matches.
You should see: Five issues, most similar first, with similarity values between -1 and 1.
4.Wrap the LIMIT 1 version in a CTE and call AI_COMPLETE('mistral-7b', CONCAT('Answer this question: ', <question>, ' using this text: ', issue_text)).
Why: Passing the retrieved text to the LLM as context is the generation step of RAG.
You should see: One generated answer based on the closest matching issue. It is NULL only if the completion fails for that row.
Stuck? Get a nudge
If the similarity call is slow, keep it in SELECT and filter on its alias, so it runs only on rows that pass your other WHERE conditions.
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“AI_EMBED: Generates an embedding vector for a text or image input, which can be used for similarity search, clustering, and classification tasks.”
↩︎ AI_EMBED: turning text into vectors“AI_SIMILARITY: Calculates the embedding similarity between two inputs.”
↩︎ AI_EMBED: turning text into vectors - 2.
“it goes beyond keyword matching to semantic similarity”
↩︎ AI_EMBED: turning text into vectors“Generally, the call to the vector similarity function should appear in the SELECT clause, not in the WHERE clause.”
↩︎ From vectors to answers: semantic search and RAG“providing context for the generative response (completion)”
↩︎ From vectors to answers: semantic search and RAG“The Snowpark Python library does not support the VECTOR_COSINE_SIMILARITY function.”
↩︎ Exam trap 2“Snowflake Cortex offers the EMBED_TEXT_768 and EMBED_TEXT_1024 functions and several Vector functions to compare them for various applications.”
↩︎ Checkpoint“create an embedding of the search term or target document, and then use a vector similarity function to locate documents with similar embeddings”
↩︎ Checkpoint - 3.
“Similarity functions operate on two VECTOR arguments of equal element type and dimension, computing the specified metric.”
↩︎ Vector functions: similarity, manipulation and aggregation“Vector manipulation functions take an existing vector and return a new vector with different properties, such as truncation or normalization.”
↩︎ Vector functions: similarity, manipulation and aggregation“perform element-wise mathematical operations such as sum, average, minimum, and maximum across all vectors in a group”
↩︎ Vector functions: similarity, manipulation and aggregation“These functions have a margin of error up to 1e-4.”
↩︎ Vector functions: similarity, manipulation and aggregation - 4.
“Normalizes a VECTOR in the L2 vector space, giving its elements values in the range of [0,1] and giving it a magnitude of 1.”
↩︎ Vector functions: similarity, manipulation and aggregation“Truncates a VECTOR to a smaller dimension.”
↩︎ Vector functions: similarity, manipulation and aggregation“Computes the element-wise sum of vectors in an aggregate.”
↩︎ Vector functions: similarity, manipulation and aggregation - 5.
“Returns an estimate of the number of input tokens in a prompt for the specified large language model or task-specific function.”
↩︎ AI_COUNT_TOKENS: estimating input before you spend“AI_COUNT_TOKENS only incurs compute costs and does not bill based on token count.”
↩︎ AI_COUNT_TOKENS: estimating input before you spend“AI_COUNT_TOKENS accepts only text, not image, audio, or video inputs.”
↩︎ AI_COUNT_TOKENS: estimating input before you spend“AI_COUNT_TOKENS estimates input tokens only. It does not estimate output (generated) tokens, which also contribute to billing.”
↩︎ Exam trap 1“This value does not include output (generated) tokens.”
↩︎ Prediction“AI_COUNT_TOKENS does not work with LLM functions in the SNOWFLAKE.CORTEX namespace or with fine-tuned models.”
↩︎ Checkpoint - 6.
“Performs the same operation as the COMPLETE function but returns NULL instead of raising an error when the operation cannot be performed.”
↩︎ TRY_COMPLETE and the text-splitting helpers“For new use cases, start with AI_COMPLETE, which is the canonical surface going forward.”
↩︎ TRY_COMPLETE and the text-splitting helpers“This legacy function will be deprecated by the end of 2026.”
↩︎ Exam trap 3 - 7.https://docs.snowflake.com/en/user-guide/snowflake-cortex/aisql-migrate-legacy-functionsOfficial docs
“response_format moves out of the object into its own argument.”
↩︎ TRY_COMPLETE and the text-splitting helpers - 8.https://docs.snowflake.com/en/sql-reference/functions/split_text_recursive_character-snowflake-cortexOfficial docs
“for preprocessing text to be used with text embedding or search indexing functions”
↩︎ TRY_COMPLETE and the text-splitting helpers“Splitting is then applied to each chunk that is longer than the specified chunk_size, recursively”
↩︎ TRY_COMPLETE and the text-splitting helpers - 9.https://docs.snowflake.com/en/sql-reference/functions/split_text_markdown_header-snowflake-cortexOfficial docs
“splits a Markdown-formatted document into structured text chunks based on header levels”
↩︎ TRY_COMPLETE and the text-splitting helpers“The function returns an array of objects, where each object contains the text chunk and the associated headers under which that chunk falls.”
↩︎ Checkpoint