NVIDIANVIDIA-Certified Professional: Agentic AI2026-105.3 Engineer planning strategies for sequential and multi-step decision-making.
Make plan completion depend on checked results
Completed by the knowledge check
Learning objective
Represent plans as to-do lists or DAGs with explicit success checks.
Core idea
A plan representation must tell an executor what can run next and what makes its result acceptable. A to-do list records intended work and progress. A directed acyclic graph (DAG) additionally makes prerequisites explicit, so independent work can proceed without releasing dependent work prematurely.
Neither representation proves that the task succeeded. A completed tool call can produce an empty document, the wrong accounting period, or a valid answer for another customer. Attach a success check to the result that a downstream step actually needs. Completion means that check passed, not that the model wrote “completed.”
See 5.2.2 for choosing verifiable subtasks. This lesson takes those subtasks and turns them into a plan that exposes readiness, execution progress, and acceptance separately.
How it works
Use a list for visible progress
LangChain’s Python TodoListMiddleware, supplied through the agent’s middleware argument, provides a write_todos tool and planning instructions. The Deep Agents overview documents task statuses pending, in_progress, and completed, stored in agent state. Starting in Deep Agents v0.7, task planning is opt-in: explicitly add TodoListMiddleware when you need it.
This is a useful representation for a short sequence whose next step is unambiguous. The list can tell a reader that the assistant is collecting documents rather than drafting its answer. Keep each item tied to a deliverable, such as “calculate the approved period’s totals,” rather than “think about the totals.”
Treat status as the progress surface, and put verification behind it. In an application built around write_todos, have the execution workflow check the associated artifact before accepting an item’s completion. The list’s status labels communicate work; the team’s acceptance logic determines whether the result can be used. A prompt asking the model to check its work is weaker than a check that reads the returned period identifier and compares it with the request.
NeMo Agent Toolkit’s rewoo_agent supplies an ordered list form: a JSON array with plan and an evidence object containing placeholder, tool, and tool_input. A later tool_input can reference #E1; execution substitutes results in step order (see 5.2.2). This format carries neither a status field nor an acceptance field, so add success checks around execution.
A plain to-do list also leaves dependencies implicit. If “draft summary” depends on both calculations and source verification, its position after those items does not by itself encode a scheduler condition. Use an explicit dependency model when a consumer must wait for several independent producers.
Use a DAG for prerequisites
LangGraph’s Python Graph API provides StateGraph, nodes, and edges. A node performs work and returns state updates; an edge expresses execution order. For a fixed DAG, add edges only from prerequisites to consumers and reject a candidate plan with a cycle before dispatching work. A repair loop can surround that DAG, but the loop is not itself acyclic.
For an always-selected pair of prerequisite branches, builder.add_edge(["totals", "sources"], "draft") waits for both listed nodes to complete before running draft. This list-form edge matters: two separate incoming edges are not equivalent when branches finish in different supersteps. The documented consequence is that the consumer can run more than once with separate edges.
If a conditional route omits a listed prerequisite, the list-form join never fires and raises no error. Use it only when every listed branch runs. For selected branches, separate incoming edges with builder.add_node(d, defer=True) run d once after those branches finish. The boundary is graph-wide: defer=True waits until no tasks are pending anywhere in the graph, including unrelated branches. A Send addressed to d still invokes it separately.
Node completion is still not business acceptance. Have a check node evaluate producer results and use add_conditional_edges() to select the consuming node or a repair/stop path. Keep acceptance state explicit, rather than leaving the next model call to infer it from narrative history.
NVIDIA’s integration path is workflow._type: langgraph_wrapper, with graph pointing to the exported graph and the nvidia-nat-langchain package installed. The wrapper runs the graph through NeMo Agent Toolkit; the graph implementation still owns dependencies and success checks. Checkpoint persistence is a separate concern covered in 5.4.2.
Define checks beside outputs
Reuse 5.2.2’s application-defined subtask fields: required_inputs, produced_result, verification, and blocked_dependents. Add execution status separately from the acceptance result. Record the observed artifact apart from the proposed plan so that a planned produced_result cannot supply its own proof of completion.
For a finance analytics assistant, useful rules include matching the requested period, reconciling a calculated sum with the source rows, and verifying that every published claim points to a source record. An HTTP success response is a transport outcome; it does not replace these checks. A model judge can assess qualitative readability, but a deterministic comparison is preferable for a period identifier or an arithmetic total.
When verification fails, record the condition and withhold the listed blocked_dependents (see 5.2.2). Keep their blocked execution status distinct from the producer’s rejected acceptance result, so the dashboard does not report every unexecuted consumer as an independent failure.
A check node, not node completion, decides whether the producer results release the draft or take the repair/stop path.
Key distinctions and trade-offs
Choose the representation by its execution requirement:
| Representation | Deciding condition | Mechanism | Cost or limitation |
|---|---|---|---|
| To-do list | A short sequence needs clear progress | TodoListMiddleware, write_todos | Dependency and acceptance rules need separate application logic |
| DAG | Multiple producers must release consumers in order | StateGraph, explicit edges and joins | More plan validation and scheduling structure |
| Check after either representation | A returned artifact must satisfy a task condition | Check node and add_conditional_edges() | Validation latency and maintenance of task-specific rules |
A DAG exposes parallelism, but parallel calls still consume shared tool and model capacity. A list is cheaper to understand, but hiding real dependencies in item wording shifts the burden onto the planner at every turn. Pick the simplest representation that makes readiness and acceptance unambiguous.
Architecture / decision scenario
A regional publisher builds an analytics assistant for campaign reports. It must finish within 25 seconds. In the team’s hypothetical test, revenue aggregation takes 8 seconds, attribution verification takes 11 seconds, and drafting takes 5 seconds. A fully serial to-do implementation consumes 24 seconds before other overhead; a parallel prerequisite pair followed by drafting consumes 16 seconds before overhead.
The product owner proposes retaining the list because it already displays progress. The workflow engineer chooses a DAG for execution and keeps the list as a view. Both aggregation and attribution verification always run, so a list-form edge joins their outputs. Drafting is eligible only after a check confirms the same campaign identifier and reporting period in both results.
A tool returns successfully but its attribution artifact covers the previous month. Marking the list item completed and releasing the draft would create a plausible report with mismatched inputs. The check routes to repair instead. The final report also requires all campaign totals to reconcile and all mandatory sections to exist; successful prerequisite nodes alone do not satisfy that final check.
For a separate two-step request that only fetches an approved report and summarizes it, a to-do list with output checks remains adequate. There is no independent prerequisite work to overlap, so a DAG adds representation cost without the 8-second saving. The workflow engineer owns execution readiness; the analytics lead owns the reconciliation rule and acceptable reporting period.
Common exam traps
- A completed item proves its output is correct. Status describes progress; a success check establishes acceptance.
- Two incoming edges always implement an all-input join. Use the documented list-form join when every prerequisite runs.
- Every graph is a DAG. Feedback and repair can introduce cycles around an acyclic plan.
- More parallelism always meets the deadline. Measure shared capacity and check latency as well as the nominal critical path.
What to remember
Use lists for clear progress and DAGs for explicit prerequisites. Place checks between returned artifacts and their consumers, and define a final task check beyond individual step completion. A readable plan becomes executable only when its readiness and acceptance rules are unambiguous.
Knowledge check
In a LangGraph StateGraph, draft consumes the outputs of two branches that always run: totals, a single node, and sources followed by sources_verify. Each branch has its own edge into draft, and traces show draft running twice. The graph also runs an unrelated audit branch in parallel, which draft must not wait for. How should you wire draft?
draft with defer=True and keep both separate incoming edgesdraft prompt wait until both outputs appear in stateadd_edge(["totals", "sources_verify"], "draft")draft outputdraft once after both complete. defer=True would also run it once, but it waits until no tasks are pending anywhere in the graph, including the audit branch.A graph routes conditionally: the sources branch runs only when a request asks for external citations, while totals always runs. draft is joined with add_edge(["totals", "sources"], "draft"). On requests without citations, no draft appears and no error is raised. The graph has no other branches. Which change makes draft run once on every request?
draft with defer=Truedraft with defer=Truerecursion_limit above the longest branchSend to draft from each branch the route selectsdefer=True run draft once after whichever branches were selected; with no unrelated branches, its graph-wide wait costs nothing extra. Deferring draft does not help while the list-form join still names sources , and a Send invokes the node separately for each message.An analytics assistant tracks its work with write_todos. A tool call succeeds, the model marks “collect attribution data” as completed, and the draft is written, but the attribution artifact covers the previous month. The draft must be released only when every input matches the requested period. Which change enforces that?
completedadd_conditional_edges() that reads the returned period identifier and compares it with the request releases the draft or takes the repair path. A prompt to self-check is weaker than a deterministic comparison, an HTTP success is a transport outcome, and DAG edges alone encode order, not acceptance.A request fetches one approved report and then summarizes it. The summary must use only the approved report. The product owner wants every workflow to use a DAG for consistency. Your criterion is the simplest representation that makes readiness and acceptance unambiguous. Which representation should you choose?
StateGraph DAG with a list-form join before the summaryrewoo_agent plan whose evidence entries record each step’s statuscompleted status serves as acceptancecompleted reports progress. ReWOO’s evidence format carries neither a status field nor an acceptance field.References
LangChain, Built-in middleware: To-do list
LangChain, Deep Agents overview
LangChain, Use the Graph API
LangChain, Graph API overview
NVIDIA, Running Existing LangGraph Agents in NVIDIA NeMo Agent Toolkit
NVIDIA, Configure the ReWOO Agent