Lesson 3. Harness and Guardrails

A model without a harness is dangerous. A Harness is all the infrastructure around the model: the context, the tools, and three protective layers – guardrails (what you can’t do), checking (did it do it right), and recovery (how to get back on track). The expanded formula: Agent = Model + Harness.

    tool call
        │
        ▼
┌───────────────┐
│1. WHITELIST│──▶ “reject”
└───────┬───────┘
        │ exists
        ▼
┌───────────────┐
│ 2. EXECUTION │──────▶ “crash caught”
└───────┬───────┘
        │ result
        ▼
┌───────────────┐
│  3. CHECKING  │──────▶ “ask again”
└───────┬───────┘
        │ ok
        ▼
    observation into context

What to read

  • [Harness-engineering] – why the harness is more important than the model itself
  • [Five functions of a Harness] – what the infrastructure consists of
  • [Guardrails] – how to forbid an agent from doing dangerous things

In code

The three layers fit into a single wrapper around the tool call:

python
def run_tool(call):
    fn = TOOLS.get(call["tool"])
    if not fn:                          # layer 1: whitelist
        return "Tool not found"
    try:
        result = fn(**call["args"])     # layer 2: catch crash
    except Exception as e:
        return f"Tool crashed: {e}"
    if result is None:                  # layer 3: check result
        return "Tool returned empty"
    return result
js
function runTool(call) {
  const fn = TOOLS[call.tool];
  if (!fn) return "Tool not found";        // layer 1
  try {
    const result = fn(call.args || {});           // layer 2
    if (result === undefined || result === null)  // layer 3
      return "Tool returned empty";
    return String(result);
  } catch (e) {
    return "Tool crashed: " + e;
  }
}

Note: tool errors do not crash the agent – they are returned to the context as an observation, and the LLM can correct itself on the next step.

Practice

For the agent from Lesson 1, come up with three guardrails: one “can’t do”, one result check, and one way to recover from an error. Then, wrap any of your functions in the run_tool from the example.

Related: [Lesson 2. ReAct cycle], [Lesson 4. Tools]