Learn Hermes AI Agent - Orchestration & Workflow Automation
Episode 10 of 23

Learn Hermes AI Agent - Orchestration & Workflow Automation

Turning the agent from a single answerer into an orchestrator: multi-step workflows with chained tools, task decomposition and planning, plus error handling, retry patterns, and fallback actions so the workflow still completes even when one step fails.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

In episode 9 you learned how to keep multi-turn conversation context alive and under control. But an agent that only answers questions has not done any work. Episode 10 raises the bar: you will make the agent complete multi-step jobs — planning, calling tools in a chain, and recovering on its own when a step fails.

Here is the roadmap for this episode: building multi-step workflows with chained tools, task decomposition and planning, and then error handling, retry patterns, and fallback actions.

Workflow: More Than Just a Chain of Tool Calls

In episode 6 you saw a simple chaining pattern: web.search then web.fetch. Orchestration takes that pattern to the next level — flows with many steps, decisions along the way, and per-step failure handling.

A classic example: an agent that handles a complaint ticket.

complaint-workflow-flow
1. cari user di database        -> db.query
2. ambil riwayat order terakhir -> db.query
3. cek status pengiriman        -> http.get ke tracking API
4. simpulkan penyebab komplain  -> model
5. susun jawaban + saran        -> model
6. kirim balasan ke user        -> http.post (perlu konfirmasi)

Notice there is a decision: if the shipping status is not found in step 3, the flow must not continue to step 4 using empty data. This is what distinguishes orchestration from merely calling many tools at random — every step knows which step preceded it and what to do if the result is not as expected.

Defining a Workflow in the Profile

Hermes lets you define workflows declaratively inside the agent config. Every step has an id, the tool it uses, and the rules for moving forward.

agents/complaint.yml - declarative workflow
workflow:
  steps:
    - id: find_user
      tool: db.query
      args: { query: "SELECT * FROM users WHERE id = {userId}" }
    - id: last_order
      tool: db.query
      args: { query: "SELECT * FROM orders WHERE user_id = {lastUserId} ORDER BY created_at DESC LIMIT 1" }
    - id: check_shipping
      tool: http.get
      args: { url: "https://api.courier.example.com/track/{order.tracking}" }
    - id: summarize
      tool: model.generate
      args: { prompt: "Rangkum status komplain dari data di atas" }

Every step uses the previous step's output through placeholders, so the flow is explicitly chained. This version uses the {userId} pattern for values coming from user input, and {order.tracking} for the result of a previous step. A declarative workflow has a big advantage: it is easy to read, easy to version-control, and easy to test step by step. Parameters like max_attempts for retry limits will be added later in the error handling section.

Task Decomposition and Planning

Not every job can be written as a static workflow. When a user gives a big, open-ended command, the agent must break it down itself — this is called task decomposition. Hermes does this through planning mode: before executing anything, the agent puts together a plan of subtasks and their order.

forcing the agent to plan first
hermes run agents/ops.yml --plan --session ops-1

With the --plan flag, the controller has the agent write a plan first: a list of subtasks, the tools each subtask needs, and the dependencies between subtasks. Only after the plan is approved does execution begin. This prevents the agent from "shooting from the hip" and skipping important steps.

A healthy decomposition pattern:

  • Break down by output — each subtask produces one verifiable artifact (a report, a number, a file).
  • Determine dependencies — a subtask that needs the result of another subtask must not run first.
  • Limit the depth — too many levels just add overhead. For most tasks, 3-5 subtasks are enough.

Info

Combine planning with runtime.max_iterations from episode 3: the plan limits what is done, max_iterations limits how many tool-call loops may be used — two guards that complement each other.

Error Handling in Workflows

A workflow step can fail for many reasons: a tool error, missing data, an API timeout, or the model rejecting a format. Error handling in orchestration means defining what happens per failure type, rather than letting the whole workflow stop.

agents/complaint.yml - error handling
on_error:
  not_found:
    - match: { tool: "db.query", error: "no rows" }
      action: complete
      response: "User tidak ditemukan. Minta email untuk verifikasi."
  timeout:
    - match: { error: "timeout" }
      action: retry
      max_attempts: 2
      backoff_ms: 1500
  rate_limited:
    - match: { error: "rate_limit" }
      action: fallback
      fallback: cache_answers

Separate the handling by error type: missing data is a normal condition (complete with a safe answer), timeouts deserve a retry, rate limits are routed to cached answers. Unknown errors fall into a default handler: stop and report to the user, do not keep processing with empty data. Values like backoff_ms determine the initial delay before a retry.

Retry Patterns and Fallback Actions

Retries must not be done haphazardly. Three patterns you need to know:

  • Fixed retry — retry with a constant delay. Simple, but it can worsen overload when all requests flood at the same time.
  • Exponential backoff — the delay grows each attempt: 1 second, 2 seconds, 4 seconds. Friendlier to a provider that is under pressure.
  • Jitter — a small random offset on the delay to prevent waves of retries from many clients colliding. The combination of backoff and jitter is the industry standard.
retry.ts
export async function withRetry(fn, config) {
  let delay = config.baseMs;
  for (let attempt = 0; attempt <= config.maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (err) {
      if (attempt === config.maxAttempts) throw err;
      const jitter = Math.random() * delay * 0.3;
      await sleep(delay + jitter);
      delay *= 2;
    }
  }
}

A fallback action is the last safety net: if the retry also fails, the workflow must not stop without a result. Examples: cache_answers for rate limits, a "the service is busy, please try again later" answer for repeated timeouts, or escalation to a human for unrecoverable errors. Choosing the right fallback keeps the agent useful even when the infrastructure behind it is failing — a topic we will dig into with circuit breakers in episode 14.

Warning

Do not retry errors that are permanent, such as failed validation or missing data. Retry only for transient failures: timeout, rate limit, dropped connection.

Conclusion

Orchestration turns the agent into a real worker: a declarative workflow chains tools together with each step's output flowing into the next; task decomposition breaks big commands into a plan; and error handling, retry, and fallback make the flow still complete even when a step fails.

Key takeaways:

  • A declarative workflow chains steps and their dependencies in a single version-controllable config.
  • Planning with --plan forces the agent to assemble subtasks before executing.
  • Each error type is handled differently: not found, timeout, and rate limit are not treated the same.
  • Retries use exponential backoff with jitter, not a thoughtless fixed delay.
  • A fallback action ensures the workflow produces something safe even when all retries fail.

In episode 11 we secure all of this power: Security & Access Control — securing tool access and API keys, restricting capabilities to safe operations, plus audit trails and policy enforcement. See you there!

Learn Hermes AI Agent - Orchestration & Workflow Automation | Learn Hermes AI Agent