NVIDIANVIDIA-Certified Professional: Agentic AI2026-102.3 Build and connect custom tools, APIs, and functions for external system interaction.
Make tool inputs and results unambiguous
Completed by the knowledge check
Learning objective
Define tool contracts: names, descriptions, JSON Schema parameters, and return types.
Core idea
A tool definition serves two readers: the model choosing an operation and the runtime validating its arguments. The name and description guide selection; the parameter schema defines admissible data; the return type defines what downstream code can consume. Weakness in any one makes the others less useful.
See 0.6 for the distinction between a proposed tool call and a structured answer. Here the design question is how precisely you expose a capability. A valid argument object can still identify the wrong invoice, exceed the caller’s authority, or produce a stale result. Schema design narrows those possibilities; the adapter enforces business and authorization checks, as covered in 2.3.2.
How it works
Name one operation and describe its selection rule
Prefer a name such as lookup_invoice_status over finance_action. Its description should say when to use it, which identifier it accepts, what it returns, and whether it changes external state. “Look up one invoice by its immutable invoice ID; return payment status without creating or changing a payment” distinguishes lookup from settlement.
Do not put server secrets or authorization rules into a description and expect the model to enforce them. Descriptions support selection. The runtime supplies credentials and enforces access. A misleading description can cause the model to select a dangerous operation even when its arguments satisfy the schema.
In NVIDIA NeMo Agent Toolkit, FunctionInfo.from_fn() constructs function metadata from a callable. You can supply description explicitly; when a registered coroutine yields a callable directly, the toolkit takes the description from its docstring. Treat that docstring as an interface exposed to the agent, rather than an internal implementation comment.
Distinguish configuration from invocation parameters
Register a configurable implementation with @register_function(config_type=...). Its configuration class derives from FunctionBaseConfig, whose name identifies the component type in configuration. A workflow’s functions section selects that implementation with _type and gives the configured instance its own name.
These are different identities: the component type chooses code; the instance name selects a configured capability; the callable’s input schema describes each invocation. A database hostname belongs in deployment configuration. An invoice ID belongs in invocation arguments. Giving the model a hostname parameter unnecessarily expands the choices it can make.
For a multi-argument callable, FunctionInfo.from_fn() generates a Pydantic input model from the annotations. You can supply input_schema explicitly to add constraints and descriptions. NVIDIA’s example uses Field(..., min_length=10) and shows invalid input raising a validation error. This is a runtime check, rather than a promise in the prompt.
Describe each parameter at its input boundary
See 0.6 for how JSON Schema’s properties, required, and additionalProperties constrain an argument object. Here, make each parameter explain the business distinction that its type cannot express. In an explicit input_schema model, Field(description=...) supplies parameter-level documentation; NVIDIA’s example combines it with min_length=10.
For invoice_id, describe an immutable billing-system identifier rather than a purchase-order number or a human-readable invoice label. All three can be strings, but they refer to different things. Keep the description beside the field so schema generation carries that distinction to the tool interface. A function-level description explains when to choose the operation; field-level descriptions explain how to populate it.
The integration owner also owns compatibility. workflow.tool_names refers to configured instance names, so renaming an instance requires updating every workflow and evaluation configuration that names it. Changing a published description changes the model’s selection instructions even when the Python signature stays identical. Treat that as a behavior change: rerun the selection evaluation, including cases where a neighboring tool is the correct choice.
Type the result as carefully as the request
NeMo Agent Toolkit functions expose an input schema and optional single-output and streaming-output schemas. These use Pydantic models for runtime validation and conversion. Annotate a callable’s return type with the intended result model rather than returning an undocumented dictionary or a sentence that downstream code must parse.
For the invoice example, define an application result model with invoice_id, payment_status, and observed_at. Explain whether observed_at is the billing system’s observation time or the adapter’s fetch time. If “not found” is an expected business outcome, give it an explicit result shape instead of returning an empty string that could also mean a broken connector.
Choose the output mode deliberately. ainvoke() consumes a single result, while astream() consumes streaming results. Check has_single_output and has_streaming_output before choosing the invocation method; NVIDIA documents an error when the requested mode is unsupported. A sequence of progress messages does not automatically establish a final, typed business result; consumers must know which output they are reading.
Key distinctions and trade-offs
The four interface elements prevent different classes of error:
| Element | Deciding question | Mechanism | Cost or limitation |
|---|---|---|---|
| Name | Which operation should the agent select? | Specific configured function name | Ambiguous names increase selection mistakes |
| Description | When does this operation fit? | description or callable docstring | Longer text consumes model context and can still be misunderstood |
| Parameters | Which argument objects are admissible? | Input model; properties, required, additionalProperties | Structural validity does not prove ownership or existence |
| Return type | What can the consumer rely on? | Typed single or streaming output schema | Conversion and validation add work; valid data can still be stale |
A broader tool can reduce the number of definitions in context, but transfers more choices into arguments. Splitting lookup and mutation gives the model clearer selection cues and lets the adapter expose different permissions. Choose granularity around distinct authority and result semantics, rather than creating one tool per low-level helper function.
Architecture / decision scenario
An accounts-payable assistant helps a manufacturing company answer invoice-status questions. Its team has 12 lookup and settlement endpoints and a rule that the assistant cannot initiate payment. In a local evaluation of 200 requests, a proposed finance_action tool sends 18 requests toward settlement operations; separate lookup definitions send two to the wrong lookup.
The integration owner chooses lookup_invoice_status rather than exposing the generic dispatcher. Its description explicitly distinguishes status lookup from settlement. Its schema requires invoice_id and rejects unrelated fields. Its return model carries the invoice ID, status, and observation time, so the response composer can distinguish a matched result from an unrelated record.
The tempting alternative is to keep the generic tool and strengthen its description. That leaves a settlement operation selectable within the same argument space. The owner removes settlement access from the adapter’s identity as well; reducing selection mistakes does not establish authorization. The team measures selection errors, validation failures, and end-to-end latency separately before accepting the interface.
Common exam traps
- Confusing a registered component’s
_typewith its configured instance name. - Treating a description such as “read only” as an enforced permission.
- Returning an arbitrary string from a tool whose consumer expects structured fields.
- Assuming an input model proves that an external record exists or belongs to the caller.
- Calling
astream()without checkinghas_streaming_output.
Where the exam guide differs
The study guide’s suggested readings name “NVIDIA Agent Intelligence Toolkit (1.1.0).” NVIDIA’s documentation calls the product NeMo Agent Toolkit and documents FunctionInfo.from_fn() and @register_function. Read an exam reference to the former toolkit name as the same product lineage; use the documented NeMo Agent Toolkit interfaces when implementing a tool.
What to remember
Make the name select one capability, the description explain when it fits, the input schema constrain arguments, and the return type define usable results. Configuration, invocation data, authorization, and business correctness are separate concerns. Inspect generated schemas and validate both sides of the callable interface.
Knowledge check
An accounts-payable assistant answers invoice-status questions and must never initiate a payment. Today a generic finance_action tool dispatches to 12 lookup and settlement endpoints, and an evaluation shows some status questions routed toward settlement. Which design meets the requirement?
finance_action and add “never settle invoices” to its descriptionlookup_invoice_status and settle_invoice tools with precise descriptionslookup_invoice_status through an adapter identity without settlement accessfinance_action and make invoice_id a required property of its schemasettle_invoice tool leaves payment selectable, and a required invoice_id only constrains the argument shape.A developer’s invoice tool takes two arguments, db_host and invoice_id, so the model fills in both on every call. The billing database host differs between staging and production but never between requests. Where should db_host be declared?
FunctionBaseConfig subclassfunctions section selects, not to the invocation schema the model populates. An optional argument still lets the model choose a host, a description is a selection hint rather than configuration, and the result model describes output, not where the call goes.The team rewrites the published description of lookup_invoice_status to mention a new “disputed” status. The Python signature, the input model and the configured instance name are unchanged. What should happen before the change ships?
tool_names that refers to the tooltool_names is what a renamed instance requires, and the input model has not changed.The response composer consumes lookup_invoice_status and must tell a user “that invoice does not exist” without confusing it with a broken billing connector. Today the tool returns an empty string in both cases. Not found is an expected business outcome. How should the tool report it?
References
- NVIDIA, Writing Custom Functions
- NVIDIA, Functions
- NVIDIA, Workflow Configuration
- JSON Schema, object
- OWASP, LLM06 Excessive Agency
- NVIDIA, NVIDIA-Certified Professional: Agentic AI Exam Study Guide