Top 10 AI automation articles from Zapier's blog in 2025 (part 3)
You're reading part 3 of the Top 10 AI Automation Articles from Zapier's Blog in 2025 series, where I let AI do the ranking for me:
-
Check out Part 1 to see the ranking.
-
Check out Part 2 to see how I downloaded and converted the articles to markdown.
So now that I had all the articles, it was time to rank them.
Concatenating the articles of 2025
I started by filtering out articles not from 2025. Then, I
concatenated the rest into the variable
last_articles_md
, and
also saved them to the file
data/ranks/articles_2025.md
.
# zapier_automation_inspiration.py
# ...
# 1. List of Articles
# ...
# 2. Download articles and convert to Markdown format
# ...
# 3. Concatenate the articles of 2025
last_articles = [a for a in articles if a.get("editorialLastPublishedDateComputed").startswith("2025")]
last_articles_md = ""
for a in last_articles:
with open(f"data/articles/{a.get('slug')}.md", "r", encoding="utf-8") as f:
last_articles_md += "\n\n" + f.read()
os.makedirs("data/ranks/", exist_ok=True)
with open("data/ranks/articles_2025.md", "w", encoding="utf-8") as f:
f.write(last_articles_md)
Ranker prompt
Next, I asked gpt-4.1
to
help me create an effective prompt for ranking these articles. I
started with this request:
I try to rank articles in Zapier's blog using an LLM. I've already
all articles contents. Help me write a performant prompt for this.
Here is a starting point. Improve it.
-----
- I'm a programmer and I'm learning about AI automation.
- I don't have much time to read all the articles written on Zapier's
blog that talks about automation. So I need your help.
- Rank the following articles.
- For each article tell me:
1. why I should read the article in a sentence?
2. why it is ranked there
After refining its reply, the prompt evolved into this:
*You are an expert AI assistant helping a programmer interested in AI
automation. Your task is to rank a list of articles from Zapier's
blog about automation from most to least useful for someone with this
profile.*
*Instructions:*
1. You are ranking these articles for a programmer (with some coding
skills) who wants to learn practical and advanced concepts in AI
automation, and who values depth, clarity, and actionable insights.
2. Assume the user has limited time and can read only the most
relevant articles.
3. Only include the 10 best articles in your ranked list. This should
be a top 10 list with exactly 10 articles.
4. For each article, provide in *one sentence*:
- *Why it's worth reading for this user.*
5. For each article, provide in *one sentence*:
- *Why you placed it at this rank*.
6. For each article, include its metadata (Link, Author, Last updated,
Time to read)
7. Output your answer as a numbered list---most recommended article
first.
*Example output format:*
1. [Article 1 Title]
- Link: [The link]
- Author: [The Author]
- Last updated: [Last update date]
- Time to read: [The time to read] min
- Why read: [One-sentence value proposition for a programmer
learning AI automation.]
- Ranking reason: [Concise justification for its rank.]
2. [Article 2 Title]
- Link: ...
- Author: ...
- ...
Hitting the tokens per min (TPM) limit with gpt-4.1
I tried using that prompt with
gpt-4.1
model and pasted
about half the articles into
Eden, my ChatGPT
interface. It didn't work. The number of tokens was too high
for my tokens per minute (TPM) limit:
{
"message": "Request too large for gpt-4.1-long-context in
organization org-wNqdQ1eu6ZLRZYX79oeMbGio on tokens per
min (TPM): Limit 200000, Requested 264554. The input or
output tokens must be reduced in order to run successfully.
Visit https://platform.openai.com/account/rate-limits to
learn more.",
"type": "tokens",
"param": null,
"code": "rate_limit_exceeded"
}
Too bad, gpt-4.1
's
context window is 1,047,576 tokens, and I really wanted to use it
for some reason.
Anyway, I verified that I was not limited in such way on Google
Cloud with
gemini-2.5-flash
model
and switched to that model.
But before running it, I checked the token count for all these articles using the tiktoken package:
import tiktoken
encoding = tiktoken.get_encoding("o200k_base")
len(encoding.encode(last_articles_md))
# 417814
Ranking the articles of 2025 with gemini-2.5-flash passing it the full articles
Finally, I passed the full articles and the ranker prompt to
gemini-2.5-flash
. I
saved the model's answer in
data/ranks/articles_2025_rank_by_gemini-2.5-flash.md
.
You can see this output in part 1 of the series.
# zapier_automation_inspiration.py
# ...
from google import genai
from google.genai import types
from dotenv import load_dotenv
# add in .env file
# GEMINI_API_KEY=...
# OPENAI_API_KEY=...
load_dotenv()
# 1. List of Articles
# ...
# 2. Download articles and convert to Markdown format
# ...
# 3. Concatenate the articles of 2025
# ...
# 4. Rank the articles of 2025 with gemini-2.5-flash passing it the full articles
ranker_prompt = """*You are an expert AI assistant helping a programmer interested in AI automation. Your task is to rank a list of articles from Zapier's blog about automation from most to least useful for someone with this profile.*
*Instructions:*
1. You are ranking these articles for a programmer (with some coding skills) who wants to learn practical and advanced concepts in AI automation, and who values depth, clarity, and actionable insights.
2. Assume the user has limited time and can read only the most relevant articles.
3. Only include the 10 best articles in your ranked list. This should be a top 10 list with exactly 10 articles.
4. For each article, provide in *one sentence*:
- *Why it's worth reading for this user.*
5. For each article, provide in *one sentence*:
- *Why you placed it at this rank*.
6. For each article, include its metadata (Link, Author, Last updated, Time to read)
7. Output your answer as a numbered list---most recommended article
first.
*Example output format:*
1. [Article 1 Title]
- Link: [The link]
- Author: [The Author]
- Last updated: [Last update date]
- Time to read: [The time to read] min
- Why read: [One-sentence value proposition for a programmer learning AI automation.]
- Ranking reason: [Concise justification for its rank.]
2. [Article 2 Title]
- Link: ...
- Author: ...
- ...
"""
client = genai.Client()
response = client.models.generate_content(
model="gemini-2.5-flash",
config=types.GenerateContentConfig(
system_instruction=ranker_prompt),
contents=last_articles_md
)
with open("data/ranks/articles_2025_rank_by_gemini-2.5-flash.md", "w", encoding="utf-8") as f:
f.write(response.text)
Ranking the articles of 2025 using summaries
I could have stopped here, but I was curious: how would the rankings change if the models used only article summaries instead of the full content?
Summarizer prompt
So, I asked
gpt-4.1
for a prompt
to generate summaries that would be useful as input for the
ranker prompt. Here's what I asked:
Give me a prompt to produce a summary for each article which would be
useful then to do the ranking of the articles with the ranker prompt
above?
After refining, I settled on this:
You are an assistant helping a programmer with some coding experience
who wants to quickly find the most relevant articles about AI
automation.
*Instructions:*
1. For the following article, provide a concise summary (2-4
sentences) that highlights:
- The main topic or purpose of the article
- Any practical techniques or insights related to AI automation that a
programmer could learn from it
- Any noteworthy examples, case studies, or real-world applications
mentioned
2. Focus on information that would help a programmer decide whether
this article is worth reading to advance their understanding of AI
automation.
*Example output format:*
# [Article Title]
- Link: [The link]
- Author: [The Author]
- Last updated: [Last update date]
- Time to read: [The time to read] min
- Summary: [Concise summary]
Generating summaries
I generated the summaries using
gemini-2.5-flash
. I
saved each one in
data/ranks/summaries/
directory, and concatenated them all into
last_articles_summaries_md
variable, also saved as
data/ranks/summaries_2025.md
.
# zapier_automation_inspiration.py
# ...
# 5. Generate summaries of articles
last_articles = [a for a in articles if a.get("editorialLastPublishedDateComputed").startswith("2025")]
os.makedirs("data/ranks/summaries/", exist_ok=True)
last_articles_summaries_md = ""
for a in last_articles:
slug = a.get('slug')
with open(f"data/articles/{slug}.md", "r", encoding="utf-8") as f:
article_content = f.read()
logger.info(f"Summarizing '{slug}'.")
response = client.models.generate_content(
model="gemini-2.5-flash",
config=types.GenerateContentConfig(
system_instruction=ranker_prompt),
contents=article_content
)
summary = response.text
last_articles_summaries_md += "\n\n" + summary
with open(f"data/ranks/summaries/{slug}.md", "w", encoding="utf-8") as f:
f.write(summary)
with open("data/ranks/summaries_2025.md", "w", encoding="utf-8") as f:
f.write(last_articles_summaries_md)
This time, the number of tokens is in the my TPM limit:
encoding = tiktoken.get_encoding("o200k_base")
len(encoding.encode(last_articles_summaries_md))
# 22550
Ranking using summaries
Finally, I generated the rankings using the ranker prompt, this time with the summaries as input:
# zapier_automation_inspiration.py
# ...
from openai import OpenAI
# ...
# 6. Rank articles of 2025 using summaries
client = genai.Client()
response = client.models.generate_content(
model="gemini-2.5-flash",
config=types.GenerateContentConfig(
system_instruction=ranker_prompt),
contents=last_articles_summaries_md
)
with open("data/ranks/articles_2025_rank_using_summaries_by_gemini-2.5-flash.md", "w", encoding="utf-8") as f:
f.write(response.text)
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
response = client.responses.create(
model="gpt-4.1",
input=[{"role": "user", "content": last_articles_summaries_md}],
instructions=ranker_prompt
)
with open("data/ranks/articles_2025_rank_using_summaries_by_gpt-4.1.md", "w", encoding="utf-8") as f:
f.write(response.output_text)
zapier_automation_inspiration.py
To install and run:
$ uv init
$ uv add beautifulsoup4 google-genai markdownify openai python-dotenv requests tiktoken
$ uv run zapier_automation_inspiration.py
# zapier_automation_inspiration.py
import requests
from bs4 import BeautifulSoup
import os
import logging
import json
from markdownify import markdownify as md
import re
from datetime import datetime
import time
from google import genai
from google.genai import types
from dotenv import load_dotenv
from openai import OpenAI
# add in .env file
# GEMINI_API_KEY=...
# OPENAI_API_KEY=...
load_dotenv()
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("zapier-inspiration")
# 1. List of Articles
base_url = "https://zapier.com"
list_url = base_url + "/blog/all-articles/automation-inspiration/"
resp = requests.get(list_url)
soup = BeautifulSoup(resp.text, "html.parser")
next_data_tag = soup.find("script", id="__NEXT_DATA__")
if next_data_tag:
next_data = json.loads(next_data_tag.string)
pagination_urls = data.get("props", {}).get("pageProps", {}).get("paginationUrls")
else:
logger.error(f'No tag with id "__NEXT_DATA__" found in {list_url}.')
articles = []
for p in pagination_urls:
articles_url = base_url + p
resp = requests.get(articles_url)
soup = BeautifulSoup(resp.text, "html.parser")
next_data_tag = soup.find("script", id="__NEXT_DATA__")
if next_data_tag:
next_data = json.loads(next_data_tag.string)
if (articles_most_recent := next_data.get("props", {}).get("pageProps", {}).get("articlesMostRecent")):
articles.extend(articles_most_recent)
logger.info(f"{len(articles_most_recent)} articles found in {articles_url}.")
else:
logger.info(f"No articles found in {articles_url}.")
os.mkdir("data")
with open("data/articles.json", "w", encoding="utf-8") as f:
json.dump(articles, f, ensure_ascii=False, indent=2)
logger.info(f"{len(articles)} articles found.")
logger.info(f"The list of articles has been saved in data/articles.json file.")
os.makedirs("data/articles/", exist_ok=True)
articles = [a for a in articles if isinstance(a, dict) and "slug" in a]
for article in articles:
slug = article.get("slug")
article_url = f"{base_url}/blog/{slug}/"
logger.info(f"Processing '{article_url}'.")
try:
resp = requests.get(article_url)
except requests.exceptions.RequestException as e:
logger.error(f"Failed to fetch {article_url}: {e}")
continue
time.sleep(2)
soup = BeautifulSoup(resp.text, "html.parser")
article_tag = soup.find("article")
if article_tag:
# Always use #-style Markdown headings
article_md = md(str(article_tag), heading_style="atx")
# Remove lines like these:
# [Try it](/webintent/create-zap?template=1379702)
# * 
article_md = "\n".join(line for line in article_md.splitlines() if not line.startswith("* ![") and not line.startswith("[Try"))
# Remove consecutive line breaks
article_md = re.sub(r"\n\s*\n+", "\n\n", article_md)
else:
article_md = ""
title = article.get("title", slug)
author = article.get("author", {}).get("name", "")
email = article.get("author", {}).get("email", "")
last_updated = datetime.fromisoformat(article.get("editorialLastPublishedDateComputed"))
time_to_read = str(int(article.get("timeToRead", 0) / 60))
description = article.get("description", "")
article_md = f"""# {title}
* Link: {article_url}
* Author: {author}
* Email: {email}
* Last updated: {last_updated.strftime('%B %d, %Y')}
* Time to read: {time_to_read} min
* Description: {description}
{article_md}"""
filename = f"data/articles/{slug}.md"
with open(filename, "w", encoding="utf-8") as f:
f.write(article_md)
if article_tag:
logger.info(f"Proccesing '{article_url}' done. See {filename}.")
else:
logger.error(f"Failed to fetch '{article_url}': no <article> tag found.")
# 3. Concatenate the articles of 2025
last_articles = [a for a in articles if a.get("editorialLastPublishedDateComputed").startswith("2025")]
last_articles_md = ""
for a in last_articles:
with open(f"data/articles/{a.get('slug')}.md", "r", encoding="utf-8") as f:
last_articles_md += "\n\n" + f.read()
os.makedirs("data/ranks/", exist_ok=True)
with open("data/ranks/articles_2025.md", "w", encoding="utf-8") as f:
f.write(last_articles_md)
# 4. Rank the articles of 2025 with gemini-2.5-flash passing it the full articles
ranker_prompt = """*You are an expert AI assistant helping a programmer interested in AI automation. Your task is to rank a list of articles from Zapier's blog about automation from most to least useful for someone with this profile.*
*Instructions:*
1. You are ranking these articles for a programmer (with some coding skills) who wants to learn practical and advanced concepts in AI automation, and who values depth, clarity, and actionable insights.
2. Assume the user has limited time and can read only the most relevant articles.
3. Only include the 10 best articles in your ranked list. This should be a top 10 list with exactly 10 articles.
4. For each article, provide in *one sentence*:
- *Why it's worth reading for this user.*
5. For each article, provide in *one sentence*:
- *Why you placed it at this rank*.
6. For each article, include its metadata (Link, Author, Last updated, Time to read)
7. Output your answer as a numbered list---most recommended article
first.
*Example output format:*
1. [Article 1 Title]
- Link: [The link]
- Author: [The Author]
- Last updated: [Last update date]
- Time to read: [The time to read] min
- Why read: [One-sentence value proposition for a programmer learning AI automation.]
- Ranking reason: [Concise justification for its rank.]
2. [Article 2 Title]
- Link: ...
- Author: ...
- ...
"""
client = genai.Client()
response = client.models.generate_content(
model="gemini-2.5-flash",
config=types.GenerateContentConfig(
system_instruction=ranker_prompt),
contents=last_articles_md
)
with open("data/ranks/articles_2025_rank_by_gemini-2.5-flash.md", "w", encoding="utf-8") as f:
f.write(response.text)
# 5. Generate summaries of articles
last_articles = [a for a in articles if a.get("editorialLastPublishedDateComputed").startswith("2025")]
os.makedirs("data/ranks/summaries/", exist_ok=True)
last_articles_summaries_md = ""
for a in last_articles:
slug = a.get('slug')
with open(f"data/articles/{slug}.md", "r", encoding="utf-8") as f:
article_content = f.read()
logger.info(f"Summarizing '{slug}'.")
response = client.models.generate_content(
model="gemini-2.5-flash",
config=types.GenerateContentConfig(
system_instruction=ranker_prompt),
contents=article_content
)
summary = response.text
last_articles_summaries_md += "\n\n" + summary
with open(f"data/ranks/summaries/{slug}.md", "w", encoding="utf-8") as f:
f.write(summary)
with open("data/ranks/summaries_2025.md", "w", encoding="utf-8") as f:
f.write(last_articles_summaries_md)
# 6. Rank articles of 2025 using summaries
client = genai.Client()
response = client.models.generate_content(
model="gemini-2.5-flash",
config=types.GenerateContentConfig(
system_instruction=ranker_prompt),
contents=last_articles_summaries_md
)
with open("data/ranks/articles_2025_rank_using_summaries_by_gemini-2.5-flash.md", "w", encoding="utf-8") as f:
f.write(response.text)
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
response = client.responses.create(
model="gpt-4.1",
input=[{"role": "user", "content": last_articles_summaries_md}],
instructions=ranker_prompt
)
with open("data/ranks/articles_2025_rank_using_summaries_by_gpt-4.1.md", "w", encoding="utf-8") as f:
f.write(response.output_text)
That's all I have for today! Talk to you soon ;)
Built with one.el.