A typical first AI coding script reads a file, sends it with "fix this bug", and writes the reply back over the original. It works. But for a one-character fix in a 497-line file, the model writes back 4,495 tokens, the whole file again, and you pay for every unchanged line it retypes just to deliver one changed character.
The fix is one character, the reply is the whole file
You pay per token, a chunk of text the model reads or writes, roughly four characters of English or code. Prices are quoted per million tokens and split in two: input tokens are everything you send, output tokens are everything the model writes back. Output is the expensive side. On most current models it costs 5–6 times as much as input.
A whole-file request puts your file on both sides of the bill. The model reads it once as input, then writes it again as output, unchanged lines included. The fix you actually wanted is a rounding error inside that second number.
That gives a rule of thumb you can work out in your head. When the model has to retype the file, the edit costs close to 1 + (output price ÷ input price) times what it costs the model to read the file. If output is 6 times the input price, that's nearly 7×, and the bigger the file, the closer you get to that ceiling.
One off-by-one bug, five models
To put numbers on it, I took a real file: textwrap.py from Python's standard library, 497 lines and 4,491 tokens. I counted them with tiktoken, OpenAI's open-source token counter, using o200k_base, the encoding of current GPT models. I broke one line, turning <= into < in the check that decides whether a word still fits, and priced the fix two ways. If the model returns the whole corrected file, that's 4,495 output tokens. If it returns a SEARCH/REPLACE block, meaning the lines to find and what they should become, that's 51.
All prices are list prices, the per-token prices vendors publish. They come from the catalog of the LLM gateway I work on, snapshot of 17.10.2026.
| Model | List price in / out, $ per 1M | Whole file back | Change only | Ratio |
|---|---|---|---|---|
| gpt-5.6-mini | 0.20 / 1.20 | $0.0063 | $0.0010 | 6.5× |
| gpt-5.6 | 2 / 12 | $0.0630 | $0.0098 | 6.5× |
| claude-sonnet-5.5 | 2 / 10 | $0.0540 | $0.0097 | 5.6× |
| deepseek-v4.1-flash | 0.30 / 1.20 | $0.0068 | $0.0014 | 4.7× |
| grok-4.3 | 1.25 / 2.50 | $0.0169 | $0.0058 | 2.9× |
On gpt-5.6, 86% of the whole-file bill is the file being typed back. Almost all of the change-only cost is the model reading the file. The ratio doesn't follow the price level: gpt-5.6-mini is ten times cheaper and lands at the same 6.5×. It follows the gap between output and input prices, which is why grok-4.3, where output costs only twice as much as input, gains least. File size matters less than you'd think. With the same block of about 50 tokens, getopt.py (215 lines) comes out at 5.8× and argparse.py (2,676 lines) at 6.9×.
For a script that makes 200 edits a day on gpt-5.6, that's $378 a month against $59.
Ask for the change, not the file
Add this to your instructions. It costs 53 input tokens per call:
Return only the change, never the whole file. Use one block per change:
<<<<<<< SEARCH
(the exact lines to change, copied from the file, plus one unchanged line above them)
=======
(the same lines as they should read after the change)
>>>>>>> REPLACE
The unchanged line goes in both halves. It's there to make the match unique, because a single line like return None may appear a dozen times in a file. Then apply the reply yourself, and refuse anything you can't match exactly once:
import re
BLOCK = re.compile(r"<<<<<<< SEARCH\n(.*?)\n=======\n(.*?)\n>>>>>>> REPLACE", re.S)
def apply_edits(source, reply):
blocks = BLOCK.findall(reply)
if not blocks:
raise ValueError("no SEARCH/REPLACE block in the reply")
for old, new in blocks:
if source.count(old) != 1:
raise ValueError(f"search text found {source.count(old)} times")
source = source.replace(old, new)
return source
src = "def area(w, h):\n # rectangle\n return w + h\n"
reply = "<<<<<<< SEARCH\n # rectangle\n return w + h\n=======\n # rectangle\n return w * h\n>>>>>>> REPLACE"
print(apply_edits(src, reply))
try:
apply_edits(src, reply.replace("w + h", "w - h", 1))
except ValueError as e:
print("refused:", e)
It prints the fixed function, then refused: search text found 0 times. Zero means the model misquoted your code, and more than one means the match is ambiguous. Guessing in either case could corrupt the file, so the function stops.
When an edit is refused, ask again for the whole file. That fallback costs one extra call, but a failed change-only call costs little more than reading the file. So on gpt-5.6 the format stays cheaper until about 85% of your edits need the fallback.
What this doesn't solve
The input side doesn't shrink: the model still reads all 4,491 tokens. Cutting that means sending only the relevant function, a different trade-off. Reasoning tokens, the notes a "thinking" model writes to itself before it answers, are billed as output in both modes. With 2,000 of them, gpt-5.6's 6.5× shrinks to 2.6×. I didn't measure how often models misquote the search text. That depends on the model and the file, so count your refusals. Claude and Gemini also split text into tokens differently from tiktoken, so the counts will shift. The ratio follows the prices.
A cheaper price per token doesn't do this job either. The gateway I mentioned sells these models 10–29% below list. But a discount takes the same share off both modes: at our price, gpt-5.6's whole-file edit is $0.054, still 5.5 times the change-only edit at full list price.
The takeaway
The fix was one character. Ask for the change, apply it with an exact-match check, and you pay once to have the file read instead of paying output price to have it typed back.
Top comments (0)