Aip 99 llmdataqualityoperator#62963
Conversation
|
Sample Task Log; |
|
@cetingokhan Converting to draft — this PR doesn't yet meet our Pull Request quality criteria.
See the linked criteria for how to fix each item, then mark the PR "Ready for review". This is not a rejection — just an invitation to bring the PR up to standard. No rush. Note: This comment was drafted by an AI-assisted triage tool and may contain mistakes. Once you have addressed the points above, an Apache Airflow maintainer — a real person — will take the next look at your PR. We use this two-stage triage process so that our maintainers' limited time is spent where it matters most: the conversation with you. |
|
Hi @kaxil and @gopidesupavan, I’ve reached a solid milestone with the LLMDataQualityOperator and wanted to share the current progress. Since LLM-based data quality is a broad topic, I’ve implemented several core features, but I’d love your feedback on whether we should keep this scope or simplify certain parts. Current Implementation Highlights: Foundation: The operator is built on top of the LLMOperator base. Performance Optimization: Instead of running individual queries for every rule, I’ve implemented batch execution. The logic intelligently groups rules by table, DQ type, and column type to minimize overhead. Approval-Ready Output: When dry_run=True, the operator writes a Markdown-formatted report to XCom. This makes the manual approval process much cleaner and more human-readable in the UI. Issue Detection (Optional): Users can opt to generate specific SQL queries to identify records that fail validation rules. Result Collection: If collect_unexpected is enabled, the operator executes the generated SQL for failed rules and lists the problematic records in XCom as JSON (governed by a configurable limit). Caching Mechanism: To avoid redundant LLM calls, I’ve implemented a way to store and reuse results in Airflow Variables when the quality rules remain unchanged. My Question: Looking forward to your guidance! |
|
Hi @kaxil and @gopidesupavan , Final ScopesPlan generation & caching
Built-in validators
Custom aggregate validators with register_validator
Custom row-level validators with register_validator(row_level=True)
dry_run mode
require_approval — HITL integration
Unexpected row collection
|
There was a problem hiding this comment.
Pull request overview
This PR adds an LLM-driven data quality feature set to the providers/common/ai provider: a new LLMDataQualityOperator (plus TaskFlow decorator), supporting models/utilities for plan generation/execution, schema introspection (DB + object storage via DataFusion), and documentation/examples.
Changes:
- Introduces
LLMDataQualityOperatorwith plan caching, optional HITL approval, and “unexpected rows” collection for failed validity checks. - Adds SQL DQ planning/execution utilities (
SQLDQPlanner), pydantic models for plans/results, and a validator registry with built-in validator factories (including row-level validation support). - Adds unit tests, example DAGs, and provider/docs wiring for the new operator/decorator.
Reviewed changes
Copilot reviewed 18 out of 19 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
uv.lock |
Updates locked dependency metadata (incl. oauth extra/authlib). |
providers/common/ai/src/airflow/providers/common/ai/operators/llm_data_quality.py |
Implements the new operator, caching, dry-run, HITL approval, and reporting. |
providers/common/ai/src/airflow/providers/common/ai/utils/dq_planner.py |
Adds LLM-based DQ plan generation and SQL execution (DB + DataFusion), including row-level handling and retry-on-invalid-SQL. |
providers/common/ai/src/airflow/providers/common/ai/utils/dq_validation.py |
Adds validator registry + built-in validator factories and LLM context injection. |
providers/common/ai/src/airflow/providers/common/ai/utils/dq_models.py |
Adds plan/result models (including row-level and unexpected-row result types). |
providers/common/ai/src/airflow/providers/common/ai/utils/db_schema.py |
Adds shared schema introspection utilities (DB + DataFusion). |
providers/common/ai/src/airflow/providers/common/ai/decorators/llm_data_quality.py |
Adds @task.llm_dq decorator wrapping the operator. |
providers/common/ai/src/airflow/providers/common/ai/example_dags/example_llm_data_quality.py |
Adds example DAGs demonstrating operator usage. |
providers/common/ai/src/airflow/providers/common/ai/get_provider_info.py |
Registers new operator/decorator docs and modules. |
providers/common/ai/provider.yaml |
Registers new operator/decorator docs and modules. |
providers/common/ai/src/airflow/providers/common/ai/mixins/approval.py |
Broadens execute_complete return type to support subclasses returning richer types. |
providers/common/ai/docs/operators/llm_data_quality.rst |
Adds operator documentation and examples. |
providers/common/ai/tests/unit/common/ai/... |
Adds unit tests for planner/models/validators/operator/decorator/schema utils. |
docs/spelling_wordlist.txt |
Adds spelling exceptions used by new docs/code. |
|
I like the overall direction here, but I wonder if the long-term authoring model should be more config-driven than Python-driven. Instead of requiring DAG authors to define many checks as Python validators/factories, could the LLM generate a simple JSON/YAML rule spec from the natural-language prompts, and then have the operator execute that spec with a deterministic engine? An example qualink https://github.com/gopidesupavan/qualink and https://gopidesupavan.github.io/qualink/guide/yaml-config/ Not sure similarly may be great expection may have something like that.. So that based on the prompts llm generates rules and we can simply execute on them? I do think a config-first layer for common checks may scale better than growing the Python validator API. Python validators could still remain as an escape hatch for advanced/custom cases. If you have any other tools may be please suggest something config driven much better for llms easily generate rules and we execute them.. WDYT? On side note at my org we started discussion to use |
Hi @gopidesupavan, Thanks for the feedback! I’ve spent some time thinking about the config-driven approach versus the current implementation. I’ve checked out Qualink as well—congratulations on that, using DataFusion is a very smart move for performance. Regarding the operator's direction, I actually started developing this by following your comment on the AIP-99 proposal, where you mentioned that users would express requirements in a prompt, and we would generate queries, translate them into internal rules, and execute them. That’s why I included the execution logic directly—to provide that seamless, all-in-one experience. In my previous LLM-based DQ projects, I’ve found that forcing an LLM to generate complex YAML or JSON schemas often leads to unexpected hallucinations. Moreover, while dealing with large-scale data, I had to rely on Spark Dataframes via Great Expectations (GEX) to handle the load, and as the rule set grows, it becomes increasingly difficult for the LLM to map natural language to the exact parameters of a specific tool's config. On the other hand, generating SQL is generally more deterministic and reliable for the LLM to handle consistently across different scales. However, if you have found a reliable way to solve this mapping challenge in your Org, I’d love to hear more about your methodology. If we can consistently avoid hallucinations while generating these rule specs, I’d be more than happy to re-evaluate this and integrate a more config-driven layer. I believe this operator should stay lean and accessible as a "first-step" tool. By focusing on SQL generation, we keep it engine-agnostic and reduce the barrier to entry for users who don't want to manage a secondary DQ platform immediately. If a user’s needs grow to an enterprise scale where they require complex rule management, they might be better served by a dedicated provider or a specialized engine. For this specific PR, my suggestion is to keep the initial version simple and focused on high-reliability SQL generation, aligning with the execution flow proposed in AIP-99. We could potentially add an "export" feature later to bridge it with tools like Qualink, SODA or GEX, but I think starting with a deterministic, SQL-first approach will provide a much more stable experience for Airflow users right out of the box, allowing Airflow users to meet most of their needs directly while enabling them to easily add minor custom check extensions for simpler requirements. I'm ready to pivot the development based on your final call. Since you are leading the direction here, I'll follow your guidance, please let me know how you’d like me to proceed, and I’ll be happy to implement it quickly. :) Regarding Qualink, I actually think it has great potential for big data scales; for instance, integrating DataFusion-Comet could be a game-changer for Spark environments, and I’d honestly love to support you on that front in the future! |
c2b2ac6 to
0094340
Compare
|
Hi @gopidesupavan and @kaxil, |
|
@cetingokhan sorry for the late reply , i will review this weekend and get back to you.. am currently bit busy with my day job.. |
eb3c376 to
3e87a61
Compare
|
Hey @cetingokhan we are getting new DQ provider #69575 lets wait for this to merge then this pr going to be easy ..llms can use that provider to generate rules . the dq provider comes with skills https://github.com/gopidesupavan/airflow/blob/1047525a4d87eb127af372461441381a95da3b48/providers/common/dataquality/src/airflow/providers/common/dataquality/skills/dataquality-rule-authoring/SKILL.md. so that the agent operator / llm operators should be able to use these skills and generate rules. |
Add
LLMDataQualityOperatortoapache-airflow-providers-common-aiThis PR introduces
LLMDataQualityOperator, a new operator that uses an LLM agent to plan and execute data-quality checks against a SQL database, with optional human-in-the-loop (HITL) approval before any SQL is executed.What is added
Core operator —
LLMDataQualityOperatorDQCheckInputdefinitions.DQReport; raisesDQCheckFailedErrorwhen any check fails.require_approval=True: the operator first runs the LLM planning phase (schema discovery + validator assignment, no SQL execution), defers for HITL review in the Airflow UI, and only executes SQL and applies validators after a human approves.Toolset layer
BaseDQToolset— abstract base for all DQ toolsets. Exposeslist_checksto the agent and declares anoutput_modeproperty with two values:"execute"— the toolset runs checks against a live data source and the operator gates on pass/fail viaDQReport."generate"— the toolset produces a configuration artifact (e.g. a Great Expectations suite JSON, a SODA YAML) that a downstream operator can feed to an external DQ framework. The operator returns the config string as its XCom value without performing pass/fail gating. This makes it straightforward to implementGEXDQToolset,SodaDQToolset, or any other framework-backed toolset by subclassingBaseDQToolsetand settingoutput_mode = "generate".SQLDQToolset— extendsBaseDQToolset(output_mode = "execute") withlist_validatorsandapply_validator. Supports scalar, row-level, and fixed (pre-assigned) validators.SQLToolset— gives the agent safe, read-only access to a SQL database viaDbApiHook. Provideslist_tables,get_schema,query, andcheck_querytools. SQL validation (sqlglot), row-limit truncation, and retryable-error handling (ModelRetry) are built in.DataFusionToolset— registers S3/object-store Parquet/CSV data as a queryable DataFusion table.Validator registry (
utils/dataquality/)ValidatorRegistry+@register_validatordecorator for defining reusable validator factories with LLM context hints.null_pct_check,row_count_check,duplicate_pct_check,between_check,exact_check.SELECT col FROM table, validator applied per-row withinvalid_pctgating).@task.llm_data_qualitydecoratorLLMDataQualityOperatorfor use in TaskFlow-style Dags.Documentation
@task.llm_data_qualitydecorator.Was generative AI tooling used to co-author this PR?
Generated-by: GitHub Copilot (Claude Sonnet 4.6) following the guidelines