Where should an AI agent's idempotency key come from?
Your agent's worker sends a payout request, and then the process gets killed before the response comes back. The supervisor restarts it. The agent reloads its plan, sees that the "pay invoice 4417" step never finished, and runs it again. The payment API supports idempotency keys, and the agent sent one both times. The vendor still got paid twice, because the agent generated a fresh UUID on each…
When an AI agent runs a tool call that supports idempotency keys, the key should be generated when the action is planned, not when it is executed. The planner decides the action, such as "pay invoice 4417 for $250," which is when the action gets its identity. This key should be persisted with the task state before the first attempt is made. If the step is stored in a database, queue message, or workflow history, the key should also be stored there before any requests are sent.
Every attempt at the action should read the key and not create a new one. In-process retries, restarted workers, and resumed workflows should all use the same key to ensure consistency. If the amount or recipient changes, that represents a new logical action and requires a new key. A transient error should not be a reason to generate a new key.
There are two ways to get task.idempotency_key: stored or derived. Storing a random value when the task row or message is created is simple and safe as long as that storage is durable and consistent for retries. Deriving the key from stable identifiers, like workflow or run ID, step ID, and business reference, can also work. However, including timestamps, attempt counters, hostnames, or text generated by the model in the key can lead to retries being treated as new actions.
The key is an identifier for a logical action, not an attempt. If two attempts look like different actions, they should be given different keys. If the server returns an error stating the key was used with a different request, stop minting new keys and investigate the issue instead of retrying the request.
In practice, using an LLM agent with retries often results in different argument values being sent due to the model's output. In this case, the key should be derived from stable identifiers such as workflow or run ID, step ID, and business reference, and the consequential arguments should be filled from task state rather than the model.
The model should decide to perform the action, and the code should supply the necessary details like amount, currency, and recipient from the stored task state. When conflicts arise, route them to a human or a planner step to sort out which version of the action is correct.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.