diff --git a/providers/common/ai/docs/operators/llm_file_analysis.rst b/providers/common/ai/docs/operators/llm_file_analysis.rst index 8b2733ab05acb..690361e6edb62 100644 --- a/providers/common/ai/docs/operators/llm_file_analysis.rst +++ b/providers/common/ai/docs/operators/llm_file_analysis.rst @@ -111,6 +111,18 @@ returns the prompt string; file settings are passed to the decorator: :start-after: [START howto_decorator_llm_file_analysis] :end-before: [END howto_decorator_llm_file_analysis] +Human-in-the-Loop Approval +--------------------------- + +Set ``require_approval=True`` to pause the task after the analysis and wait +for a human reviewer to approve the output before it is returned. +When ``allow_modifications=True``, the reviewer can also edit the output: + +.. exampleinclude:: /../../ai/src/airflow/providers/common/ai/example_dags/example_llm_file_analysis.py + :language: python + :start-after: [START howto_operator_llm_file_analysis_approval] + :end-before: [END howto_operator_llm_file_analysis_approval] + Parameters ---------- diff --git a/providers/common/ai/src/airflow/providers/common/ai/decorators/llm_file_analysis.py b/providers/common/ai/src/airflow/providers/common/ai/decorators/llm_file_analysis.py index 1ad569d810535..e6ad0fcf2bd19 100644 --- a/providers/common/ai/src/airflow/providers/common/ai/decorators/llm_file_analysis.py +++ b/providers/common/ai/src/airflow/providers/common/ai/decorators/llm_file_analysis.py @@ -36,7 +36,18 @@ class _LLMFileAnalysisDecoratedOperator(DecoratedOperator, LLMFileAnalysisOperator): - """Wrap a callable that returns the prompt string for file analysis.""" + """ + Wraps a callable that returns a prompt for LLM-backed file analysis. + + The user function is called at execution time to produce the prompt string. + All other parameters (``llm_conn_id``, ``file_path``, ``multi_modal``, etc.) + are passed through to + :class:`~airflow.providers.common.ai.operators.llm_file_analysis.LLMFileAnalysisOperator`. + + :param python_callable: A reference to a callable that returns the prompt string. + :param op_args: Positional arguments for the callable. + :param op_kwargs: Keyword arguments for the callable. + """ template_fields: Sequence[str] = ( *DecoratedOperator.template_fields, diff --git a/providers/common/ai/src/airflow/providers/common/ai/example_dags/example_llm_file_analysis.py b/providers/common/ai/src/airflow/providers/common/ai/example_dags/example_llm_file_analysis.py index d1983d14846b6..27a368479e7ad 100644 --- a/providers/common/ai/src/airflow/providers/common/ai/example_dags/example_llm_file_analysis.py +++ b/providers/common/ai/src/airflow/providers/common/ai/example_dags/example_llm_file_analysis.py @@ -119,6 +119,28 @@ def example_llm_file_analysis_structured(): example_llm_file_analysis_structured() +# [START howto_operator_llm_file_analysis_approval] +@dag(tags=["example"]) +def example_llm_file_analysis_approval(): + from datetime import timedelta + + LLMFileAnalysisOperator( + task_id="analyze_contract_with_approval", + prompt="Summarize the key obligations and flag any unusual termination clauses.", + llm_conn_id="pydanticai_default", + file_path="s3://legal/contracts/vendor-agreement.pdf", + file_conn_id="aws_default", + require_approval=True, + approval_timeout=timedelta(hours=1), + allow_modifications=True, + ) + + +# [END howto_operator_llm_file_analysis_approval] + +example_llm_file_analysis_approval() + + # [START howto_decorator_llm_file_analysis] @dag(tags=["example"]) def example_llm_file_analysis_decorator(): diff --git a/providers/common/ai/src/airflow/providers/common/ai/operators/llm_file_analysis.py b/providers/common/ai/src/airflow/providers/common/ai/operators/llm_file_analysis.py index 8e919acf13b27..7b757ba22caf7 100644 --- a/providers/common/ai/src/airflow/providers/common/ai/operators/llm_file_analysis.py +++ b/providers/common/ai/src/airflow/providers/common/ai/operators/llm_file_analysis.py @@ -44,6 +44,12 @@ class LLMFileAnalysisOperator(LLMOperator): :param prompt: The analysis prompt for the LLM. :param llm_conn_id: Connection ID for the LLM provider. + :param model_id: Model identifier (e.g. ``"openai:gpt-5"``). + Overrides the model stored in the connection's extra field. + :param system_prompt: Additional instructions appended to the built-in + file-analysis system prompt. + :param agent_params: Additional keyword arguments passed to the pydantic-ai + ``Agent`` constructor (e.g. ``retries``, ``model_settings``, ``tools``). :param file_path: File or prefix to analyze. :param file_conn_id: Optional connection ID for the storage backend. Overrides a connection embedded in ``file_path``. @@ -62,6 +68,12 @@ class LLMFileAnalysisOperator(LLMOperator): while ``max_file_size_bytes`` and ``max_total_size_bytes`` limit bytes read from storage and ``max_text_chars`` limits the final prompt text budget. Default ``10``. + + Human-in-the-Loop approval parameters are inherited from + :class:`~airflow.providers.common.ai.operators.llm.LLMOperator` + (``require_approval``, ``approval_timeout``, ``allow_modifications``). + The task pauses after the file analysis and only returns the result once a + reviewer approves. """ template_fields: Sequence[str] = (