Chapter 9, second edition working draft

Feedback

How observations change the next attempt.

Contents

Feedback uses the results of an agent's work to guide what it does next. Evaluation tells us where the work succeeds or fails. To improve the work, the system must use that assessment: give the findings to a model that can revise the answer, or let code choose the next action. An assessment saved only for reporting cannot correct the work by itself.

The agent loop already returns tool results to the model. But another turn does not necessarily bring the task closer to completion. The model needs information that helps it decide what to change, what to keep, or whether to try another approach. Designing feedback means making that information available where the next decision happens.

The same assessment can end in a log or return to a model input or controller branch that changes the next operation.
Feedback exists when an observation influences the next decision. A stored assessment alone leaves the task unchanged.

The Revision Loop

A revision loop gives the model a chance to correct its work after checking it. The program evaluates a draft, supplies the findings with that draft to another model call, and checks the revised version. Repeating these operations lets the system work toward the task's requirements instead of depending entirely on its first answer.

The citation example from Evaluation makes the connection concrete. The draft says a product is available now; its source describes a future release. The revision call receives the original task, the draft, the source, and the finding that identifies the unsupported claim. It can remove or qualify the claim. The next evaluation checks whether the revised answer now agrees with the evidence.

let draft = await callModel({
  instructions: "Answer the task using the supplied sources.",
  input: { task, sources },
})
let assessment = await evaluate({ task, draft, sources })

for (let attempt = 0; attempt < maxRevisions; attempt++) {
  if (assessment.result !== "fail") break

  draft = await callModel({
    instructions: "Revise the draft using the findings.",
    input: {
      task,
      sources,
      draft,
      findings: assessment.findings,
    },
  })
  assessment = await evaluate({ task, draft, sources })
}

return { draft, assessment }

Here, evaluate applies the checks from the previous chapter and returns pass, fail, or unknown, together with its findings. The loop retries failures up to maxRevisions. An unknown assessment returns to the application, since rewriting alone may not supply missing evidence. This simple loop returns the latest draft with its assessment; keeping earlier versions adds the option of backtracking, which we discuss below.

A bounded loop generates a candidate, evaluates it, and either accepts, revises with findings, or stops.
Revision returns the task, draft, and findings to another call. Each revision uses an attempt; unavailable evidence can require a different next step.

Diagnostic feedback

The usefulness of a revision depends on what the feedback tells the model. “The answer is wrong” leaves it to guess which part failed. A finding that identifies the claim, quotes the relevant source, and explains why it does not support the claim narrows the problem. The model can spend its next attempt addressing that discrepancy instead of rewriting unrelated parts.

A score can tell the program which draft to prefer or whether a threshold was met. To direct a repair, the model usually needs more detail. In the citation example, the useful information is why the source fails to support the claim. A suggested replacement can help, but it is a proposal to check against the source; the reviewer may have diagnosed the problem correctly while suggesting another unsupported claim.

Vague feedback gives no location. A precise finding identifies claim 17, the expected evidence of current availability, and a source announcing a future release. The claim lacks support; a suggested fix is checked separately.
A finding identifies the unsupported claim and its source. The suggested fix remains a proposal to check against the evidence.

Coding agents have useful sources of this kind of feedback. A type checker can report that a function expected a number but received a string, with a file and line number. The agent can inspect that expression and its callers to decide what needs changing. Rerunning the checker then tests the change. The diagnostic narrows the investigation without having to prescribe the correct fix.

Other tasks need checks that provide comparable detail. For a research answer, the finding from Evaluation can travel with the source passage and the version of the draft it concerns. The passage lets the model inspect the evidence immediately. The version lets the application check whether the finding still applies to the current draft.

const feedback = {
  candidateRevision: 12,
  location: "claim-17",
  expected: "Evidence of current availability",
  observed: "The source describes a future release",
  source: {
    id: "source-4",
    passage: "Product B is scheduled for release next month.",
  },
  suggestedFix: "Qualify the claim or find release evidence",
}
An issue record connects revision 12 and claim 17 to source 4, paragraph 6. Checking the source and revision can support, reject, or defer the criticism.
A finding identifies the inspected revision and its source evidence. The application can check whether it still applies to the current draft.

Responses to tool results

Not every problem needs another draft. The next step depends on what the result tells us about the work. An agent that keeps rewriting a request while a service is unavailable is changing the wrong thing. Tool results should preserve enough detail to distinguish problems the agent can fix from conditions it needs to wait for.

Common responses include:

  • Invalid tool arguments: return the invalid field and the expected format so the model can correct its request.
  • A rate limit: use the service's retry time to schedule another attempt.
  • An unfinished background job: keep the job identifier and check its status later.
  • An uncertain save: read the destination to find out whether the write succeeded before repeating it.

Code can handle a known response directly. A result such as { kind: "rate_limited", retryAt } contains what the scheduler needs to arrange a retry. A result that requires interpretation can enter the next model call instead. If a search returns irrelevant sources, the model can examine what it found and change the query. Both paths use feedback; they differ in who chooses the response.

Structured outcomes route to a scheduled wait, a later job status check, a stop, or reconciliation. Ambiguous evidence follows a separate model interpretation path.
Known operational conditions can select a next step directly; ambiguous evidence may need model interpretation.

Backtracking

A revision can fix one problem and introduce another. Correcting an unsupported claim might also remove a caveat the answer needed. Checking only the reported defect would miss that loss. Regression checks revisit requirements that earlier work already satisfied, so a local repair does not silently undo progress.

Keeping a previous version gives the system a way back. The application can save the draft and its assessment, try a revision, and compare the results before replacing the saved version. If the revision loses required information, the next attempt can start from the earlier draft with that new finding. Versioned artifacts make this possible without asking the model to reconstruct the old text from memory.

A new candidate fixes a citation but drops a caveat, so regression checks keep the incumbent instead of replacing it.
Keep a saved version while testing a candidate. Here, the revision fixes a citation but loses a required caveat, so the earlier version remains available.

Candidate selection

Sometimes it is unclear which approach is worth pursuing. The system can generate several candidates and evaluate them against the same requirements before choosing one to develop. This is often called best-of-N selection. It can explore more alternatives than repeatedly editing a single draft, at the cost of generating and checking more work.

Selection uses feedback through the choice of candidate. The next call can continue from the selected answer and its remaining findings. A candidate that fails a required check does not become acceptable merely because it scores better than the others; the program can keep searching or return the unresolved result. The criteria from Evaluation determine what the selection can meaningfully prefer.

A bounded set of candidate briefings is assessed against the same criteria and an acceptable winner is retained, or none is selected.
Several candidates can expand the search. The evaluator still determines what the system selects.

Convergence

The aim is for revisions to converge on work that meets the requirements. Repetition alone does not produce that outcome; a loop can also settle on a wrong answer. The model must be able to interpret the feedback and make a useful change, and the next check must be able to distinguish an improvement from a different answer.

Conflicting requirements can make the loop go back and forth. If one review asks for a shorter answer and the next asks for the evidence that was removed, each revision can undo the previous one. A concise answer with supporting detail in a separate section may satisfy both needs. The useful change is to clarify what the answer must preserve, then evaluate revisions against that stable requirement.

A briefing alternates between too long and too little evidence until the task is clarified into a concise conclusion with supporting detail.
Repeated criticism does not resolve an ambiguous objective. Clarifying the intended result can change the search.

Repeated failure is information about the approach. If the same claim remains unsupported after several rewrites, another rewrite may add little. The system may need to retrieve a missing source or state that the evidence is unavailable. Recording which findings were resolved and which persist helps it distinguish progress from repeated activity.

The loop needs a way to finish even when it cannot solve the task:

  • The checks pass: return the result with its assessment.
  • The attempt or cost limit is reached: return the best saved work and the unresolved findings.
  • The same problem keeps returning: change the approach or stop the attempt.
  • Required evidence is unavailable: record what is missing so the work can resume when it becomes available.
Four stopping conditions return either an accepted artifact or a clear record of the incumbent and unresolved findings; repeated failures may inform a future lesson.
Acceptance, exhausted resources, stalled progress, and missing information are all legitimate ways to end an attempt.

Feedback lets the system use what happened to improve its current attempt. A later task may still repeat the same mistake. To carry the benefit forward, the system needs to preserve something reusable from the experience, such as a better procedure for checking sources. That connection from one task to future tasks is the subject of Learning.