What you will be able to do
- Grant the account privilege and database role a role needs before application code can call Cortex AI functions
- Explain why a chat built on COMPLETE has to resend the whole conversation on every turn
- Build a messages array with system, user and assistant roles in the correct order
- Choose an entry point for application code that supports the multi-message form of COMPLETE
Key concept
Stateless completion — Each call to COMPLETE or AI_COMPLETE is independent: the model keeps no memory between calls. A chat interface feels conversational only because the application stores the conversation and sends all of it with every new request.
1.Setting up access: one privilege plus one database role
Before you write any chat code, the role your application runs as must be allowed to call Cortex. Access depends on two separate things, and you need both. The first is the account-level privilege USE AI FUNCTIONS, or a per-function privilege such as USE AI FUNCTION AI_COMPLETE. The second is one of the database roles in the SNOWFLAKE database, either CORTEX_USER or AI_FUNCTIONS_USER. Having only one of the two is a common reason a new chat app fails on its first call.
The defaults are permissive. USE AI FUNCTIONS is granted to PUBLIC by default, and so is CORTEX_USER. Because every user and role gets PUBLIC, a new account can usually call Cortex functions straight away. To lock this down, an administrator revokes the grants from PUBLIC and gives them to chosen roles. Only ACCOUNTADMIN can manage the USE AI FUNCTIONS privilege. Neither database role can be granted directly to a user. You grant it to an account role, and then grant that account role to users.
USE ROLE ACCOUNTADMIN;
-- Remove blanket access from PUBLIC
REVOKE USE AI FUNCTIONS ON ACCOUNT FROM ROLE PUBLIC;
-- Create a role with access to only AI_COMPLETE
CREATE ROLE ai_complete_user_role;
GRANT USE AI FUNCTION AI_COMPLETE ON ACCOUNT TO ROLE ai_complete_user_role;
GRANT DATABASE ROLE SNOWFLAKE.CORTEX_USER TO ROLE ai_complete_user_role;
GRANT ROLE ai_complete_user_role TO USER example_user;The two database roles differ in scope, and the difference matters for chat. AI_FUNCTIONS_USER covers the scalar AI functions only. It does not include the aggregate functions AI_AGG and AI_SUMMARIZE_AGG, and it gives no access to Cortex services such as Cortex Agent, Cortex Analyst or Cortex Search. It is also not granted to PUBLIC by default. A chat app that only calls AI_COMPLETE can run under AI_FUNCTIONS_USER. An app that calls an agent cannot, because agents need a different role (see the Cortex Agents lesson). Per-function grants and the blanket privilege work as an OR: a role with USE AI FUNCTIONS can call everything, whatever per-function grants it has or has lost.
| Database role | Granted to PUBLIC by default? | What it covers |
|---|---|---|
| SNOWFLAKE.CORTEX_USER | Yes | Cortex AI functions, including the aggregate functions |
| SNOWFLAKE.AI_FUNCTIONS_USER | No | Scalar AI functions only; no Cortex Agent, Cortex Analyst, Cortex Fine-tuning or Cortex Search |
| CORTEX_EMBED_USER | Not stated | AI_EMBED, EMBED_TEXT_768, EMBED_TEXT_1024 and Cortex Search Services with managed embeddings |
Checkpoint 1 of 7· Check yourself
An administrator revoked USE AI FUNCTIONS from PUBLIC and then granted it to the role CHAT_APP_ROLE. The app's first AI_COMPLETE call still fails. What is the most likely missing grant?
Cortex needs both the account privilege and one of the two database roles. A per-function grant adds nothing when the blanket privilege is already there, and the database role can only be granted to a role, not to a user.
“and one of the CORTEX_USER or AI_FUNCTIONS_USER database roles to use Snowflake Cortex AI Functions.”Source: docs.snowflake.com
Checkpoint 2 of 7· Exam question
Which database role provides the minimum privileges required for a user to invoke Cortex Analyst, following the principle of least privilege?
Correct answer: A — SNOWFLAKE.CORTEX_ANALYST_USER
- A. This database role is scoped specifically to Cortex Analyst usage, so granting it gives a caller exactly the access needed without extending broader Cortex privileges.
- B. This is a general administrative role for managing database objects; it does not inherently grant the ability to call Cortex Analyst.
- C. This role has global account privileges, which is far broader than necessary and violates least-privilege design for a chat-with-data feature.
- D. This role grants access to Cortex functions more broadly than Analyst alone, so it is not the narrowest role available for this specific need.
Sources1
2.Multi-turn architecture: the messages array
The second argument of COMPLETE is called prompt_or_history, and the name explains what it does. Without the options argument, it must be a single prompt string. With options, even an empty object {}, it must be an array of message objects listed in the order they happened. Each object has a role key and a content key. This array is the parameter you update on every turn: add the user's new message, call the function, then add the model's reply as an assistant message so it is there for the next call.
| role | content | Placement rule |
|---|---|---|
| system | Background information and instructions for response style; the model does not reply to it | At most one, and it must be first |
| user | A prompt from the user | Follows the system prompt (if any) or an assistant response |
| assistant | A response the model gave earlier | Must follow a user prompt |
Checkpoint 3 of 7· Put it in order
Put the entries of a second-turn messages array in the order COMPLETE requires
- 1.system: instructions on tone and background
- 2.user: the follow-up question
- 3.user: the first question
- 4.assistant: the model's earlier answer
The single system prompt has to come first. After that, user and assistant messages alternate: each assistant message follows a user prompt, and each later user prompt follows an assistant response.
“Only one system prompt may be provided, and if it is present, it must be the first in the array.”Source: docs.snowflake.com
This design has a cost. The history grows every turn, so the number of tokens processed also grows each round, and cost rises with it. Passing options also changes what comes back. Without options you get a plain string. With options but no response_format, you get a JSON string with choices (the reply), created, model and usage (completion_tokens, prompt_tokens, total_tokens). You can use the usage field to watch a conversation grow. The options object also sets the generation parameters listed below. AI_COMPLETE is the updated version of COMPLETE and the one to use for new code. The legacy COMPLETE page says that function will be deprecated by the end of 2026.
| Option | Effect | Default |
|---|---|---|
| temperature | Randomness of output, 0 to 1 | 0 |
| top_p | Restricts the set of possible tokens; alternative to temperature | 0 |
| max_tokens | Maximum output tokens (maximum allowed 8192) | 4096 |
| guardrails | Filters unsafe responses using Cortex Guard | FALSE |
| response_format | JSON schema the response must follow | Not set |
Checkpoint 4 of 7· Check yourself
A developer adds options => {} to an existing COMPLETE call that passed a single prompt string, and the call stops working. Why?
Passing options at all, even {}, changes how the second argument is read: it must then be a conversation array, not a string.
“If options is present, the argument must be an array of objects representing a conversation in chronological order.”Source: docs.snowflake.com
Checkpoint 5 of 7· Exam question
A team builds a Streamlit in Snowflake app that calls Cortex Analyst using a semantic model YAML file stored in an internal stage. Business users already hold the CORTEX_ANALYST_USER role but still get "insufficient privileges" errors when submitting questions. What is the most likely missing grant?
Correct answer: B — READ access on the stage that holds the semantic model file
- A. Ownership of the file is not required to query it through Cortex Analyst; ordinary read access on the containing stage is what matters, so transferring ownership would not resolve the error.
- B. Cortex Analyst reads the semantic model file directly from the stage at query time, so a role without stage read access will fail even if it holds the Analyst role.
- C. Database roles like this one do not require a separate USAGE grant on a parent role concept in Snowflake's RBAC model, so this is not the missing piece.
- D. This privilege relates to using objects shared from the SNOWFLAKE database, not to reading a customer-owned semantic model file from a stage.
3.Calling Cortex from application code
A Streamlit app or a Python script can call Cortex functions without writing SQL. The Snowpark Python API includes snake_case versions of the newer functions, such as ai_complete, ai_classify and ai_filter. Snowflake ML (snowflake.cortex) includes the older ones, such as complete, summarize and translate. If a script runs outside Snowflake, it must first create a Snowpark session. With Snowflake ML, you pass hyperparameters through a CompleteOptions object.
Checkpoint 6 of 7· Fill the gap
Which option name limits how many output tokens this Snowflake ML call can generate?
from snowflake.cortex import complete, CompleteOptions
model_options1 = CompleteOptions(
{' ? ':30}
)
print(complete("llama3.1-8b", "how do snowflakes get their unique patterns?", options=model_options1))max_tokens sets the maximum number of output tokens. temperature and top_p control randomness, and guardrails turns on Cortex Guard filtering.
Source: docs.snowflake.comFor a chat app, one limitation matters more than any other. The multi-message, chat-style form of COMPLETE is not supported in Snowflake ML Python or in the Snowflake CLI. Those surfaces take a single prompt only. To send a messages array, call the function through SQL, for example from a Streamlit app that runs a query. On the app side, the conversation lives in client state. Snowflake's Streamlit agent guide keeps chat history in Streamlit session state to support multi-turn conversations. That client-held history is what you turn into prompt_or_history on each call.
Checkpoint 7 of 7· Check yourself
A team wants its Python chatbot to pass a system/user/assistant history to COMPLETE. Which approach does the documentation support?
The chat-style form is not supported in Snowflake ML Python or the Snowflake CLI, so the history array has to go through the SQL function.
“The advanced chat-style (multi-message) form of COMPLETE is not currently supported in Snowflake ML Python.”Source: docs.snowflake.com
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Granting USE AI FUNCTIONS to a role is enough to let it call AI_COMPLETE.Why is that wrong?
The account privilege must be paired with the CORTEX_USER or AI_FUNCTIONS_USER database role. Either one alone is not enough.
Covered in Setting up access: one privilege plus one database role
2.Snowflake remembers earlier turns of a COMPLETE conversation, so the app only needs to send the newest question.Why is that wrong?
COMPLETE is stateless. The app must resend all earlier prompts and responses, and the token cost grows each round.
Covered in Multi-turn architecture: the messages array
3.The Snowflake CLI command snow cortex complete can run a multi-turn conversation.Why is that wrong?
The chat-style multi-message form of COMPLETE is not supported in the Snowflake CLI.
Covered in Calling Cortex from application code
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“By default, the USE AI FUNCTIONS privilege is granted to the PUBLIC role.”
↩︎ Setting up access: one privilege plus one database role“You must use the ACCOUNTADMIN role to manage the USE AI FUNCTIONS account-level privilege.”
↩︎ Setting up access: one privilege plus one database role“The SNOWFLAKE.CORTEX_USER database role cannot be granted directly to a user.”
↩︎ Setting up access: one privilege plus one database role“without granting access to Cortex services such as Cortex Agent, Cortex Analyst, Cortex Fine-tuning, or Cortex Search.”
↩︎ Setting up access: one privilege plus one database role“AI_FUNCTIONS_USER role is not granted to the PUBLIC role by default.”
↩︎ Setting up access: one privilege plus one database role“If a role has USE AI FUNCTIONS, it can call all Cortex AI functions, regardless of any per-function grants or revocations.”
↩︎ Setting up access: one privilege plus one database role“and one of the CORTEX_USER or AI_FUNCTIONS_USER database roles to use Snowflake Cortex AI Functions.”
↩︎ Exam trap 1“and one of the CORTEX_USER or AI_FUNCTIONS_USER database roles to use Snowflake Cortex AI Functions.”
↩︎ Checkpoint - 2.
“Each object must contain a role key and a content key.”
↩︎ Multi-turn architecture: the messages array“The model does not generate a response to a system prompt.”
↩︎ Multi-turn architecture: the messages array“the number of tokens processed increases for each”
↩︎ Multi-turn architecture: the messages array“affects how the prompt argument is interpreted and how the response is formatted”
↩︎ Multi-turn architecture: the messages array“An object recording the number of tokens consumed and generated by this completion.”
↩︎ Multi-turn architecture: the messages array“This legacy function will be deprecated by the end of 2026.”
↩︎ Multi-turn architecture: the messages array“COMPLETE does not retain any state from one call to the next.”
↩︎ Key concept“COMPLETE does not retain any state from one call to the next.”
↩︎ Exam trap 2“pass all previous user prompts and model responses in the conversation as part of the prompt_or_history array”
↩︎ Prediction“Only one system prompt may be provided, and if it is present, it must be the first in the array.”
↩︎ Checkpoint“If options is present, the argument must be an array of objects representing a conversation in chronological order.”
↩︎ Checkpoint - 3.
“AI_COMPLETE is the updated version of COMPLETE. For the latest functionality, use AI_COMPLETE.”
↩︎ Multi-turn architecture: the messages array - 4.
“integrate AI Functions into application code or scripts rather than running them as SQL statements”
↩︎ Calling Cortex from application code“If you run your Python script outside of Snowflake, you must create a Snowpark session to use these functions.”
↩︎ Calling Cortex from application code“The advanced chat-style (multi-message) form of COMPLETE is not currently supported in Snowflake CLI.”
↩︎ Calling Cortex from application code“The advanced chat-style (multi-message) form of COMPLETE is not currently supported in Snowflake CLI.”
↩︎ Exam trap 3“The advanced chat-style (multi-message) form of COMPLETE is not currently supported in Snowflake ML Python.”
↩︎ Checkpoint - 5.https://www.snowflake.com/en/developers/guides/build-multi-tool-ai-agent-app-with-streamlit-and-snowflake-cortexSecondary source
“allowing for multi-turn conversations”
↩︎ Calling Cortex from application code