Snowflake's AI_PARSE_DOCUMENT got an agentic mode Snowflake's AI_PARSE_DOCUMENT added an AGENTIC mode, released to public preview on October 28, 2026, which classifies charts, diagrams, tables and infographics in a document and returns semantic summaries alongside extracted text. In a hands-on test over a SharePoint library of 18,352 PDFs (64 GB), 6,459 .docx files (1.3 GB), 800 .aspx files (3 MB) and 115 .pptx files (1.8 GB), the author measured AGENTIC at 8.18 credits per 1,000 pages versus 0.68 for OCR, and found slide decks were the only file type where the 12x cost paid off. The author also reported two undocumented behaviors: image summaries live outside the page content, and the mode parameter must be a literal, since a CASE expression returns NULL with no error. Lakehouse https://www.sfrt.io/tag/lakehouse/ Snowflake's AI PARSE DOCUMENT got an agentic mode 12x the price of OCR per page, and it earned that on one file type TL/DR: Snowflake's AI PARSE DOCUMENT now has an AGENTIC mode. It classifies the charts, diagrams, tables and infographics inside a document, writes a summary of each, and hands that back alongside extracted text. I ran it over my SharePoint library that feeds one of my Cortex Search services. Measured cost: 8.18 credits per 1,000 pages OCR at 0.68 . Slide decks were the only place it earned the difference, my PDFs had nothing worth describing 😅 I learned two things not mentioned in the docs: image summaries live outside the page content , and mode has to be a literal. Putting a CASE expression there returns NULL with no error at all. The question The new mode was released to public preview on October 28th, 2026. Would it help me with any of the document pipelines already running? I load many docs from SharePoint into ❄️, parse them there and feed a search service with the content. So that's my obvious playground to test that new mode... What the pipeline looks like I use a dlt pipeline to load the docs into Azure Blob Storage. For the docs themselves I wouldn't really need dlt, but I also load the SharePoint permissions along with the documents using Azure Graph + SharePoint REST APIs for obvious reasons not every user should read every doc . So I bundled those two components into one pipeline running on dltHub. And this happens downstream: 1. An external stage sits on top of the blob container. 2. Every time the dlt pipeline load is done, a task triggered as a last step at the end of the dlt pipeline lists the stage directory, MD5s it against a metadata table, and tags each file NEW , MODIFIED or DELETED . 3. NEW and MODIFIED docs get fed to AI PARSE DOCUMENT with page split enabled, and land in a pages table. 4. Chunking then cuts pages into 1,400-char pieces with a 200-char overlap neighbouring pages ride along as context and writes them to a chunks table. 5. And finally, a Cortex Search service on top of those chunks is what the agent queries. What the stage held: - 18,352 .pdf, 64 GB - 6,459 .docx, 1.3 GB - 800 .aspx, 3 MB - 115 .pptx, 1.8 GB Every one of those files was previously parsed with {'mode': 'OCR', 'page split': true} . What the docs say about agentic mode Three modes are available: LAYOUT text with structure, tables and headers , OCR plain fast extraction and AGENTIC . Using the agentic mode, Snowflake looks at the visual elements in a file charts, diagrams, screenshots, forms, images , classifies them, decides which processing each of them needs, and returns semantic summaries plus structured data: chart series and their values, table headers and cells, diagram components and how they relate, all next to the usual text and layout. Of course, that mode has its own limits: - Agentic mode caps at 2,000 images per document. - extract images doesn't work here... set it to TRUE and the function hands back NULL. - Accepted types are PDF, PPTX, DOCX, JPEG, JPG, PNG, TIFF, TIF, HTML, TXT. A file can be at most 100 MB and 2,000 pages. - The image schemas describe what the model is expected to output, with no guarantee that it conforms. Any field I depend on needs validation. - page filter limits the work to selected pages and implies page split . That's the cheapest way to play with the new mode 😜 Billing is quoted per page with no mention of a separate agentic rate. Which meant I had to measure it myself... A first comparison on just a few files I randomly picket three PPTX and three PDFs between 1.5 and 10 MB, each parsed twice OCR and AGENTIC . Then I compared pages, characters and image counts. | File | Pages | OCR chars | AGENTIC chars | |---|---|---|---| | PDF, insurance statement | 34 | 39,174 | 43,677 | | PDF, invoice | 3 | 2,171 | 2,522 | | PDF, single page | 1 | 2,041 | 2,197 | | PPTX, 28 slides | 28 | 10,566 | 10,842 | | PPTX, 23 slides | 23 | 12,586 | 12,125 | | PPTX, 6 slides | 6 | 5,674 | 5,917 | Pages came back equal and characters landed within roughly 10% of each other, so agentic doesn't extract more text. However, the reading order is changed: On a two-column slide, OCR interleaves the columns line by line, whereas agentic gives back clean markdown with headings and | table | rows. For all six files the images column came back NULL. I initially suspected the sample probably had no visuals in it. That was wrong, though... Where the image data actually is Turn page split on and the images aren't at the top level of the response anymore. Instead, every page object carries its own images array: {"metadata": {...}, "pages": {"index": 0, "content": " Title\n\n img-0.jpeg img-0.jpeg ", "dimensions": {...}, "images": {"id": "img-0.jpeg", "top left x": ..., "results": {...}} } } Two notes on how to use this: - content only holds placeholders img-0.jpeg img-0.jpeg , the summaries are not inlined - so there is no visual interpretation here. - The shape of results follows image type : Photos carry description and visible text ; an app screenshot carries app or page , purpose , state signals and visible text ; charts carry chart type and key values ; diagrams carry a components array of labels and roles. What kinds of images exist in practice The second sample: 8 random PPTX plus 8 random PDFs, first 8 pages of each page filter: {'start': 0, 'end': 8} . I flattened every image and grouped by image type : | image type | Images | Files | Typical content | |---|---|---|---| | other | 39 | 14 | logos, stock illustrations | | photo with text | 13 | 7 | photos with cropped text | | diagram | 14 | 4 | swimlane process flows, quarterly roadmaps, a risk framework drawn as a temple | | infographic | 6 | 1 | posters with sections and key facts | | chart | 5 | 2 | bar charts | | table | 3 | 1 | wide process/control matrices | The chart output is most interesting here. One of them returned this: "most frequent topic across all periods, peaking at 4,754 in the fourth period; all categories except one show a continuous upward trend ... ". A roadmap diagram came back with every initiative label and its status. None of that appeared in the OCR text of the same slides. However, image descriptions are mostly noise 😅 The first four types in the above list logos and stock photos would just dump junk into a search index. The filter I ended up with keeps chart , diagram , table and infographic , and throws away other and photo with text . But that decision presumably is very dependent on the use case. Do PDFs have the same payoff? Since 18,000 of the files are PDFs, those would be the major cost drivers. Another experimental run: 12 random PDFs sized 1 to 20 MB, first 8 pages, agentic only. | image type | Images | Files | Content | |---|---|---|---| | other | 19 | 8 | Swiss QR-bill codes, one grainy photo | | photo with text | 11 | 4 | signature blocks | | chart, diagram, table, infographic | 0 | 0 | none | Invoices, statements and contracts make up most of my PDF library. Nothing from the sample would have survived the previously mentioned filter. Now, twelve files can easily miss a rare type, and a few chart-heavy reports probably exist somewhere in there I didn't look at each PDF and its content, obviously , but that i.m.h.o. doesn't justify paying a significantly higher price across every PDF. What it costs Credits and a metrics array with the page count sit in SNOWFLAKE.ACCOUNT USAGE.CORTEX AI FUNCTIONS USAGE HISTORY , one row per query and model: | Mode | Pages | Credits | Per 1,000 pages | |---|---|---|---| | OCR | 95 | 0.0646 | 0.68 | | AGENTIC | 95 same six files | 0.7771 | 8.18 | | AGENTIC | 528 20-file run | 4.319 | 8.18 | | AGENTIC | 64 three separate runs | 0.5235 | 8.18 | Every agentic query landed on a flat 8.18 credits per 1,000 pages, no matter how many images a page carried. A page of plain text bills the same as a page full of charts. That's roughly 12 times what OCR costs. Projected onto my SharePoint catalog: 115 public PPTX covering 1,559 pages the exact page count came straight from the already existing pages table , so about 12.8 credits under agentic - compared to roughly 1.1 for OCR. When I apply the same math on the PDFs, it's a few hundred credits above OCR... for a result that presumably adds value only on rare occasion. The pipeline change What I settled on: AGENTIC for PPTX files, OCR for everything else. And image summaries only for the four useful types appended to the page text. The non-ASPX parse step of my task turned into: cte content as select p.blob file path, p.blob last modified , ai parse document to file '@raw.sharepoint.s documents', p.blob file path , {'mode': 'AGENTIC', 'page split': true} as parsed pages from cte to process p where p.file extension ilike '.pptx' union all select p.blob file path, p.blob last modified , ai parse document to file '@raw.sharepoint.s documents', p.blob file path , {'mode': 'OCR', 'page split': true} as parsed pages from cte to process p where p.file extension not ilike '.pptx' , cte pages as select c.blob file path, c.blob last modified , f.value:index::integer as page index , f.value:content::varchar as page text , f.value:images as page images from cte content c , lateral flatten input = c.parsed pages:pages f , cte image text as select pg.blob file path, pg.page index , listagg array to string array construct compact concat ' ', im.value:results:image type::varchar, ' ' , im.value:results:summary::varchar , im.value:results:details:chart type::varchar , nullif array to string coalesce im.value:results:details:key values , im.value:results:key values , '; ' , '' , nullif array to string transform im.value:results:details:components , c - c:label::varchar , ', ' , '' , nullif array to string im.value:results:details:columns, ', ' , '' , ' ' , '\n' as image text from cte pages pg , lateral flatten input = pg.page images im where im.value:results:image type::varchar in 'chart', 'diagram', 'table', 'infographic' group by pg.blob file path, pg.page index select ... , nullif array to string array construct compact pg.page text, it.image text , '\n\n' , '' as page content from cte pages pg join public docs pd on pd.blob file path = pg.blob file path left join cte image text it on it.blob file path = pg.blob file path and it.page index = pg.page index A few side notes on this: - My first attempt used concat ws and produced empty strings where the image text should have been... array construct compact handles NULL differently. - Empty pages stay NULL thanks to the outer nullif ..., '' . The chunker skips NULLs, but a blank string would have created empty chunks. - Scalar subqueries can't contain a correlated flatten "Unsupported subquery type cannot be evaluated" , so the image text sits in its own CTE and joins back on its file's page. In the index, a page containing a chart now looks like this: