← Back to list

Integrating AI into Big Data Pipelines using Amazon Bedrock and OpenAI

Introduction

Sanskar Khatri in MeghGen · 2025-06-16 03:15 · 51 claps · 13.7 min read
Open on Medium ↗
Wiki topics: LLM · Large Language Models 🔧 · Data Engineering

Integrating AI into Big Data Pipelines using Amazon Bedrock and OpenAI

Introduction

In today’s data-driven world, organizations are constantly seeking ways to extract deeper insights from their ever-growing data lakes. Traditional data processing methods, while reliable, often fall short when it comes to understanding unstructured data or extracting nuanced patterns. This is where Artificial Intelligence, particularly Large Language Models (LLMs), enters the picture.

In this blog post, we will walk you through how we integrated AI capabilities into an AWS Data Lakehouse using Amazon Bedrock and OpenAI. This implementation has transformed our data pipeline, enabling us to process vast amounts of data and extract meaningful insights at scale.

Why use AI in pipelines?

Before diving into the technical implementation, let’s understand why integrating AI into data pipelines is becoming essential rather than optional.

Various Use Cases and Examples

AI integration in data pipelines opens doors to numerous possibilities:

  1. Document Processing: Automatically extract structured information from invoices, contracts, or reports.
  2. Sentiment Analysis: Gauge customer sentiment from support tickets, social media mentions, or reviews.
  3. Content Categorization: Organize large document repositories by automatically categorizing content.
  4. Data Enrichment: Enhance existing structured data with additional context extracted from unstructured sources.
  5. Anomaly Detection: Identify unusual patterns in data that might indicate fraud or operational issues.

Why Further Use Batch Processing?

While real-time AI processing is valuable, batch processing remains crucial for the following reasons:

  • Cost Efficiency: Processing data in batches enables efficient processing of large volumes of data at 50% less cost compared to on-demand pricing
  • Scale: Batch processing can handle enormous volumes of data without the constraints of real-time systems.

Benefits of Using LLMs for Processing on Time and Accuracy

LLMs have revolutionized how we interact with and process textual data:

  • Context Understanding: Unlike rule-based systems, LLMs understand context and nuance in language.
  • Flexibility: The same model can perform multiple tasks without task-specific training.
  • Continuous Improvement: As foundation models evolve, your pipelines benefit from improvements without architectural changes.
  • Reduced Time-to-Insight: Complex text analysis that once took weeks can now be completed in hours.

Step 1: Architecture and Requirements

Our implementation uses these key AWS components:

  • Storage: Amazon S3 for input/output files
  • Security: SSM & Secret Manager for configs and API keys
  • AI Platforms: Amazon Bedrock (Claude, Nova, etc) and OpenAI (GPT)
  • Orchestration: Managed Apache Airflow for workflow
  • Core Python Dependencies: boto3, openai, pandas, pyarrow

AWS SDK and OpenAI Authentication

When running within AWS environment, AWS services (including Bedrock) authenticate automatically via IAM roles, but to use OpenAI, an API key is required. This key can be stored in Secrets Manager and then retrieved in the python script.

Step 2: Preparing the Input Files for the Batch Jobs

The effectiveness of AI processing heavily depends on how you prepare your input data and engineer your prompts. Both Amazon Bedrock and OpenAI have specific requirements for batch processing that we need to accommodate.

Prompt Engineering for Data Processing

Effective prompt engineering is crucial for getting consistent, high-quality results from AI models in batch processing scenarios. Here are the key principles we follow:

Essential Components of Effective Prompts

When crafting prompts for data processing, ensure you include these critical elements:

  1. Task Specification Clearly mention the specific task that needs to be performed by the AI. Be explicit about what you want the model to do — whether it’s classification, extraction, summarization, or analysis.
  2. Input Data Description Describe the input data format and structure in detail. This helps the AI model understand what to expect and how to process the information correctly.
  3. Output Format Specification Clearly define what the output should look like, including the exact format and structure. This is especially important for structured data extraction tasks.
  4. Record Identification Always include a unique identifier for each record in your input data and instruct the AI to include this identifier in the output. This enables you to map the processed results back to the original input data accurately.

Here’s an example of a well-structured system prompt following these principles:

You are a helpful assistant specialized in advertisement data analysis.

You are provided with advertisement data that includes three fields:
- ad_id: This field contains a unique id used to identify the ad.
- ad_title: This field often indicates the brand behind the ad.
- ad_description: This field contains the advertisement copy, which may include both the brand name and details about the product.

Your task is to analyze each advertisement record and determine:

1. Brand(s):
   - Identify which brand is advertising (e.g., "Apple", "Tesla", "Call of Duty", "Amex").
   - Use the ad_title as a strong hint, but also scan the ad text for any additional brand names.
   - If the ad_title and the ad_description suggest different brands, include both in the output.
   - Synonym Handling: If you detect a brand that is commonly known by both an abbreviation and a full name (for example, "Amex" and "American Express"), include both variants in the output, regardless of which variant is mentioned.

2. Product(s):
   - Identify the specific product being advertised (e.g., "iPhone", "Model 3").
   - The product may be mentioned in the ad text.

Instructions:
- Use both the ad_title and ad_description to determine the brand(s) and product(s).
- If the ad_title clearly indicates one brand but the ad_description mentions another, list both.
- When multiple brands or products are mentioned, list all that apply.
- If the information is ambiguous, provide your best judgment with a brief explanation of the uncertainty.
- For brands with known synonyms: Always include both the common abbreviation and its full name (e.g., if you encounter "Amex" or "American Express," include both).
- The Output should have : ad_id, brands_mentioned, products_mentioned.

Please process each advertisement record independently and provide your analysis accordingly. The output response should have below json structure and response should have only the JSON content

{
    type: 'object',
    properties: {
        results: {
            type: 'array',
            items: {
                type: 'object',
                properties: {
                    ad_id: {
                        type: 'string'
                    },
                    brands_mentioned: {
                        type: 'array',
                        items: {
                            type: 'string'
                        }
                    },
                    products_mentioned: {
                        type: 'array',
                        items: {
                            type: 'string'
                        }
                    }
                }
            }
        }
    }
}

Here is the data:

Input File Formats

Both OpenAI and Amazon Bedrock require input files to be in JSONL (JSON Lines) format for batch processing. Each line in the file represents one call to the LLM model. However, the specific JSON structure varies between providers and models.

Amazon Bedrock Input Format

For Bedrock, you upload your JSONL file to an S3 location and reference this location in the batch job configuration. The JSON structure depends on the specific LLM model being used.

For Anthropic Models (Claude):

{
    "recordId": "ad_001_analysis", 
    "modelInput": {
        "anthropic_version": "bedrock-2023-05-31", 
        "max_tokens": 10000, 
        "messages": [
            {
                "role": "user", 
                "content": [
                    {
                        "type": "text", 
                        "text": "You are a helpful assistant specialized in advertisement data analysis...\n\nHere is the data:\n{\"ad_id\": \"ad_001\", \"ad_title\": \"Latest iPhone\", \"ad_description\": \"Get the newest iPhone with amazing features...\"}"
                    }
                ]
            }
        ]
    }
}

OpenAI Input Format

For OpenAI, you create the JSONL file and upload it using OpenAI’s Files API. You also need to mention the GPT model that you want to use for the batch job. The JSON structure follows OpenAI’s batch API format:

{
    "custom_id": "ad_001_analysis", 
    "method": "POST", 
    "url": "/v1/chat/completions", 
    "body": {
        "model": "gpt-4o-mini", 
        "temperature": 0.1, 
        "response_format": {
            "type": "json_object"
        }, 
        "messages": [
            {
                "role": "system", 
                "content": "You are a helpful assistant specialized in advertisement data analysis. You are provided with advertisement data..."
            }, 
            {
                "role": "user", 
                "content": "{\"ad_id\": \"ad_001\", \"ad_title\": \"Latest iPhone\", \"ad_description\": \"Get the newest iPhone with amazing features...\"}"
            }
        ]
    }
}

Important Considerations

JSON Response Handling: One key difference between the platforms is how they handle JSON output formatting:

  • OpenAI: Supports explicit JSON response formatting through the response_format parameter, ensuring structured output
  • Bedrock: Cannot be explicitly configured to return JSON format. The JSON output needs to be enforced using the prompt only.

File Processing Workflow: Here’s a typical workflow for preparing your input files:

  1. Data Preparation: Extract your source data and structure it according to your processing needs
  2. Prompt Integration: Combine your system prompt with individual data records
  3. JSONL Generation: Create platform-specific JSONL files with proper formatting
  4. File Upload:
  • For Bedrock: Upload to S3 and reference in job configuration
  • For OpenAI: Upload via Files API and get file ID for batch job creation
  1. Validation: Ensure all records have unique identifiers and proper formatting

This structured approach to input preparation ensures reliable, traceable batch processing results that can be efficiently mapped back to your original data sources.

Step 3: Creating the Batch Jobs

The batch job creation and monitoring can be handled using Python scripts that integrate seamlessly into your data pipeline architecture. These scripts can be defined as jobs within your orchestration framework, where upstream jobs handle the creation of source data and input files, while downstream jobs process the LLM output and consume the newly generated insights.

Creating Batch Inference Jobs on Amazon Bedrock

When creating a Bedrock batch job, you need to specify these critical parameters:

  • jobName: A unique identifier for your batch job. Must follow AWS naming conventions (alphanumeric characters and hyphens only)
  • roleArn: The Amazon Resource Name (ARN) of the service role with permissions to create and manage the job. This role needs access to read from your input S3 location, write to your output S3 location, and invoke the specified model. For detailed information on setting up the service role, see Create a custom service role for batch inference
  • modelId: The ID or ARN of the foundation model to use for inference (e.g., anthropic.claude-3-sonnet-20240229-v1:0 or amazon.nova-lite-v1:0)
  • inputDataConfig: Configuration specifying the S3 location containing your input JSONL files. Batch inference processes all JSONL files at the specified location, whether it’s a folder or a single file
  • outputDataConfig: Configuration specifying the S3 location where model responses will be written

Python Code for Creating Bedrock Batch Jobs

import boto3
from datetime import datetime

# Replace the region with your preferred AWS region where Bedrock is available
bedrock_client = boto3.client('bedrock', region_name='us-east-1')

# Replace with the model ID for the model of your choice
model_id = 'anthropic.claude-3-haiku-20240307-v1:0'

# Unique name for the batch job
job_name = f"batch-job-{datetime.now().strftime('%Y%m%d%H%M%S')}"

# Replace with your own s3 paths
input_files_s3_path = 's3://my-bucket/bedrock/batch-inference/input'  
output_files_s3_path = 's3://my-bucket/bedrock/batch-inference/output'

# Replace with your the appropriate Role ARN
role_arn = 'arn:aws:iam::xxxxxxxxxxxx:role/xxxxxx'

# Job Configuration
job_request = {
    "jobName": job_name,
    "modelId": model_id,  
    "inputDataConfig": {
        "s3InputDataConfig": {
            "s3Uri": input_files_s3_path
        }  
    },  
    "outputDataConfig": {  
        "s3OutputDataConfig": {  
            "s3Uri": output_files_s3_path
        }  
    },  
    "roleArn": role_arn
}  

# Create the batch job
response = bedrock_client.create_model_invocation_job(**job_request)  
job_arn = response['jobArn']

Creating Batch Jobs on OpenAI

OpenAI’s batch processing requires a different approach compared to Bedrock, as input files must be uploaded directly to OpenAI’s platform rather than referencing S3 locations.

Important OpenAI Configurations

For OpenAI batch jobs, you need:

  • OpenAI API Key: Authentication credentials for accessing OpenAI’s API services
  • Input File Upload: Unlike Bedrock, OpenAI requires you to upload the JSONL file directly to their platform using the Files API before creating the batch job. The uploaded file’s ID is necessary for creating the batch job.

Python Code for Creating OpenAI Batch Jobs

Here the input JSONL file is first being fetched from S3 and then being uploaded to OpenAI.

import boto3
from openai import OpenAI

# Replace with your own OpenAI API key
openai_api_key = 'xxxxxxxxxxxx'

openai_client = OpenAI(api_key=openai_api_key)  
s3_client = boto3.client('s3')

# Replace with your own s3 paths
input_files_s3_bucket_name = 'my-bucket' 
input_file_s3_file_key = 'bedrock/batch-inference/input'

s3_response = s3_client.get_object(  
    Bucket=input_files_s3_bucket_name,  
    Key=input_file_s3_file_key  
)
file_obj = s3_response['Body']

# Upload file to OpenAI  
batch_file = openai_client.files.create(  
    file=file_obj,  
    purpose='batch'
)
batch_file_id = batch_file.id

# Create the batch job  
batch_job = openai_client.batches.create(  
    input_file_id=batch_file_id,  
    endpoint='/v1/chat/completions',
    completion_window='24h'
)
job_id = batch_job.id

Step 4: Monitoring the Jobs

Monitoring batch jobs is absolutely critical in AI-powered data pipelines due to the long-running nature of these operations. Batch jobs can run anywhere from 1 hour to 24 hours depending on the size of the input data and the availability of the model resources. Since downstream jobs in your pipeline can only proceed once the batch jobs have completed successfully, monitoring ensures your entire data pipeline operates reliably and efficiently.

Programmatic Job Status Tracking

Both Amazon Bedrock and OpenAI provide APIs for tracking batch job status programmatically. The key identifiers used for monitoring are:

  • Amazon Bedrock: Job ARN (Amazon Resource Name) returned when creating the batch job
  • OpenAI: Job ID returned when creating the batch job

Python Code for Monitoring Bedrock Batch Jobs

import boto3
import time

def wait_for_job_completion(config, job_arn, poll_interval=30):  
    """  
    Wait for the batch inference job to complete.  
    :param job_arn: Job ARN to monitor
    :param poll_interval: Seconds between status checks
    """

    # Replace the region with your preferred AWS region where Bedrock is available
    bedrock = boto3.client('bedrock', region_name='us-east-1')  
    attempts = 0  
    while True:  
        try:  
            # Fetch the status of the Job
            status = bedrock.get_model_invocation_job(jobIdentifier=job_arn)['status']  
            logger.info(f'Job status for {job_arn} - {status}')  

            # Job has terminated
            if status.upper() in ['COMPLETED', 'FAILED', 'PARTIALLYCOMPLETED', 'STOPPED', 'EXPIRED']:  
                if status.upper() == 'COMPLETED' or status.upper() == 'PARTIALLYCOMPLETED':  
                    # Successful completion
                    return True  
                else:  
                    # Failed
                    return False  

            # Job is still in progress
            time.sleep(poll_interval)  
            attempts += 1  

        except Exception as e:  
            logger.error(f"Error checking job status for {job_arn}: {e}")  
            return False

Python Code for Monitoring OpenAI Batch Jobs

Here you can also return the output file ID from OpenAI along with the status of the Job.

import time
from openai import OpenAI

# Replace with your own OpenAI API key
openai_api_key = 'xxxxxxxxxxxx'

def wait_for_job_completion(config, job_id, poll_interval=30):  
    """  
    Wait for the batch job to complete.  
    :param job_id: Job ID to monitor    
    :param poll_interval: Seconds between status checks
    """    

    openai_client = OpenAI(api_key=openai_api_key)  
    attempts = 0  
    while True:  
        try:  
            # Fetch the status of the Job
            batch = openai_client.batches.retrieve(job_id)  
            status = batch.status  
            logger.info(f'Job status for {job_id} - {status}')  

            # Job has terminated
            if status.upper() in ['COMPLETED', 'FAILED', 'CANCELLED', 'EXPIRED']: 
                if status.upper() == 'COMPLETED':  
                    # Successful completion
                    return True, batch.output_file_id  
                else:  
                    # Failed
                    return False, ""  

            # Job is still in progress
            time.sleep(poll_interval)  
            attempts += 1  

        except Exception as e:  
            logger.error(f"Error checking job status for {job_id}: {e}")  
            return False, ""

Step 5: Storing the Output

Once your batch jobs complete successfully, the next critical step is processing and storing the LLM responses in a format that enables efficient downstream consumption. The raw output from different LLM providers comes in various formats and requires specific processing approaches to extract the valuable structured data.

Understanding LLM Response Formats

Each AI provider returns batch job results in different structures, and the actual AI responses are embedded within these provider-specific wrappers. Here’s what you need to know:

Amazon Bedrock: Returns responses as JSONL files stored in your specified S3 output location, with different response structures depending on the model used (Anthropic Claude vs Amazon Nova). Example response from Anthropic Claude 3 Haiku model -

{
  "modelInput": {
    "anthropic_version": "bedrock-2023-05-31",
    "max_tokens": 10000,
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "You are a helpful assistant specialized in advertisement data analysis...\n\nHere is the data:\n{\"ad_id\": \"ad_001\", \"ad_title\": \"Latest iPhone\", \"ad_description\": \"Get the newest iPhone with amazing features...\"}"
          }
        ]
      }
    ]
  },
  "modelOutput": {
    "id": "msg_bdrk_013B9W7zf1K9MGzSwx3SutVx",
    "type": "message",
    "role": "assistant",
    "model": "claude-3-haiku-20240307",
    "content": [
      {
        "type": "text",
        "text": "{\n    \"results\": [\n        {\n            \"ad_id\": \"37x6pFiEE1dn8ijWGQlXd8TMsgXQqHPuvyN01+kmuvY=\",\n            \"brands_mentioned\": [\n                \"Ketra\"\n            ],\n            \"products_mentioned\": [\n     ..."
      }
    ],
    "stop_reason": "end_turn",
    "stop_sequence": null,
    "usage": {
      "input_tokens": 1567,
      "output_tokens": 913
    }
  },
  "recordId": "CALL93C80A7"
}

OpenAI: Returns responses through their Files API, which you need to download and process. The responses follow OpenAI’s batch API response format. Example response from gpt-4o model -

{
  "id": "batch_req_6834baf17e4c819090334382d621642e",
  "custom_id": "CALL2DE64F76",
  "response": {
    "status_code": 200,
    "request_id": "d9de908c0e1919dfce2248f41fad6878",
    "body": {
      "id": "chatcmpl-BbWpSrBztrALVZLyh1sjJluxxraD8",
      "object": "chat.completion",
      "created": 1748284030,
      "model": "gpt-4o-2024-08-06",
      "choices": [
        {
          "index": 0,
          "message": {
            "role": "assistant",
            "content": "{\n  \"ad_id\": \"jp.konami.Yug...",
            "refusal": null,
            "annotations": []
          },
          "logprobs": null,
          "finish_reason": "stop"
        }
      ],
      "usage": {
        "prompt_tokens": 448,
        "completion_tokens": 71,
        "total_tokens": 519,
        "prompt_tokens_details": {
          "cached_tokens": 0,
          "audio_tokens": 0
        },
        "completion_tokens_details": {
          "reasoning_tokens": 0,
          "audio_tokens": 0,
          "accepted_prediction_tokens": 0,
          "rejected_prediction_tokens": 0
        }
      },
      "service_tier": "default",
      "system_fingerprint": "fp_07871e2ad8"
    }
  },
  "error": null
}

Processing Anthropic Claude Responses from Bedrock and upload parquet to S3

Anthropic models through Bedrock return responses in a nested structure where the actual AI output is contained within the modelOutput field:


import boto3
import json
import pandas as pd
from io import BytesIO

def process_jsonl_to_parquet_s3(batch_job_output_s3_path: str, parquet_s3_path: str, aws_region: str) -> None:
    """
    Processes multiple JSON Lines (.jsonl.out) files stored in an S3 bucket, extracts relevant content,
    converts the data to a DataFrame, and uploads it as Parquet files to another S3 location.

    @param batch_job_output_s3_path: S3 path to the folder containing JSONL output files. Example: 's3://bucket-name/input-prefix/'
    @param parquet_s3_path: S3 path where the resulting Parquet files will be stored. Example: 's3://bucket-name/output-prefix/'
    @param aws_region: AWS region where the S3 buckets are located. Default is 'us-east-1'.

    @return: None
    """

    # Parse bucket name and folder paths
    batch_job_output_bucket, batch_job_output_prefix = batch_job_output_s3_path.replace("s3://", "").split("/", 1)
    parquet_output_bucket, parquet_output_prefix = parquet_s3_path.replace("s3://", "").split("/", 1)

    # Initialize S3 client
    s3_client = boto3.client("s3", region_name=aws_region)

    # List all JSONL.out files in the batch job output S3 folder
    response = s3_client.list_objects_v2(Bucket=batch_job_output_bucket, Prefix=batch_job_output_prefix)
    if "Contents" not in response:
        logger.warning(f"No files found in {batch_job_output_s3_path}")
        return

    jsonl_files = [obj["Key"] for obj in response["Contents"] if obj["Key"].endswith(".jsonl.out")]

    # Process each file
    for file_key in jsonl_files:
        logger.info(f"Processing file: {file_key}")
        try:
            # Download the JSONL file
            obj = s3_client.get_object(Bucket=batch_job_output_bucket, Key=file_key)
            file_content = obj["Body"].read().decode("utf-8")

            # Store all results
            all_results = []

            # Process the JSONL content
            for line_number, line in enumerate(file_content.splitlines(), 1):
                try:
                    # Parse each line as JSON
                    data = json.loads(line)

                    # Extract the results from the model output
                    if 'modelOutput' not in data:
                        logger.warning(f"Line {line_number}: Missing modelOutput key")
                        continue

                    content_text = data['modelOutput']['content'][0]['text']

                    try:
                        results = json.loads(content_text)['results']
                        all_results.extend(results)
                    except json.JSONDecodeError:
                        logger.warning(f"Line {line_number}: Invalid JSON in model output.")

                except json.JSONDecodeError as e:
                    logger.error(f"Error parsing JSON at line {line_number}: {e}")
                    continue
                except Exception as e:
                    logger.error(f"Error processing line {line_number}: {e}")
                    continue

            if not all_results:
                logger.warning(f"No valid results found in {file_key}")
                continue

            # Convert to DataFrame
            df = pd.DataFrame(all_results)

            # Write to Parquet and upload back to S3
            output_file_key = f"{parquet_output_prefix}{file_key.split('/')[-1].replace('.jsonl.out', '.parquet')}"
            parquet_buffer = BytesIO()
            df.to_parquet(parquet_buffer,
                          index=False,
                          engine='pyarrow',
                          compression='snappy')

            # Upload the Parquet file to S3
            s3_client.put_object(Bucket=parquet_output_bucket,
                                 Key=output_file_key,
                                 Body=parquet_buffer.getvalue())
            logger.info(f"Successfully wrote {len(df)} records to s3://{parquet_output_bucket}/{output_file_key}")

        except Exception as e:
            logger.error(f"Error processing file {file_key}: {e}")
            continue

Processing OpenAI Responses

OpenAI batch responses need to be downloaded from their platform first, then processed:

import boto3
import json
import pandas as pd
from io import BytesIO
from openai import OpenAI

def process_jsonl_to_parquet_s3(file_id: str, parquet_s3_path: str, aws_region: str) -> None:
    """
    Processes a JSONL file stored in OpenAI's file API, extracts structured results from model responses,
    converts the data to a DataFrame, and uploads it as a Parquet file to a specified S3 path.

    @param file_id: The ID of the file stored in OpenAI's file system.
    @param parquet_s3_path: The full S3 path (bucket and prefix) where the resulting Parquet file will be stored. Example: 's3://my-bucket/output-prefix/'
    @param aws_region: AWS region where the S3 bucket is hosted.

    @return: None
    """

    # Parse bucket name and folder path
    parquet_output_bucket, parquet_output_prefix = parquet_s3_path.replace("s3://", "").split("/", 1)

    # Initialize OpenAI client (ensure api_key is set in the environment or defined)
    openai_client = OpenAI(api_key=openai_api_key)

    all_results = []

    # Fetch content from OpenAI file API
    file_response = openai_client.files.content(file_id).content

    for line_number, line in enumerate(file_response.splitlines(), 1):
        try:
            # Parse each line as JSON
            data = json.loads(line)

            # Extract the model's generated response text
            content_text = data['response']['body']['choices'][0]['message']['content']

            try:
                # Parse the content into result objects
                results = json.loads(content_text)['results']
                all_results.extend(results)
            except json.JSONDecodeError:
                logger.warning(f"Line {line_number}: Invalid JSON in model output.")

        except json.JSONDecodeError as e:
            logger.error(f"Error parsing JSON at line {line_number}: {e}")
            continue
        except Exception as e:
            logger.error(f"Error processing line {line_number}: {e}")
            continue

    # Initialize S3 client
    s3_client = boto3.client("s3", region_name=aws_region)

    # Convert to DataFrame
    df = pd.DataFrame(all_results)

    # Prepare Parquet output
    parquet_buffer = BytesIO()
    df.to_parquet(parquet_buffer,
                  index=False,
                  engine='pyarrow',
                  compression='snappy')

    # Define output file key
    output_file_key = f"{parquet_output_prefix}{file_id}.parquet"

    # Upload the Parquet file to S3
    s3_client.put_object(Bucket=parquet_output_bucket,
                         Key=output_file_key,
                         Body=parquet_buffer.getvalue())
    logger.info(f"Successfully wrote {len(df)} records to s3://{parquet_output_bucket}/{output_file_key}")

This structured approach to output processing ensures that your AI-enhanced data is immediately ready for consumption by downstream applications, analytics tools, and business intelligence platforms.

Step 6: Consume!

Now that we have our AI-processed data stored in an optimized format, we can use it in various downstream applications:

  1. Business Intelligence: Connect tools like QuickSight or Tableau directly to the processed data
  2. Machine Learning: Use the structured outputs as features for ML models
  3. Data APIs: Create APIs that serve the processed insights to applications
  4. Further Processing: Feed the results into additional data pipelines

Conclusion

Integrating AI capabilities into our data lakehouse architecture has transformed how we extract value from unstructured data. By leveraging Amazon Bedrock and OpenAI platforms, we’ve created a scalable, cost-effective batch processing system that can handle a wide variety of AI tasks.

Key benefits we’ve realized:

  1. Deeper Insights: We’re now extracting structured information from previously untapped unstructured data sources.
  2. Scalability: Our batch processing approach allows us to handle millions of documents cost-effectively.
  3. Flexibility: By supporting multiple AI providers, we can select the optimal model for each specific task.
  4. Future-Proof: As AI models improve, our pipeline architecture allows us to easily adopt newer, more capable models.

The integration of AI into data pipelines is no longer a futuristic concept — it’s a present-day requirement for organizations looking to maximize the value of their data assets. By following the approach outlined in this blog post, you can start realizing these benefits in your own data infrastructure.

What AI use cases are you considering for your data pipeline? I’d love to hear your thoughts in the comments below!

About the Author

[ADD AUTHOR BIO: Include a brief bio about yourself, your experience, and how readers can connect with you]


메타데이터
post_id
d8cee762ecc4
slug
integrating-ai-into-big-data-pipelines-using-amazon-bedrock-and-openai-d8cee762ecc4
url
https://medium.com/meghgen/integrating-ai-into-big-data-pipelines-using-amazon-bedrock-and-openai-d8cee762ecc4
canonical_url
https://medium.com/meghgen/integrating-ai-into-big-data-pipelines-using-amazon-bedrock-and-openai-d8cee762ecc4
author_url
https://medium.com/@sanskarapkhatri
status
ok
fetched_at
2026-06-10 08:17:25