Skip to lesson

NVIDIANVIDIA-Certified Professional: Agentic AI2026-101.2 Implement reasoning and action frameworks (e.g., ReAct).

Bound each ReAct execution path

Completed by the knowledge check

Learning objective

Implement the ReAct thought-action-observation loop with tool constraints and termination controls.

Core idea

A ReAct agent chooses an action, observes its actual result, and uses that observation to choose the next action. The loop earns its inference cost when the next useful operation depends on information unavailable before the previous tool finishes.

Production control requires more than a prompt telling the agent to stop. In NeMo Agent Toolkit, configure the available tools, the text parser’s recovery, the tool-error path, and the maximum tool calls independently. Add an elapsed-time boundary in the caller when the service has a deadline. None of these controls proves that a returned answer is correct.

How it works

Connect reasoning to actual execution

The toolkit’s ReAct implementation requires nvidia-nat[langchain]. Configure workflow._type: react_agent, select a configured model through llm_name, and select configured functions or function groups through tool_names. These names connect the agent to executable components; prose mentioning a tool does not register it.

The model emits a text protocol with Thought, Action, and Action Input. The runtime dispatches the action and supplies the resulting Observation. The next model decision uses that result. Completion uses Final Answer instead of another action. The model must wait for a real observation rather than writing the result it expects a tool to produce.

The model must wait for a real observation before its next decisionRead top to bottom. Inside the loop the model emits Thought, Action and Action Input, the runtime dispatches the action to the tool, the tool returns its actual result, and the runtime supplies it to the model as the Observation. The loop repeats until the model emits Final Answer instead of another action.ToolRuntimeModelloop[Next model decision uses thatresult]Thought, Action, Action InputDispatches the actionActual resultSupplies ObservationFinal Answer

This distinction matters for a lookup returning no records. An empty result is information that can justify another lookup or an unresolved answer. A plausible invented result cannot support either. In a debugging trace, identify the executed tool and its returned observation before blaming the model’s final synthesis. See 1.1.2 for presenting user-facing status rather than exposing intermediate reasoning.

If you override system_prompt, preserve the {tools} and {tool_names} variables and the ReAct output format required by the documentation. Otherwise the model may produce sensible conversational text that the parser cannot dispatch. Repair the prompt or choose an implementation with a different interface; more retries do not make an incompatible output protocol compatible.

Constrain tool selection and arguments

tool_names defines what the agent can call. Use the smallest set that solves the subtask. A read-only investigation specialist should receive lookup functions, not an operational mutation function merely because both exist in the application. This narrows selection at the agent layer; the tool service still owns its actual authorization rules.

NeMo Agent Toolkit functions use Pydantic BaseModel schemas for runtime validation and conversion. In the ReAct configuration, include_tool_input_schema_in_tool_description defaults to True and adds the input schema to tool descriptions. This helps the model construct arguments; runtime schema validation remains a separate check. A schema-valid identifier can still refer to the wrong business entity.

Quote handling is another explicit choice. normalize_tool_input_quotes defaults to True: if JSON parsing fails, the implementation tries replacing single quotes with double quotes. The docs identify SQL and other quote-sensitive input as reasons to set it to False and pass the raw string. Prefer a well-defined structured input over depending on repair of arbitrary generated query text.

Separate recovery budgets

The documented default for retry_agent_response_parsing_errors is True, and parse_agent_response_max_retries defaults to 1. These govern malformed model output. With raise_on_parsing_failure: true (the default), exhausted parsing retries raise ReActAgentParsingFailedError; setting it to False returns error messages as the answer. An error returned as text must not become a successful answer merely because the transport completed.

Tool errors have different controls. tool_call_max_retries defaults to 1. pass_tool_call_errors_to_agent defaults to True, passing errors back to the agent; set it to False to raise an exception instead. An actionable read error can help the agent choose a valid alternative. A known configuration defect is better surfaced to the application owner than repeatedly restated to the model.

Choose these settings from the failure you want to recover. Parsing retries cannot fix an unavailable database. Tool retries cannot fix a prompt that never emits Action Input. When a run fails, classify it by the component that rejected the operation before increasing any limit.

Bound completion and elapsed time

max_tool_calls defaults to 15 and sets the tool-call budget; reaching the limit does not guarantee an answer. It is not a timeout in seconds. A slow first tool can violate a service deadline even with a small call budget. max_history, also documented with a default of 15, limits retained conversation messages; it is not the tool-call cap.

The v1.8.0 implementation translates this budget into the LangGraph setting recursion_limit = (max_tool_calls + 1) * 2. If the graph exhausts that limit, the single-response entry point re-raises GraphRecursionError. The streaming entry point catches the exception and yields a fixed error message explaining that the agent could not produce a final answer within the configured iterations because tool calls did not converge. The caller must recognize both outcomes as incomplete runs; a completed text stream is not proof of success. This behavior is documented in the release source rather than the configuration page.

For a Python asynchronous caller, asyncio.wait_for(aw, timeout) supplies a timeout in seconds. On timeout it cancels the awaitable and raises TimeoutError. Python documents that it waits for cancellation to complete, so elapsed time can exceed the specified timeout. Treat this as cooperative cancellation, not a hard guarantee that remote work has stopped.

Keep the failure outcome explicit in the caller’s exception handling. Call-budget exhaustion, exhausted parsing recovery, a propagated tool failure, and cancellation are different reasons for an incomplete run. The workflow owner chooses which result the product returns for each. Do not represent the call-limit error text as verified completion of the business task.

Key distinctions and trade-offs

Each control addresses a different boundary:

ControlWhat it constrainsWhat it does not establish
tool_namesExposed callable componentsBusiness authorization for every argument
parse_agent_response_max_retriesRecovery from output parsing errorsRecovery from tool availability failures
tool_call_max_retriesTool-error retry allowanceA request’s elapsed-time deadline
max_tool_callsTool-call budgetAnswer correctness or fixed latency
asyncio.wait_forAwaiting an asynchronous operationImmediate cancellation of external effects

The iterative loop consumes inference and tool time on every additional step. Lower budgets contain waste but can cut off legitimate investigations. Raise a limit only after identifying successful tasks that need it and failure traces that would otherwise spend it uselessly. verbose defaults to False; enabling it logs input, output, and intermediate steps, so the workflow owner must account for sensitive content before using those traces.

Architecture / decision scenario

A retailer’s customer-support assistant investigates missing refunds using read-only status tools. Its hypothetical service target is 8 seconds. Measured model decisions take 0.7 seconds and each lookup takes 0.5 seconds. Three lookups plus a final model decision consume about 4.3 seconds under those assumptions; fifteen lookups plus a final decision consume about 18.7 seconds before retries.

The tempting change is to retain the default fifteen-call budget and tell the model to finish quickly. The workflow owner instead configures max_tool_calls: 3, exposes only refund and payment lookups through tool_names, and wraps the asynchronous invocation in asyncio.wait_for with an 8-second timeout. That deadline does not replace the call budget: a fast but repetitive run can still waste calls, while a single stalled lookup can still exhaust time.

Malformed action output gets one parsing recovery attempt. For this service, the owner sets pass_tool_call_errors_to_agent: false so unavailable lookup infrastructure raises to the caller rather than inviting alternative guesses. The caller handles the failure as an incomplete investigation. Tests distinguish a valid empty result, malformed model output, unavailable tools, call-budget exhaustion on both entry points, and a cancellation that finishes late. If failures cluster around malformed arguments, the team repairs the tool description or input schema rather than increasing the loop cap.

Common exam traps

  • Letting the model invent Observation text instead of using the tool result.
  • Treating max_tool_calls, max_history, and a timeout as interchangeable.
  • Assuming parsing retries also recover failed tool execution.
  • Removing required prompt variables while customizing system_prompt.
  • Interpreting returned error text or an exhausted call budget as business success.

What to remember

Bound access, parsing recovery, tool-error recovery, tool calls, and elapsed time separately. ReAct’s value is adaptation to real observations. Its failure mode is spending more steps on an invalid premise, malformed interface, or unavailable dependency; diagnose that cause before extending the loop.

Knowledge check

References