AI agents and automation Assemble manually
Workflow, queues, and retries for an AI agent
An AI agent isn’t a magic box—it requires a clear workflow, a reliable task queue, and the ability to handle failures gracefully. This guide shows how to build an agent that doesn’t crash but waits and retries.
What is an agent workflow?
Workflow is the sequence of stages a task goes through from arrival to completion. For an AI agent, this means: Request receipt → Goal analysis → Tool selection → Execution → Result processing → Logging → Response. If an error occurs at any stage, the workflow must either terminate with a fallback or be queued for retry.
Standard agent workflow
flowchart TD
A[Request received] --> B{Context check}
B -->|OK| C[Parse goal]
B -->|Error| Z[Fallback / human review]
C --> D[Select tool]
D --> E[Call tool]
E --> F{Success?}
F -->|Yes| G[Form response]
F -->|No| H[Log + retry]
H --> I{Attempts exhausted?}
I -->|Yes| Z
I -->|No| E
G --> J[Send response]
Why are queues needed?
Queue — a buffer between incoming requests and the agent. It solves three problems: load (agent is not overloaded), Priorities (important tasks—forward), fault tolerance (requests are not lost when the agent crashes). At CodeVibers, we use Redis Streams or RabbitMQ for asynchronous task processing.
Example: submitting a task to a queue
// Pseudocode: sending a task to the queue
const task = {
id: uuid(),
user_id: "u_123",
goal: "Check balance for account 4711",
context: { account_id: "4711", timestamp: Date.now() },
priority: "normal",
max_retries: 3,
retry_delay_ms: 2000
};
await redis.xAdd("agent:tasks:queue", "*", "payload", JSON.stringify(task));
// Redis Stream: key "agent:tasks:queue" — task queue
Retry handling: simple loop
async function processTask(task) {
let attempt = 0;
while (attempt < task.max_retries) {
try {
const result = await agent.run(task);
return { status: "success", result };
} catch (err) {
attempt++;
if (attempt === task.max_retries) {
log.error(`Task ${task.id} failed after ${attempt} attempts`, err);
return { status: "failed", error: err.message, needs_human_review: true };
}
await sleep(task.retry_delay_ms * attempt); // exponential backoff
}
}
}
Common mistakes
- Infinite retries — without a limit and exponential backoff, the agent can “hang” and block resources.
- Queue without TTL — outdated tasks accumulate and hinder processing of current ones.
- No separation by error types — Network? LLM? Data? — needs to be logged and processed differently.
- Retries without idempotency checks — Repeated tool invocation may create duplicates (e.g., orders).
Reliable Agent Workflow Checklist
| What to check | Why |
|---|---|
| Queue with TTL and length limit | Avoid accumulation of “dead” tasks and overload |
| Retries with exponential backoff and limit | Do not spam external APIs or block the agent. |
| Error categorization: network / LLM / data / tool | Different fallback and logging strategies |
| Idempotent keys for repeated calls | Avoid duplicate actions (orders, payments) |
| Metrics: queue time, % retries, % fallback | Detect system degradation in time |
| Manual review via human_review_queue | Don’t miss critical cases and train the agent. |
Next step
Now that the agent can operate in the stream and won’t crash, it’s time to teach it test yourself and evaluate the quality of the result. This is critical for automatic fallback and training.