Part 1 covered the 25 scripts I reach for every week — reliable, production-ready automation building blocks. This part covers the part that takes longer to figure out: how to chain them together when the control flow involves a decision.
Pure script-chaining is easy. Run A, pipe output to B, done. But real automation pipelines hit decision points: should this file be processed or skipped? Is this API response an error, a retry, or a success? Does this content need review or can it proceed?
Historically you handled this with if/elif trees. This works fine when the decision logic is clear and stable. It falls apart when the decision requires judgment — parsing ambiguous output, classifying content that doesn’t fit neat categories, handling the long tail of edge cases that if statements don’t cover.
The pattern I’ve landed on: use the scripts in the Cookbook for the deterministic parts of the pipeline (HTTP calls, file I/O, scheduling, retries), and use a small AI prompt for the judgment calls. The two fit together cleanly because neither is trying to do the other’s job.
The shape of an AI-in-the-loop pipeline
Here’s a three-script pipeline before and after adding an AI decision layer.
Before — pure script chaining:
# Download files
python http_client.py --url $API_ENDPOINT --output raw/
# Process each file
for f in raw/*.json; do
python csv_converter.py --input $f --output processed/
done
# Archive
python file_archiver.py --source processed/ --destination archive/
Enter fullscreen mode Exit fullscreen mode
This works if every file from the API is well-formed JSON that maps cleanly to CSV. In practice: some files have malformed encoding, some have unexpected schema changes, some are empty, some are error responses that look like successful ones. The script chain fails silently on these, or fails loudly and stops the whole pipeline.
After — with an AI triage step:
# Download files
python http_client.py --url $API_ENDPOINT --output raw/
# AI triage: classify each file before processing
python prompt_runner.py \
--prompt "classify_file_quality" \
--input-dir raw/ \
--output triage_report.json
# Route based on triage result
python pipeline_router.py \
--triage triage_report.json \
--good-dest processing/ \
--bad-dest review/ \
--skip-dest archive/
# Process clean files only
for f in processing/*.json; do
python csv_converter.py --input $f --output processed/
done
Enter fullscreen mode Exit fullscreen mode
The AI triage step doesn’t replace the Cookbook scripts — it routes between them. That’s the pattern.
What the AI step actually does
The triage prompt is small. Here’s the actual prompt I use for file quality classification:
CLASSIFY_FILE_QUALITY = """You are a data quality classifier. Given a JSON file's contents, classify it as one of:
- PROCESS: well-formed, expected schema, ready for conversion
- REVIEW: unusual structure, possible schema change, needs human look
- SKIP: empty, error response, or duplicate of a file already processed
Respond with exactly one word: PROCESS, REVIEW, or SKIP.
Do not explain. Do not add caveats.
File contents:
{file_contents}
"""
Enter fullscreen mode Exit fullscreen mode
Three outputs. No explanation. The AI is not being asked to think — it’s being asked to classify. This is the right scope for an in-pipeline AI call.
The key constraints:
- Single-word output — downstream code parses this; ambiguity breaks the pipeline
- No reasoning trail — you don’t need it and it slows the call
- Enumerated choices — if you give the model open-ended output, you’ll get open-ended answers
The pattern generalizes. You can use the same shape for:
- Classifying log entries (ERROR / WARNING / INFO / NOISE)
- Scoring extracted data quality (HIGH / MEDIUM / LOW / REJECT)
- Routing customer messages to the right queue (BILLING / SUPPORT / FEEDBACK / IGNORE)
- Deciding whether a scraped page contains the content type you’re looking for
The prompt_runner.py script
The Cookbook includes prompt_runner.py — a lightweight wrapper that handles the boilerplate for in-pipeline AI calls: API client initialization, token budgeting, error handling, output parsing, and retry logic.
Here’s how it works:
# Usage:
python prompt_runner.py \
--prompt classify_file_quality \
--input-file raw/data_2026_03_23.json \
--output-file triage/data_2026_03_23.triage
# Batch mode (processes all files in a directory):
python prompt_runner.py \
--prompt classify_file_quality \
--input-dir raw/ \
--output-dir triage/ \
--workers 4
Enter fullscreen mode Exit fullscreen mode
The --prompt flag takes a prompt name from prompts/ directory (where you store your project’s prompt templates). It loads the template, substitutes the input content, calls the API, and writes structured output to the output file.
The batch mode runs workers in parallel (default 4) with automatic backoff on rate limit errors. For a 100-file batch, it typically runs in 30-60 seconds depending on file size and API response time.
When to use a prompt vs. when to write code
The pattern I use for deciding whether a decision goes in code or in a prompt:
Write code if:
- The classification is fully enumerable in advance (
status == 200) - The inputs are structured and deterministic (dates, numbers, known enum values)
- You need the decision to be auditable without an API call
- You’re running at high volume where API costs matter
Use a prompt if:
- The classification requires reading unstructured text
- The input format varies in ways you can’t predict
- Edge cases exist that you haven’t mapped yet
- Getting it 80% right automatically is better than getting it 0% right manually
The boundary I’ve found in practice: code handles the deterministic path, prompts handle the long tail. A well-designed pipeline has both.
A real example: automated PR review triage
The most useful pipeline I’ve built using this pattern: automated triage of incoming GitHub PR review requests.
The problem: I work on a codebase that gets 15-30 PRs per day. Not all of them need deep review — some are docs updates, typo fixes, or dependency bumps. But identifying which ones can be auto-approved vs. which ones need attention requires reading the diff.
The scripts involved:
-
webhook_receiver.py— receives GitHub webhook, writes PR metadata + diff to a queue directory -
prompt_runner.py— classifies each PR using the triage prompt -
pipeline_router.py— routes based on classification -
notification_sender.py— sends Slack notification with routing decision
The triage prompt:
TRIAGE_PR = """You are a senior developer reviewing pull requests for triage priority.
Given a pull request diff and metadata, classify it as:
- AUTO: safe to auto-approve (docs, formatting, dependency updates with no API changes, comment additions)
- REVIEW: needs human review (logic changes, new features, API changes, security-sensitive code)
- URGENT: needs immediate review (rollback, hotfix, security patch)
Rules:
- If you can't determine the scope from the diff, classify as REVIEW
- If any test files are modified, classify as at least REVIEW
- If any auth, security, or credential-handling code is touched, classify as URGENT
Respond with exactly one word: AUTO, REVIEW, or URGENT.
PR title: {title}
Author: {author}
Files changed: {file_count}
Diff summary:
{diff}
"""
Enter fullscreen mode Exit fullscreen mode
The routing logic:
# pipeline_router.py takes the triage output and acts on it
AUTO → add "auto-approved" label, merge if checks pass
REVIEW → add to review queue, notify team on next batch
URGENT → page on-call immediately via notification_sender.py
Enter fullscreen mode Exit fullscreen mode
What it does: Reduces manual triage from 20-30 minutes per day to 2-3 minutes. AUTO classifications are almost always right (>95%). URGENT classifications have had 0 false negatives in 6 months — it’s conservative on purpose.
The cost question
Running AI calls in a pipeline has a cost. The math that made this viable for me:
- Average classification call: ~200 input tokens + 1 output token
- At current API pricing: < $0.001 per call
- 100-file daily batch: < $0.10/day
For most automation pipelines, the cost of AI triage is dominated by the time cost of writing and maintaining the if/elif tree it replaces — which needs to be updated every time a new edge case appears.
The break-even is roughly: if you’d spend more than 10 minutes writing code to handle the edge case, the API call is cheaper.
Combining Part 1 scripts with the AI layer
The scripts most useful as AI pipeline components:
Script Role in AI pipelinehttp_client.py
Fetch data for AI processing; handles retries on API rate limits
file_watcher.py
Trigger AI triage when new files appear
webhook_receiver.py
Accept external events that feed into triage
queue_processor.py
Process AI-classified items from a queue
notification_sender.py
Send routing decisions and escalations
retry_runner.py
Wrap AI calls themselves — handles transient API errors
cron_wrapper.py
Schedule batch AI processing jobs
The pipeline pattern:
-
Collect —
http_client.pyorwebhook_receiver.pyorfile_watcher.py -
Triage —
prompt_runner.pywith your classification prompt -
Route —
pipeline_router.pybased on triage output - Process — whichever scripts fit the routed path
-
Notify —
notification_sender.pyon completion or escalation
You don’t always need all five stages. The triage step is what makes it AI-in-the-loop instead of pure script chaining.
Building your first AI triage step
If you have a pipeline that currently uses manual classification or a brittle if tree, here’s the migration path:
Identify the judgment call. Where in the pipeline does a human or messy code currently make a decision that requires reading unstructured input?
Define the output enum. What are the possible classifications? 2-4 choices is ideal. More than 6 and the prompt gets unreliable.
Write the prompt. Follow the pattern: role assignment → enumerated choices with definitions → rules for edge cases → required output format (one word). Test it on 10-20 representative examples before deploying.
Add
prompt_runner.pyto the pipeline. Replace the judgment call with a script call. Log outputs for the first week to validate accuracy.Tune the rules. After seeing real output, refine the rules section of the prompt to handle edge cases you didn’t anticipate. This is faster than updating code.
The prompt library
The prompts above are starting points — designed to be modified for your pipeline’s specific enum and rules. The general shape is always the same: role assignment → enumerated choices with definitions → rules for edge cases → required one-word output format.
Once you have a working triage prompt, the marginal cost of adding classification steps to your pipeline is low. Each new decision point is another prompt + another routing branch in pipeline_router.py.
If you’re building agent SaaS on top of these pipelines
One thing I keep running into as I expand these pipelines into production services: the pricing model matters as much as the architecture. Pipelines that run on a per-request basis have fundamentally different cost structures than pipelines that run on a per-user seat. If you’re building toward a paid product, worth thinking about early.
I wrote a full breakdown of the six pricing models that work for AI agent products — including worked examples, a cost calculator, and the decision framework I actually use:
Pricing Your Python AI Agent SaaS in 2026 →
Six pricing models, Notion cost calculator, worked examples. $39 one-time.
And if you want Part 3 (failure modes, output validation, human-in-the-loop checkpoints) in your inbox when it drops — the list is here:
What part 3 covers
Part 3 is about failure modes — specifically, what happens when an AI step in your pipeline produces the wrong classification and you don’t catch it. It covers: output validation, human-in-the-loop checkpoints for high-stakes decisions, logging patterns for pipeline observability, and how to build a correction loop that improves prompt accuracy over time.
If you’re building AI-in-the-loop pipelines right now, leave a comment with what you’re working on — I’m actively building from production use cases, and reader questions drive what goes in Part 3. (#discuss)
답글 남기기