Skip to lesson

MicrosoftMicrosoft Certified: Multi-Agent AI Solutions Expert2026-102.3 Build and integrate tool ecosystems

Constrain arguments before executing a tool

Completed by the knowledge check

Learning objective

Implement typed function-calling contracts and integrate built-in or custom tools.

Core idea

A function-call contract describes what the model can request; the implementation determines what actually happens. For an architect integrating tools, the important separation is between a schema-valid proposal and an authorized operation. You need both before a tool changes business state.

Microsoft Foundry Models function calling lets you describe functions through JSON Schema. The model returns a tool name and arguments, and your application executes a custom function and returns its result. A built-in hosted tool has a different execution owner: the provider runs the supported capability. Neither arrangement turns tool descriptions into an access-control policy.

See 0.4 for the complete agent control loop. Here the focus is the input and result contract at the point where that loop meets executable software.

How it works

Define an interface the model can follow

For Azure OpenAI Chat Completions, supply tools entries with type: "function" and a function object containing name, description, and parameters. The parameters describe a JSON object, its properties, and required fields. Use precise names and descriptions that distinguish a lookup from a mutation. A function named process with an unconstrained string argument leaves the model to invent the business interface.

Where the selected model supports structured outputs, enable strict: true inside the function definition. Microsoft documents a supported subset of JSON Schema, rather than every schema keyword. All fields must be required, and objects must set additionalProperties: false. Represent an optional value through a required field whose type includes null. Set parallel_tool_calls: false: Microsoft’s structured-output documentation says parallel function calls aren’t supported with structured outputs.

This illustrative Chat Completions tool definition restricts the shape of an order lookup:

{
  "type": "function",
  "function": {
    "name": "lookup_order",
    "description": "Read an order by its identifier.",
    "strict": true,
    "parameters": {
      "type": "object",
      "properties": { "order_id": { "type": "string" } },
      "required": ["order_id"],
      "additionalProperties": false
    }
  }
}

lookup_order and order_id are application-defined identifiers. This fragment defines an interface, not a complete request or implementation. Check the supported-model list before choosing strict generation; a valid schema doesn’t establish support in every deployment.

Validate the business meaning before dispatch

Strict generation constrains argument shape. It doesn’t establish that an order exists, belongs to the caller, or is eligible for the requested operation. Check those conditions against authoritative business data inside the handler. Take the caller identity from the authenticated application context rather than accepting a model-supplied customer identifier as proof of ownership.

For non-strict calls, parse the arguments and validate their shape as well as their meaning. Microsoft’s function-calling guidance explicitly calls for validation because generated arguments can be invalid. Reject unknown function names through an explicit dispatch map; don’t use a returned name to invoke arbitrary code. Avoid passing generated strings directly to an unrestricted command interpreter or database query.

Keep input validation distinct from result validation. If the downstream service returns an unexpected order status, the application shouldn’t convert that into a successful lookup merely because the input matched its schema. An application-defined result contract can distinguish found, not found, forbidden, and failed outcomes. Those categories are your domain design, not reserved Foundry fields.

Connect the contract to the control loop

After validating a proposal, return its observed result through the call-correlation mechanism described in 0.4. That Bite also owns tool_choice and the distinction between a conversational call identifier and business idempotency.

Choose the execution owner deliberately

Microsoft Agent Framework distinguishes local function tools from hosted tools and documents support by provider. A local function can wrap an existing business API while keeping validation and credentials in your process. A hosted tool delegates the supported operation to the service and uses that provider’s configuration and execution behavior.

Code Interpreter and File Search are hosted capabilities with specific client support. In Agent Framework’s OpenAI and Azure OpenAI provider matrix, both require the Responses client or the Foundry integration; neither is supported by Chat Completion. Choosing a model with tool-calling support doesn’t add these hosted capabilities to a Chat Completion client.

In the Python matrix, the Foundry column applies to FoundryChatClient. For FoundryAgent, configure the tools on the Foundry agent definition rather than treating that remote agent as a client-side tool host. These identifiers select the integration surface: decide whether the application constructs a client-backed agent or consumes an agent whose tool configuration lives in Foundry.

For file analysis, choose Code Interpreter on a supported client. For retrieval from uploaded files, choose File Search when that is the required capability. Keep the custom lookup_order handler responsible for the order API. A hosted analysis or retrieval capability doesn’t automatically inherit that handler’s caller checks or business result contract.

For a custom business operation, define the narrow interface and own its implementation. For a supported built-in capability, use the provider’s integration instead of inventing a local imitation. When a hosted tool needs approval, follow its provider mechanism; local function-tool approval doesn’t automatically intercept service-side execution. See 2.3.4 for the MCP approval path.

Key distinctions and trade-offs

Typed arguments versus authorized actions: JSON Schema constrains structure. The backend enforces caller access and business rules. A schema-valid identifier can still identify someone else’s order.

Function declaration versus implementation: A model can request a declared function without implementing it. Your handler or the hosted provider must execute it and supply an observed result.

Built-in versus custom: Built-in tools reduce implementation work for a supported capability. Custom functions expose your domain operations but make your application responsible for validation, error handling, and execution.

A narrow contract improves predictable selection and validation. An unrestricted text parameter accommodates more requests but moves interpretation into the handler. Don’t broaden the interface merely to avoid rejecting ambiguous input; clarification can be the correct outcome.

Architecture / decision scenario

An order assistant needs to read order status and analyze a customer-uploaded file. You keep lookup_order on Azure OpenAI Chat Completions as a strict local function with only order_id. The handler checks caller ownership using the application’s authenticated context. File analysis goes through a separate Responses-backed agent using Code Interpreter; you don’t attach that hosted tool to the Chat Completion client.

Your dispatch map validates the lookup and queries the authorized backend, returning the observation through the loop described in 0.4. A forbidden lookup remains forbidden even if its arguments are schema-valid. The assistant receives that outcome instead of an invented status.

If you deploy the analysis role through Foundry instead, select FoundryChatClient for a client-backed Agent Framework integration, or configure Code Interpreter on the agent definition for FoundryAgent. Record which component owns each operation so a failed hosted analysis isn’t mistaken for a bug in the order handler. Strict generation, business validation, and provider integration each solve a different part of the request.

Common exam traps

  • Treating strict: true as authorization or business validation.
  • Assuming the full JSON Schema language is supported for strict function calling.
  • Leaving parallel_tool_calls enabled with structured outputs.
  • Executing a model-returned function name outside an approved dispatch map.
  • Attaching Code Interpreter or File Search to a Chat Completion client.
  • Assuming a hosted tool works with every framework model provider.

What to remember

Define the tool schema, validate the requested operation, and return an observed result to its call identifier. Strict generation controls shape; the handler controls business meaning. Choose local or hosted execution from the capability and the documented provider support.

Knowledge check

References