Create AWS SageMaker Flow Definitions

The aws:sagemaker/flowDefinition:FlowDefinition resource, part of the Pulumi AWS provider, defines a SageMaker AI human review workflow: how tasks are routed to reviewers, when reviews are triggered, and where results are stored. This guide focuses on three capabilities: private and public workteam routing, public workforce pricing, and automatic activation from AWS AI services.

Flow definitions depend on SageMaker workteams, Human Task UI definitions, S3 buckets, and IAM roles. The examples are intentionally small. Combine them with your own workteam setup, UI templates, and storage infrastructure.

Route human review tasks to a private workteam

Most human-in-the-loop workflows start by defining how tasks are presented to your own team of reviewers and where results land.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.sagemaker.FlowDefinition("example", {
    flowDefinitionName: "example",
    roleArn: exampleAwsIamRole.arn,
    humanLoopConfig: {
        humanTaskUiArn: exampleAwsSagemakerHumanTaskUi.arn,
        taskAvailabilityLifetimeInSeconds: 1,
        taskCount: 1,
        taskDescription: "example",
        taskTitle: "example",
        workteamArn: exampleAwsSagemakerWorkteam.arn,
    },
    outputConfig: {
        s3OutputPath: `s3://${exampleAwsS3Bucket.bucket}/`,
    },
});
import pulumi
import pulumi_aws as aws

example = aws.sagemaker.FlowDefinition("example",
    flow_definition_name="example",
    role_arn=example_aws_iam_role["arn"],
    human_loop_config={
        "human_task_ui_arn": example_aws_sagemaker_human_task_ui["arn"],
        "task_availability_lifetime_in_seconds": 1,
        "task_count": 1,
        "task_description": "example",
        "task_title": "example",
        "workteam_arn": example_aws_sagemaker_workteam["arn"],
    },
    output_config={
        "s3_output_path": f"s3://{example_aws_s3_bucket['bucket']}/",
    })
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sagemaker"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sagemaker.NewFlowDefinition(ctx, "example", &sagemaker.FlowDefinitionArgs{
			FlowDefinitionName: pulumi.String("example"),
			RoleArn:            pulumi.Any(exampleAwsIamRole.Arn),
			HumanLoopConfig: &sagemaker.FlowDefinitionHumanLoopConfigArgs{
				HumanTaskUiArn:                    pulumi.Any(exampleAwsSagemakerHumanTaskUi.Arn),
				TaskAvailabilityLifetimeInSeconds: pulumi.Int(1),
				TaskCount:                         pulumi.Int(1),
				TaskDescription:                   pulumi.String("example"),
				TaskTitle:                         pulumi.String("example"),
				WorkteamArn:                       pulumi.Any(exampleAwsSagemakerWorkteam.Arn),
			},
			OutputConfig: &sagemaker.FlowDefinitionOutputConfigArgs{
				S3OutputPath: pulumi.Sprintf("s3://%v/", exampleAwsS3Bucket.Bucket),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Sagemaker.FlowDefinition("example", new()
    {
        FlowDefinitionName = "example",
        RoleArn = exampleAwsIamRole.Arn,
        HumanLoopConfig = new Aws.Sagemaker.Inputs.FlowDefinitionHumanLoopConfigArgs
        {
            HumanTaskUiArn = exampleAwsSagemakerHumanTaskUi.Arn,
            TaskAvailabilityLifetimeInSeconds = 1,
            TaskCount = 1,
            TaskDescription = "example",
            TaskTitle = "example",
            WorkteamArn = exampleAwsSagemakerWorkteam.Arn,
        },
        OutputConfig = new Aws.Sagemaker.Inputs.FlowDefinitionOutputConfigArgs
        {
            S3OutputPath = $"s3://{exampleAwsS3Bucket.Bucket}/",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sagemaker.FlowDefinition;
import com.pulumi.aws.sagemaker.FlowDefinitionArgs;
import com.pulumi.aws.sagemaker.inputs.FlowDefinitionHumanLoopConfigArgs;
import com.pulumi.aws.sagemaker.inputs.FlowDefinitionOutputConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new FlowDefinition("example", FlowDefinitionArgs.builder()
            .flowDefinitionName("example")
            .roleArn(exampleAwsIamRole.arn())
            .humanLoopConfig(FlowDefinitionHumanLoopConfigArgs.builder()
                .humanTaskUiArn(exampleAwsSagemakerHumanTaskUi.arn())
                .taskAvailabilityLifetimeInSeconds(1)
                .taskCount(1)
                .taskDescription("example")
                .taskTitle("example")
                .workteamArn(exampleAwsSagemakerWorkteam.arn())
                .build())
            .outputConfig(FlowDefinitionOutputConfigArgs.builder()
                .s3OutputPath(String.format("s3://%s/", exampleAwsS3Bucket.bucket()))
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:sagemaker:FlowDefinition
    properties:
      flowDefinitionName: example
      roleArn: ${exampleAwsIamRole.arn}
      humanLoopConfig:
        humanTaskUiArn: ${exampleAwsSagemakerHumanTaskUi.arn}
        taskAvailabilityLifetimeInSeconds: 1
        taskCount: 1
        taskDescription: example
        taskTitle: example
        workteamArn: ${exampleAwsSagemakerWorkteam.arn}
      outputConfig:
        s3OutputPath: s3://${exampleAwsS3Bucket.bucket}/

The humanLoopConfig block defines the review workflow. The workteamArn points to your private team, humanTaskUiArn specifies the review interface, and taskCount sets how many reviewers see each item. Results flow to the S3 path specified in outputConfig. The roleArn grants SageMaker permission to write results and invoke services on your behalf.

Use Amazon Mechanical Turk for public crowdsourcing

When you need scale beyond your internal team, Amazon’s public workforce provides access to thousands of workers.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.sagemaker.FlowDefinition("example", {
    flowDefinitionName: "example",
    roleArn: exampleAwsIamRole.arn,
    humanLoopConfig: {
        humanTaskUiArn: exampleAwsSagemakerHumanTaskUi.arn,
        taskAvailabilityLifetimeInSeconds: 1,
        taskCount: 1,
        taskDescription: "example",
        taskTitle: "example",
        workteamArn: `arn:aws:sagemaker:${current.region}:394669845002:workteam/public-crowd/default`,
        publicWorkforceTaskPrice: {
            amountInUsd: {
                cents: 1,
                tenthFractionsOfACent: 2,
            },
        },
    },
    outputConfig: {
        s3OutputPath: `s3://${exampleAwsS3Bucket.bucket}/`,
    },
});
import pulumi
import pulumi_aws as aws

example = aws.sagemaker.FlowDefinition("example",
    flow_definition_name="example",
    role_arn=example_aws_iam_role["arn"],
    human_loop_config={
        "human_task_ui_arn": example_aws_sagemaker_human_task_ui["arn"],
        "task_availability_lifetime_in_seconds": 1,
        "task_count": 1,
        "task_description": "example",
        "task_title": "example",
        "workteam_arn": f"arn:aws:sagemaker:{current['region']}:394669845002:workteam/public-crowd/default",
        "public_workforce_task_price": {
            "amount_in_usd": {
                "cents": 1,
                "tenth_fractions_of_a_cent": 2,
            },
        },
    },
    output_config={
        "s3_output_path": f"s3://{example_aws_s3_bucket['bucket']}/",
    })
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sagemaker"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sagemaker.NewFlowDefinition(ctx, "example", &sagemaker.FlowDefinitionArgs{
			FlowDefinitionName: pulumi.String("example"),
			RoleArn:            pulumi.Any(exampleAwsIamRole.Arn),
			HumanLoopConfig: &sagemaker.FlowDefinitionHumanLoopConfigArgs{
				HumanTaskUiArn:                    pulumi.Any(exampleAwsSagemakerHumanTaskUi.Arn),
				TaskAvailabilityLifetimeInSeconds: pulumi.Int(1),
				TaskCount:                         pulumi.Int(1),
				TaskDescription:                   pulumi.String("example"),
				TaskTitle:                         pulumi.String("example"),
				WorkteamArn:                       pulumi.Sprintf("arn:aws:sagemaker:%v:394669845002:workteam/public-crowd/default", current.Region),
				PublicWorkforceTaskPrice: &sagemaker.FlowDefinitionHumanLoopConfigPublicWorkforceTaskPriceArgs{
					AmountInUsd: &sagemaker.FlowDefinitionHumanLoopConfigPublicWorkforceTaskPriceAmountInUsdArgs{
						Cents:                 pulumi.Int(1),
						TenthFractionsOfACent: pulumi.Int(2),
					},
				},
			},
			OutputConfig: &sagemaker.FlowDefinitionOutputConfigArgs{
				S3OutputPath: pulumi.Sprintf("s3://%v/", exampleAwsS3Bucket.Bucket),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Sagemaker.FlowDefinition("example", new()
    {
        FlowDefinitionName = "example",
        RoleArn = exampleAwsIamRole.Arn,
        HumanLoopConfig = new Aws.Sagemaker.Inputs.FlowDefinitionHumanLoopConfigArgs
        {
            HumanTaskUiArn = exampleAwsSagemakerHumanTaskUi.Arn,
            TaskAvailabilityLifetimeInSeconds = 1,
            TaskCount = 1,
            TaskDescription = "example",
            TaskTitle = "example",
            WorkteamArn = $"arn:aws:sagemaker:{current.Region}:394669845002:workteam/public-crowd/default",
            PublicWorkforceTaskPrice = new Aws.Sagemaker.Inputs.FlowDefinitionHumanLoopConfigPublicWorkforceTaskPriceArgs
            {
                AmountInUsd = new Aws.Sagemaker.Inputs.FlowDefinitionHumanLoopConfigPublicWorkforceTaskPriceAmountInUsdArgs
                {
                    Cents = 1,
                    TenthFractionsOfACent = 2,
                },
            },
        },
        OutputConfig = new Aws.Sagemaker.Inputs.FlowDefinitionOutputConfigArgs
        {
            S3OutputPath = $"s3://{exampleAwsS3Bucket.Bucket}/",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sagemaker.FlowDefinition;
import com.pulumi.aws.sagemaker.FlowDefinitionArgs;
import com.pulumi.aws.sagemaker.inputs.FlowDefinitionHumanLoopConfigArgs;
import com.pulumi.aws.sagemaker.inputs.FlowDefinitionHumanLoopConfigPublicWorkforceTaskPriceArgs;
import com.pulumi.aws.sagemaker.inputs.FlowDefinitionHumanLoopConfigPublicWorkforceTaskPriceAmountInUsdArgs;
import com.pulumi.aws.sagemaker.inputs.FlowDefinitionOutputConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new FlowDefinition("example", FlowDefinitionArgs.builder()
            .flowDefinitionName("example")
            .roleArn(exampleAwsIamRole.arn())
            .humanLoopConfig(FlowDefinitionHumanLoopConfigArgs.builder()
                .humanTaskUiArn(exampleAwsSagemakerHumanTaskUi.arn())
                .taskAvailabilityLifetimeInSeconds(1)
                .taskCount(1)
                .taskDescription("example")
                .taskTitle("example")
                .workteamArn(String.format("arn:aws:sagemaker:%s:394669845002:workteam/public-crowd/default", current.region()))
                .publicWorkforceTaskPrice(FlowDefinitionHumanLoopConfigPublicWorkforceTaskPriceArgs.builder()
                    .amountInUsd(FlowDefinitionHumanLoopConfigPublicWorkforceTaskPriceAmountInUsdArgs.builder()
                        .cents(1)
                        .tenthFractionsOfACent(2)
                        .build())
                    .build())
                .build())
            .outputConfig(FlowDefinitionOutputConfigArgs.builder()
                .s3OutputPath(String.format("s3://%s/", exampleAwsS3Bucket.bucket()))
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:sagemaker:FlowDefinition
    properties:
      flowDefinitionName: example
      roleArn: ${exampleAwsIamRole.arn}
      humanLoopConfig:
        humanTaskUiArn: ${exampleAwsSagemakerHumanTaskUi.arn}
        taskAvailabilityLifetimeInSeconds: 1
        taskCount: 1
        taskDescription: example
        taskTitle: example
        workteamArn: arn:aws:sagemaker:${current.region}:394669845002:workteam/public-crowd/default
        publicWorkforceTaskPrice:
          amountInUsd:
            cents: 1
            tenthFractionsOfACent: 2
      outputConfig:
        s3OutputPath: s3://${exampleAwsS3Bucket.bucket}/

The workteamArn uses AWS’s managed public workforce endpoint. The publicWorkforceTaskPrice block sets compensation: cents for whole cents, tenthFractionsOfACent for fractional amounts (e.g., cents: 1, tenthFractionsOfACent: 2 equals $0.012 per task). This pricing structure only applies to public workforce tasks.

Trigger reviews automatically from AWS AI services

SageMaker can route predictions from Textract or Rekognition to human reviewers when confidence is low or sampling conditions are met.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.sagemaker.FlowDefinition("example", {
    flowDefinitionName: "example",
    roleArn: exampleAwsIamRole.arn,
    humanLoopConfig: {
        humanTaskUiArn: exampleAwsSagemakerHumanTaskUi.arn,
        taskAvailabilityLifetimeInSeconds: 1,
        taskCount: 1,
        taskDescription: "example",
        taskTitle: "example",
        workteamArn: exampleAwsSagemakerWorkteam.arn,
    },
    humanLoopRequestSource: {
        awsManagedHumanLoopRequestSource: "AWS/Textract/AnalyzeDocument/Forms/V1",
    },
    humanLoopActivationConfig: {
        humanLoopActivationConditionsConfig: {
            humanLoopActivationConditions: `        {
\\t\\t\\t\\"Conditions\\": [
\\t\\t\\t  {
\\t\\t\\t\\t\\"ConditionType\\": \\"Sampling\\",
\\t\\t\\t\\t\\"ConditionParameters\\": {
\\t\\t\\t\\t  \\"RandomSamplingPercentage\\": 5
\\t\\t\\t\\t}
\\t\\t\\t  }
\\t\\t\\t]
\\t\\t}
`,
        },
    },
    outputConfig: {
        s3OutputPath: `s3://${exampleAwsS3Bucket.bucket}/`,
    },
});
import pulumi
import pulumi_aws as aws

example = aws.sagemaker.FlowDefinition("example",
    flow_definition_name="example",
    role_arn=example_aws_iam_role["arn"],
    human_loop_config={
        "human_task_ui_arn": example_aws_sagemaker_human_task_ui["arn"],
        "task_availability_lifetime_in_seconds": 1,
        "task_count": 1,
        "task_description": "example",
        "task_title": "example",
        "workteam_arn": example_aws_sagemaker_workteam["arn"],
    },
    human_loop_request_source={
        "aws_managed_human_loop_request_source": "AWS/Textract/AnalyzeDocument/Forms/V1",
    },
    human_loop_activation_config={
        "human_loop_activation_conditions_config": {
            "human_loop_activation_conditions": """        {
\t\t\t\"Conditions\": [
\t\t\t  {
\t\t\t\t\"ConditionType\": \"Sampling\",
\t\t\t\t\"ConditionParameters\": {
\t\t\t\t  \"RandomSamplingPercentage\": 5
\t\t\t\t}
\t\t\t  }
\t\t\t]
\t\t}
""",
        },
    },
    output_config={
        "s3_output_path": f"s3://{example_aws_s3_bucket['bucket']}/",
    })
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/sagemaker"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := sagemaker.NewFlowDefinition(ctx, "example", &sagemaker.FlowDefinitionArgs{
			FlowDefinitionName: pulumi.String("example"),
			RoleArn:            pulumi.Any(exampleAwsIamRole.Arn),
			HumanLoopConfig: &sagemaker.FlowDefinitionHumanLoopConfigArgs{
				HumanTaskUiArn:                    pulumi.Any(exampleAwsSagemakerHumanTaskUi.Arn),
				TaskAvailabilityLifetimeInSeconds: pulumi.Int(1),
				TaskCount:                         pulumi.Int(1),
				TaskDescription:                   pulumi.String("example"),
				TaskTitle:                         pulumi.String("example"),
				WorkteamArn:                       pulumi.Any(exampleAwsSagemakerWorkteam.Arn),
			},
			HumanLoopRequestSource: &sagemaker.FlowDefinitionHumanLoopRequestSourceArgs{
				AwsManagedHumanLoopRequestSource: pulumi.String("AWS/Textract/AnalyzeDocument/Forms/V1"),
			},
			HumanLoopActivationConfig: &sagemaker.FlowDefinitionHumanLoopActivationConfigArgs{
				HumanLoopActivationConditionsConfig: &sagemaker.FlowDefinitionHumanLoopActivationConfigHumanLoopActivationConditionsConfigArgs{
					HumanLoopActivationConditions: pulumi.String(`        {
\t\t\t\"Conditions\": [
\t\t\t  {
\t\t\t\t\"ConditionType\": \"Sampling\",
\t\t\t\t\"ConditionParameters\": {
\t\t\t\t  \"RandomSamplingPercentage\": 5
\t\t\t\t}
\t\t\t  }
\t\t\t]
\t\t}
`),
				},
			},
			OutputConfig: &sagemaker.FlowDefinitionOutputConfigArgs{
				S3OutputPath: pulumi.Sprintf("s3://%v/", exampleAwsS3Bucket.Bucket),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Sagemaker.FlowDefinition("example", new()
    {
        FlowDefinitionName = "example",
        RoleArn = exampleAwsIamRole.Arn,
        HumanLoopConfig = new Aws.Sagemaker.Inputs.FlowDefinitionHumanLoopConfigArgs
        {
            HumanTaskUiArn = exampleAwsSagemakerHumanTaskUi.Arn,
            TaskAvailabilityLifetimeInSeconds = 1,
            TaskCount = 1,
            TaskDescription = "example",
            TaskTitle = "example",
            WorkteamArn = exampleAwsSagemakerWorkteam.Arn,
        },
        HumanLoopRequestSource = new Aws.Sagemaker.Inputs.FlowDefinitionHumanLoopRequestSourceArgs
        {
            AwsManagedHumanLoopRequestSource = "AWS/Textract/AnalyzeDocument/Forms/V1",
        },
        HumanLoopActivationConfig = new Aws.Sagemaker.Inputs.FlowDefinitionHumanLoopActivationConfigArgs
        {
            HumanLoopActivationConditionsConfig = new Aws.Sagemaker.Inputs.FlowDefinitionHumanLoopActivationConfigHumanLoopActivationConditionsConfigArgs
            {
                HumanLoopActivationConditions = @"        {
\t\t\t\""Conditions\"": [
\t\t\t  {
\t\t\t\t\""ConditionType\"": \""Sampling\"",
\t\t\t\t\""ConditionParameters\"": {
\t\t\t\t  \""RandomSamplingPercentage\"": 5
\t\t\t\t}
\t\t\t  }
\t\t\t]
\t\t}
",
            },
        },
        OutputConfig = new Aws.Sagemaker.Inputs.FlowDefinitionOutputConfigArgs
        {
            S3OutputPath = $"s3://{exampleAwsS3Bucket.Bucket}/",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.sagemaker.FlowDefinition;
import com.pulumi.aws.sagemaker.FlowDefinitionArgs;
import com.pulumi.aws.sagemaker.inputs.FlowDefinitionHumanLoopConfigArgs;
import com.pulumi.aws.sagemaker.inputs.FlowDefinitionHumanLoopRequestSourceArgs;
import com.pulumi.aws.sagemaker.inputs.FlowDefinitionHumanLoopActivationConfigArgs;
import com.pulumi.aws.sagemaker.inputs.FlowDefinitionHumanLoopActivationConfigHumanLoopActivationConditionsConfigArgs;
import com.pulumi.aws.sagemaker.inputs.FlowDefinitionOutputConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new FlowDefinition("example", FlowDefinitionArgs.builder()
            .flowDefinitionName("example")
            .roleArn(exampleAwsIamRole.arn())
            .humanLoopConfig(FlowDefinitionHumanLoopConfigArgs.builder()
                .humanTaskUiArn(exampleAwsSagemakerHumanTaskUi.arn())
                .taskAvailabilityLifetimeInSeconds(1)
                .taskCount(1)
                .taskDescription("example")
                .taskTitle("example")
                .workteamArn(exampleAwsSagemakerWorkteam.arn())
                .build())
            .humanLoopRequestSource(FlowDefinitionHumanLoopRequestSourceArgs.builder()
                .awsManagedHumanLoopRequestSource("AWS/Textract/AnalyzeDocument/Forms/V1")
                .build())
            .humanLoopActivationConfig(FlowDefinitionHumanLoopActivationConfigArgs.builder()
                .humanLoopActivationConditionsConfig(FlowDefinitionHumanLoopActivationConfigHumanLoopActivationConditionsConfigArgs.builder()
                    .humanLoopActivationConditions("""
        {
\t\t\t\"Conditions\": [
\t\t\t  {
\t\t\t\t\"ConditionType\": \"Sampling\",
\t\t\t\t\"ConditionParameters\": {
\t\t\t\t  \"RandomSamplingPercentage\": 5
\t\t\t\t}
\t\t\t  }
\t\t\t]
\t\t}
                    """)
                    .build())
                .build())
            .outputConfig(FlowDefinitionOutputConfigArgs.builder()
                .s3OutputPath(String.format("s3://%s/", exampleAwsS3Bucket.bucket()))
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:sagemaker:FlowDefinition
    properties:
      flowDefinitionName: example
      roleArn: ${exampleAwsIamRole.arn}
      humanLoopConfig:
        humanTaskUiArn: ${exampleAwsSagemakerHumanTaskUi.arn}
        taskAvailabilityLifetimeInSeconds: 1
        taskCount: 1
        taskDescription: example
        taskTitle: example
        workteamArn: ${exampleAwsSagemakerWorkteam.arn}
      humanLoopRequestSource:
        awsManagedHumanLoopRequestSource: AWS/Textract/AnalyzeDocument/Forms/V1
      humanLoopActivationConfig:
        humanLoopActivationConditionsConfig:
          humanLoopActivationConditions: |2
                    {
            \t\t\t\"Conditions\": [
            \t\t\t  {
            \t\t\t\t\"ConditionType\": \"Sampling\",
            \t\t\t\t\"ConditionParameters\": {
            \t\t\t\t  \"RandomSamplingPercentage\": 5
            \t\t\t\t}
            \t\t\t  }
            \t\t\t]
            \t\t}
      outputConfig:
        s3OutputPath: s3://${exampleAwsS3Bucket.bucket}/

The humanLoopRequestSource specifies which AWS AI service triggers reviews (here, Textract document analysis). The humanLoopActivationConfig contains a JSON conditions document that defines when to activate human review. In this example, 5% of predictions are randomly sampled for review. The conditions document supports sampling, confidence thresholds, and other activation logic.

Beyond these examples

These snippets focus on specific flow definition features: private and public workteam configuration, pricing for public workforce tasks, and automatic activation from AWS AI services. They’re intentionally minimal rather than full human review pipelines.

The examples rely on pre-existing infrastructure such as SageMaker workteams and Human Task UI definitions, S3 buckets for output storage, and IAM roles with SageMaker and S3 permissions. They focus on configuring the flow definition rather than provisioning the surrounding infrastructure.

To keep things focused, common flow definition patterns are omitted, including:

  • Task timeout configuration (taskTimeLimitInSeconds)
  • Custom task keywords and categories
  • Advanced activation conditions beyond sampling
  • Integration with Amazon Rekognition

These omissions are intentional: the goal is to illustrate how each flow definition feature is wired, not provide drop-in human review modules. See the SageMaker Flow Definition resource reference for all available configuration options.

Let's create AWS SageMaker Flow Definitions

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Immutability
What properties are required to create a flow definition?
Four properties are required: flowDefinitionName, humanLoopConfig, outputConfig, and roleArn. The humanLoopConfig defines tasks for human reviewers, outputConfig specifies the S3 path for results, and roleArn provides permissions to call other AWS services.
What properties can't I change after creating a flow definition?
Most core properties are immutable: flowDefinitionName, humanLoopConfig, outputConfig, roleArn, humanLoopActivationConfig, and humanLoopRequestSource. Changes to these properties require replacing the resource.
What region does my flow definition use?
The region property defaults to the region configured in your AWS provider. You can override this by explicitly setting the region property.
Workteam Configuration
How do I use Amazon's public workteam instead of a private one?
Set workteamArn to arn:aws:sagemaker:{region}:394669845002:workteam/public-crowd/default and include publicWorkforceTaskPrice in your humanLoopConfig with amountInUsd specifying cents and tenthFractionsOfACent.
What's the difference between a private and public workteam?
Private workteams use your own workteamArn without pricing configuration. Public workteams require the specific public workteam ARN format and must include publicWorkforceTaskPrice to compensate public workers.
Human Loop Activation
When should I use humanLoopActivationConfig?
Use humanLoopActivationConfig to define conditions that automatically trigger human review, such as sampling a percentage of requests. Configure it with humanLoopActivationConditionsConfig containing a JSON conditions array.
What AWS services can automatically trigger human loops?
Amazon Rekognition and Amazon Textract can trigger human loops when configured via humanLoopRequestSource. The example shows AWS/Textract/AnalyzeDocument/Forms/V1 as an integration source.

Using a different cloud?

Explore analytics guides for other cloud providers: