Foundation Models vs Purpose-Built AI Services
Two of AWS's AI layers can often do the same job. Choosing between them is the most common decision in this landscape.
Search across all documentation pages
Two of AWS's AI layers can often do the same job. Choosing between them is the most common decision in this landscape.
A purpose-built service like Amazon Comprehend does one task extremely well. A foundation model on Amazon Bedrock can do almost any language task if you prompt it right. When both can, say, detect sentiment, which do you pick?
This page gives you a decision, the trade-offs behind it, and code that shows the same job done both ways.
The decision comes down to one question: does a purpose-built service already name your task?
Here is the same job - sentiment detection - done both ways. Amazon Comprehend answers directly; a Bedrock foundation model answers through a prompt.
# --- Python (boto3) ---
import boto3
text = "The delivery was late but support fixed it quickly."
# Purpose-built: one call, structured answer, no prompt.
comprehend = boto3.client("comprehend", region_name="us-east-1")
task = comprehend.detect_sentiment(Text=text, LanguageCode="en")
print("task service:", task["Sentiment"]) # e.g. "NEUTRAL"
# Foundation model: flexible, but you must prompt and parse.
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
fm = bedrock.converse(
modelId="anthropic.claude-3-5-sonnet-20240620-v1:0",
messages=[{"role": "user",
"content": [{"text": f"Reply with one word (POSITIVE/NEGATIVE/NEUTRAL): {text}"}]}],
)
print("foundation model:", fm["output"]["message"]["content"][0]["text"].strip())// --- TypeScript (AWS SDK v3) ---
import { ComprehendClient, DetectSentimentCommand } from "@aws-sdk/client-comprehend";
import { BedrockRuntimeClient, ConverseCommand } from "@aws-sdk/client-bedrock-runtime";
const text = "The delivery was late but support fixed it quickly.";
// Purpose-built: one call, structured answer.
const comprehend = new ComprehendClient({ region: "us-east-1" });
const task = await comprehend.send(new DetectSentimentCommand({ Text: text, LanguageCode: "en" }));
console.log("task service:", task.Sentiment); // e.g. "NEUTRAL"
// Foundation model: flexible, prompt-driven.
const bedrock = new BedrockRuntimeClient({ region: "us-east-1" });
const fm = await bedrock.send(new ConverseCommand({
modelId: "anthropic.claude-3-5-sonnet-20240620-v1:0",
messages: [{ role: "user",
content: [{ text: `Reply with one word (POSITIVE/NEGATIVE/NEUTRAL): ${text}` }] }],
}));
console.log("foundation model:", fm.output?.message?.content?.[0]?.text?.trim());Both return a sentiment. The task service returns it as a labeled field with confidence scores; the model returns it as text you asked it to shape.
The interesting cases are the ones where only one layer fits well. Consider a document-processing feature.
Extracting the raw text and table structure from a scanned invoice is a fixed, well-defined task, and Amazon Textract targets it exactly. Deciding whether that invoice looks fraudulent, or drafting a polite follow-up email about it, is open-ended reasoning that no single API names - that is foundation-model work.
# --- Python (boto3) ---
import boto3
# Step 1 - purpose-built: extract structured text from a scan (fixed task).
textract = boto3.client("textract", region_name="us-east-1")
doc = textract.analyze_document(
Document={"S3Object": {"Bucket": "invoices", "Name": "inv-42.pdf"}},
FeatureTypes=["TABLES", "FORMS"],
)
extracted = " ".join(b["Text"] for b in doc["Blocks"] if b.get("BlockType") == "LINE")
# Step 2 - foundation model: reason over the extraction (open-ended task).
bedrock = boto3.client("bedrock-runtime", region_name="us-east-1")
answer = bedrock.converse(
modelId="anthropic.claude-3-5-sonnet-20240620-v1:0",
messages=[{"role": "user",
"content": [{"text": f"List any unusual charges in this invoice:\n{extracted}"}]}],
)
print(answer["output"]["message"]["content"][0]["text"])// --- TypeScript (AWS SDK v3) ---
import { TextractClient, AnalyzeDocumentCommand } from "@aws-sdk/client-textract";
import { BedrockRuntimeClient, ConverseCommand } from "@aws-sdk/client-bedrock-runtime";
// Step 1 - purpose-built extraction.
const textract = new TextractClient({ region: "us-east-1" });
const doc = await textract.send(new AnalyzeDocumentCommand({
Document: { S3Object: { Bucket: "invoices", Name: "inv-42.pdf" } },
FeatureTypes: ["TABLES", "FORMS"],
}));
const extracted = (doc.Blocks ?? [])
.filter((b) => b.BlockType === "LINE").map((b) => b.Text).join(" ");
// Step 2 - foundation model reasoning.
const bedrock = new BedrockRuntimeClient({ region: "us-east-1" });
const answer = await bedrock.send(new ConverseCommand({
modelId: "anthropic.claude-3-5-sonnet-20240620-v1:0",
messages: [{ role: "user",
content: [{ text: `List any unusual charges in this invoice:\n${extracted}` }] }],
}));
console.log(answer.output?.message?.content?.[0]?.text);Neither layer replaces the other here. Textract does the mechanical extraction it was built for; the foundation model does the judgment no fixed API offers. This split - extract with a task service, reason with a model - is one of the most durable patterns in AWS AI.
A purpose-built service is trained and tuned for its one job, so on that job it tends to be more accurate, more consistent, and cheaper than a general model coaxed with a prompt.
It returns structured data - labeled fields, confidence scores, bounding boxes - that your code can consume without parsing prose. There is no prompt to design, no output format to enforce, and far less run-to-run variation. For high-volume, well-defined work like moderation, transcription, or OCR, that predictability is worth a lot.
A foundation model shines exactly where no service names your task. Open-ended summarization, drafting, classification into your own custom categories, multi-step reasoning, question answering over context you supply - these have no dedicated API.
A model also collapses many small tasks into one endpoint. Instead of wiring Comprehend for sentiment, another call for key phrases, and custom logic for categories, one well-designed prompt can do all three. The flexibility is the point.
The billing shapes differ, and that difference should inform the choice. Purpose-built services bill per unit - per image analyzed, per page read, per character synthesized. Foundation models bill per token of input and output, so long prompts and long answers cost more. Keep these directional rather than exact, since published rates drift.
Effort differs too. A task service is often a one-line call. A foundation model needs prompt design, output parsing, and guardrails against unexpected responses. Factor that engineering time into the comparison, not just the per-call price.
Ask, in order: Does a purpose-built service name my exact task? If yes and volume is high, use it. Is the task open-ended, custom-format, or multi-step? If yes, use a foundation model. Do I need both extraction and reasoning? Then chain them - task service first, model second.
A purpose-built service is trained for one fixed task and returns structured output directly. A foundation model is general and returns free text shaped by your prompt.
When a service names your exact task - sentiment, labels, OCR, transcription - especially at high volume. It is typically cheaper, faster, and more consistent than a prompted model.
When the task is open-ended, needs a custom output format, or requires multi-step reasoning that no single API targets - summarizing, drafting, or classifying into your own categories.
Task services bill per unit of input (image, page, character); foundation models bill per token of input and output. Keep both directional, since published rates change over time.
Sometimes. One prompt can cover sentiment, key phrases, and custom categories at once. The trade-off is more prompt engineering, higher per-call cost, and more output variation.
They are more consistent run to run, because the model is fixed and returns structured fields. Foundation-model output can vary between calls, which matters for audits and tests.
A task service does the mechanical part it was built for (extract text, transcribe audio) cheaply and reliably; the model reasons over that result flexibly. It plays to each layer's strength.
Prompt for a specific format (for example JSON or a single label), keep the output short, and validate it in code. Do not assume the model always obeys the format on every run.
Yes. Bedrock model customization tunes a foundation model on your examples, trading some flexibility for more consistent, task-like behavior without building a service from scratch.
You pay each service on its own model, so a chained flow adds the stages. That is often still cheaper and more accurate than forcing one layer to do a job it is poorly suited to.
Ask whether a purpose-built service names your task. If yes and volume is high, use it. If the task is open-ended or custom, use a foundation model. If you need both, chain them.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Reviewed by Chris St. John·Last updated Jul 24, 2026