Skip to content

feat: Agentic Query In Dashboard #32649

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

Abhishek-kumar-ISM
Copy link
Contributor

@Abhishek-kumar-ISM Abhishek-kumar-ISM commented Mar 13, 2025

SUMMARY

This PR is to add LLM agentic query search button at the top of the dashboard if the feature flag is set to True

SIP: #32650

I have added a search button at the top of the dashboard, allowing users to ask any query related to the dashboard, charts, anomalies, summaries, etc. When the button is clicked, it will perform an LLM agent query and return the query response in a modal.

By default, the search button will not be visible. To enable it, set the SHOW_DASHBOARD_AGENT_QUERY feature flag to True and update the OpenAI API key in superset_config. If you are using a locally hosted LLM, update the base URL instead.

DASHBOARD_AGENTIC_QUERY_CONFIG = {
    "model": "gpt-4o",
    "temperature": 0.8,
    "max_tokens": None,
    "timeout": None,
    "max_retries": 2,
    "api_key": "-",
    "base_url": "",
}

Use cases:

  1. Users can perform natural language query-based searches on the dashboard.
  2. Users can ask specific questions about any chart using natural language.
  3. Users can request a summary of a chart or the entire dashboard by asking the search button to do so.
  4. Feature Flag: Users have an option to make feature flag as False if they don't want to use the feature.

Screenshots

When Feature Flag is False i.e default i.e no change exactly like original superset

107 99 237 72_9000_superset_dashboard_1__native_filters_key=6maYj4nzD9I

When Feature Flag is True

ss5
ss3
ss4

CLI logs

ss1
ss2

@github-actions github-actions bot added api Related to the REST API packages labels Mar 13, 2025
@dosubot dosubot bot added change:frontend Requires changing the frontend dashboard Namespace | Anything related to the Dashboard labels Mar 13, 2025
Copy link

@korbit-ai korbit-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by Korbit AI

Korbit automatically attempts to detect when you fix issues in new commits.
Category Issue Fix Detected
Functionality Invalid JSON Extraction ▹ view
Functionality Unsafe List Extraction Logic ▹ view
Readability Misleading Function Name ▹ view
Security Missing Authorization Check for Chart Data Access ▹ view
Readability Unclear Variable Name ▹ view
Functionality Incomplete Tool List in Prompt Template ▹ view
Functionality Invalid timestamp truncation ▹ view
Readability Incorrect Return Type Annotation ▹ view
Readability Inconsistent Placeholder Values ▹ view
Functionality Invalid AI Model Name ▹ view
Files scanned
File Path Reviewed
superset-frontend/src/dashboard/actions/dashboardAgentQuery.js
superset/dashboards/dashboard_agentic_query/unix_timestamp_to_human_readable.py
superset/dashboards/dashboard_agentic_query/get_all_charts_name.py
superset/dashboards/dashboard_agentic_query/get_chart_data.py
superset/dashboards/dashboard_agentic_query/utils.py
superset-frontend/packages/superset-ui-core/src/utils/featureFlags.ts
docker/pythonpath_dev/superset_config.py
superset/dashboards/dashboard_agentic_query/dashboard_agentic_query.py
superset-frontend/src/dashboard/components/DashboardGrid.jsx
superset/dashboards/api.py

Explore our documentation to understand the languages and file types we support and the files we ignore.

Need a new review? Comment /korbit-review on this PR and I'll review your latest changes.

Korbit Guide: Usage and Customization

Interacting with Korbit

  • You can manually ask Korbit to review your PR using the /korbit-review command in a comment at the root of your PR.
  • You can ask Korbit to generate a new PR description using the /korbit-generate-pr-description command in any comment on your PR.
  • Too many Korbit comments? I can resolve all my comment threads if you use the /korbit-resolve command in any comment on your PR.
  • On any given comment that Korbit raises on your pull request, you can have a discussion with Korbit by replying to the comment.
  • Help train Korbit to improve your reviews by giving a 👍 or 👎 on the comments Korbit posts.

Customizing Korbit

  • Check out our docs on how you can make Korbit work best for you and your team.
  • Customize Korbit for your organization through the Korbit Console.

Feedback and Support

from superset.dashboards.dashboard_agentic_query.utils import refactor_input, extract_int_if_possible
from superset.charts.schemas import ChartEntityResponseSchema

def get_charts_list(dashboard_id) -> str:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect Return Type Annotation category Readability

Tell me more
What is the issue?

The return type annotation is incorrect. The function returns a list of dictionaries, not a string.

Why this matters

This incorrect type hint could mislead other developers and cause type checking tools to fail. The function actually returns a list of dictionaries containing chart information.

Suggested change ∙ Feature Preview

Correct the return type annotation to List[Dict[str, Union[str, int]]]:

from typing import List, Dict, Union

def get_charts_list(dashboard_id) -> List[Dict[str, Union[str, int]]]:

Report a problem with this comment

💬 Looking for more details? Reply to this comment to chat with Korbit.

Comment on lines +7 to +8
if(len(unix_timestamp) > 10):
unix_timestamp = unix_timestamp[:10]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid timestamp truncation category Functionality

Tell me more
What is the issue?

Arbitrary truncation of timestamps longer than 10 digits could lead to incorrect date conversions

Why this matters

This can result in wrong date calculations for timestamps after September 2001 (timestamps > 999999999) or for millisecond precision timestamps

Suggested change ∙ Feature Preview

Handle different timestamp precisions properly:

def convert_unix_to_human_readable(unix_timestamp):
    unix_timestamp = refactor_input(unix_timestamp)
    unix_timestamp = extract_int_if_possible(unix_timestamp)
    
    # Handle milliseconds precision
    if len(str(unix_timestamp)) > 10:
        unix_timestamp = int(unix_timestamp) / 1000
    else:
        unix_timestamp = int(unix_timestamp)

Report a problem with this comment

💬 Looking for more details? Reply to this comment to chat with Korbit.

Comment on lines +34 to +42
def extract_json_from_string(input_str):
start_open_curly = -1
end_close_curly = -1

for i in range(len(input_str)):
if(input_str[i] == '{' and start_open_curly == -1):
start_open_curly = i
elif(input_str[i] == '}'):
end_close_curly = i
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid JSON Extraction category Functionality

Tell me more
What is the issue?

The function doesn't handle nested JSON objects correctly and can return invalid JSON if the input contains multiple closing braces.

Why this matters

When processing complex dashboard data that contains nested JSON structures, this can lead to corrupted data being returned to the agentic query feature.

Suggested change ∙ Feature Preview
def extract_json_from_string(input_str):
    try:
        start = input_str.find('{')
        if start == -1:
            raise ValueError("No JSON object found")
        brace_count = 0
        for i in range(start, len(input_str)):
            if input_str[i] == '{':
                brace_count += 1
            elif input_str[i] == '}':
                brace_count -= 1
                if brace_count == 0:
                    # Validate the extracted JSON
                    result = input_str[start:i + 1]
                    json.loads(result)  # Will raise JSONDecodeError if invalid
                    return result
        raise ValueError("Unmatched braces")
    except json.JSONDecodeError:
        raise ValueError("Invalid JSON structure")

Report a problem with this comment

💬 Looking for more details? Reply to this comment to chat with Korbit.

Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [get_charts_list, get_chart_data]

This comment was marked as resolved.


DASHBOARD_AGENTIC_QUERY_CONFIG = current_app.config["DASHBOARD_AGENTIC_QUERY_CONFIG"]

mrkl_template_value = '''
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unclear Variable Name category Readability

Tell me more
What is the issue?

The variable name 'mrkl_template_value' is unclear and uses an unexplained abbreviation.

Why this matters

Cryptic variable names force readers to research or guess their meaning, slowing down code comprehension.

Suggested change ∙ Feature Preview
agent_prompt_template = '''

Report a problem with this comment

💬 Looking for more details? Reply to this comment to chat with Korbit.

Comment on lines +4 to +13
def correct_lst(input_str):
first_open = -1
last_close = -1
for i in range(len(input_str)):
if(input_str[i]=='[' and first_open==-1):
first_open = i
elif(input_str[i]==']'):
last_close = i

return input_str[first_open : last_close + 1]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsafe List Extraction Logic category Functionality

Tell me more
What is the issue?

The function fails to handle cases where no brackets are found (first_open or last_close remain -1) or where there are nested lists.

Why this matters

This can lead to IndexError exceptions or incorrect list extraction when processing nested data structures, which is critical for dashboard data processing.

Suggested change ∙ Feature Preview
def correct_lst(input_str):
    if not input_str:
        raise ValueError("Empty input string")
    first_open = input_str.find('[')
    if first_open == -1:
        raise ValueError("No opening bracket found")
    bracket_count = 0
    for i in range(first_open, len(input_str)):
        if input_str[i] == '[':
            bracket_count += 1
        elif input_str[i] == ']':
            bracket_count -= 1
            if bracket_count == 0:
                return input_str[first_open:i + 1]
    raise ValueError("Unmatched brackets")

Report a problem with this comment

💬 Looking for more details? Reply to this comment to chat with Korbit.

Comment on lines +24 to +26
def get_chart_data(chart_id) -> str:
chart_id = refactor_input(chart_id)
chart_id = extract_int_if_possible(chart_id)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing Authorization Check for Chart Data Access category Security

Tell me more
What is the issue?

The chart_id input validation relies on external utility functions without clear validation guarantees. The code doesn't explicitly verify if the user has permission to access the requested chart data.

Why this matters

Without proper authorization checks, users might be able to access chart data they shouldn't have permission to view. This could lead to data exposure vulnerabilities.

Suggested change ∙ Feature Preview
def get_chart_data(chart_id) -> str:
    # Add authorization check before processing
    if not current_user.has_access_to_chart(chart_id):
        raise PermissionError('User not authorized to access this chart')
    chart_id = refactor_input(chart_id)
    chart_id = extract_int_if_possible(chart_id)

Report a problem with this comment

💬 Looking for more details? Reply to this comment to chat with Korbit.

input_str = input_str[:-1]
return input_str

def extract_int_if_possible(input_str):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Misleading Function Name category Readability

Tell me more
What is the issue?

Misleading function name as it doesn't actually extract or convert to an integer

Why this matters

The function name suggests integer extraction but it only performs string splitting, leading to confusion for maintainers.

Suggested change ∙ Feature Preview
def extract_value_after_delimiter(input_str):

Report a problem with this comment

💬 Looking for more details? Reply to this comment to chat with Korbit.

Comment on lines +109 to +110
"api_key": "-",
"base_url": "",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent Placeholder Values category Readability

Tell me more
What is the issue?

Placeholder values for sensitive configuration use non-standard conventions.

Why this matters

Using '-' and '' as placeholders is inconsistent and may be confused with valid values. This makes it unclear whether these are intentionally empty or missing values.

Suggested change ∙ Feature Preview
    "api_key": None,  # Required: Set via environment variable
    "base_url": None,  # Required: Set via environment variable

Report a problem with this comment

💬 Looking for more details? Reply to this comment to chat with Korbit.

FEATURE_FLAGS = {"ALERT_REPORTS": True, "SHOW_DASHBOARD_AGENT_QUERY": False}

DASHBOARD_AGENTIC_QUERY_CONFIG = {
"model": "gpt-4o",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid AI Model Name category Functionality

Tell me more
What is the issue?

The model name 'gpt-4o' appears to be incorrect as it's not a standard OpenAI model name (should probably be 'gpt-4' or 'gpt-3.5-turbo')

Why this matters

Using an invalid model name will cause API calls to fail, preventing the Agentic Query feature from functioning

Suggested change ∙ Feature Preview

Correct the model name to a valid OpenAI model identifier:

"model": "gpt-4",  # or gpt-3.5-turbo depending on requirements

Report a problem with this comment

💬 Looking for more details? Reply to this comment to chat with Korbit.

@mistercrunch
Copy link
Member

mistercrunch commented Apr 9, 2025

I think this is an interesting proof of concept, but to me it raises more questions than it provides answers. Raising some of the questions here:

  • seems we're deciding to tightly couple with langchain/openai here, bringing new dependencies to the core project for something that's being a feature flag, is that the path forward? what about other LLMs? do we want to bundle langchain and commit to it as the bridge to LLMs? are there other toolkits we should consider before committing to langchain?
  • the design is a bit rough (injecting a prompt over the chart title), potentially could be many more LLM "touchpoints" in the app, what's the pattern to expose AI features in the UX? chat-vs-single-prompt approach? What's the better pattern to trigger and expose this particular feature?
  • sharing data/metadata with external providers: I can see how different environments may or may not be cool with sharing either metadata and/or data here. FF would have to come with heavy disclaimers. "THIS FEATURE FLAG WILL ALLOW USERS TO SHARE SENSITIVE DATA WITH THE PROVIDER ... "
  • the prompt is good, but there's no such thing as a "perfect prompt", so should the prompt be configurable too? maybe that'd need to be exposed as a configuration parameter as well?
  • wider context: do we need an env level prompt preamble "This instance of Superset is set up for CompanyX, we care a lot about ..."
  • no vector db: here we're passing some of the current context for these types of features in the pass we might need a vector db - do we need to know whether/how this fits in as a foundational part of the wider "LLM interaction framework" as it evolves?
  • async support, given some of these requests can take time, especially in a chain-of-thought of langgraph-type setting, should these features support/force async workloads through Celery? Seems they should be set up to run async in envs where Celery is set up...

My intuition around much potential AI features - given that there are a hundred ways to implement them depending on prefs / environment constraints - and that design patterns (both UX and backend-wise) are still evolving rapidly - is that they probably belong in extensions, at least for the time being.

@Abhishek-kumar-ISM
Copy link
Contributor Author

  1. Yes i have tightly coupled with langchain for agent creation but i can implement that agent without langchain i.e using for loop of thought, action, action input and observation, and move prompt template to environment ( I was waiting for some green signal to work on it ). Regarding tight coupling with openai - no its not coupled - one can run their custom llm in local and and configure 'base_url' in superset_config. I am only using openai library. Even i am not using open ai token while testing(i am using locally running llama3.1-8b)

  2. Mostly all llm configurations i have kept in superset_config, and i thought based on usecases we can have separate prompts in backend that's why i didn't kept prompt in env(if want i can do that)

  3. No, user need not to share data to external providers, i have kept 'base_url' in superset_config. If anyone runs their own llm maybe using TGI(then they can configure local llm path and no data will go outside). If user is using openai token then its external call.

  4. Yes prompt i also thought to move to env, this i can do.

  5. This maybe specific user can configure when we move prompt to env. But i didnt thought its benefit so i didn't did.

  6. Yes RAG approach in deciding which chart data call tool should be called can be there. Earlier i didn't added because it will start a new vector db docker component(I thought that if i add new container service, no one will see the PR) Currently its not there because i have left to llm to decide which chart data tool to call by using chart titles.

  7. Yes async support is already supported, i am showing superset provided progress bar till response is not fetched.

@Abhishek-kumar-ISM
Copy link
Contributor Author

@mistercrunch I have addressed your queries above,
Please have a look.

@Abhishek-kumar-ISM
Copy link
Contributor Author

@rusackas @mistercrunch
can you pls update the status ?

@mistercrunch
Copy link
Member

mistercrunch commented Jul 8, 2025

I'll give you my take, but curious to hear from others too. Here are a few structured-with-AI thoughts:


1. If in Superset, LLM config should be modular and first-class

What we need here goes way beyond a single config block in superset_config. The idea of one global LLM setup doesn't scale—different features may need different models, token limits, temps, prompt chains, etc. Think OpenAI for one use case, Anthropic or local Llama for another.

Feels like LLM configs should be treated more like database connections: centrally defined and then mapped to features. We'd need:

  • a registry of LLM configs (maybe via an admin UI or file),
  • a mapping system that assigns features to specific LLMs,
  • prompt templates that are overridable, probably Jinja-based, and customizable per org/use case.

2. Feature flags aren’t the right control plane

The current pattern of scattering feature flags for every AI experiment isn't going to scale. In theory, FFs were designed for progressive rollouts of “forever features,” but in practice they've already become a de facto config framework.

What we probably need is something more intentional: a centralized AI_FEATURE_CONFIG layer that lets you:

  • toggle individual AI-powered features,
  • assign them to specific LLM configs,
  • override/extend prompts,
  • control behavior more cleanly and scalably.

3. Superset already has a huge product surface

We have a lot of ground to cover already, and anything we land here we’re likely stuck supporting for the next decade. Every new AI integration adds cognitive and maintenance load in a fast-moving space with fragile dependencies and shifting UX norms.

That’s a real risk, especially when the ecosystem and design patterns are changing daily


4. The right place for this is the extension framework

This is exactly the kind of thing that should live in our (in-dev) extension framework. That would let us:

  • avoid overloading core Superset,
  • validate the modular design needed for the AI wave,
  • and create space for orgs to experiment and customize safely.

If Superset becomes more like VSCode—with rich, modular extensions—this type of feature becomes additive instead of burdensome.


5. The way I think about it: MCP is the path forward

MCP is the cleanest way to support AI in a scalable, deterministic way. Instead of trying to bolt LLMs into Superset, we focus on exposing a solid API that external agents can use.

The flow becomes:

“Hey LLM, I’m looking at the ‘Sales’ dashboard in Superset—what’s up with international orders in Canada?”

And the LLM uses MCP calls to introspect metadata, generate SQL, request charts, etc. Superset stays composable, auditable, and predictable—and the fuzzy magic stays outside the boundary.


6. A backend-up abstraction could work well

I’d be happy to help shape a backend-first approach - ideally through an extension:

  • A superset-extension-langchain could expose LLM configs and register new REST endpoints,
  • Extensions in the frontend can use those endpoints to build UX,
  • And we define the safe, pluggable backend pieces: RBAC, prompt templating, async support, etc.

That gives us a clean, layered system—one that avoids LangChain/LLM lock-in, and gives orgs real flexibility.


7. AI testing is still shaky

Worth calling out: we don’t have great patterns yet for testing these kinds of flows. Even small prompt tweaks or model changes can create huge diffs in output. The more this stuff ends up in core, the more brittle our test matrix becomes.


TL;DR: This is a super cool POC, and the use case is legit—but we’re not ready to enshrine this in core. Let’s use this as a proof point for the extension framework, build modular LLM abstractions, and anchor our long-term AI strategy around MCP. That path gives us power and flexibility, without locking us into early decisions we’ll regret.

@mistercrunch
Copy link
Member

Side note: given the SIP on MCP #33870, wondering if some of the use cases could be satisfied through MCP. Sure it's not the same experience with having a chart analysis fully done right-in-context in the UI with a nice popover embedded straight in the right place, but from my early testing of what superset-mcp (community contributed https://github.com/aptro/superset-mcp) can do already through our REST API, it feels like it should be able to fetch any chart metadata, run some queries, perform analysis, and tell you about it.

Anyhow, ultimately I think both RAG and MCP approaches are useful and valid, but MCP is so much more "our lane" to support.

@mistercrunch
Copy link
Member

Worked with gpt as to what a foundational, backend-first extension could look like. Somehow feels like tightly coupling with langgraph (at least at this time) is a reasonable approach, more future-proof than langchain from my understanding. Anyhow, I think there are some good ideas in here:

🧠 Superset Extension: superset-extension-langgraph

A modular LLM framework for Superset, built on LangGraph, exposing secure and configurable APIs that the Superset UI (or external agents) can call.


✅ 1. Choose LangGraph as the Orchestration Engine

  • LangGraph gives us:
    • explicit state handling and branching logic
    • retries, failure handling, async support
    • composability (define base graphs, let users override parts)
  • Still compatible with LangChain tools and models.
  • Better suited for long-lived, stateful, production-ready agent workflows.

📦 2. Define LLMConfiguration Objects

Analogous to a DB connection — stored in metadata DB, RBAC-controlled, API-exposed.

LLMConfiguration {
  id: UUID,
  name: str,
  provider: str,  # "openai", "anthropic", "llama-cpp", etc.
  base_url: Optional[str],
  model: str,
  temperature: float,
  max_tokens: int,
  headers: Dict[str, str],
  default_prompt_context: str,
  metadata: JSON,
  created_by / modified_by: FK,
  permissions: [perm_id]
}

Can be encrypted/stored securely like database credentials.


🔐 3. Define RBAC Permissions

Use Superset's existing RBAC model to control access:

  • can_use_llm_config[llm_config_name]
  • can_run_llm_graph[graph_name]
  • Optional: can_use_ai_on_dashboard, can_run_sql_via_ai, etc.

These permissions get attached to LLM config objects or graph identifiers. Admins decide which roles/users can use which LLM.


⚙️ 4. Support for Graph/Chain Configs

  • Define default LangGraph graphs (dashboard_summary_graph, chart_question_graph, etc.)
  • Let operators:
    • inject pre-prompts or override sections
    • disable/enable certain tools
    • alter text templates
  • Graphs can be registered via:
    • Python config (graph_registry.py)
    • YAML files (graph_config.yaml)
    • CLI/API in future

📡 5. New REST API Endpoints

Expose endpoints to:

  • list available graphs per user
  • execute a specific graph with a selected LLM config
  • return typed, schema-validated responses

Example: POST /api/v1/llm/execute

{
  "llm_config_id": "123",
  "graph": "dashboard_summary",
  "input": {
    "dashboard_id": 22,
    "question": "What’s happening with international orders in Canada?"
  }
}

Response

{
  "type": "dashboard_summary_response",
  "summary": "...",
  "related_charts": [123, 456],
  "sql_suggestions": [...]
}

Use pydantic + JSONSchema for validation and frontend integration.


🧩 6. Frontend Integration

  • Add generic callLLM(configId, graphName, inputPayload) helper
  • Register UI hooks per graph (e.g., “Summarize Dashboard” button)
  • Build a <LLMPanel> React component:
    • takes a graph ID
    • handles input/output schema
    • renders result, handles loading/errors

🔍 7. Observability & Debugging

Track and optionally store:

  • user ID, graph name, config used
  • input + output (opt-in redaction)
  • token usage, latency, retries
  • success/failure state

Store in llm_graph_invocations table or stream to logs/tracing tools (e.g., LangSmith, OpenTelemetry).


🔬 8. Local Dev & Testing

  • CLI tool: superset llm test-graph dashboard_summary --input '{...}'
  • Include mock data, unit test scaffolds
  • Allow extension devs to quickly test prompt variations + payload shape

💡 Summary

This architecture:

  • Keeps Superset modular, secure, and flexible
  • Supports multiple backends and AI providers
  • Scales to many AI-powered features across the app
  • Aligns with the long-term vision of Superset as a platform (like VSCode)
  • Complements Superset’s MCP strategy, treating LLMs as clients rather than dependencies

Want a working scaffold with stubs for the backend config, graph loader, and REST layer? Let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api Related to the REST API change:frontend Requires changing the frontend dashboard Namespace | Anything related to the Dashboard hold:sip! packages size/L
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants