“It should shrink” was wrong twice: cutting AI calls and what I measured afterward

日本語版

Development log of Torecadash / October 2026

My iOS app Torecadash collects information on reservations, lotteries and first-come sales of trading cards (Pokémon, Yu-Gi-Oh!, One Piece) and notifies users. It uses an AI (Gemini) to decide “which product an article is about.” While trying to reduce calls to that AI, things I had written down as “it should shrink” were wrong twice. In order, with the numbers left in my commits:

This is a development log of the app.

What I ask the AI

The article title (for example “30th CELEBRATION Premium Deck Set Espeon”) is matched against a list of recent product candidates (the latest 60), and the AI answers which product it is. One call is about 3,083 tokens, of which about 1,800 were the same fixed instruction text every time.

First: if the title is exactly a product name, no need to ask

If a title matches a known product name exactly, there is no need to ask the AI. When I added this “short circuit,” 43% of X monitoring matched in real data. There were 0 disagreements (the short circuit’s answer differing from the AI’s). So I recorded that it should cut about 45%.

But 90 minutes after deployment, the short circuit had not fired even once. Recounting, it looked like this:

SourceCould short-circuitAlready free beforeNewly saved
X monitoring81376845 (2%)
Others419188231 (32%)

Before this step, there was an already free path that checks against the official catalog. Most articles that could be short-circuited were already settled there. Adding up what is newly saved, it is about 39 calls a day, about 4.5% of the total. Not 45%, but 4.5%.

The share a rule applies to and the calls it actually removes are different things.

If there is a free path before it, you have to count the difference. That is what the lessons field in my commit says. The logic itself was correct and safe, so I kept it. But as an AI reduction, it was small.

Second: ask in batches

The next main idea was to combine several articles into one call, because the fixed instruction text is then paid only once. Articles of the same genre share “the latest 60,” so the merged candidate list barely grows.

In the design I took care of two things.

I measured the effect by reconstructing candidate lists from the real articles of the last two days (characters sent).

Batch sizeOne by oneBatchedReduction
221,76213,427−38%
332,67314,964−54%
443,57116,192−63%
665,00017,729−73%

Third: deployed, and it never batched once

Six hours after deployment, there were 47 product-matching calls and 0 batches. Although 2 to 7 calls came in the same minute, each was asked one at a time.

The cause was the “send condition.” I had checked “number waiting ≥ number of unfinished jobs (pending),” but jobs that had come to wait were also counted in pending. X monitoring runs 32 accounts at once. If 31 had already finished, pending was 1. The moment the last one came to wait, the condition held and it was sent immediately as a single item.

The fix was to check “are there zero jobs that have not even come to wait yet.” When the number completely finished plus the number now waiting reaches the total, send. I also shortened the safety cap from 20 seconds to 6 seconds. If only one item comes, waiting 20 seconds every time would be longer than one X monitoring run (17.8 seconds measured) and delay the rounds.

During this check, the first short circuit was also reviewed. In 6 hours, 28 of 47 calls (60%) were handled without calling the AI. The short circuit was working correctly.

What I learned

The numbers in this article come from my commit record (September 4 and 5, 2026). I do not write amounts of money.

This is the English version of the original Japanese article.

More in English