<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[GoodData Developers - Medium]]></title>
        <description><![CDATA[News, resources, and advice for developers and data analysts who building on the world&#39;s most open, secure, scalable, and reliable cloud BI Platform. - Medium]]></description>
        <link>https://medium.com/gooddata-developers?source=rss----e8ee419648ea---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>GoodData Developers - Medium</title>
            <link>https://medium.com/gooddata-developers?source=rss----e8ee419648ea---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 08 Apr 2026 21:51:06 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/gooddata-developers" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[From RAG to GraphRAG: Knowledge Graphs, Ontologies and Smarter AI]]></title>
            <link>https://medium.com/gooddata-developers/from-rag-to-graphrag-knowledge-graphs-ontologies-and-smarter-ai-01854d9fe7c3?source=rss----e8ee419648ea---4</link>
            <guid isPermaLink="false">https://medium.com/p/01854d9fe7c3</guid>
            <category><![CDATA[ontology]]></category>
            <category><![CDATA[graphrag]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[rags]]></category>
            <category><![CDATA[knowledge-graph]]></category>
            <dc:creator><![CDATA[Marcelo G. Almiron]]></dc:creator>
            <pubDate>Tue, 02 Sep 2025 16:45:09 GMT</pubDate>
            <atom:updated>2025-09-03T07:05:08.566Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dEjt8QwdjI2l4qpTGNIrVQ.png" /></figure><p>Modern AI chatbots often rely on Retrieval-Augmented Generation (RAG), a technique where the chatbot pulls in external data to ground its answers in real facts. If you’ve used a “Chat with your” tool, you’ve seen RAG in action: the system finds relevant snippets from a document and feeds them into a Large Language Model (LLM) so it can answer your question with accurate information.</p><p>RAG has greatly improved the factual accuracy of LLM answers. However, traditional RAG systems mostly treat knowledge as <strong>disconnected text passages</strong>. The LLM is given a handful of relevant paragraphs and left to piece them together during its response. This works for simple questions, but it <strong>struggles with complex queries</strong> that require connecting the dots across multiple sources.</p><p>This article will demystify two concepts that can take chatbots to the next level, namely, <strong>ontologies</strong> and <strong>knowledge graphs</strong>, and show how they combine with RAG to form a GraphRAG (Graph-based Retrieval-Augmented Generation). We’ll explain what they mean and why they matter in simple terms.</p><p>Why does this matter, you might ask? Because <strong>GraphRAG</strong> promises to make chatbot answers <strong>more accurate, context-aware, and insightful</strong> than what you get with a traditional RAG. Businesses exploring AI solutions value these qualities — an AI that can truly <strong>understand context, avoid mistakes, and reason through complex questions</strong> can be a game-changer. (Although this needs a perfect implementation, which often is not the case in practice.)</p><p>By combining unstructured text with a structured knowledge graph, GraphRAG systems can provide answers that feel far more informed. Bridging knowledge graphs with LLMs is a key step toward AI that doesn’t just retrieve information, but actually <strong>understands</strong> it.</p><h3>What is RAG?</h3><p>Retrieval-Augmented Generation, or RAG, is a technique for enhancing language model responses by <strong>grounding them in external knowledge</strong>. Instead of replying based solely on what’s in its model memory, which might be outdated or incomplete, a RAG-based system will fetch relevant information from an outside source (e.g., documents, databases and the web) and feed that into the model to help formulate the answer.</p><p>In simple terms, <strong>RAG = LLM + Search Engine</strong>: the model first <strong>retrieves</strong> supporting data, <strong>augments</strong> its understanding of the topic and then <strong>generates</strong> a response using both its built-in knowledge and the retrieved info.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4ypsbNzZys8nrpdqZ7Gw_A.png" /><figcaption><strong>Figure 1</strong>: Traditional RAG Pipeline.</figcaption></figure><p>As shown in the figure above the typical RAG pipeline involves a few steps that mirror a smart lookup process:</p><ol><li><strong>Indexing Knowledge:</strong> First, the system breaks the knowledge source (say a collection of documents) into chunks of text and creates vector embeddings for each chunk. These embeddings are numerical representations of the text meaning. All these vectors are stored in a vector database or index.</li><li><strong>Query Embedding:</strong> When a user asks a question, the query is also converted into a vector embedding using the same technique.</li><li><strong>Similarity Search:</strong> The system compares the query vector to all the stored vectors to find which text chunks are most “similar” or relevant to the question.</li><li><strong>Generation with Context:</strong> Finally, the language model is given the user’s question plus the retrieved snippets as context. It then generates an answer that incorporates the provided information.</li></ol><p>RAG has been a big step forward for making LLMs useful in real-world scenarios. It’s how tools like Bing Chat or various document QA bots can provide current, specific answers with references. By grounding answers in retrieved text, RAG <strong>reduces hallucinations</strong> (the model can be pointed to the facts) and allows access to information beyond the AI’s training cutoff date. However, traditional RAG also has some well-known limitations:</p><ul><li>It treats the retrieved documents essentially as <strong>separate, unstructured blobs</strong>. If an answer requires synthesising info across multiple documents or understanding relationships, the model has to do that heavy lifting itself during generation.</li><li>RAG retrieval is usually based on semantic similarity. It finds relevant passages but <strong>doesn’t inherently understand the meaning of the content</strong> or how one fact might relate to another.</li><li>There is no built-in mechanism for <strong>reasoning</strong> or enforcing consistency across the retrieved data; the LLM just gets a dump of text and tries its best to weave it together.</li></ul><p>In practice, for straightforward factual queries, e.g., “When was this company founded?”, traditional RAG is great. For more complex questions, e.g., “Compare the trends in Q1 sales and Q1 marketing spend and identify any correlations.”, traditional RAG might falter. It could return one chunk about sales, another about marketing, but <strong>leave the logical integration to the LLM</strong>, which may or may not succeed coherently.</p><p>These limitations point to an opportunity. What if, instead of giving the AI system just a pile of documents, we also gave it a <strong>knowledge graph</strong> (i.e. a network of entities and their relationships) as a scaffold for reasoning? If RAG retrieval could return not just text based on similarity search, but a set of interconnected facts, the AI system could follow those connections to produce a more insightful answer.</p><p><strong>GraphRAG</strong> is about integrating this graph-based knowledge into the RAG pipeline. By doing so, we aim to overcome the multi-source, ambiguity, and reasoning issues highlighted above.</p><p>Before we get into how GraphRAG works, though, let’s clarify what we mean by knowledge graphs and ontologies — the building blocks of this approach.</p><h3>Knowledge Graphs</h3><p>A <strong>knowledge graph</strong> is a networked representation of real-world knowledge, where each node represents an <strong>entity</strong> and each edge represents a <strong>relationship</strong> between entities.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8YdRDanogryjPHKR1f6iQw.png" /><figcaption><strong>Figure 2</strong>: Knowledge (sub-)graph sample from <a href="https://archive.ics.uci.edu/dataset/352/online+retail">Online Retail dataset</a>.</figcaption></figure><p>In the figure above, we see a graphical representation of what a knowledge graph looks like. It structures data as a graph, not as tables or isolated documents. This means information is stored in a way that inherently captures connections. Some key traits:</p><ul><li>They are <strong>flexible</strong>: You can add a new type of relationship or a new property to an entity without upending the whole system. Graphs can easily evolve to accommodate new knowledge.</li><li>They are <strong>semantic</strong>: Each edge has meaning, which makes it possible to traverse the graph and retrieve meaningful chains of reasoning. The graph can represent <em>context</em> along with content.</li><li>They naturally support <strong>multi-hop queries</strong>: If you want to find how two entities are connected, a graph database can traverse neighbors, then neighbors-of-neighbors, and so on.</li><li>Knowledge graphs are usually stored in specialised <strong>graph databases</strong> or triplestores. These systems are optimised for storing nodes and edges and running graph queries.</li></ul><p>The structure of knowledge graphs is a boon for AI systems, especially in the RAG context. Because facts are linked, an LLM can get a <strong>web of related information</strong> rather than isolated snippets. This means:</p><ul><li>AI systems can better <strong>disambiguate context</strong>. For example, if a question mentions “Jaguar,” the graph can clarify whether it refers to the car or the animal through relationships, providing context that text alone often lacks.</li><li>An AI system can use <strong>“joins” or traversals to collect related facts</strong>. Instead of separate passages, a graph query can provide a connected subgraph of all relevant information, offering the model a pre-connected puzzle rather than individual pieces.</li><li>Knowledge graphs ensure <strong>consistency</strong>. For example, if a graph knows Product X has Part A and Part B, it can reliably list only those parts, unlike text models that might hallucinate or miss information. The structured nature of graphs allows complete and correct aggregation of facts.</li><li>Graphs offer <strong>explainability</strong> by tracing the nodes and edges used to derive an answer, allowing for a clear chain of reasoning and increased trust through cited facts.</li></ul><p>To sum up, a knowledge graph injects <strong>meaning</strong> into the AI’s context. Rather than treating your data as a bag of words, it treats it as a network of knowledge. This is exactly what we want for an AI system tasked with answering complex questions: a rich, connected context it can navigate, instead of a heap of documents it has to brute-force parse every time.</p><p>Now that we know what knowledge graphs are, and how they can benefit AI systems, let’s see what ontologies are and how they may help to build better knowledge graphs.</p><h3>Ontologies</h3><p>In the context of knowledge systems, an <strong>ontology</strong> is a formal specification of knowledge for a particular domain. It defines the <strong><em>entities</em></strong> (or concepts) that exist in the domain and the <strong><em>relationships</em></strong> between those entities.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QcvIvVCVjqNyGazv6BRhtw.png" /><figcaption><strong>Figure 3</strong>: A simplified example of ontology for e-commerce.</figcaption></figure><p>Ontologies often organise concepts into hierarchies or taxonomies. But can also include logical constraints or rules: for example, one could declare “Every Order must have at least one Product item.”</p><p>Why ontologies matter? You may ask. Well, an ontology provides a <strong>shared understanding</strong> of a domain, which is incredibly useful when integrating data from multiple sources or when building AI systems that need to reason about the domain. By defining a common set of entity types and relationships, an ontology ensures that different teams or systems refer to things consistently. For example, if one dataset calls a person a “Client” and another calls them “Customer,” mapping both to the same ontology class (say Customer as a subclass of Person) lets you merge that data seamlessly.</p><p>In the context of AI and GraphRAG, an ontology is the <strong>blueprint for the knowledge graph</strong> — it dictates what kinds of nodes and links your graph will have. This is crucial for complex reasoning. If your chatbot knows that “Amazon” in the context of your application is a Company (not a river) and that Company is defined in your ontology (with attributes like headquarters, CEO, etc., and relationships like hasSubsidiary), it can ground its answers much more precisely.</p><p>Now that we know about knowledge graphs and ontologies, let’s see how we put it all together in a RAG-alike pipeline.</p><h3>GraphRAG</h3><p><strong>GraphRAG</strong> is an evolution of the traditional RAG approach that explicitly incorporates a knowledge graph into the retrieval process. In GraphRAG, when a user asks a question, the system doesn’t just do a vector similarity search over text; it also queries the knowledge graph for relevant entities and relationships.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mw-TdYTmNjhwDvXHsgswAw.png" /><figcaption><strong>Figure 4</strong>: GraphRAG Pipeline.</figcaption></figure><p>Let’s walk through a typical GraphRAG pipeline at a high level:</p><ol><li><strong>Indexing knowledge</strong>: Both structured data (e.g., databases, CSV files) and unstructured data (e.g., documents) are taken as input. Structured data goes through data transformation, converting table rows to triples. Unstructured data is broken down into manageable text chunks. Entities and relationships are extracted from these chunks and simultaneously embeddings are calculated to create triples with embeddings.</li><li><strong>Question Analysis and Embedding</strong>: The user’s query is analyzed to identify key terms or entities. These elements are embedded with the same embedding model used for indexing.</li><li><strong>Graph Search</strong>: The system queries the knowledge graph for any nodes related to those key terms. Instead of retrieving only semantically similar items, the system also leverages relationships.</li><li><strong>Generation with Graph Context</strong>: A generative model uses the user’s query and the retrieved graph-enriched context to produce an answer.</li></ol><p>Under the hood, GraphRAG can use various strategies to integrate the graph query. The system might first do a semantic search for top-K text chunks <em>as usual</em>, then <strong>traverse the graph neighborhood</strong> of those chunks to gather additional context, before generating the answer. This ensures that if relevant info is spread across documents, the graph will help pull in the connecting pieces. In practice, GraphRAG might involve extra steps like entity disambiguation (to make sure the “Apple” in the question is linked to the right node, either Company or Fruit) and graph traversal algorithms to expand the context. But the high-level picture is as described: <strong>search + graph lookup</strong> instead of search alone.</p><p>Overall, for non-technical readers, you can think of GraphRAG as giving the AI a <strong>“brain-like” knowledge network</strong> in addition to the library of documents. Instead of reading each book (document) in isolation, the AI also has an encyclopedia of facts and how those facts relate. For technical readers, you might imagine an architecture where we have both a vector index and a graph database working in tandem — one retrieving raw passages, the other retrieving structured facts, both feeding into the LLM’s context window.</p><h3>Building a Knowledge Graph for RAG: Approaches</h3><p>There are two broad ways to build the knowledge graph that powers a GraphRAG system: a <strong>Top-Down approach</strong> or a <strong>Bottom-Up approach</strong>. They’re not mutually exclusive (often you might use a bit of both), but it’s helpful to distinguish them.</p><h3>Approach 1: Top-Down (Ontology First)</h3><p>The top-down approach to ontology begins by defining the domain’s ontology before adding data. This involves domain experts or industry standards to establish classes, relationships, and rules. This schema, loaded into a graph database as empty scaffolding, guides data extraction and organization, acting as a blueprint.</p><p>Once the ontology (schema) is in place, the next step is to <strong>instantiate</strong> it with real data. There are a few sub-approaches here:</p><ul><li><strong>Using Structured Sources</strong>: If you have existing structured databases or CSV files, you map those to the ontology. This can sometimes be done via automated ETL tools that convert SQL tables to graph data if the mapping is straightforward.</li><li><strong>Extracting from Text via Ontology</strong>: For unstructured data (like documents, PDFs, etc.), you would use NLP techniques but <em>guided by the ontology</em>. This often involves writing extraction rules or using an LLM with prompts that reference the ontology’s terms.</li><li><strong>Manual or Semi-Manual Curation</strong>: In critical domains, a human might verify each extracted triple or manually input some data into the graph, especially if it’s a one-time setup of key knowledge. For example, a company might manually input its org chart or product hierarchy into the graph according to the ontology, because that data is relatively static and very important.</li></ul><p>The key is that with a top-down approach, <strong>the ontology acts as a guide</strong> at every step. It tells your extraction algorithms what to look for and ensures the data coming in fits a coherent model.</p><p>One big advantage of using a formal ontology is that you can leverage <strong>reasoners and validators</strong> to keep the knowledge graph consistent. Ontology reasoners can automatically infer new facts or check for logical inconsistencies, while tools like SHACL enforce data shape rules (similar to richer database schemas). These checks prevent contradictory facts and enrich the graph by automatically deriving relationships. In GraphRAG, this means answers can be found even if multi-hop connections aren’t explicit, as the ontology helps derive them.</p><h3>Approach 2: Bottom-Up (Data First)</h3><p>The bottom-up approach seeks to generate knowledge graphs directly from data, without relying on a predefined schema. Advances in NLP and LLMs enable the extraction of structured triples from unstructured text, which can then be ingested into a graph database where entities form nodes and relationships form edges.</p><p>Under the hood, bottom-up extraction can combine classical NLP and modern LLMs:</p><ul><li><strong>Named Entity Recognition (NER)</strong>: Identify names of people, organizations, places, etc., in text.</li><li><strong>Relation Extraction (RE)</strong>: Identify if any of those entities have a relationship mentioned.</li><li><strong>Coreference Resolution</strong>: Figure out the referent of a pronoun in a passage, so the triple can use the full name.</li></ul><p>There are libraries like <a href="https://spacy.io/">spaCy</a> or <a href="https://flairnlp.github.io/">Flair</a> for the traditional approach, and newer libraries that integrate LLM calls for IE (Information Extraction). Also, techniques like ChatGPT plugins or LangChain agents can be set up to populate a graph: the agent could iteratively read documents and call a “graph insert” tool as it finds facts. Another interesting strategy is using LLMs to <strong>suggest the schema</strong> by reading a sample of documents (this edges towards ontology generation, but bottom-up).</p><p>A big caution with bottom-up extraction is that <strong>LLMs can be imperfect or even “creative”</strong> in what they output. They might hallucinate a relationship that wasn’t actually stated, or they might mis-label an entity. Therefore, an important step is validation:</p><ul><li>Cross-check critical facts against the source text.</li><li>Use multiple passes: e.g., first pass for entities, second pass just to verify and fill relations.</li><li>Human spot-checking: Have humans review a sample of the extracted triples, especially those that are going to be high impact.</li></ul><p>The process is typically iterative. You run the extraction, find errors or gaps, adjust your prompts or filters, and run again. Over time, this can dramatically refine the knowledge graph quality. The good news is that even with some errors, the knowledge graph can still be useful for many queries — and you can prioritize cleaning the parts of the graph that matter most for your use cases.</p><p>Finally, keep in mind that sending text for extraction exposes your data to the LLM/service, so you should ensure compliance with privacy and retention requirements.</p><h3>Tools and Frameworks in the GraphRAG Ecosystem</h3><p>Building a GraphRAG system might sound daunting, you need to manage a vector database, a graph database, run LLM extraction pipelines, etc. The good news is that the community is developing tools to make this easier. Let’s briefly mention some of the tools and frameworks that can help, and what role they play.</p><h3>Graph Storage</h3><p>First, you’ll need a place to store and query your knowledge graph. Traditional graph databases like <a href="https://neo4j.com"><strong>Neo4j</strong></a>, <a href="https://aws.amazon.com/neptune/"><strong>Amazon Neptune</strong></a>, <a href="https://www.tigergraph.com"><strong>TigerGraph</strong></a>, or RDF triplestores (like <a href="https://graphdb.ontotext.com">GraphDB</a> or <a href="https://www.stardog.com">Stardog</a>) are common choices.</p><p>These databases are optimized for exactly the kind of operations we discussed:</p><ul><li>traversing relationships</li><li>finding neighbors</li><li>executing graph queries</li></ul><p>In a GraphRAG setup, the retrieval pipeline can use such queries to fetch relevant subgraphs. Some vector databases (like <a href="https://milvus.io">Milvus</a> or Elasticsearch with <a href="https://www.elastic.co/elasticsearch/graph">Graph plugin</a>) are also starting to integrate graph-like querying, but generally, a specialized graph DB offers the richest capabilities. The important thing is that your graph store should allow efficient retrieval of both direct neighbors and multi-hop neighborhoods, since a complex question might require grabbing a whole network of facts.</p><h3>Emerging Tools</h3><p>New tools are emerging to combine graphs with LLMs:</p><ul><li><a href="https://www.cognee.ai"><strong>Cognee</strong></a> — An open-source “AI memory engine” that builds and uses knowledge graphs for LLMs. It acts as a semantic memory layer for agents or chatbots, turning unstructured data into structured graphs of concepts and relationships. LLMs can then query these graphs for precise answers. Cognee hides graph complexity: developers only need to provide data, and it produces a graph ready for queries. It integrates with graph databases and offers a pipeline for ingesting data, building graphs, and querying them with LLMs.</li><li><a href="https://help.getzep.com/graphiti"><strong>Graphiti (by Zep AI)</strong></a> — A framework for AI agents needing <strong>real-time, evolving memory</strong>. Unlike many RAG systems with static data, Graphiti updates knowledge graphs incrementally as new information arrives. It stores both facts and their temporal context, using Neo4j for storage and offering an agent-facing API. Unlike earlier batch-based GraphRAG systems, Graphiti handles streams efficiently with incremental updates, making it suited for long-running agents that learn continuously. This ensures answers always reflect the latest data.</li><li><strong>Other frameworks</strong> — Tools like <a href="https://www.llamaindex.ai"><strong>LlamaIndex</strong></a> and <a href="https://haystack.deepset.ai"><strong>Haystack</strong></a> add graph modules without being graph-first. LlamaIndex can extract triplets from documents and support graph-based queries. Haystack experimented with integrating graph databases to extend question answering beyond vector search. Cloud providers are also adding graph features: <a href="https://aws.amazon.com/bedrock/knowledge-bases/"><strong>AWS Bedrock Knowledge Bases</strong></a> supports GraphRAG with managed ingestion into Neptune, while <strong>Azure Cognitive Search </strong>integrates with graphs. The ecosystem is evolving quickly.</li></ul><h3>No Need to Reinvent the Wheel</h3><p>The takeaway is that if you want to experiment with GraphRAG, you don’t have to build everything from scratch. You can:</p><ul><li>Use <strong>Cognee</strong> to handle knowledge extraction and graph construction from your text (instead of writing all the prompts and parsing logic yourself).</li><li>Use <strong>Graphiti</strong> if you need a plug-and-play memory graph especially for an agent that has conversations or time-based data.</li><li>Use <strong>LlamaIndex</strong> or others to get basic KG extraction capabilities with just a few lines of code.</li><li>Rely on proven <strong>graph databases</strong> so you don’t have to worry about writing a custom graph traversal engine.</li></ul><p>In summary, while GraphRAG is at the cutting edge, the surrounding ecosystem is rapidly growing. You can leverage these libraries and services to stand up a prototype quickly, then iteratively refine your knowledge graph and prompts.</p><h3>Conclusion</h3><p>Traditional RAG works well for simple fact lookups, but struggles when queries demand deeper reasoning, accuracy, or multi-step answers. This is where <strong>GraphRAG</strong> excels. By combining documents with a knowledge graph, it grounds responses in structured facts, reduces hallucinations, and supports multi-hop reasoning. Thus enabling AI to connect and synthesize information in ways standard RAG cannot.</p><p>Of course, this power comes with trade-offs. Building and maintaining a knowledge graph requires schema design, extraction, updates, and infrastructure overhead. For straightforward use cases, traditional RAG remains the simpler and more efficient choice. But when richer answers, consistency, or explainability matter, GraphRAG delivers clear benefits.</p><p>Looking ahead, knowledge-enhanced AI is evolving rapidly. Future platforms may generate graphs automatically from documents, with LLMs reasoning directly over them. For companies like <a href="https://www.gooddata.com"><strong>GoodData</strong></a>, GraphRAG bridges AI with analytics, enabling insights that go beyond “what happened” to “why it happened.”</p><p>Ultimately, GraphRAG moves us closer to AI that doesn’t just retrieve facts, but truly understands and reasons about them, like a human analyst, but at scale and speed. While the journey involves complexity, the destination (more accurate, explainable, and insightful AI) is well worth the investment. The key lies in not just collecting facts, but connecting them.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=01854d9fe7c3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/gooddata-developers/from-rag-to-graphrag-knowledge-graphs-ontologies-and-smarter-ai-01854d9fe7c3">From RAG to GraphRAG: Knowledge Graphs, Ontologies and Smarter AI</a> was originally published in <a href="https://medium.com/gooddata-developers">GoodData Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Analytics as Code with Cursor: How do you make the most out of it?]]></title>
            <link>https://medium.com/gooddata-developers/analytics-as-code-with-cursor-how-do-you-make-the-most-out-of-it-f9870cd44557?source=rss----e8ee419648ea---4</link>
            <guid isPermaLink="false">https://medium.com/p/f9870cd44557</guid>
            <category><![CDATA[developer-experience]]></category>
            <category><![CDATA[analytics]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Andrii Chumak]]></dc:creator>
            <pubDate>Wed, 06 Aug 2025 11:07:35 GMT</pubDate>
            <atom:updated>2025-08-06T15:46:00.986Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zGdwn0bNB1OPaYoUnUu4Kg.png" /></figure><p><strong>Analytics as Code</strong> slowly becoming the norm for analytics solution, same as Infrastructure as Code or Security as Code. The level of confidence in your solution that you get from version control and CI/CD pipelines is hard to beat.</p><p>Meanwhile, smart IDEs, like <strong>Cursor</strong> and <strong>Windsurf</strong>, are getting more and more popular, helping software engineers to be more productive. For data analysts, Cursor can help write SQL or Python code. It’s generally good with widespread technologies and languages, as there is a lot of data to train on. But how can you take advantage of AI features for more niche technologies like Analytics as Code?</p><p>In this article, I’ll show you how to make the most of any AI-powered IDE when working with Analytics as Code by leveraging <strong>rule files</strong>, <strong>VS Code extensions</strong>, and <strong>MCP servers</strong>.</p><h3>Out-of-the-Box Cursor Experience</h3><p>I must admit, when I first tried using our Analytics as Code with Cursor, I was worried we’d have to make a lot of changes to our setup to take advantage of AI features in full. But the out-of-the-box experience was surprisingly good.</p><h4>Work by Example</h4><p>First of all, <strong>AI coding agents are quite good at creating new code by example</strong>. If you’re not starting from scratch and already have some analytics in the workspace, the chances are Cursor will work great for you. It helps that our Analytics as Code syntax is based on YAML, and AI models know how to write a valid YAML file already — that’s included in the training. They only need to figure out the correct schema for our specific use case.</p><h4>VS Code Extension</h4><p>The second contributing factor is that we already have a VS Code extension — that works in Cursor and Windsurf as they’re both based on VS Code.</p><p>The extension is available in both <a href="https://marketplace.visualstudio.com/items?itemName=GoodData.gooddata-vscode">Microsoft Marketplace for VS Code</a> and <a href="https://open-vsx.org/extension/GoodData/gooddata-vscode">OpenVSX Marketplace</a> for Cursor. Just looks for “GoodData” in the extensions tab.</p><p>Our extension does a lot of things, from syntax highlighting to autocomplete, reference resolution, and previews. But most importantly, schema validation and reference integrity validation. <strong>Cursor listens to any validation errors the extension produces and is capable of fixing them automatically.</strong></p><figure><img alt="GoodData for VS Code highlighting referential error" src="https://cdn-images-1.medium.com/max/1024/0*kZCitlt9J-skB2mV" /><figcaption><em>GoodData for VS Code highlighting referential error</em></figcaption></figure><p>Let’s say you’re building a new visualization: Cursor will look at any existing visualizations for examples and produce a new one. Sure, it may hallucinate a reference to some non-existing metric, but then our extension will highlight the error and suggest a list of valid metrics that can be used instead. And since Cursor works iteratively, it can choose the right metric and fix the code before handing control back to you.</p><h3>A Better Cursor Experience</h3><p>But we can take this even further by leveraging more advanced Cursor features, <strong>rule files</strong> and <strong>MCP server integration</strong>.</p><p>It’s worth noting that most of the features described here will also work in other VS Code-based smart IDEs, like Windsurf.</p><h4>Cursor Rules</h4><p>The rule files are designed for developers to <strong>give Cursor more context about the workspace</strong>. It’s a simple Markdown file where you can describe how to work with certain file types, how the project is structured, how to perform a specific task, and so on. All the things you probably should have had in the internal documentation a long time ago, but were too lazy to write down.</p><p>Rule files are the perfect place to provide Cursor with examples to reduce its dependence on pre-existing items for examples, as well as to cover rare cases that you likely don’t have in the workspace just yet.</p><h4>MCP Server</h4><p>I was <a href="https://www.gooddata.com/blog/everyone-s-talking-about-mcp-i-built-a-server-to-see-if-it-s-ready/">checking out Model Context Protocol (MCP)</a> and noticed a lot of commonalities with Language Server Protocol (LSP). Both protocols provide a useful abstraction for the communication between server and client, as well as features discoverability, authentication, and transport for the messages. This means you can implement your LLM app as an MCP client and not need to care if the MCP servers you’re connecting to are written in different programming languages, running locally, or deployed on a 3rd party server.</p><p><strong>This makes an MCP server a perfect companion for AI-driven development in Cursor, as it complements the Language Server.</strong> It can provide additional context and trigger (read-only) actions on the user’s behalf — all good things for your productivity.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FFe9z8Ugy80A%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DFe9z8Ugy80A&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FFe9z8Ugy80A%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/c68cfa6d974dfd0015e2b0215e405ca5/href">https://medium.com/media/c68cfa6d974dfd0015e2b0215e405ca5/href</a></iframe><p>Imagine you have a new table added to the data source. With well-defined rules, Language Server and MCP Server, Cursor can automatically:</p><ul><li>Scan the database model to review the new table.</li><li>Sample the data to understand the contents.</li><li>Create the dataset definition.</li><li>Validate it and fix any issues.</li><li>Run the dataset preview to verify the result.</li></ul><h3>We’ve Got You Covered</h3><p>Starting <strong>v0.14.0</strong>, the GoodData for VS Code extension comes with batteries included for AI-assisted development.</p><h4>New Project Initialization and Cursor Rules</h4><p>When starting a new project, you can now pass a --cursor parameter to add boilerplate Cursor rules and a configuration for the MCP server to let Cursor know how to connect to it. See all commands and options <a href="https://www.gooddata.com/docs/cloud/api-and-sdk/vs-code-extension/cli/">in our documentation</a>.</p><p>The rule files are a good starting point for any analytics project, but feel free to edit those as you identify any gaps in Cursor’s understanding of your code.</p><h4>Bundled MCP Server</h4><figure><img alt="GoodData for VS Code MCP Server connected to Cursor" src="https://cdn-images-1.medium.com/max/1024/0*z7r0j4m-ergNESd1" /><figcaption><em>GoodData for VS Code MCP Server connected to Cursor</em></figcaption></figure><p>The extension itself now comes with the MCP server bundled in. Once enabled and configured in Cursor, it will provide tools for database schema scanning, all kinds of previews, as well as shortcuts for workspace deploy and clone commands.</p><h3>Conclusion</h3><p>AI-assisted software engineering is in a volatile state these days. Some people swear by it, others hate it. Some say it’s a productivity booster, while others call it a time-waster. It’s not clear what final form it will take when all is said and done, but it’s quite clear that software engineering is changing. <strong>And, more importantly, data analysts take note, or risk being left behind.</strong></p><h4>Want to learn more?</h4><p>If you’d like to learn more about our different AI initiatives, you can read some of our other articles, such as <a href="https://www.gooddata.com/blog/why-ai-in-analytics-needs-metadata/">Why AI in Analytics Needs Metadata</a> or our other technical articles.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f9870cd44557" width="1" height="1" alt=""><hr><p><a href="https://medium.com/gooddata-developers/analytics-as-code-with-cursor-how-do-you-make-the-most-out-of-it-f9870cd44557">Analytics as Code with Cursor: How do you make the most out of it?</a> was originally published in <a href="https://medium.com/gooddata-developers">GoodData Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Evaluation of AI Applications In Practice]]></title>
            <link>https://medium.com/gooddata-developers/evaluation-of-ai-applications-in-practice-ecbb5a97d878?source=rss----e8ee419648ea---4</link>
            <guid isPermaLink="false">https://medium.com/p/ecbb5a97d878</guid>
            <category><![CDATA[llm-as-a-judge]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[ai-evaluation]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Jakub Zovak]]></dc:creator>
            <pubDate>Wed, 06 Aug 2025 09:20:31 GMT</pubDate>
            <atom:updated>2025-08-06T09:20:31.310Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1bedRtL6Oo8rFnwOny1_hg.png" /></figure><p>In recent years, many companies have rushed to develop AI features or products, yet most initiatives fail to progress beyond the proof-of-concept stage.</p><p>The main reason behind the failure to productize these applications is often a lack of evaluation and proper data science. The so-called “vibe” development paradigm can only get you so far before things start to fall apart and you begin to feel like you are building something on top of a quicksand.</p><p>In this article, I describe how to address these problems by discussing the proper evaluation of applications that utilize LLMs and how to leverage this knowledge to produce reliable solutions.</p><h3>Lifecycle Of AI Application Development</h3><p>There is nothing wrong with writing custom prompts without any evaluation when starting a new product or feature. On the contrary, I would argue that it is a preferred approach when you need to create a proof-of-concept as quickly as possible. However, after a while, you will find that it is insufficient, especially when you begin to transition to the production phase. Without proper evaluation, you will end up going in circles from one regression to another.</p><p>Moreover, you do not have any data to support the reliability of your solution.Therefore, after the initial phase of prototyping your idea, you should move to implementing the evaluation of your AI application. With the evaluation in place, you can get confidence in how your solution performs and improve it iteratively without reintroducing bugs or undesired behavior.</p><p>Furthermore, you can move on to another step in AI app development and use prompt optimizers such as <a href="https://arxiv.org/pdf/2310.03714">DSPy</a> and discard manual prompt tuning completely. You can see this lifecycle visualized below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*9zGy0q2Iigo2qZIn" /><figcaption>Development life cycle of an AI application</figcaption></figure><h3>Evaluation of AI Applications</h3><p>Evaluating AI applications differs significantly from traditional software testing or data science validation. These systems, often referred to as <a href="https://www.ycombinator.com/library/MW-andrej-karpathy-software-is-changing-again">Software 3.0</a>, blend traditional software engineering with data science. As a result, the evaluation does not focus on the underlying LLM, nor does it resemble standard unit testing. Instead, it assesses the behavior of an application built on top of various AI models, such as LLMs, embedding models, and rerankers.</p><p>The primary objective is to evaluate the configuration of the complete AI system. This might include RAG pipelines (retrieval and reranking stages), prompt templates (e.g., structured instructions, few-shot examples, prompting strategies), and any surrounding pre-/post-processing logic. This article focuses specifically on the evaluation of the LLM components (i.e., prompt templates) of such applications. The evaluation of RAG pipelines falls under the domain of information retrieval and deserves a separate article.</p><p>To conduct a meaningful evaluation, three core elements are needed:</p><ul><li>A <strong>dataset</strong> with ground truth outputs, if available,</li><li>Appropriate <strong>evaluation metrics</strong> that reflect desired behavior</li></ul><p>An <strong>evaluation infrastructure</strong> to run and monitor the evaluation process.</p><h3>Datasets</h3><p>To evaluate an AI application, you need a dataset with expected outputs, also called ground truth. The hardest part is often getting the initial dataset. Fortunately, even a tiny dataset can help you meaningfully tune your application and check if it behaves as expected.</p><p>There are three main ways to obtain a dataset. First, you can manually write a few input-output pairs. This helps clarify exactly what you expect from the application, rather than relying on vague specifications. Second, if your company policy allows and the application is already running, you can use user interactions with positive feedback to extend the dataset. Lastly, you can use an LLM to generate synthetic examples from crafted prompts or existing dataset items, but always review these carefully before using them.</p><h3>Evaluation Metrics</h3><p>Choosing the right metrics is crucial when performing an evaluation to determine whether your AI application behaves as you expect. Metrics can assess the output on their own (e.g., politeness, toxicity, contextual relevance) or measure how closely it aligns with the expected result. Broadly, these evaluation metrics fall into three categories: analytical metrics (commonly used in traditional ML), deterministic assertions (akin to unit tests), and LLM-as-a-judge (a newer approach using LLM for evaluation).</p><p>A common mistake is to start with LLM-as-a-Judge and use it for every aspect of the evaluation. While the LLM-as-a-judge is selected for its ease of use, this approach comes with significant drawbacks. These include the cost and latency of calling the judge itself, as well as the uncertainty it introduces into the evaluation.</p><p><strong>Therefore, it is recommended to use LLM-as-a-Judge always as a last resort when traditional approaches such as analytical metrics or deterministic assertions are not enough. </strong>It is beneficial to consider these metrics in a similar manner to unit, integration, and E2E tests, where E2E tests are akin to LLM-as-a-judge since they have the highest cost. Here is the view of these metric types visualized :</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/750/0*e1TjDmqWt_U8cjsF" /><figcaption>A pyramid illustrating the use of metrics according to their cost.</figcaption></figure><h3>Analytical Metrics</h3><p>Analytical metrics are quantitative functions that assign a numerical score to the output of the AI application. These metrics are present at the bottom of our pyramid since they are broadly applicable to all test cases with minimal implementation or real cost. Let’s describe these metrics, explain how to use them, and discuss their interpretation. Note that the selection of a metric always depends on the specific use case you are evaluating.</p><p>Let’s list commonly used analytical metrics:</p><h4><a href="https://huggingface.co/docs/transformers/en/perplexity"><strong>Perplexity</strong></a></h4><ul><li><strong>Explanation:</strong> Perplexity measures how well the model predicts the sequence of tokens. It is defined as the exponentiated average negative log-likelihood of a token sequence.</li><li><strong>Interpretation:</strong> The lower the perplexity, the more confident the LLM is in its prediction.</li><li><strong>Use Case</strong>: It is a good practice to track Perplexity every time you have access to the token output probabilities.</li></ul><h4>Cosine Similarity</h4><ul><li><strong>Explanation: </strong>Cosine similarity measures how similar two embedding vectors are. These vectors are produced by encoder models (e.g., BERT) trained to capture the semantic meaning of sentences. The similarity corresponds to the cosine of the angle between the vectors.</li><li><strong>Interpretation:</strong> The cosine similarity score can be challenging to interpret because it depends significantly on the underlying embedding models and the distribution of scores they produce.</li><li><strong>Use Case: </strong>Due to the difficulty of interpretation, I would not recommend relying on this measure when doing iterative development, but it can be leveraged in automatic prompt optimization frameworks.</li></ul><h4>NLP Metrics (<a href="https://aclanthology.org/P02-1040.pdf"><strong>BLUE</strong></a><strong>, </strong><a href="https://aclanthology.org/W04-1013.pdf"><strong>ROUGE</strong></a><strong>, </strong><a href="https://aclanthology.org/W05-0909.pdf"><strong>METEOR</strong></a><strong>)</strong></h4><ul><li><strong>Explanation: </strong>Traditional NLP metrics that compare differences between two texts use token-level overlaps, n-grams, or the number of edits to get the same text.</li><li><strong>Interpretation: </strong>The result of these metrics is usually normalized between zero and one, where one is the best possible score.</li><li><strong>Use Case: </strong>These types of metrics are ideal for relatively short texts with lower variability.</li></ul><h4>Other</h4><ul><li>Apart from the aforementioned metrics, you can track a host of other aspects of the generation, such as the number of tokens, the number of reasoning tokens, latency, cost, etc.</li></ul><h4>Our Evaluation Infrastructure</h4><p>To achieve proper evaluation in the compound AI system with multiple components that depend on each other and take advantage of LLM, it is essential to have these <strong>LLM components </strong>encapsulated so they can be easily tested and evaluated.</p><p>This approach was inspired by the chapter “Design Your Evaluation Pipeline” from the book <a href="https://github.com/chiphuyen/aie-book/tree/main?tab=readme-ov-file#about-the-book">AI Engineering by Chip Huyen.</a></p><p>In our evaluation infrastructure, each LLM component has its own dataset and evaluation pipeline. You can think of the LLM component as an arbitrary machine learning model that is being evaluated. This separation of components is necessary in a complex application like ours, which focuses on an AI-assisted analytics use case, because evaluating such a system end-to-end can be extremely challenging.</p><p>To evaluate each of these components, we use the following tools:</p><h4><a href="https://langfuse.com/">Langfuse</a></h4><ul><li>An LLM observability framework that is used primarily to track and log user interaction with an AI application</li><li>Additionally, it supports dataset and experiment tracking, which we employ in our infrastructure.</li></ul><h4><a href="https://docs.pytest.org/en/stable/">Pytest</a></h4><ul><li>It is a minimalistic framework for running unit tests</li><li>We use it as our script runner when evaluating different LLM components</li></ul><h4><a href="https://github.com/confident-ai/deepeval">DeepEval</a></h4><ul><li>An LLM evaluation framework that implements evaluation metrics</li><li>We use it mainly for its <a href="https://docs.google.com/document/d/142tMeTqMcjBzSJ-7vCKS_8IQDYuY_9t35UORNeogf70/edit?tab=t.0">Conversational G-Eval</a> implementation</li></ul><p>For each component, we have precisely one test. Each test is parametrized using the <a href="https://docs.pytest.org/en/stable/how-to/parametrize.html#basic-pytest-generate-tests-example">pytest_generate_tests</a> function, so it runs for each item of the dataset for each element. The whole infrastructure setup with the use of these tools visualized:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*T1ADZaGhdDZHfuzd" /><figcaption>Visualization of our evaluation setup.</figcaption></figure><p>The results of the evaluation of the specific LLM component are logged to the Langfuse, shown in the next image. As you can see, we are using G-Eval LLM-as-a-Judge. We are thresholding scores from the G-Eval to determine if the output is correct. On top of that, we are tracking the perplexity of the model. If perplexity values start to spike, it can be an indication that something might be wrong in the configuration of the LLM component.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*r3HwAYSypgj-Zt7H" /><figcaption>Result of the evaluation of the specific component in the Langfuse.</figcaption></figure><h4>Conclusion</h4><p>Evaluation is essential for building reliable and production-ready AI applications. Compared to traditional unit testing or model evaluation, evaluating AI systems presents its unique challenges. The first step is always creating or gathering a dataset that matches your business goals and helps guide improvements. Then, selecting the right metrics is crucial to understanding how effectively your system performs. With these foundations in place, you can apply the ideas through a practical evaluation setup, as described in this article. I hope it helps you take the next step in evaluating your AI application.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ecbb5a97d878" width="1" height="1" alt=""><hr><p><a href="https://medium.com/gooddata-developers/evaluation-of-ai-applications-in-practice-ecbb5a97d878">Evaluation of AI Applications In Practice</a> was originally published in <a href="https://medium.com/gooddata-developers">GoodData Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Make Key Driver Analysis Smarter with Automation]]></title>
            <link>https://medium.com/gooddata-developers/make-key-driver-analysis-smarter-with-automation-559a32e255f5?source=rss----e8ee419648ea---4</link>
            <guid isPermaLink="false">https://medium.com/p/559a32e255f5</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[automation]]></category>
            <category><![CDATA[kda]]></category>
            <category><![CDATA[analytics]]></category>
            <dc:creator><![CDATA[Štěpán Machovský]]></dc:creator>
            <pubDate>Mon, 28 Jul 2025 08:44:11 GMT</pubDate>
            <atom:updated>2025-07-28T11:49:23.487Z</atom:updated>
            <content:encoded><![CDATA[<p><strong><em>What is Key Driver Analysis, and why should you care?</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cu3Y67cjIMcuYE6atgGrkg.png" /></figure><p>Key Driver Analysis (KDA) identifies the primary factors that influence changes in your data, enabling informed and timely decisions. Imagine managing an ice cream shop: if your suppliers’ ice cream prices spike unexpectedly, you’d want to quickly pinpoint the reasons. Be it rising milk costs, chocolate shortages, or external market factors.</p><p>Traditional KDA can compute what drove the changes in the data. And while it provides valuable insights, it often arrives too late, delaying critical decisions. Why? Because KDA traditionally involves extensive statistical analysis, which can be resource-intensive and slow.</p><p>Automation transforms this scenario by streamlining the process and bringing KDA into your decision-making much faster through modern analytical tools.</p><h3>Why Bring KDA Closer to Your Decisions?</h3><p>Consider the ice cream shop scenario: one morning, your supply of vanilla ice cream spikes by 63%. A manual KDA might reveal — hours or even days later, depending on when it’s run (or whether someone remembers to check the dashboard) — that milk and chocolate prices have surged, leaving you scrambling for solutions in the meantime.</p><p>Automating this process through real-time alerts ensures you never miss crucial events:</p><ul><li><strong>Webhook triggers</strong> when ingredient prices exceed defined thresholds.</li><li><strong>Immediate automated KDA execution</strong> identifies critical drivers within moments.</li><li><strong>Instant alerts</strong> enable swift actions like sourcing alternative suppliers or adjusting prices, safeguarding your business agility.</li></ul><p>These systems can significantly reduce your response times, allowing you to mitigate risks and leverage opportunities immediately, rather than reacting post-mortem.</p><h3>Automating KDA</h3><p>Automation significantly streamlines the KDA process. Sometimes, you don’t need to react to alerts immediately, but you need your answers by the next morning. Let’s explore how you can set this up using a practical example with Python for overnight jobs:</p><pre>def get_notifications(self, workspace_id: str) -&gt; list[Notification]:<br>    params = {<br>        &quot;workspaceId&quot;: workspace_id,<br>        &quot;size&quot;: 1000,<br>    }<br>    res = requests.get(<br>        f&quot;{self.host}/api/v1/actions/notifications&quot;,<br>        headers={&quot;Authorization&quot;: f&quot;Bearer {self.token}&quot;},<br>        params=params,<br>    )<br>    res.raise_for_status()<br><br>    ResponseModel = ResponseEnvelope[list[Notification]]<br>    parsed = ResponseModel.model_validate(res.json())<br>    <br>    return parsed.data</pre><p><em>For this example, I have deliberately chosen 1000 as the polling size for notifications. In case you have more than 1000 notifications on a single workspace each day, you might want to reconsider your alerting rules. Or you might greatly benefit from things like Anomaly Detection, which I touch on in the last section.</em></p><p>This simply retrieves all notifications for a given workspace, allowing you to run KDA selectively during the night. This saves your computation resources and helps you focus only on relevant events in your data.</p><p>Alternatively, you can also automate the processing of the notifications with webhooks or our <a href="https://www.gooddata.com/docs/python-sdk/latest/">PySDK</a>, so you don’t have to poll them proactively. You can easily just react to them and have your KDA computed as soon as any outlier in your data is detected.</p><h3>Automated KDA in GoodData</h3><p>While we are currently working on integrated Key Driver Analysis as an internal feature, we already have a working flow that elegantly automates this externally. Let’s have a look at the details. If you’d like to learn more or want to try to implement it yourself, feel free to reach out!</p><p>Every time a configured alert in GoodData is triggered, it initiates the KDA workflow (through a webhook). The workflow operates in multiple steps:</p><ul><li><strong>Data Extraction</strong></li><li><strong>Semantic Model Integration</strong></li><li><strong>Work Separation</strong></li><li><strong>Partial Summarization</strong></li><li><strong>External Drivers</strong></li><li><strong>Final Summarization</strong></li></ul><h4>Data Extraction + Semantic Model integration</h4><p>First, it extracts information about the metric and filters involved in the alert, including the value that triggered the notification, and then it reads the related semantic models using the <a href="https://www.gooddata.com/docs/python-sdk/latest/">PySDK</a>.</p><p>The analysis planner then prepares an analysis plan based on the priority of dimensions available in the semantic model. This plan defines which dimensions and combinations will be used to analyze the metric.</p><h4>Setting up the Work</h4><p>The analysis planner then initiates analysis workers that execute the plan in parallel. Each worker uses the plan to query data and perform its assigned analyses. These analyses produce signals that the worker evaluates for potential drivers (what drives the change in the data).</p><h4>Partial Summarization</h4><p>If any drivers are found, they are passed to LLM, which selects the most relevant ones based on past user feedback. It also generates a summary, provides recommendations, and checks for external events that could be related.</p><h4>External Drivers</h4><p>The analysis workers process the plan starting from the most important dimension combinations and continue until all combinations are analyzed or the allocated analysis credits are used up. The credit system is something we implemented to allow users to assign a specific amount of credits to each KDA in order to manage the duration and cost of the analysis/LLMs.</p><h4>Final Summarization</h4><p>Once the analyses are completed, a post-processing step organizes the root causes into a hierarchical tree for easier exploration and understanding of nested drivers. The LLM then generates an executive summary that highlights the most important findings.</p><p>We are currently working on enhancing KDA using the semantic model of the metrics. This will help identify root causes based on combinations of underlying dimensions and related metrics. For example, a decline in ice-cream margins may be caused by an increase in the milk price.</p><h3>A Sneak Peek Into the Future</h3><p>Currently, there are three very promising technologies that we are experimenting with.</p><h4>FlexConnect: Enhancing KDA with External APIs</h4><p>Expanding automated KDA further, <a href="https://www.gooddata.com/resources/flexconnect-connect-to-any-data-source/">FlexConnect</a> integrates external data through APIs, providing additional layers of context. Imagine an ice cream shop’s data extended with external market trends, consumer behavior analytics, or global commodity price indexes.</p><p>This integration allows deeper insights beyond internal data limitations. This can make your decision-making process more robust and future-proof. For instance, connecting to a weather API could proactively predict ingredient price fluctuations based on forecasted agricultural impacts.</p><h4>Enhanced Anomaly Detection</h4><p>Integrated machine learning models that highlight significant outliers, improving signal-to-noise ratios and accuracy. This would mean that you can easily move beyond simple thresholds and/or change gates. Your alerts can take into account the seasonality of your data and simply adapt to it.</p><h4>Chatbot Integration</h4><p>We are currently expanding the possibilities for our AI chatbot, which, of course, includes Key Driver Analysis. Soon, with this capability, the chatbot can help you set up alerts for automatic detection of outliers and send you notifications about them. Also, in the future, it may recommend you next steps based on KDA.</p><p>The output could look something like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/462/1*cKDiQeC1feceHEB1CanUzA.png" /></figure><h4>Practical Application: Ice Cream Shop Example</h4><p>To illustrate, assume your <strong>Anomaly Detection</strong> detects a price deviation. Immediately:</p><ol><li>An automated KDA process initiates, revealing milk shortages as the primary driver.</li><li>Simultaneously,<strong> FlexConnect</strong> fetches external market data, showing a global dairy shortage due to weather conditions.</li><li>An <strong>AI agent</strong> notifies you via instant messaging (or e-mail), offering alternative suppliers or recommending price adjustments based on historical data.</li><li>You can then chat with this agent and reveal even more information (or ask it to use additional data) on the anomaly. The agent has the whole context, as he has been briefed even before you knew about the anomaly.</li></ol><p>And while this might sound like a very distant future, we are currently experimenting with each of these! Don’t worry, when each of these features is nearing deployment, we’ll share the PoC with you on this.</p><h3>Want to learn more?</h3><p>If you’d like to dig deeper into automation in analytics, check out our article on how to <a href="https://www.gooddata.com/blog/5-tips-to-effectively-utilize-scheduled-exports-and-data-alerts-in-your-data-product/">effectively utilize Scheduled Exports &amp; Data Exports</a>. It explores how to use automation to set up alerts correctly, so that they are useful and not simply a distraction.</p><p>Stay tuned if you’re interested in learning more about KDA, as we’ll soon follow up with a more in-depth article while also exploring its practical application in analytics.</p><p>Have questions or want to implement automated KDA in your workflow? Reach out — we’re here to help!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=559a32e255f5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/gooddata-developers/make-key-driver-analysis-smarter-with-automation-559a32e255f5">Make Key Driver Analysis Smarter with Automation</a> was originally published in <a href="https://medium.com/gooddata-developers">GoodData Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Listen to your dashboards. Literally!]]></title>
            <link>https://medium.com/gooddata-developers/listen-to-your-dashboards-literally-80b15e452347?source=rss----e8ee419648ea---4</link>
            <guid isPermaLink="false">https://medium.com/p/80b15e452347</guid>
            <category><![CDATA[podcast]]></category>
            <category><![CDATA[analytics]]></category>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[business-intelligence]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Tomáš Muchka]]></dc:creator>
            <pubDate>Mon, 23 Jun 2025 11:29:13 GMT</pubDate>
            <atom:updated>2025-06-23T14:47:48.110Z</atom:updated>
            <content:encoded><![CDATA[<h4>Transforming your dashboards into a data podcast is easy</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*BRSkNG3yRhKFkYp1" /></figure><p>Making your data speak was one of the earliest applications of AI on analytics I saw. I remember asking myself two questions. How hard would it be to implement it, and is there actually a real user need behind it? TLDR; it is actually easier than you could imagine and in this article I will outline how you can create your own data podcast. And although I was a bit skeptical about its usefulness, after trying it out for a week, I must admit it is my <strong>#1 activity on my way to work</strong>.</p><h3>How to build a data podcast</h3><p>Building a naive implementation of an AI-driven data podcast is quite easy. Especially if your analytics platform provides a robust SDK. I will showcase the steps using GoodData and its Python SDK. This nicely matches OpenAI’s Python SDK I’m using to communicate with AI.</p><h4>Step 1: Export dashboard</h4><p>OK, let’s do it. First I need to connect GoodData to an existing workspace. Workspace is a logical unit that combines data, model and dashboards.</p><pre># GoodData base URL, e.g. &quot;https://www.example.com&quot;<br>host = &quot;https://example.cloud.gooddata.com/&quot;<br>token = os.environ.get(&quot;GOODDATA_API_TOKEN&quot;)<br>sdk = GoodDataSdk.create(host, token)</pre><p>Now once I’m connected to the right workspace, let’s find the dashboard I’m interested in and export it. GoodData currently allows <a href="https://www.gooddata.com/docs/python-sdk/latest/execution/exports/">exporting the whole dashboard</a> into a PDF file, so let’s use it.</p><pre>EXPORT_FILE_NAME = &quot;test&quot;<br>EXPORT_SUFFIX = &quot;export&quot;<br><br>def export_dashboard_to_images():<br>  # Export a dashboard in PDF format<br>  export_path = Path.cwd() / EXPORT_SUFFIX<br>  export_path.mkdir(parents=True, exist_ok=True)<br>  sdk.export.export_pdf(<br>    workspace_id = &quot;demo_workspace&quot;,<br>    dashboard_id = &quot;demo_dashboard&quot;,<br>    file_name = EXPORT_FILE_NAME,<br>    store_path = export_path,<br>    metadata = {}<br>  )</pre><p>Here is the exported dashboard I spoke about. I’m using the standard GoodData demo dashboard here. The dashboard informs about various aspects of customer engagement in a hypothetical e-shop.</p><figure><img alt="A GoodData dashboard focused on customer analytics for an e-shop. Visuals include a donut chart with all customers as return customers, a bar chart confirming 0 new and 22 return customers, and rankings listing top spenders and buyers." src="https://cdn-images-1.medium.com/max/1024/1*Eu63akrw8Z9nMSVwNurDjg.png" /><figcaption><em>A GoodData demo dashboard used as a podcast source</em></figcaption></figure><p>OpenAI unfortunately accepts PDF files only in their chatbot interface. On the API, it accepts just text and images. That’s why I need to convert the PDF into images.</p><pre># Convert PDF to images<br>  images = convert_from_path(export_path / (EXPORT_FILE_NAME + &quot;.pdf&quot;), dpi=300)  # Change dpi for quality<br>  <br>  image_data = []<br>  for img in images:<br>    buffered = io.BytesIO()<br>    img.save(buffered, format=&quot;PNG&quot;)<br>    img_str = base64.b64encode(buffered.getvalue()).decode(&quot;utf-8&quot;)<br>    <br>    image_data.append(img_str)<br><br>  # Return the list of base64-encoded images <br>  return image_data</pre><h4>Step 2: Describe the dashboard</h4><p>With the dashboard exported in a format that OpenAI accepts, let’s get a nice description out of it.</p><p>Noticeable parts of the code:</p><ul><li>The prompt clearly states that the description should be used for the podcast talktrack.</li><li>The language of the podcast can be easily set using the prompt again. Just add “Write the text in {language}.” at the end of it.</li></ul><pre>def describe_dashboard(images, language=&quot;en&quot;):<br>    client = OpenAI(<br>        # This is the default and can be omitted<br>        api_key=os.environ.get(&quot;OPENAI_API_KEY&quot;),<br>    )<br><br>    message = [<br>      {<br>      &quot;role&quot;: &quot;user&quot;,<br>      &quot;content&quot;: [<br>        {<br>        &quot;type&quot;: &quot;text&quot;,<br>        &quot;text&quot;: (<br>          &quot;Act as a data analyst who creates a daily data summary podcast. &quot;<br>          &quot;Start with the current day and a brief introduction of the dashboard, &quot;<br>          &quot;then describe the dashboard in a way that is easy to understand for a &quot;<br>          &quot;non-technical audience. Don&#39;t mention there is actually a dashboard&quot;<br>          &quot;, make it sound like you are reading a daily summary report. &quot;<br>          f&quot;Write the text in {language}.&quot;<br>        ),<br>        }<br>      ]<br>      }<br>    ]<br><br>    for image in images:<br>      message[0][&quot;content&quot;].append(<br>        {<br>          &quot;type&quot;: &quot;image_url&quot;,<br>          &quot;image_url&quot;: {&quot;url&quot;: f&quot;data:image/jpeg;base64,{image}&quot;},<br>        }<br>      )<br><br>    outcome = client.chat.completions.create(<br>      model=&quot;gpt-4o&quot;,<br>      messages=message<br>    )<br>    return outcome.choices[0].message.content</pre><h4>Step 3: Generate audio</h4><p>Generating the audio is by far the easiest step in this guide. OpenAI offers an API for this exact purpose. You just need to set the model and voice type. The output can be stored straight into a file.</p><pre>def generate_audio(text, file, voice=&quot;alloy&quot;):<br>  client = OpenAI()<br><br>  response = client.audio.speech.create(<br>      model=&quot;tts-1&quot;,<br>      voice=voice,<br>      input=text,<br>  )<br>  response.stream_to_file(file+&quot;.mp3&quot;)</pre><p><em>Note: OpenAI automatically detects the language from the text, so there is no need to set it explicitly.</em></p><h4>Step 4: Send it to your audience</h4><p>There are multiple ways to distribute your new podcast to your audience. E.g., Oracle Analytics decided to <a href="https://blogs.oracle.com/analytics/post/analytics-anywhere-oracle-analytics-on-mobile">add podcasting capabilities</a> into their mobile app.</p><p>I chose a different direction — publishing the podcast episodes straight into a podcast app (Youtube Music in my case).</p><figure><img alt="YouTube Music for GoodData Dashboard Insights podcast, featuring episodes that convert dashboard data into narrated insights. Latest episode from June 8, 2025, discusses customer engagement and a 14% increase in active customers." src="https://cdn-images-1.medium.com/max/1024/0*3lp43wTttHY6HODF" /><figcaption>Youtube Music with GoodData dashboard insights podcast</figcaption></figure><p>First, we need to generate a title and a description for each episode. This can be done using a simple OpenAI call. Just take the full dashboard description as an input and generate a brief summary out of it.</p><pre>def generate_summary(text, timestamp):<br>    client = OpenAI()<br><br>    message = [<br>        {<br>        &quot;role&quot;: &quot;user&quot;,<br>        &quot;content&quot;: [<br>          {<br>            &quot;type&quot;: &quot;text&quot;,<br>            &quot;text&quot;: (<br>              &quot;Act as a podcaster and data analyst publishing a new podcast episode. Generate output in JSON format with two fields: &#39;title&#39; and &#39;description&#39;.&quot;<br>              &quot; - &#39;title&#39; should be a string of 6 to 10 words, following this pattern: &#39;&lt;Month&gt; &lt;Day&gt;, &lt;Year&gt; - &lt;Short Episode Title&gt;&#39; (e.g. &#39;June 1, 2025 - Exploring the Dynamic Expansion of LEGO Sets&#39;).&quot;<br>              &quot; - &#39;description&#39; should be a very short and brief summary of the episode, suitable for RSS feeds.&quot;<br>              &quot;Important: Output only raw JSON. Do not include any Markdown formatting, code block markers, or extra commentary.&quot;<br>              f&quot;Text to summarize: {text}&quot;<br>              f&quot;Current date is: {timestamp}&quot;<br><br>            ),<br>          }<br>        ]<br>        }<br>      ]<br><br>    outcome = client.chat.completions.create(<br>        model=&quot;gpt-4o&quot;,<br>        messages=message<br>      )<br>    return outcome.choices[0].message.content</pre><p>The code results in a simple JSON structure that has two props, title and description. The title always contains the current date and barebone of the episode summary.</p><p><strong>Now, with the audio file, title and description in place, we can finally publish the episode! But, how?</strong></p><p>I spent quite a time trying to figure out the most suitable way to do it. Here are a few of the dead-ends I encountered.</p><ol><li><strong>Don’t try to upload the podcast to Git pages.</strong> Although I was able to generate an rss file and added the podcast to the YT Music app, it could not play any audio. Later I discovered that Github pages are not optimized to stream media files, which is mandatory for podcasts.</li><li>Soundcloud is quite unfriendly for 3rd party integrations. Having already a Soundcloud account, I thought it would be easy to upload the episodes there. I however found the Soundcloud API and integrations quite hostile towards my simple Python-upload use case.</li></ol><p>In the end I found a podcast platform called <a href="https://www.buzzsprout.com/">Buzzsprout</a>. Uploading episodes is quite easy thanks to their API. Before uploading the first episode, I just had to create an API token and a new podcast entity on the Buzzsprout website.</p><p>Uploading the episode requires an HTTP call with episode details in form of a JSON payload and the episode audio file.</p><pre>def upload_episode(path, summary, season_number, episode_number):<br>    API_TOKEN = os.getenv(&quot;BUZZSPROUT_API_TOKEN&quot;)<br>    PODCAST_ID = os.getenv(&quot;BUZZSPROUT_PODCAST_ID&quot;)<br>    summary = json.loads(summary)<br><br><br>    # Endpoint<br>    url = f&quot;https://www.buzzsprout.com/api/{PODCAST_ID}/episodes.json?&quot;<br><br>    # Metadata<br>    data = {<br>        &quot;title&quot;: summary[&quot;title&quot;],<br>        &quot;description&quot;: summary[&quot;description&quot;],<br>        &quot;summary&quot;: summary[&quot;description&quot;],<br>        &quot;artist&quot;: &quot;GoodData AI Assistant&quot;,<br>        &quot;episode_number&quot;: episode_number,<br>        &quot;season_number&quot;: season_number,<br>        &quot;explicit&quot;: False,<br>        &quot;private&quot;: False,<br>        &quot;email_user_after_audio_processed&quot;: True,<br>        &quot;artwork_url&quot;: &quot;https://www.gooddata.com/img/blog/_1200x630/01_21_2022_goodatasociallaunch_rebrand_og.png.webp&quot;<br>    }<br><br>    headers = {<br>        &quot;User-Agent&quot;: &quot;Mozilla/5.0 (compatible; BuzzsproutBot/1.0)&quot;,<br>        &quot;Accept&quot;: &quot;application/json&quot;,<br>        &quot;Authorization&quot;: f&quot;Token token={API_TOKEN}&quot;<br>    }<br><br>    # File upload<br>    files = {<br>        &quot;audio_file&quot;: (os.path.basename(path), open(path, &quot;rb&quot;), &quot;audio/mpeg&quot;)<br>    }<br><br>    # POST request<br>    response = requests.post(url, data=data, headers=headers, files=files)</pre><p><a href="https://www.buzzsprout.com/2507509?artist=GoodData+AI+Assistant&amp;client_source=large_player&amp;iframe=true&amp;referrer=https%3A%2F%2Fwww.buzzsprout.com%2F2507509%2Fpodcast%2Fembed">Podcast Episode</a></p><h3>Automate it</h3><p>The circle is closed, the podcast is published. The only downside is in the need to run the code locally every time a new episode should get created.</p><p>I’m a software engineer by soul and I hate tedious error-prone processes, which is exactly this case. Creating a sticky note is not something that really solves the underlying problem. Instead, let’s find an easy way to automate the release of a new podcast episode.</p><p><strong>Github actions to the rescue.</strong></p><p>The easiest solution is probably <a href="https://github.com/features/actions">Github actions</a>. I set a daily schedule to release a new episode and Github took care of the rest.</p><p>Notice the env variables it uses. These are defined in my local unversioned .env file and then in Github settings. This way these won’t leak to unwanted locations.</p><p>Poppler is used during the transformation of PDF to images and the utility is not available out of the box in the latest Ubuntu environment.</p><pre>name: Daily Run<br><br>on:<br>  schedule:<br>    - cron: &#39;0 6 * * *&#39;  # Runs every day at 8:00 Czech time (GMT+2)<br>  workflow_dispatch:      # Allows you to manually trigger it<br><br>jobs:<br>  run-python-script:<br>    runs-on: ubuntu-latest<br><br>    env:<br>      GOODDATA_WORKSPACE_ID: ${{ secrets.GOODDATA_WORKSPACE_ID }}<br>      GOODDATA_API_TOKEN: ${{ secrets.GOODDATA_API_TOKEN }}<br>      GOODDATA_DASHBOARD_ID: ${{ secrets.GOODDATA_DASHBOARD_ID }}<br>      GOODDATA_ENDPOINT: ${{ secrets.GOODDATA_ENDPOINT }}<br>      BUZZSPROUT_API_TOKEN: ${{ secrets.BUZZSPROUT_API_TOKEN }}<br>      BUZZSPROUT_PODCAST_ID: ${{ secrets.BUZZSPROUT_PODCAST_ID }}<br>      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}<br><br>    steps:<br>      - name: Checkout code<br>        uses: actions/checkout@v3<br><br>      - name: Set up Python<br>        uses: actions/setup-python@v4<br>        with:<br>          python-version: &#39;3.11&#39;<br>      <br>- name: Install Poppler<br>        run: sudo apt-get update &amp;&amp; sudo apt-get install -y poppler-utils<br>        <br>      - name: Install dependencies<br>        run: |<br>          pip install -r requirements.txt<br><br>      - name: Run script<br>        run: |<br>          python app.py</pre><p>And the result as seen on Github:</p><figure><img alt="List of eight successful ‘Daily Run’ workflow executions, each triggered by a scheduled event." src="https://cdn-images-1.medium.com/max/1024/0*58KrJI5HmYraYTDV" /><figcaption>Daily releases of the podcast episodes through Github actions</figcaption></figure><h3>But… is there a use case?</h3><p>During my 7 years of UX design for an analytics platform, I never heard any customer wish to listen to the dashboard summaries as a podcast.</p><p>Having said that, I often hear customers wish to reduce the time to insight as much as possible. A quick audio summary of what happened in the last X days might actually fulfil this need quite well. I would personally like to push the idea a bit further and accompany the audio summary with additional infographic to make it stand out.</p><h3>Conclusion</h3><p>In this article I outlined to you that building a dashboard podcast is actually quite easy and with proper tooling requires just a few lines of code. All thanks to the developer friendly platform. If you&#39;d like to learn how that works, check out my <a href="https://medium.com/gooddata-developers/the-road-to-ai-generated-visualizations-923428728479?source=collection_home---5------6-----------------------">AI-generated Visualizations</a> article.</p><h4>There is one but…</h4><p>As already mentioned, the examples above have one big flaw; I’m sending the data through a visual export, losing most of the actual dashboard data.</p><p>For a summary podcast, or a quick glance at the dashboard, a visual export is acceptable, but for in-depth analysis, work directly with the data, not just the visual output.</p><h4>How to make it useful</h4><p>Sending a daily or weekly dashboard summary as a podcast sounds good, but don’t forget to properly set the date filters and possibly also include the previous snapshots and tell the AI to point out the changes. This way your podcast will be much more relevant.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=80b15e452347" width="1" height="1" alt=""><hr><p><a href="https://medium.com/gooddata-developers/listen-to-your-dashboards-literally-80b15e452347">Listen to your dashboards. Literally!</a> was originally published in <a href="https://medium.com/gooddata-developers">GoodData Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Everyone’s Talking About MCP. I Built a Server to See If It’s Ready]]></title>
            <link>https://medium.com/gooddata-developers/everyones-talking-about-mcp-i-built-a-server-to-see-if-it-s-ready-f85a4c565d62?source=rss----e8ee419648ea---4</link>
            <guid isPermaLink="false">https://medium.com/p/f85a4c565d62</guid>
            <category><![CDATA[mcp-server]]></category>
            <category><![CDATA[analytics]]></category>
            <category><![CDATA[model-context-protocol]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Andrii Chumak]]></dc:creator>
            <pubDate>Tue, 20 May 2025 13:46:41 GMT</pubDate>
            <atom:updated>2025-05-20T13:46:41.241Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hQG_VIpfpBCIjv0m73yGUQ.png" /></figure><p><a href="https://modelcontextprotocol.io/introduction">Model Context Protocol</a> (MCP) has received a lot of attention lately. Anthropic keeps promoting it as a unified protocol for LLMs. CursorAI now supports it as a client. Even big players like OpenAI, Azure, and Google are getting on board.</p><p>But do we really need yet another abstraction layer? Isn’t the good old REST API (in the form of OpenAI’s function calling) enough?</p><h3>What MCP is and is not</h3><p>Well, I was a little skeptical about MCP at first. OpenAI has had function calling for a while now, and at first glance, it seemed that MCP was no more than a marketing move from Anthropic. What caught my attention was a passage in the documentation about the protocol being inspired by VSCode’s Language Server. At GoodData, we created our own Language Server for our <a href="https://www.gooddata.com/blog/analytics-as-code-integrated-development-environment/">analytics as code features</a>, and I’m a big fan of the protocol. It is more than just a set of rules and schemas for communication with your IDE, it is changing the way a language developer thinks about the integration. So, I got curious if MCP can do the same for LLM apps.</p><p>Building an AI agent, or even a simple reactive chatbot, is hard. You need to both understand how LLMs work and be a decent software engineer. A colleague of mine (hey, Jakub!) has described this well with a Venn diagram.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*llAbtFDoi3cV8J8c" /><figcaption>Why building AI applications is hard</figcaption></figure><p>Model Context Protocol is a way to make LLM Apps’ development accessible to a wide variety of software engineers, even those with no data science background, such as myself. I no longer need to have a deep understanding of all the LLM oddities in order to create an agent, just as I don’t need to know how VSCode works under the hood in order to add support for my language with Language Server.</p><h3>GoodData MCP Server PoC</h3><p>There is no better way to learn about a new technology than to use it. So, I went and built a prototype MCP Server with just enough GoodData features to cover a simple usage scenario.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F3lvRRjWEKdQ%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D3lvRRjWEKdQ&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F3lvRRjWEKdQ%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/a118dd218b1b638f1e764cc96f79aefa/href">https://medium.com/media/a118dd218b1b638f1e764cc96f79aefa/href</a></iframe><p>As a starting point, I chose TypeScript SDK. There are plenty of relevant examples on GitHub using this SDK and it’s one of the official ones, supported by Anthropic.</p><p>As a client, I’m using the Claude Desktop app. Although some feature support is spotty, it is the official client from Anthropic.</p><p>If you want to see my implementation for yourself, check out this <a href="https://github.com/andriichumak/gooddata-mcp">repository</a>.</p><h3>MCP First DevEx Impressions</h3><p>MCP is still under heavy development, and this is immediately evident. Documentation is inconsistent at times, the official desktop client does not support all the MCP features, and there are inconsistencies between different server SDKs. This is understandable, given the pace at which MCP is evolving, and it is largely compensated by <a href="https://github.com/modelcontextprotocol/servers">a plethora of examples on Github</a>.</p><p>Your MCP server can deliver several types of integrations: <strong>Tools</strong>, <strong>Resources</strong>, <strong>Prompts</strong>, <strong>Sampling,</strong> and <strong>Roots</strong>.</p><h3>Tools</h3><p><a href="https://modelcontextprotocol.io/docs/concepts/tools"><strong>Tools</strong></a> are by far the most well-supported and robust type of integration. They have existed for a long while (remember OpenAI function calling?). Tools are also well-supported by Claude Desktop.</p><p>The idea is that you define a function name and a JSON Schema of the expected input, and the LLM will request the execution of the function with input based on the user prompt.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*GXAhhTed_oM_cZnO" /><figcaption><em>A Semantic Search Tool defined with TS SDK</em></figcaption></figure><p>The main purpose of Tools is to provide a way for the AI Assistant to execute actions on the user’s behalf.</p><h4>Resources</h4><p>With <a href="https://modelcontextprotocol.io/docs/concepts/resources"><strong>Resources</strong></a> and <strong>Resource Templates,</strong> you can provide the LLM with the context it needs to reply to the user’s question. It can be anything from documentation in PDF files to JSON entities out of your REST API.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*F7zYKP0RmkV8nMAu" /><figcaption><em>Resource is used to help LLM pick the right visualization type</em></figcaption></figure><p>Personally, I can see how this may become one of the most powerful integration types in MCP. However right now, in Claude Desktop, the LLM can’t choose which resources to use on its own. The user has to explicitly include the resource in each question. This limits the usefulness of the Resources, and I hope this becomes seamless in the future.</p><h4>Prompts</h4><p><a href="https://modelcontextprotocol.io/docs/concepts/prompts"><strong>Prompts</strong></a> is another integration type with great potential. At the surface level, Prompts are just prompt templates predefined by your MCP server. They provide the user with a standardized way to ask LLMs for certain tasks. The real power of Prompts, however, lies in parametrization and workflows. Think of this as Tools on steroids. Your MCP server can process the input arguments and output a set of instructions to the LLM on how to process the results, how to respond to the user, and which tools to use next in the pre-defined workflow.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*AXAAYyC9RFLfhrXi" /><figcaption><em>A prompt that loads data for a given visualization and asks Claude to analyze it</em></figcaption></figure><p>Claude Desktop’s integration for Prompts is less fluent compared to Tools. The user needs to explicitly generate the prompt and provide the input parameters manually.</p><h4>Sampling</h4><p><a href="https://modelcontextprotocol.io/docs/concepts/sampling"><strong>Sampling</strong></a> is the latest addition to the MCP. It allows the server to ask for help from the LLM through the client, while keeping the human in the loop. This will be especially useful if you want to orchestrate complex multi-step tasks, like creating a data analytics visualization. Here is how it would work:</p><ol><li>Your user asks a question to create a visualization.</li><li>Let’s say the user did not specify the exact visualization type they wanted. The MCP server can do some heuristics and narrow down the options based on the metrics and dimensionality, but in the end, it needs to decide whether to use a bar chart or a line chart. Something a quick call to the LLM can easily solve.</li><li>The server sends a Sampling request to the client with the user’s original prompt, a narrowed-down list of supported visualizations, and a guideline on how to select the visualization type.</li><li><strong>Optionally,</strong> this is then displayed to the user, who can edit, approve, or even reject the LLM call. Users can also change the selected model.</li><li>The client forwards it to the LLM and then routes the response back to the server.</li></ol><p>This workflow ensures that all LLM communication always goes through the client, while the user has the final say in what to send to the LLM.</p><p>At the time of writing this article, Sampling is not yet supported by the Claude Desktop.</p><h4>Roots</h4><p><a href="https://modelcontextprotocol.io/docs/concepts/roots"><strong>Roots</strong></a> is a way for an MCP client to tell an MCP server which resources it should be accessing for a given operation. A typical example would be a directory where the filesystem-operating MCP server should be working in. This is also applicable to API base URLs or any other URI-identified resources.</p><h3>What’s next for MCP?</h3><p>MCP has come a long way since it was first introduced, and I’m looking forward to seeing it mature further. Here are a few improvements I’d really like to see:</p><ul><li>More seamless integration for <strong>Resources</strong>, <strong>Prompts,</strong> and <strong>Sampling</strong> on the Claude Desktop side. I don’t want my users to manually pick the Resource or fill in the variables for a Prompt. Why not let the LLM choose to access these in the same way it does with <strong>Tools</strong>?</li><li>I want to be able to add my own content types to MCP client, the server, and to the client UI. One good use case is GoodData’s data visualization. I can easily write a server that returns a GoodData-specific data visualization JSON, but there is no way I can render it in Claude Desktop’s UI, unless I export it to a plain, non-interactive image. Imagine if an MCP server could also provide a link to a WebComponent (React/Angular component) capable of rendering the new content type.</li></ul><h3>What’s in it for GoodData?</h3><p>At GoodData, we are keeping a very close eye on MCP. You can expect to see more PoCs and eventually production integrations from our side. Here is a sneak peek into what’s brewing:</p><ul><li>Now Anthropic has finished the specification for a remote MCP server, we’re trying that out and will eventually integrate it into our servers.</li><li>Some time ago we built the GoodData <a href="https://www.gooddata.com/docs/cloud/api-and-sdk/vs-code-extension/">VSCode extension</a> to support our Analytics as Code format. Using this extension in VSCode-based AI-enabled IDE (like, Cursor) and adding an MCP server to it should be quite a powerful combination.</li><li>Last but not least, we are about to release GoodData AI Assistant. Making it an MCP client will unlock a lot of new use cases. Imagine an analytics-focused assistant that our customers can connect to their own MCP servers and provide additional context and tooling.</li></ul><h3>Conclusion</h3><p>MCP is a very promising technology. One can see all the effort the team at Anthropic put into the protocol design. It needs to mature, though. I would be hesitant to write a generic MCP server with anything other than <strong>Tools</strong>, unless I’m targeting a very specific MCP client implementation or, better yet, I’m writing my own.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f85a4c565d62" width="1" height="1" alt=""><hr><p><a href="https://medium.com/gooddata-developers/everyones-talking-about-mcp-i-built-a-server-to-see-if-it-s-ready-f85a4c565d62">Everyone’s Talking About MCP. I Built a Server to See If It’s Ready</a> was originally published in <a href="https://medium.com/gooddata-developers">GoodData Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Hyper personalised analytics is coming]]></title>
            <link>https://medium.com/gooddata-developers/hyper-personalised-analytics-is-coming-21e4a810fd11?source=rss----e8ee419648ea---4</link>
            <guid isPermaLink="false">https://medium.com/p/21e4a810fd11</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[hyper-personalization]]></category>
            <category><![CDATA[business-intelligence]]></category>
            <category><![CDATA[analytics]]></category>
            <category><![CDATA[chatgpt]]></category>
            <dc:creator><![CDATA[Tomáš Muchka]]></dc:creator>
            <pubDate>Wed, 07 May 2025 09:25:37 GMT</pubDate>
            <atom:updated>2025-05-09T07:30:32.195Z</atom:updated>
            <content:encoded><![CDATA[<h4>Yet, most of the current analytics solutions are stuck in “one to rule them all” dashboards</h4><figure><img alt="Illustration of a glowing human silhouette at the center of a futuristic dashboard interface, surrounded by flowing data streams and colorful charts, graphs, and icons in shades of purple, blue, and pink, symbolizing hyperpersonalized analytics against a dark purple background." src="https://cdn-images-1.medium.com/max/1024/0*lB7g8yqIX9nsxOOe" /></figure><p>Two years ago, I interviewed a candidate for a UX designer position for our web and marketing team. During the interview, he brought up hyper-personalization as the next big thing in digital marketing. It sounded interesting, but I didn’t give it much thought at the time. Now that this trend is coming to analytics, <strong>the current tools aren’t ready for it</strong>.</p><p>Most of the analytics solutions are still stuck in the pattern of a standardized set of dashboards which rule all of the consumers. To add an impression of personalisation, these standard dashboards are often accompanied with dozens of filters. This however only adds to their complexity. Making them incomprehensible at first glance.</p><blockquote><strong>Politely said, the current personalisation experience in analytics is suboptimal. But how to get out of this?</strong></blockquote><h3>Moonshot: Dashboards are dead</h3><p>I know we have been hearing about the dashboards being dead at least <a href="https://medium.com/data-science/dashboards-are-dead-3-years-later-72347757bfa6">since 2020</a>, yet they are still here with us. However, if hyper-personalization is really coming, dashboards are not the ideal interface for it. They should evolve into personal spaces or homepages.</p><figure><img alt="Mobile banking app showing current balance of $8,750, monthly spending of $1,250 with a line chart, and category breakdown: Food &amp; Drink $450, Groceries $320, Shopping $210." src="https://cdn-images-1.medium.com/max/1024/0*RofRsWw6B3ImgUew" /><figcaption>Example of a personalised homepage from ChatGPT</figcaption></figure><p>Another option that nicely matches with hyper-personalizations are AI chatbots and conversational patterns in general. Surprisingly, chatbots already know a lot about us, just ask them yourselves.</p><figure><img alt="Summary of user’s professional background and interests, showing they are a UX Architect at GoodData Corporation working on design consistency, accessibility, and AI analytics chatbots, with projects in smart search, external recipients, and visualization prototyping" src="https://cdn-images-1.medium.com/max/896/0*Pw7KQaq_ECAhAE61" /><figcaption><em>Image of what does ChatGPT know about Tomas Muchka (author of this article)</em></figcaption></figure><p><strong>Now imagine connecting the information chatbot knows about you, to your data needs.</strong></p><p>However, I haven’t seen a single analytics platform that would be able to deliver such an experience. Even tech giants like <a href="https://www.theverge.com/news/629940/apple-siri-robby-walker-delayed-ai-features">Apple are still struggling to adopt and integrate new AI-</a>driven features. And building this from scratch would require a tremendous amount of work.</p><h3>Realistic goal: Personalized dashboards</h3><p>As I said at the beginning, hyper-personalization is a tempting goal, however, most of the analytics solutions have close to zero personalized content. This is not because data analysts are villains wanting their dashboard users to suffer, but they just don’t have enough time and resources to manage personalized versions of their dashboards for everyone.</p><p><strong>I believe AI can help us personalize analytics.</strong></p><p>How exactly can AI help us here? In my article <a href="https://medium.com/p/4b9a1ba6e199">Can your BI tool import sketched dashboards?</a> I outlined how GoodData professional services work. They look at the data and cooperate with our customers to deliver the best possible analytics for their desired use cases. AI can help us bootstrap this process.</p><p>Let’s look at three steps AI can help us with personalized dashboards.</p><h4>1. Propose audience based on the data</h4><p>While the common knowledge is to start with the audience and their use cases before building data around it, reality often flips this approach — we start with the data and then we seek the right audience. This is precisely where AI can help us.</p><p>Here is a demo explaining the idea. First, I select data sources and <strong>LLM will analyze their metadata to identify the best possible audience and use cases for it.</strong></p><figure><img alt="Modal dialog titled ‘Select your data sources’ with checkboxes; ‘Bricks Set Catalog’ is selected, and there are ‘Cancel’ and ‘Select’ buttons at the bottom." src="https://cdn-images-1.medium.com/max/920/0*oxXzm_SAr80ENTSl" /><figcaption><em>In the first step, select the data sources to build the analytics</em></figcaption></figure><p>Would you dare connect your database to LLM directly? How would your security and compliance department feel about it? Doing this through GoodData has one big advantage — <strong>you don’t connect your data to the LLM, just the tables and column names</strong>.</p><p>In this step, AI creates a list of personas and their use cases based on the data, which we will use in the next step, where we create the model.</p><pre>tables = sdk.catalog_data_source.scan_data_source(data_source_id=data_source)<br>proposed_personas = ask_ai_to_suggest_personas(tables)</pre><figure><img alt="Dialog titled ‘Generate analytics’ with persona checkboxes; ‘Bricks Historian’ and ‘Market Growth Analyst’ are selected, with a text field to add a custom persona and ‘Cancel’ and ‘Generate’ buttons." src="https://cdn-images-1.medium.com/max/920/0*PLZAm0w6a5bXb92M" /><figcaption>AI generated list of possible personas that might be interested in the data</figcaption></figure><h4>2. Generate audience-based model</h4><p>Now with the proposed audience, we are ready to generate a logical data model. <strong>A robust model is the very heart of a modern AI-ready analytics platform</strong>. And it is also the part where data analysts and analytics engineers spend most of their time. Some tools allow you to generate the model as a 1:1 copy from the database tables.</p><p>How much can such a copy of physical data structures serve your analytics needs? The only exception is if you already prepare your analytics model directly in the database. In such a case you spend most of your time creating the very same logical model just in a different tool.</p><p>AI can bootstrap the model creation by taking the audience and their use cases into account. Any information you can provide to the AI can help your model become a better fit.</p><pre>datasets = ask_ai_to_create_model(tables, personas)<br><br>datasets_directory = os.path.join(&#39;analytics&#39;, &#39;datasets&#39;)<br>if os.path.exists(datasets_directory):<br>    shutil.rmtree(datasets_directory)<br>os.makedirs(datasets_directory, exist_ok=True)<br><br>for dataset in datasets:<br>    create_dataset(str(dataset))</pre><h4>3. Generate audience-oriented dashboards</h4><p>With the logical data model and audience in place, we can go a bit further and generate personalised dashboards and visualizations.</p><pre>personas_with_vizs = ask_ai_to_create_visualizations(list_of_personas)<br><br>for persona in personas_with_vizs:<br>    # Create a directory for each persona&#39;s title<br>    directory = os.path.join(visualisations_directory, persona[&#39;title&#39;])<br>    os.makedirs(directory, exist_ok=True)<br>        <br>    # Iterate over the visualizations for each persona<br>    for viz in persona[&#39;visualisations&#39;]:<br>       create_visualization(str(viz), directory, False)<br><br>dashboards = ask_ai_to_create_dashboards(personas_with_vizs)<br>for dashboard in dashboards:<br>   create_dashboard(str(dashboard), False)<br>deploy_analytics()</pre><figure><img alt="Dashboard titled ‘Market Growth Analyst’ showing LEGO set analytics from 1996 to 2023, including total sets (6,165), sets released over time, annual growth by origin (licensed vs native), top themes by growth, average price per license, and yearly revenue growth by theme." src="https://cdn-images-1.medium.com/max/1024/0*j5vXQ7MLHgl_fwbu" /><figcaption>AI generated dashboard for Market Growth Analysts</figcaption></figure><p>Not super happy about the outcome? No problem, all the assets are clearly separated. Feel free to update/create any of the steps manually or even better let the AI try it again with more specific instructions and more information.</p><h3>Try it yourself</h3><p>In the <a href="https://github.com/gooddata/gooddata-article-demos">repository</a>, you can find the whole code, including large parts of the prompts. It is very simple, yet elegant, because chatbot does most of the heavy lifting.</p><p>You might ask yourself, why would you even want to use GoodData, if even light prompting can lead to such results. And the reason why is exactly that, you only need light prompts, because our very AI friendly analytics as code approach.</p><p>As you can see in the presented code, we use OpenAIs’ GPT-4o for the first step, which is the only step where you want the AI to be creative. Then we use o3-mini, because it is basically generating code, as in GoodData you can represent anything as code.</p><p><strong><em>Disclaimer: </em></strong><em>In the code, we omitted parts that mimic the chatbot of GoodData, so it will not work as seamlessly as in our testing. We also omitted parts of the prompts, and shortened them for demonstration purposes.</em></p><h3>Conclusion</h3><p>Although the future is bright and hyper personalized analytics is soon™ coming through conversational interfaces or even AI workflows, there is something we can do about personalisation even now. AI can help us to generate personalized analytics, so data analysts don’t need to start from scratch.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=21e4a810fd11" width="1" height="1" alt=""><hr><p><a href="https://medium.com/gooddata-developers/hyper-personalised-analytics-is-coming-21e4a810fd11">Hyper personalised analytics is coming</a> was originally published in <a href="https://medium.com/gooddata-developers">GoodData Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Can your BI tool import sketched dashboards?]]></title>
            <link>https://medium.com/gooddata-developers/can-your-bi-tool-import-sketched-dashboards-4b9a1ba6e199?source=rss----e8ee419648ea---4</link>
            <guid isPermaLink="false">https://medium.com/p/4b9a1ba6e199</guid>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[analytics]]></category>
            <category><![CDATA[dashboard]]></category>
            <dc:creator><![CDATA[Tomáš Muchka]]></dc:creator>
            <pubDate>Tue, 01 Apr 2025 11:51:49 GMT</pubDate>
            <atom:updated>2025-04-01T11:51:49.775Z</atom:updated>
            <content:encoded><![CDATA[<h4>If not, you should probably look for a new one</h4><figure><img alt="Split-screen illustration showing a transition from a rough wireframe dashboard on the left to a polished, colorful data dashboard on the right, symbolizing design or development progress." src="https://cdn-images-1.medium.com/max/1024/0*TFWsp1Ex8yujVo07" /></figure><p>Sketching a dashboard is still one of the most common ways to start basically any analytical project. With today’s technologies even a paper sketch can be transformed into an interactive dashboard.</p><p>From our experience at GoodData, a typical analytics project starts over a whiteboard. The solution architect and UX designer meet with the customer and put together the first draft of the future analytics product.</p><figure><img alt="Miro board showing a use case table, colored sticky notes, and a prioritization matrix with axes labeled “Impact” and “Effort,” divided into iterations for planning." src="https://cdn-images-1.medium.com/max/1024/0*1zWvLiHP-DaY0xZK" /><figcaption>Example of a project start in a whiteboard tool</figcaption></figure><p>While a future-proof data model is a cornerstone of any successful project, customers can provide much more feedback when discussing the visuals of their future product, in our case dashboards.</p><p>That’s why we create wireframes of the dashboards as fast as possible and continuously discuss and iterate them with the customer. We even developed the <a href="https://www.gooddata.com/blog/introducing-goodwire/">GoodWire</a> Figma library to speed up the process. These wireframes are focused on information architecture and dashboards’ layout. With such a sketch, we can already validate with the end users whether the dashboard communicates the desired insights correctly.</p><figure><img alt="Dashboard titled “LEGO Journey” displaying LEGO sales analytics, including total sales value, line chart of sets over years, bar charts of biggest and most expensive sets, and a scatter plot showing set size vs. price." src="https://cdn-images-1.medium.com/max/1024/0*N_OIqVQwgHL1PY83" /><figcaption><em>Example of a sketched dashboard</em></figcaption></figure><p>However, the juiciest stuff are the annotations. Our customers tend to clarify their needs through sticky notes on dashboard sketches. These usually include interactions or additional clarification that cannot be seen on the dashboard sketch (e.g., when the filters should have a parent-child relationship).</p><figure><img alt="Interactive LEGO analytics dashboard with parent-child filters, zoom-enabled line chart, and a scatter plot that allows drilling into set details on bubble click." src="https://cdn-images-1.medium.com/max/1024/0*TWzE4zXnK3M6HuOZ" /><figcaption><em>Example of a sketched dashboard with annotations</em></figcaption></figure><p>OK, now imagine what happens, when the dashboard sketch gets approved. The solution architect creates the corresponding semantic layer, so the solution designer can take the approved sketch… and <strong>throw it away</strong>, because it needs to be rebuilt from scratch step by step in the BI tool.</p><blockquote><strong>Rebuilding approved sketches into dashboards is a waste of everyone’s time.</strong></blockquote><h3>Don’t rebuild, generate!</h3><p>Instead of recreating the dashboard according to the sketch manually, let’s take the previously created sketch and generate a real dashboard out of it. Wouldn’t it be beautiful?</p><p>Although GoodData does not offer such a functionality out of the box, I decided to explore the possibilities and build such a feature on top of our existing tooling. Similar to my article <a href="https://medium.com/gooddata-developers/from-sketch-to-interactive-data-what-is-napkin-analytics-all-about-d78024a43e6e">From Sketch to Interactive Data</a>, my idea was to use AI to generate the YAML definition of dashboard based on the sketch.</p><p>GoodData sports the concept of <a href="https://www.gooddata.com/resources/what-is-composable-data-and-analytics/">composable analytics</a>. Which means it separates visualisations from dashboards. So I need to create not only the dashboard definition, but also separate definitions for all the visualisations on the dashboard.</p><p>Fortunately, GoodData supports the as-code representation of the analytics entities including <a href="https://www.gooddata.com/docs/cloud/api-and-sdk/vs-code-extension/structures/#dashboard">dashboards</a> and <a href="https://www.gooddata.com/docs/cloud/api-and-sdk/vs-code-extension/structures/#visualization">visualisations</a>.</p><p>With all of that, check the interactive dashboard generated from the sketch.</p><figure><img alt="Side-by-side comparison of a wireframe sketch and a finished interactive dashboard for LEGO analytics, showing improvements in visual clarity, interactivity, and detailed data visualizations." src="https://cdn-images-1.medium.com/max/1024/0*uTWz6sU7Ow6zXK3j" /><figcaption><em>Result of our work: an autogenerated dashboard</em></figcaption></figure><h3>As code + AI = ♥️</h3><p>Now let’s take a look at how to make the as-code work with AI, namely OpenAI’s GPT-4o (o1 or o3 might be better for this, but it will take much longer). I’m not using the chatbot interface, but the OpenAI API. Never tried that? Then read the <a href="https://platform.openai.com/docs/quickstart?api-mode=chat">official quickstart</a> first.</p><h4>Step 1: Create the visualisations</h4><p>First we are going to send the base64 encoded dashboard sketch to AI, expecting to get a list of visualisations that are on the image.</p><pre>outcome = client.chat.completions.create(<br>        model=&quot;gpt-4o&quot;,<br>        messages=[<br>            {&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: INSTRUCTIONS},<br>            {&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: f&quot;Here are the fields from which you can build visualizations. Use only existing attributes and facts. {PROMPT_DATASETS}&quot;},<br>            {&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: f&quot;Here are examples of existing visualizations: {PROMPT_EXAMPLES_OF_VISUALIZATION}&quot;},<br>            {&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: f&quot;Here are the metrics from which you can build visualizations. Use only existing metrics. {PROMPT_METRICS}&quot;},<br>            {<br>                &quot;role&quot;: &quot;user&quot;,<br>                &quot;content&quot;: [<br>                    {<br>                        &quot;type&quot;: &quot;text&quot;,<br>                        &quot;text&quot;: &quot;Identify visualisations (charts) on the image and map it to the described visualization structure. Use the available fields. If not found, use the most similar fields.&quot;,<br>                    },<br>                    {<br>                        &quot;type&quot;: &quot;image_url&quot;,<br>                        &quot;image_url&quot;: {&quot;url&quot;: f&quot;data:image/jpeg;base64,{base64_image}&quot;},<br>                    },<br>                ],<br>            }<br>        ], <br>        response_format = schema<br>    )</pre><p>And the schema starts like this:</p><pre>&quot;type&quot;: &quot;json_schema&quot;,<br>    &quot;json_schema&quot;: {<br>        &quot;name&quot;: &quot;visualisations_schema&quot;,<br>        &quot;schema&quot;: {<br>            &quot;type&quot;: &quot;object&quot;,<br>            &quot;properties&quot;: {<br>                &quot;visualisations&quot;: {<br>                    &quot;type&quot;: &quot;array&quot;,<br>                    &quot;items&quot;: {<br>                        &quot;type&quot;: &quot;object&quot;,<br>                        &quot;title&quot;: &quot;Visualisation&quot;,<br>                        &quot;description&quot;: &quot;JSON schema for GoodData Analytics Visualisation&quot;,</pre><p>Once we have the visualisations ready, save them:</p><pre>visus = ask_ai_to_create_dashboard_visualizations(encoded_file)<br>for visu in visus:<br>    create_visualization(visu)</pre><p>Are you interested in more details on how this works? In my article <a href="https://medium.com/gooddata-developers/the-road-to-ai-generated-visualizations-923428728479">The Road to AI-generated Visualizations</a> I go over the whole process.</p><h4>Step 2: Create dashboard</h4><pre>dashboard = ask_ai_to_create_dashboard(encoded_file)<br>create_dashboard(dashboard)</pre><p>Where AI sets the dashboard layout and finds the most suitable visualisations to populate it.</p><pre>outcome = client.chat.completions.create(<br>        model=&quot;gpt-4o&quot;,<br>        messages=[<br>            {&quot;role&quot;: &quot;system&quot;, &quot;content&quot;: INSTRUCTIONS},<br>            {&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: f&quot;Here are the fields from which you can build dashboard filters. {PROMPT_DATASETS}&quot;},<br>            {&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: f&quot;Here are existing visualizations which you can use when building dashboard: {PROMPT_EXAMPLES_OF_VISUALIZATION}&quot;},<br>            {&quot;role&quot;: &quot;assistant&quot;, &quot;content&quot;: f&quot;Here are already existing dashboards to learn from: {PROMPT_EXAMPLES_OF_DASHBOARDS}&quot;},<br>            {<br>                &quot;role&quot;: &quot;user&quot;,<br>                &quot;content&quot;: [<br>                    {<br>                        &quot;type&quot;: &quot;text&quot;,<br>                        &quot;text&quot;: &quot;Map what is on the image to the described dashboard structure. Use existing visualizations and connect it to the newly created dashboard.&quot;,<br>                    },<br>                    {<br>                        &quot;type&quot;: &quot;image_url&quot;,<br>                        &quot;image_url&quot;: {&quot;url&quot;: f&quot;data:image/jpeg;base64,{base64_image}&quot;},<br>                    },<br>                ],<br>            }<br>        ], <br>        response_format = schema<br>    )</pre><p>Have you noticed that I’m sending the image twice? It isn’t ideal, but from my experience asking the AI to do many things at once often doesn’t lead to a good result. It yields much better results when I first create the visualisations and then build the workspace. These two calls have much different expected outputs (schemas) and prompts.</p><p>Next, you may also notice that, when building the dashboard in the second step, the AI looks for visualisations created in the first step. In theory, it could find some of the already existing visualizations more suitable than the newly created ones, but I haven’t observed this behaviour so far.</p><p>Here is the final flow from sketch to an interactive dashboard:</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FaksSs_n4Vvc%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DaksSs_n4Vvc&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FaksSs_n4Vvc%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/f9be151cdde3a5a72af27c84873e5672/href">https://medium.com/media/f9be151cdde3a5a72af27c84873e5672/href</a></iframe><h3>Conclusion</h3><p>Having the ability to transform sketched dashboards into their interactive twins greatly reduces the time to insight. Even if such a transformation should not be 100% correct and additional updates should be needed, it is an appreciated helper for anyone who builds analytics solutions.</p><p>Want to learn more about the GoodData analytics as code approach? Check out our other articles on <a href="https://medium.com/gooddata-developers">Medium</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4b9a1ba6e199" width="1" height="1" alt=""><hr><p><a href="https://medium.com/gooddata-developers/can-your-bi-tool-import-sketched-dashboards-4b9a1ba6e199">Can your BI tool import sketched dashboards?</a> was originally published in <a href="https://medium.com/gooddata-developers">GoodData Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Are AI Frameworks Production-ready?]]></title>
            <link>https://medium.com/gooddata-developers/are-ai-frameworks-production-ready-fef852a83d00?source=rss----e8ee419648ea---4</link>
            <guid isPermaLink="false">https://medium.com/p/fef852a83d00</guid>
            <category><![CDATA[developer]]></category>
            <category><![CDATA[ai-framework]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Štěpán Machovský]]></dc:creator>
            <pubDate>Tue, 25 Mar 2025 12:21:17 GMT</pubDate>
            <atom:updated>2025-03-26T09:07:03.150Z</atom:updated>
            <content:encoded><![CDATA[<h4>Everyone is implementing AI. Are AI frameworks ready to help us maintain it?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IoUuh-BQy1ox_cqGl5AbJQ.png" /></figure><p>Nearly everyone is trying to implement some sort of AI into their product. From online shopping, like Amazon’s <a href="https://www.aboutamazon.com/news/retail/how-to-use-amazon-rufus">Rufus</a>, to e-mail helpers like <a href="https://support.google.com/mail/answer/14199860?hl=en&amp;co=GENIE.Platform%3DAndroid">Gemini in Gmail</a>.</p><p>Not saying whether that’s a bad thing or not, that’s beyond the scope of this article. However, when even small businesses are trying to use Large Language Models (LLM), there unsurprisingly is a pretty significant demand for something, that would help you abstract everything that is related to the LLM and help you focus solely on the business logic of the application itself.</p><p>So it is only natural that I was posed a question, whether it would make sense to incorporate one of these “somethings”. For now, these are open-source libraries, which help you abstract technicalities and your use-case, but in the future, it might be something different altogether.</p><p>As a part of my exploration, I’ve tried four of these frameworks:</p><ol><li><a href="https://github.com/langchain-ai/langchain">LangChain</a></li><li><a href="https://github.com/run-llama/llama_index">LlamaIndex</a></li><li><a href="https://github.com/deepset-ai/haystack">Haystack</a></li><li><a href="https://github.com/huggingface/smolagents/tree/main">smolagents</a></li></ol><blockquote>Just as a small disclaimer, I am not interested in a simple “slap a chatbot on it” approach, which of course was implemented millions of times over and quite often only leads to distraught users. I am rather interested in more complex use-cases.</blockquote><h3>What are AI Frameworks?</h3><p>AI frameworks are essentially libraries that help you create LLM based applications. From chatbots to an Alexa-like application, which could potentially orchestrate your IoT at home through voice input.</p><p>In theory, they should help you focus on what you want to create, rather than creating, abstracting and orchestrating all of the “AI magic” — LLM endpoints, vector stores and all the other already existing (and upcoming) fun stuff you can do with LLMs.</p><p>I started with only a handful of libraries, which are the most well-known in the industry. My logic behind this is that if none of them worked, I wouldn’t have to bother trying the others. But to be extra safe, I’ve included <strong>smolagents</strong> as well, which focus solely on the agentic approach.</p><p>Before I give you a short rundown of each, let’s focus on why you would even consider using such a framework in the first place.</p><h3>Why would I want to use these frameworks?</h3><p>With these frameworks, you should be able to iterate much faster, because you would only be changing the way your application behaves, rather than focusing on the stuff happening behind the scenes.</p><p>Say, there is a new and emerging trend in AI. Some sort of an optimization of how we work with LLM (or vector databases). You could possibly only change one or two components, which are readily available from the framework, and thanks to the abstraction, you wouldn’t have to adjust everything around it.</p><p>Of course, for it to run optimally, you would have to tweak a thing or two, but it should help you keep your finger on the pulse of the AI trends. And don’t get me wrong, in smaller scale applications, this is true and I most definitely recommend using one of the frameworks for PoCs.</p><p>Now, let’s look at how they work in a bigger picture, when you want to incorporate them into your product. This can get quite complex pretty quickly.</p><h3>Are they what they claim to be in practice?</h3><p>From my experience? Not really.</p><p>If I were to give you an analogy of how it feels to work with these frameworks, it’s as if you are riding a bike with training wheels.</p><p>When you start riding a bike, you might fall a few times. Well, that’s what training wheels are for! Suddenly you don’t have to worry about the balance as much and things “just work”. The first few trips with training wheels are a bliss and you are getting bolder and bolder. Now you are not only riding around your neighborhood, but would also like to go somewhere else.</p><p>Now you might get into some trouble, but it’s still better to play it safe and leave your training wheels on. You know, getting stuck in a sewer cover might be annoying, but it doesn’t really happen every time you go out, right?</p><p>And after a little more while, you try to go and ride <a href="https://en.wikipedia.org/wiki/Single_track_(mountain_biking)">singletracks</a>. And oh boy do things go south from here. On the first sharper curve your training wheels force you out of the track and you are plunging head first into a tree. You come home and tell yourself that you will remove the training wheels, but oh no, they are bolted onto the bike, so you have two options. You either buy a new bike, or you meticulously remove the training wheels with a grinder and then paint over the mess you will inevitably create.</p><p>As you might’ve guessed by now, the frameworks are the training wheels in this analogy. At first, you need to chain prompts quickly. But later on (e.g., when debugging), you will need more granular control, and the abstraction stands in the way.</p><h3>Back to frameworks</h3><p>Now you might be thinking that I might be a little too harsh on the AI frameworks and to be frank I am not sure whether I am or not.</p><p>My initial experiments went pretty well, but once I started to test out more complex things it went downhill pretty fast.</p><p>In today’s fast-paced AI-world, where LLM endpoints seem to change every now and then, the only thing you really need is another source of unreliability. It can lock you out of those changes, because they might not be reflected in your framework of choice for quite some time.</p><p>Also, when AI is only a small part of a larger complex system with multiple micro-services (and components), you might want to interact over gRPC, to check whether some transactions are possible, etc… And for this you would have to customize the solution quite heavily.</p><p>Ok, now let’s look a little more into the details of these frameworks.</p><p>I feel comfortable making any judgments about LangChain and Haystack, and for the others I will just list some more high-level notes I made. I will definitely dig deeper in the upcoming articles.</p><h4><strong>LangChain</strong></h4><p><strong>Pros</strong>:</p><ul><li><em>Out of the bunch, it was definitely the easiest to iterate with.</em></li><li><em>Seemed pretty beginner-friendly.</em></li><li><em>It has the biggest and liveliest developer community.</em></li><li><em>Excellent, when you need to create a POC.</em></li></ul><p><strong>Cons</strong>:</p><ul><li>It<strong> changes your prompts.</strong></li><li>Not as customizable, as I’d like it to be.</li><li>It <strong>changes your prompts.</strong></li><li>Too much abstraction.</li></ul><p>Alright, so let’s break it down for LangChain. The pros are definitely there and there is a reason why so many people are using it. Credit, where credit is due.</p><p>However, you might’ve noticed that I’ve bolded and even repeated one of the cons. And it is because it quite drastically changes your prompt “behind the scenes”. From my perspective, this is unacceptable and goes hand-in-hand with the last con, that there is too much abstraction.</p><p>While it helps you keep your code relatively up-to-date with the current trends, you lose granular control on each of the steps and in the long run, you will lose a lot of your knowledge, because you won’t be using it. <em>Vibe-coding vibes anyone? :)</em></p><h4><strong>Haystack</strong></h4><p><strong>Pros</strong>:</p><ul><li><em>Highly customizable!</em></li><li><em>Lively community and a lot of examples of the usage.</em></li><li><em>Total control over every single step of the process.</em></li></ul><p><strong>Cons</strong>:</p><ul><li><em>Highly volatile.</em></li><li><em>Most of the examples of usage are already out-of-date.</em></li><li><em>While customizable, you have to customize.</em></li><li><em>Less connections than LangChain.</em></li></ul><p>If I really had to go with one of the frameworks I’ve used so far, it would definitely be Haystack. It may not be the most complete, when it comes to connections. It also makes you do a lot of custom coding, but that’s where Haystack shines.</p><p>When I was trying to create a small PoC for our use-case, I chose to use DuckDB as the vector store of choice. And no, I am not insane, don’t worry. I know it might not be the best vector store there is, but it is small, easy to implement and I’ve worked with it in the past.</p><p>When implementing the DuckDB for Haystack, I actually hit a wall, because it does not support it. However, I’ve used a custom component and just imported the LangChain’s connection and used it instead.</p><p>Haystack is not only rainbows and sunshine. When I tried to use some of the Haystack examples, most of them were out-of-date and used the older version. It also forces you to make nearly everything custom (when non-trivial). I can see a future, where we actually use Haystack, but I think we need to give it more time to stabilize.</p><h4><strong>LlamaIndex</strong></h4><p><strong>Pros:</strong></p><ul><li><em>Very good for RAG applications.</em></li><li><em>Excellent Data Connectors.</em></li><li><em>Well-suited for question answering.</em></li></ul><p><strong>Cons:</strong></p><ul><li><em>Seems more like a part of the AI stack, rather than the backbone.</em></li><li><em>Not as feature-rich as LangChain.</em></li><li><em>Middle of the road customizability.</em></li></ul><p>I don’t feel confident giving a judgment about LlamaIndex just yet. Please wait for one of the follow-up articles, where I will focus solely on LlamaIndex.</p><h4><strong>smolagents</strong></h4><p><strong>Pros</strong>:</p><ul><li><em>Very easy to create agents with.</em></li><li><em>Lightweight</em></li></ul><p><strong>Cons</strong>:</p><ul><li><em>Relies on third-parties for their connections (LangChain, </em><a href="https://github.com/BerriAI/litellm"><em>LiteLLM</em></a><em>..)</em></li><li><em>Not really the perfect fit for our use-case.</em></li></ul><p>While smolagents seem like a good library for a fun project, where I could explore the limitations of current agentic approach, I don’t feel like it is a good fit for our use-case, where we do a hybrid-approach, to ensure the absolute correctness of everything that is provided by the LLM (crunching the data, numbers and checking the responses).</p><p>In one of the upcoming articles, I’ll try to implement the whole architecture using this approach.</p><h3>Let’s give them a second chance</h3><p>Well, to be honest, my tests are a little dated, so I will try to make new ones and give these frameworks a new go.</p><p>This time I will create an article for each of the frameworks and try to implement the same structure, which I will show you in the next article. At the end, I will create the application without any of these frameworks and will give another final judgement, whether it makes sense for us to use them.</p><p>In the next article, I will show you a “complex” application, where I will be utilizing LangChain and then in subsequent ones I will try to recreate the same functionality with multiple other frameworks. If you have a framework that you would like me to try, let me know in the comments! :)</p><h3>So, should you use AI frameworks?</h3><p>This <strong>boils down to what you expect</strong>. If you want to do some POC, then go for it!</p><p>If you want to implement AI into your production, you should be a little more cautious of what you use, because while it can be worth it in the short term, it can definitely lock you out of some functionality in the long run.</p><p>If you are interested in our AI experiments, be sure to check out our <a href="https://medium.com/gooddata-developers">other articles on Medium</a>! :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fef852a83d00" width="1" height="1" alt=""><hr><p><a href="https://medium.com/gooddata-developers/are-ai-frameworks-production-ready-fef852a83d00">Are AI Frameworks Production-ready?</a> was originally published in <a href="https://medium.com/gooddata-developers">GoodData Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[From Sketch to Interactive Data: What Is Napkin Analytics All About?]]></title>
            <link>https://medium.com/gooddata-developers/from-sketch-to-interactive-data-what-is-napkin-analytics-all-about-d78024a43e6e?source=rss----e8ee419648ea---4</link>
            <guid isPermaLink="false">https://medium.com/p/d78024a43e6e</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[business-intelligence]]></category>
            <category><![CDATA[data]]></category>
            <category><![CDATA[visualization]]></category>
            <category><![CDATA[analytics]]></category>
            <dc:creator><![CDATA[Tomáš Muchka]]></dc:creator>
            <pubDate>Thu, 20 Mar 2025 12:34:41 GMT</pubDate>
            <atom:updated>2025-03-25T19:43:04.049Z</atom:updated>
            <content:encoded><![CDATA[<h4>In high-stakes business moments, you often grab the closest tools available. It can even be a napkin. You sketch your vision on it, but does your BI know what to do with such a sketch?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6tDEsxwgxFd8z-EAfU7lAw.png" /></figure><p>Imagine you’re in a high-stakes moment. Maybe you’re pitching your startup idea to investors, brainstorming a new product feature with your team, or solving a critical analytics problem during a hackathon. The concept in your head is crystal clear, but you need a way to illustrate it. With no laptop in sight, you grab the closest tool available — a napkin — and sketch your vision.</p><figure><img alt="Two hand-drawn ink sketches on napkins depict surreal alien-themed scenes. The left napkin features a UFO hovering above a city skyline at night, with a crescent moon and stars in the sky. A tentacled alien with a bulbous body appears to be emerging from or interacting with the spacecraft. The right napkin shows a large grinning alien creature with a round, expressive face, tentacle-like appendages, and a segmented body floating above the city. Smaller sun-like creatures surround it, e" src="https://cdn-images-1.medium.com/max/1024/0*HalQbeflFDQNvAA0.jpg" /><figcaption><em>Tim Burton, the famous film director, producer, screenwriter, and animator, sketched most of his ideas on napkins. He even published a </em><a href="https://www.timburton.com/merchandise/napkin-book"><em>napkin book</em></a><em>. Image from </em><a href="https://www.timburton.com/merchandise/napkin-book">timburton.com</a>.</figcaption></figure><p>Your colleague gets it. The idea is solid. But now what? He can take the napkin… and throw it in the trash, because he still needs to manually recreate the visualization from scratch.</p><p>That’s the problem — your BI tool doesn’t know what to do with your napkin sketch. Or does it?</p><p>What if your quick doodle could be recognized, understood, and transformed into an interactive chart? What if AI could bridge the gap between analog sketches and digital analytics?</p><p>Let’s find out.</p><h3>Welcome to the era of napkins analytics</h3><p>I’m currently part of the AI team of GoodData analytics platform, trying to excavate the innovation potential of the LLMs and generative AI in general.</p><p>From our experience every analytics project starts with a drawing board (be it real, or just virtual), where the business people and analysts agree on what to measure and how. This board is actually a manifest of how the analytics should behave. It would be a waste, if the analysts would need to go to the BI tool and manually re-create all the sketches and magnificent ideas.</p><p>That’s where napkin analytics comes into play. It t<strong>akes all your analytics sketches and translates them into interactive analytics objects.</strong></p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F3rN61MBTqXA%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D3rN61MBTqXA&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F3rN61MBTqXA%2Fhqdefault.jpg&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/8c4078fcc83e46d830c341e65f45c2e4/href">https://medium.com/media/8c4078fcc83e46d830c341e65f45c2e4/href</a></iframe><h3>How it works under the hood</h3><p>Napkin analytics consists of two major parts. In the first it recognizes what is on the image, and then this gets mapped into the existing semantic layer and recreated as an interactive analytics object.</p><h4>Recognizing the image content</h4><p>Image recognition is a well-known challenge with many algorithms such as <a href="https://en.wikipedia.org/wiki/Convolutional_neural_network">Convolutional Neural Networks</a>, <a href="https://en.wikipedia.org/wiki/You_Only_Look_Once">You Only Look Once</a>, or even non-deep learning algorithms like <a href="https://en.wikipedia.org/wiki/Support_vector_machine">Support vector machines</a>.</p><p>In our prototype we actually used an LLM (GPT-4o), which reliably identifies the major characteristics of the chart. The performance is not great, but good enough for the demonstration.</p><p>On the image we search for aspects such as chart title, chart type, axis names, series names…</p><p>Example call to OpenAI to get the image description:</p><pre>{<br><br>  &quot;role&quot;: &quot;user&quot;,<br>    &quot;content&quot;: [<br>      {<br>         &quot;type&quot;: &quot;text&quot;,<br>         &quot;text&quot;: &quot;Map what is on the image to the described visualization structure. Use the available fields. If not found, use the most similar fields.&quot;,<br>      },<br>      {<br>         &quot;type&quot;: &quot;image_url&quot;,<br>         &quot;image_url&quot;: {&quot;url&quot;: f&quot;data:image/jpeg;base64,{base64_image}&quot;},<br>      },<br>    ],<br>}</pre><h4>Creating interactive charts</h4><p>Now let’s get to the meat. First we need to map the extracted chart properties into existing analytics objects. Thankfully GoodData uses the concept of semantic layer, which greatly simplifies the work. All the fields with analytical meaning are available through a catalog, including their relationships.</p><p>With selected analytics fields and additional chart properties it should be quite easy to recreate the chart itself. But only in case the BI tool supports some sort of programmatic description of the chart that would be easy to grasp for the AI. GoodData has exactly such a human (and LLM) <a href="https://www.gooddata.com/docs/cloud/api-and-sdk/vs-code-extension/structures/">readable YAML representation</a> of all the analytics elements.</p><p>With all this knowledge, we used OpenAI’s <a href="https://platform.openai.com/docs/guides/structured-outputs">structured output</a> to force the LLM to return a valid chart object.</p><p>First few lines of the JSON schema to GoodData visualizations:</p><pre>{<br>    &quot;type&quot;: &quot;json_schema&quot;,<br>    &quot;json_schema&quot;: {<br>        &quot;name&quot;: &quot;datasets_schema&quot;,<br>        &quot;schema&quot;: {<br>            &quot;type&quot;: &quot;object&quot;,<br>            &quot;title&quot;: &quot;Visualisation&quot;,<br>            &quot;description&quot;: &quot;JSON schema for GoodData Analytics Visualisation&quot;,<br>            &quot;properties&quot;: {<br>                &quot;type&quot;: {<br>                    &quot;description&quot;: &quot;Type of visualisation.&quot;,<br>                    &quot;type&quot;: &quot;string&quot;,<br>                    &quot;enum&quot;: [<br>                        &quot;table&quot;, &quot;bar_chart&quot;, &quot;column_chart&quot;, &quot;line_chart&quot;,<br>                        &quot;area_chart&quot;, &quot;scatter_chart&quot;, &quot;bubble_chart&quot;, &quot;pie_chart&quot;,<br>                        &quot;donut_chart&quot;, &quot;treemap_chart&quot;, &quot;pyramid_chart&quot;, &quot;funnel_chart&quot;,<br>                        &quot;heatmap_chart&quot;, &quot;bullet_chart&quot;, &quot;waterfall_chart&quot;,<br>                        &quot;dependency_wheel_chart&quot;, &quot;sankey_chart&quot;, &quot;headline_chart&quot;,<br>                        &quot;combo_chart&quot;, &quot;geo_chart&quot;, &quot;repeater_chart&quot;<br>                    ]<br>                },</pre><p>And here is the outcome:</p><figure><img alt="A screenshot of a browser window displaying three stages of chart creation. On the left, a hand-drawn sketch of a line chart labeled “Number of sets” on the vertical axis and “Date (years)” on the horizontal axis. In the center, a code snippet defining the chart as a line chart using structured data. On the right, the final interactive chart titled “Number of Sets Over Time,” showing plotted data points with “Number of Sets” on the vertical axis and “Launch date — Year” on the horizontal axis." src="https://cdn-images-1.medium.com/max/1024/0*aqMqd7a-4WDSait2" /><figcaption><em>The “flow of a napkin”. From image to Yaml code and then finally to interactive chart.</em></figcaption></figure><blockquote>Have you spotted the suspicious spike in the interactive chart? Keep an eye out for the next article, where I’ll share techniques for handling such anomalies.</blockquote><h4>Tech Stack</h4><p>By now you might wonder why I haven’t mentioned any programming languages. And I didn’t mention them for a good reason — it doesn’t really matter.</p><p>Our platform is made with Developer Experience (DX) in mind, which also includes high flexibility of implementation. This is also part of the reason why GoodData is very well prepared for all the AI innovations to come. Be it visualization generation, or even helping you make decisions directly.</p><p>OK, code-philosophy aside, most of my code is done in Python (with our <a href="https://www.gooddata.com/docs/python-sdk/latest/">PySDK</a>) and it has less than 100 lines of code for the whole backend (not counting the prompts…). Another 150 lines of code to create a compatible front-end with canvas for drawing the visualizations and all the other bells and whistles.</p><h3>Conclusion</h3><p>To sum this up, the basic idea is quite simple. The hidden knowledge is, as usual with LLMs in the initial prompt, tons of examples and API-first analytics platform. Are you interested in knowing more about these? Then check my article <a href="https://medium.com/gooddata-developers/the-road-to-ai-generated-visualizations-923428728479">The Road to AI-generated Visualizations</a>.</p><h4><strong>Why does this matter?</strong></h4><p>The most important thing is that there is less friction between your idea and your visualization. With this, the sky is the limit, you don’t need a deep understanding of the model, you only need to know what you want to see.</p><h4><strong>What’s Next? From Sketches to Dashboards</strong></h4><p>Luckily visualizations are not the limits of the sketches in analytics. Next stop is dashboards, so buckle up for a new article that I plan to publish in the near future!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d78024a43e6e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/gooddata-developers/from-sketch-to-interactive-data-what-is-napkin-analytics-all-about-d78024a43e6e">From Sketch to Interactive Data: What Is Napkin Analytics All About?</a> was originally published in <a href="https://medium.com/gooddata-developers">GoodData Developers</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>