在執行時用結構化輸入自訂代理行為

你可以用 結構化輸入自訂代理的 Foundry 模型在執行時處理請求的方式。 結構化輸入是使用 Handlebar 範本語法在 Agent 中定義的預留位置 ({{variableName}})。 執行時,你可以提供實際值,動態自訂代理指令、工具資源配置和回應參數——而不必為每個配置建立獨立的代理版本。

在本文中,您將學習如何:

  • 在代理人定義中定義結構化輸入
  • 在 Agent 指示中使用 Handlebar 範本
  • 動態配置工具資源,如程式碼直譯器與檔案搜尋
  • 在執行時透過 Responses API 傳遞結構化輸入值

先決條件

  • 基本 或標準代理環境。
  • 這是你語言的最新 SDK 套件。 請參閱 快速入門 頁面了解安裝步驟。
  • Azure憑證已配置以進行身份驗證(例如 DefaultAzureCredential)。
  • 你的 Foundry 專案端點網址和模型部署名稱。

Important

不要將秘密、存取權杖或其他憑證作為結構化輸入傳遞。 應用程式日誌或追蹤可能會在請求中擷取結構化輸入值。 把憑證存放在專案連線或其他管理的秘密儲存庫裡。

什麼是結構化輸入?

結構化輸入使用把手列模板語法({{variableName}})來建立參數化的代理定義。 你可以在代理定義中定義輸入結構,每個 structured_inputs輸入都有名稱、描述、類型和可選的預設值。 執行時,先提供實際值以取代模板佔位符,然後由代理處理請求。

結構化輸入支援兩種覆寫類別:

  • 指令覆寫:參數化代理指令、回應層指令及系統或開發者訊息。
  • 工具資源覆寫:在程式運行時動態配置工具的屬性,包括:
    • 檔案搜尋向量儲存區 ID
    • 程式碼直譯器檔案 ID 與容器
    • 模型情境協定(MCP)伺服器網址與標頭

對於像 file_ids 和 vector_store_ids這樣的陣列欄位,系統會在執行時自動移除空字串值。 此功能允許彈性輸入數量——定義比所需更多的模板槽位,並保留未使用的槽位。

支援的結構化輸入屬性

下表列出支援把手列範本的代理定義屬性:

分類 財產 描述
說明 代理人 instructions 代理層級指令文字
說明 回應 instructions 回應 API 請求中傳遞的指令
說明 系統/開發者訊息 content 輸入陣列中的訊息內容
檔案搜尋 vector_store_ids 向量儲存 ID 陣列(空值被移除)
程式碼直譯器 container (字串) 預設定容器的容器 ID
程式碼直譯器 container.file_ids (陣列) 自動容器中的檔案 ID(空值被移除)
MCP server_label MCP 伺服器的標籤
MCP server_url MCP 伺服器端點的網址
MCP headers (數值) HTTP 標頭值作為鍵值對
Azure AI 搜尋服務 filter 套用於搜尋索引的 OData 濾波表達式

使用結構化輸入搭配代理指令

結構化輸入最簡單的用途是參數化代理指令。 在instructions欄位中定義 Handlebars 模板,並在運行時賦予值。 這種方法讓你能針對不同使用者或情境個人化代理行為,而無需建立多個代理版本。

以下範例建立一個代理,其指令包含使用者專屬細節,並在建立回應時提供這些值。

from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import PromptAgentDefinition, StructuredInputDefinition
from azure.identity import DefaultAzureCredential

# Format: "https://resource_name.ai.azure.com/api/projects/project_name"
PROJECT_ENDPOINT = "your_project_endpoint"

# Create clients to call Foundry API
project = AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=DefaultAzureCredential())
openai = project.get_openai_client()

# Create agent with handlebar templates in instructions
agent = project.agents.create_version(
    agent_name="structured-input-agent",
    definition=PromptAgentDefinition(
        model="gpt-5-mini",
        instructions=(
            "You are a helpful assistant. "
            "The user's name is {{userName}} and their role is {{userRole}}. "
            "Greet them and confirm their details."
        ),
        structured_inputs={
            "userName": StructuredInputDefinition(
                description="The user's name", required=True, schema={"type": "string"},
            ),
            "userRole": StructuredInputDefinition(
                description="The user's role", required=True, schema={"type": "string"},
            ),
        },
    ),
)
print(f"Agent created: {agent.name}, version: {agent.version}")

# Create conversation and send request with runtime values
conversation = openai.conversations.create()
response = openai.responses.create(
    conversation=conversation.id,
    input="Hello! Can you confirm my details?",
    extra_body={
        "agent_reference": {"name": agent.name, "type": "agent_reference"},
        "structured_inputs": {"userName": "Alice Smith", "userRole": "Senior Developer"},
    },
)
print(response.output_text)

預期產出

Agent created: structured-input-agent, version: 1
Hello Alice Smith! I can confirm your details: your name is Alice Smith and your role is Senior Developer. How can I help you today?

代理在處理請求之前,會將說明中的{{userName}}和{{userRole}}佔位符替換成「Alice Smith」和「Senior Developer」。

using System;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.AI.Extensions.OpenAI;
using Azure.Identity;
using OpenAI.Responses;

// Format: "https://resource_name.ai.azure.com/api/projects/project_name"
var projectEndpoint = "your_project_endpoint";

// Create project client to call Foundry API
AIProjectClient projectClient = new(
    endpoint: new Uri(projectEndpoint),
    tokenProvider: new DefaultAzureCredential());

// Create agent with handlebar templates in instructions
DeclarativeAgentDefinition agentDefinition = new(model: "gpt-5-mini")
{
    Instructions = "You are a helpful assistant. "
        + "The user's name is {{userName}} and their role is {{userRole}}. "
        + "Greet them and confirm their details.",
    StructuredInputs =
    {
        ["userName"] = new StructuredInputDefinition
            { Description = "The user's name", IsRequired = true },
        ["userRole"] = new StructuredInputDefinition
            { Description = "The user's role", IsRequired = true }
    }
};
AgentVersion agent = projectClient.AgentAdministrationClient.CreateAgentVersion(
    agentName: "structured-input-agent", options: new(agentDefinition));

// Send response with runtime structured input values
AgentReference agentRef = new(name: agent.Name, version: agent.Version);
ProjectResponsesClient responseClient =
    projectClient.ProjectOpenAIClient.GetProjectResponsesClientForAgent(agentRef);

CreateResponseOptions responseOptions = new()
{
    Input = [ResponseItem.CreateUserMessageItem("Hello! Can you confirm my details?")]
};
responseOptions.Patch.Set(
    "$.structured_inputs[\"userName\"]"u8,
    BinaryData.FromObjectAsJson("Alice Smith"));
responseOptions.Patch.Set(
    "$.structured_inputs[\"userRole\"]"u8,
    BinaryData.FromObjectAsJson("Senior Developer"));

ResponseResult response = responseClient.CreateResponse(responseOptions);
Console.WriteLine(response.GetOutputText());

// Clean up
projectClient.AgentAdministrationClient.DeleteAgentVersion(
    agentName: agent.Name, agentVersion: agent.Version);

預期產出

Hello Alice Smith! I can confirm your details: your name is Alice Smith and your role is Senior Developer. How can I help you today?

StructuredInputs代理定義上的字典會將範本名稱對應到其結構。 執行時,使用 Patch.Set 方法於 CreateResponseOptions 透過 $.structured_inputs JSON 路徑提供實際值。

import { DefaultAzureCredential } from "@azure/identity";
import { AIProjectClient } from "@azure/ai-projects";

// Format: "https://resource_name.ai.azure.com/api/projects/project_name"
const PROJECT_ENDPOINT = "your_project_endpoint";

export async function main(): Promise<void> {
  // Create clients to call Foundry API
  const project = new AIProjectClient(PROJECT_ENDPOINT, new DefaultAzureCredential());
  const openai = project.getOpenAIClient();

  // Create agent with handlebar templates in instructions
  const agent = await project.agents.createVersion("structured-input-agent", {
    kind: "prompt",
    model: "gpt-5-mini",
    instructions:
      "You are a helpful assistant. " +
      "The user's name is {{userName}} and their role is {{userRole}}. " +
      "Greet them and confirm their details.",
    structured_inputs: {
      userName: { description: "The user's name", required: true },
      userRole: { description: "The user's role", required: true },
    },
  });
  console.log(`Agent created: ${agent.name}, version: ${agent.version}`);

  // Create conversation and send request with runtime values
  const conversation = await openai.conversations.create();
  const response = await openai.responses.create(
    {
      conversation: conversation.id,
      input: "Hello! Can you confirm my details?",
    },
    {
      body: {
        agent_reference: { name: agent.name, type: "agent_reference" },
        structured_inputs: { userName: "Alice Smith", userRole: "Senior Developer" },
      },
    },
  );
  console.log(response.output_text);

  // Clean up
  await project.agents.deleteVersion(agent.name, agent.version);
}

main().catch(console.error);

預期產出

Agent created: structured-input-agent, version: 1
Hello Alice Smith! I can confirm your details: your name is Alice Smith and your role is Senior Developer. How can I help you today?

代理定義用於 structured_inputs 宣告範本結構。 執行時,將參數中的 body 實際值與 agent_reference. 一併傳遞。

新增相依性至您的pom.xml:

<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-ai-agents</artifactId>
    <version>2.4.0</version>
</dependency>
import com.azure.ai.agents.AgentsClient;
import com.azure.ai.agents.AgentsClientBuilder;
import com.azure.ai.agents.AgentsServiceVersion;
import com.azure.ai.agents.ResponsesClient;
import com.azure.ai.agents.models.AgentReference;
import com.azure.ai.agents.models.AgentVersionDetails;
import com.azure.ai.agents.models.AzureCreateResponseOptions;
import com.azure.ai.agents.models.PromptAgentDefinition;
import com.azure.ai.agents.models.StructuredInputDefinition;
import com.azure.core.util.BinaryData;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.openai.models.responses.Response;
import com.openai.models.responses.ResponseCreateParams;

import java.util.LinkedHashMap;
import java.util.Map;

public class StructuredInputInstructionsExample {
    public static void main(String[] args) {
        // Format: "https://resource_name.ai.azure.com/api/projects/project_name"
        String projectEndpoint = "your_project_endpoint";

        AgentsClientBuilder builder = new AgentsClientBuilder()
            .credential(new DefaultAzureCredentialBuilder().build())
            .endpoint(projectEndpoint)
            .serviceVersion(AgentsServiceVersion.getLatest());

        AgentsClient agentsClient = builder.buildAgentsClient();
        ResponsesClient responsesClient = builder.buildResponsesClient();

        // Define structured input schemas
        Map<String, StructuredInputDefinition> inputDefs = new LinkedHashMap<>();
        inputDefs.put("userName",
            new StructuredInputDefinition().setDescription("The user's name").setRequired(true));
        inputDefs.put("userRole",
            new StructuredInputDefinition().setDescription("The user's role").setRequired(true));

        // Create agent with handlebar templates in instructions
        AgentVersionDetails agent = agentsClient.createAgentVersion(
            "structured-input-agent",
            new PromptAgentDefinition("gpt-5-mini")
                .setInstructions("You are a helpful assistant. "
                    + "The user's name is {{userName}} and their role is {{userRole}}. "
                    + "Greet them and confirm their details.")
                .setStructuredInputs(inputDefs));

        // Supply structured input values at runtime
        Map<String, BinaryData> inputValues = new LinkedHashMap<>();
        inputValues.put("userName", BinaryData.fromObject("Alice Smith"));
        inputValues.put("userRole", BinaryData.fromObject("Senior Developer"));

        Response response = responsesClient.createAzureResponse(
            new AzureCreateResponseOptions()
                .setAgentReference(
                    new AgentReference(agent.getName()).setVersion(agent.getVersion()))
                .setStructuredInputs(inputValues),
            ResponseCreateParams.builder()
                .input("Hello! Can you confirm my details?"));

        System.out.println("Response: " + response.output());

        // Clean up
        agentsClient.deleteAgentVersion(agent.getName(), agent.getVersion());
    }
}

預期產出

Response: Hello Alice Smith! I can confirm your details: your name is Alice Smith and your role is Senior Developer. How can I help you today?

Java SDK 使用 StructuredInputDefinition 作為代理架構,Map<String, BinaryData> 作為透過 AzureCreateResponseOptions 傳遞的執行時值。

建立一個具有結構化輸入的代理

curl -X POST "$FOUNDRY_PROJECT_ENDPOINT/agents?api-version=v1" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  --data-binary @- <<EOF
{
    "name": "structured-input-agent",
    "definition": {
      "kind": "prompt",
      "model": "<MODEL_DEPLOYMENT>",
      "instructions": "You are a helpful assistant. The user's name is {{userName}} and their role is {{userRole}}. Greet them and confirm their details.",
      "structured_inputs": {
        "userName": {
          "type": "string",
          "description": "The user's name",
          "default_value": "Unknown"
        },
        "userRole": {
          "type": "string",
          "description": "The user's role",
          "default_value": "User"
        }
      }
    }
}
EOF

建立帶有結構化輸入值的回應

curl -X POST "$FOUNDRY_PROJECT_ENDPOINT/openai/v1/responses" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -d '{
    "agent_reference": {
      "type": "agent_reference",
      "name": "structured-input-agent"
    },
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": "Hello! Can you confirm my details?"
      }
    ],
    "structured_inputs": {
      "userName": "Alice Smith",
      "userRole": "Senior Developer"
    }
  }'

代理定義的 structured_inputs 物件宣告了帶有描述和預設值的結構。 回應請求的 structured_inputs 提供了取代 {{userName}} 和 {{userRole}} 範本的實際執行時值。

搭配 Code Interpreter 使用結構化輸入

透過結構化輸入,你可以動態配置程式碼解譯器工具在執行時使用的檔案與容器。 在工具的 file_ids 或 container 屬性中定義 Handlebar 範本,然後在建立回應時提供實際的 ID。

from io import BytesIO
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
    PromptAgentDefinition,
    CodeInterpreterTool,
    AutoCodeInterpreterToolParam,
    StructuredInputDefinition,
)
from azure.identity import DefaultAzureCredential

# Format: "https://resource_name.ai.azure.com/api/projects/project_name"
PROJECT_ENDPOINT = "your_project_endpoint"

# Create clients to call Foundry API
project = AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=DefaultAzureCredential())
openai = project.get_openai_client()

# Upload a CSV file for the code interpreter
csv_file = BytesIO(b"x\n1\n2\n3\n")
csv_file.name = "numbers.csv"
uploaded = openai.files.create(purpose="assistants", file=csv_file)
print(f"File uploaded (id: {uploaded.id})")

# Create agent with a template placeholder for the file ID
tool = CodeInterpreterTool(
    container=AutoCodeInterpreterToolParam(file_ids=["{{analysis_file_id}}"])
)
agent = project.agents.create_version(
    agent_name="code-interp-structured",
    definition=PromptAgentDefinition(
        model="gpt-5-mini",
        instructions="You are a helpful data analyst.",
        tools=[tool],
        structured_inputs={
            "analysis_file_id": StructuredInputDefinition(
                description="File ID for the code interpreter",
                required=True,
                schema={"type": "string"},
            ),
        },
    ),
)

# Supply the actual file ID at runtime
conversation = openai.conversations.create()
response = openai.responses.create(
    conversation=conversation.id,
    input="Read numbers.csv and return the sum of x.",
    extra_body={
        "agent_reference": {"name": agent.name, "type": "agent_reference"},
        "structured_inputs": {"analysis_file_id": uploaded.id},
    },
    tool_choice="required",
)
print(response.output_text)

預期產出

File uploaded (id: <file-id>)
The sum of x in numbers.csv is 6.

{{analysis_file_id}}工具陣列中的file_ids佔位符會在執行時被實際的檔案 ID 取代。 透過這種方法,你可以為每個請求重複使用相同的代理定義,但使用不同的檔案。

using System;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.AI.Extensions.OpenAI;
using Azure.Identity;
using OpenAI.Responses;

// Format: "https://resource_name.ai.azure.com/api/projects/project_name"
var projectEndpoint = "your_project_endpoint";

// Create project client to call Foundry API
AIProjectClient projectClient = new(
    endpoint: new Uri(projectEndpoint),
    tokenProvider: new DefaultAzureCredential());

// Create agent with a structured input placeholder for the file ID
DeclarativeAgentDefinition agentDefinition = new(model: "gpt-5-mini")
{
    Instructions = "You are a helpful data analyst.",
    Tools = {
        ResponseTool.CreateCodeInterpreterTool(
            new CodeInterpreterToolContainer(
                CodeInterpreterToolContainerConfiguration
                    .CreateAutomaticContainerConfiguration(
                        fileIds: ["{{analysis_file_id}}"])))
    },
    StructuredInputs =
    {
        ["analysis_file_id"] = new StructuredInputDefinition
            { Description = "File ID for the code interpreter", IsRequired = true }
    }
};
AgentVersion agent = projectClient.AgentAdministrationClient.CreateAgentVersion(
    agentName: "code-interp-structured", options: new(agentDefinition));

// Supply the actual file ID at runtime
AgentReference agentRef = new(name: agent.Name, version: agent.Version);
ProjectResponsesClient responseClient =
    projectClient.ProjectOpenAIClient.GetProjectResponsesClientForAgent(agentRef);

CreateResponseOptions responseOptions = new()
{
    Input = [ResponseItem.CreateUserMessageItem(
        "Read numbers.csv and return the sum of x.")]
};
responseOptions.Patch.Set(
    "$.structured_inputs[\"analysis_file_id\"]"u8,
    BinaryData.FromObjectAsJson("<uploaded-file-id>"));

ResponseResult response = responseClient.CreateResponse(responseOptions);
Console.WriteLine(response.GetOutputText());

// Clean up
projectClient.AgentAdministrationClient.DeleteAgentVersion(
    agentName: agent.Name, agentVersion: agent.Version);

預期產出

The sum of x in numbers.csv is 6.
import { DefaultAzureCredential } from "@azure/identity";
import { AIProjectClient } from "@azure/ai-projects";

// Format: "https://resource_name.ai.azure.com/api/projects/project_name"
const PROJECT_ENDPOINT = "your_project_endpoint";

export async function main(): Promise<void> {
  const project = new AIProjectClient(PROJECT_ENDPOINT, new DefaultAzureCredential());
  const openai = project.getOpenAIClient();

  // Upload a file for code interpreter
  const file = new File(["x\n1\n2\n3\n"], "numbers.csv");
  const uploaded = await openai.files.create({ file, purpose: "assistants" });
  console.log(`File uploaded (id: ${uploaded.id})`);

  // Create agent with a template placeholder for the file ID
  const agent = await project.agents.createVersion("code-interp-structured", {
    kind: "prompt",
    model: "gpt-5-mini",
    instructions: "You are a helpful data analyst.",
    tools: [
      {
        type: "code_interpreter",
        container: { type: "auto", file_ids: ["{{analysis_file_id}}"] },
      },
    ],
    structured_inputs: {
      analysis_file_id: {
        description: "File ID for the code interpreter",
        required: true,
      },
    },
  });

  // Supply the actual file ID at runtime
  const conversation = await openai.conversations.create();
  const response = await openai.responses.create(
    {
      conversation: conversation.id,
      input: "Read numbers.csv and return the sum of x.",
      tool_choice: "required",
    },
    {
      body: {
        agent_reference: { name: agent.name, type: "agent_reference" },
        structured_inputs: { analysis_file_id: uploaded.id },
      },
    },
  );
  console.log(response.output_text);

  // Clean up
  await project.agents.deleteVersion(agent.name, agent.version);
}

main().catch(console.error);

預期產出

File uploaded (id: <file-id>)
The sum of x in numbers.csv is 6.
import com.azure.ai.agents.AgentsClient;
import com.azure.ai.agents.AgentsClientBuilder;
import com.azure.ai.agents.AgentsServiceVersion;
import com.azure.ai.agents.ResponsesClient;
import com.azure.ai.agents.models.*;
import com.azure.core.util.BinaryData;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.openai.models.responses.Response;
import com.openai.models.responses.ResponseCreateParams;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

public class CodeInterpreterStructuredInputExample {
    public static void main(String[] args) {
        // Format: "https://resource_name.ai.azure.com/api/projects/project_name"
        String projectEndpoint = "your_project_endpoint";

        AgentsClientBuilder builder = new AgentsClientBuilder()
            .credential(new DefaultAzureCredentialBuilder().build())
            .endpoint(projectEndpoint)
            .serviceVersion(AgentsServiceVersion.getLatest());

        AgentsClient agentsClient = builder.buildAgentsClient();
        ResponsesClient responsesClient = builder.buildResponsesClient();

        // Create code interpreter tool with a template placeholder
        CodeInterpreterTool tool = new CodeInterpreterTool()
            .setContainer(new AutoCodeInterpreterToolParameter()
                .setFileIds(Arrays.asList("{{analysis_file_id}}")));

        Map<String, StructuredInputDefinition> inputDefs = new LinkedHashMap<>();
        inputDefs.put("analysis_file_id",
            new StructuredInputDefinition()
                .setDescription("File ID for the code interpreter")
                .setRequired(true));

        AgentVersionDetails agent = agentsClient.createAgentVersion(
            "code-interp-structured",
            new PromptAgentDefinition("gpt-5-mini")
                .setInstructions("You are a helpful data analyst.")
                .setTools(Arrays.asList(tool))
                .setStructuredInputs(inputDefs));

        // Supply the actual file ID at runtime
        Map<String, BinaryData> inputValues = new LinkedHashMap<>();
        inputValues.put("analysis_file_id",
            BinaryData.fromObject("<uploaded-file-id>"));

        Response response = responsesClient.createAzureResponse(
            new AzureCreateResponseOptions()
                .setAgentReference(
                    new AgentReference(agent.getName()).setVersion(agent.getVersion()))
                .setStructuredInputs(inputValues),
            ResponseCreateParams.builder()
                .input("Read numbers.csv and return the sum of x."));

        System.out.println("Response: " + response.output());

        // Clean up
        agentsClient.deleteAgentVersion(agent.getName(), agent.getVersion());
    }
}

預期產出

Response: The sum of x in numbers.csv is 6.

建立一個包含動態程式碼直譯器檔案的代理程式

curl -X POST "$FOUNDRY_PROJECT_ENDPOINT/agents?api-version=v1" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  --data-binary @- <<EOF
{
    "name": "code-interp-structured",
    "definition": {
      "kind": "prompt",
      "model": "<MODEL_DEPLOYMENT>",
      "instructions": "You are a helpful data analyst.",
      "tools": [
        {
          "type": "code_interpreter",
          "container": {
            "type": "auto",
            "file_ids": ["{{analysis_file_id}}"]
          }
        }
      ],
      "structured_inputs": {
        "analysis_file_id": {
          "description": "File ID for the code interpreter",
          "required": true,
          "schema": {"type": "string"}
        }
      }
    }
}
EOF

建立包含檔案 ID 的回應

curl -X POST "$FOUNDRY_PROJECT_ENDPOINT/openai/v1/responses" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -d '{
    "agent_reference": {
      "type": "agent_reference",
      "name": "code-interp-structured"
    },
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": "Read numbers.csv and return the sum of x."
      }
    ],
    "structured_inputs": {
      "analysis_file_id": "<FILE_ID>"
    },
    "tool_choice": "required"
  }'

執行時,{{analysis_file_id}} 的範本會被實際的檔案 ID file_ids 取代。 你可以設定多個檔案 ID 佔位符,並保留未使用的。 空值會自動從陣列中移除。

透過結構化輸入,你可以動態設定執行時哪個向量會儲存檔案搜尋工具的查詢。 在 vector_store_ids 陣列中定義模板佔位符,然後在建立回應時提供實際的向量儲存區 ID。

from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
    PromptAgentDefinition,
    FileSearchTool,
    StructuredInputDefinition,
)
from azure.identity import DefaultAzureCredential

# Format: "https://resource_name.ai.azure.com/api/projects/project_name"
PROJECT_ENDPOINT = "your_project_endpoint"

# Create clients to call Foundry API
project = AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=DefaultAzureCredential())
openai = project.get_openai_client()

# Create a vector store and upload a file
vector_store = openai.vector_stores.create(name="ProductInfoStore")
with open("product_info.md", "rb") as f:
    file = openai.vector_stores.files.upload_and_poll(
        vector_store_id=vector_store.id, file=f
    )
print(f"Vector store created (id: {vector_store.id})")

# Create agent with a template placeholder for vector store ID
tool = FileSearchTool(vector_store_ids=["{{vector_store_id}}"])
agent = project.agents.create_version(
    agent_name="file-search-structured",
    definition=PromptAgentDefinition(
        model="gpt-5-mini",
        instructions="You are a helpful assistant that searches product information.",
        tools=[tool],
        structured_inputs={
            "vector_store_id": StructuredInputDefinition(
                description="Vector store ID for file search",
                required=True,
                schema={"type": "string"},
            ),
        },
    ),
)

# Supply the actual vector store ID at runtime
conversation = openai.conversations.create()
response = openai.responses.create(
    conversation=conversation.id,
    input="Tell me about Contoso products",
    extra_body={
        "agent_reference": {"name": agent.name, "type": "agent_reference"},
        "structured_inputs": {"vector_store_id": vector_store.id},
    },
)
print(response.output_text)

預期產出

Vector store created (id: <vector-store-id>)
Based on the product information, Contoso offers several product lines including...

{{vector_store_id}}佔位符會在執行時被實際的向量儲存 ID 取代。 你可以定義多個向量儲存佔位符,以啟用分層或特定情境的知識庫。

using System;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.AI.Extensions.OpenAI;
using Azure.Identity;
using OpenAI.Responses;

// Format: "https://resource_name.ai.azure.com/api/projects/project_name"
var projectEndpoint = "your_project_endpoint";

AIProjectClient projectClient = new(
    endpoint: new Uri(projectEndpoint),
    tokenProvider: new DefaultAzureCredential());

// Create agent with a template placeholder for vector store ID
DeclarativeAgentDefinition agentDefinition = new(model: "gpt-5-mini")
{
    Instructions = "You are a helpful assistant that searches product information.",
    Tools = {
        ResponseTool.CreateFileSearchTool(
            vectorStoreIds: ["{{vector_store_id}}"])
    },
    StructuredInputs =
    {
        ["vector_store_id"] = new StructuredInputDefinition
            { Description = "Vector store ID for file search", IsRequired = true }
    }
};
AgentVersion agent = projectClient.AgentAdministrationClient.CreateAgentVersion(
    agentName: "file-search-structured", options: new(agentDefinition));

// Supply the actual vector store ID at runtime
AgentReference agentRef = new(name: agent.Name, version: agent.Version);
ProjectResponsesClient responseClient =
    projectClient.ProjectOpenAIClient.GetProjectResponsesClientForAgent(agentRef);

CreateResponseOptions responseOptions = new()
{
    Input = [ResponseItem.CreateUserMessageItem("Tell me about Contoso products")]
};
responseOptions.Patch.Set(
    "$.structured_inputs[\"vector_store_id\"]"u8,
    BinaryData.FromObjectAsJson("<vector-store-id>"));

ResponseResult response = responseClient.CreateResponse(responseOptions);
Console.WriteLine(response.GetOutputText());

// Clean up
projectClient.AgentAdministrationClient.DeleteAgentVersion(
    agentName: agent.Name, agentVersion: agent.Version);

預期產出

Based on the product information, Contoso offers several product lines including...
import { DefaultAzureCredential } from "@azure/identity";
import { AIProjectClient } from "@azure/ai-projects";

// Format: "https://resource_name.ai.azure.com/api/projects/project_name"
const PROJECT_ENDPOINT = "your_project_endpoint";

export async function main(): Promise<void> {
  const project = new AIProjectClient(PROJECT_ENDPOINT, new DefaultAzureCredential());
  const openai = project.getOpenAIClient();

  // Create a vector store (assumes file already uploaded)
  const vectorStore = await openai.vectorStores.create({ name: "ProductInfoStore" });
  console.log(`Vector store created (id: ${vectorStore.id})`);

  // Create agent with a template placeholder for vector store ID
  const agent = await project.agents.createVersion("file-search-structured", {
    kind: "prompt",
    model: "gpt-5-mini",
    instructions: "You are a helpful assistant that searches product information.",
    tools: [
      {
        type: "file_search",
        vector_store_ids: ["{{vector_store_id}}"],
      },
    ],
    structured_inputs: {
      vector_store_id: {
        description: "Vector store ID for file search",
        required: true,
      },
    },
  });

  // Supply the actual vector store ID at runtime
  const conversation = await openai.conversations.create();
  const response = await openai.responses.create(
    {
      conversation: conversation.id,
      input: "Tell me about Contoso products",
    },
    {
      body: {
        agent_reference: { name: agent.name, type: "agent_reference" },
        structured_inputs: { vector_store_id: vectorStore.id },
      },
    },
  );
  console.log(response.output_text);

  // Clean up
  await project.agents.deleteVersion(agent.name, agent.version);
}

main().catch(console.error);

預期產出

Vector store created (id: <vector-store-id>)
Based on the product information, Contoso offers several product lines including...
import com.azure.ai.agents.AgentsClient;
import com.azure.ai.agents.AgentsClientBuilder;
import com.azure.ai.agents.AgentsServiceVersion;
import com.azure.ai.agents.ResponsesClient;
import com.azure.ai.agents.models.AgentReference;
import com.azure.ai.agents.models.AgentVersionDetails;
import com.azure.ai.agents.models.AzureCreateResponseOptions;
import com.azure.ai.agents.models.FileSearchTool;
import com.azure.ai.agents.models.PromptAgentDefinition;
import com.azure.ai.agents.models.StructuredInputDefinition;
import com.azure.core.util.BinaryData;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.openai.models.responses.Response;
import com.openai.models.responses.ResponseCreateParams;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

public class FileSearchStructuredInputExample {
    public static void main(String[] args) {
        // Format: "https://resource_name.ai.azure.com/api/projects/project_name"
        String projectEndpoint = "your_project_endpoint";

        AgentsClientBuilder builder = new AgentsClientBuilder()
            .credential(new DefaultAzureCredentialBuilder().build())
            .endpoint(projectEndpoint)
            .serviceVersion(AgentsServiceVersion.getLatest());

        AgentsClient agentsClient = builder.buildAgentsClient();
        ResponsesClient responsesClient = builder.buildResponsesClient();

        // Create agent with a template placeholder for vector store ID
        FileSearchTool tool = new FileSearchTool()
            .setVectorStoreIds(Arrays.asList("{{vector_store_id}}"));

        Map<String, StructuredInputDefinition> inputDefs = new LinkedHashMap<>();
        inputDefs.put("vector_store_id",
            new StructuredInputDefinition()
                .setDescription("Vector store ID for file search")
                .setRequired(true));

        AgentVersionDetails agent = agentsClient.createAgentVersion(
            "file-search-structured",
            new PromptAgentDefinition("gpt-5-mini")
                .setInstructions(
                    "You are a helpful assistant that searches product information.")
                .setTools(Arrays.asList(tool))
                .setStructuredInputs(inputDefs));

        // Supply the actual vector store ID at runtime
        Map<String, BinaryData> inputValues = new LinkedHashMap<>();
        inputValues.put("vector_store_id",
            BinaryData.fromObject("<vector-store-id>"));

        Response response = responsesClient.createAzureResponse(
            new AzureCreateResponseOptions()
                .setAgentReference(
                    new AgentReference(agent.getName()).setVersion(agent.getVersion()))
                .setStructuredInputs(inputValues),
            ResponseCreateParams.builder()
                .input("Tell me about Contoso products"));

        System.out.println("Response: " + response.output());

        // Clean up
        agentsClient.deleteAgentVersion(agent.getName(), agent.getVersion());
    }
}

預期產出

Response: Based on the product information, Contoso offers several product lines including...

建立一個帶有動態檔案搜尋向量儲存的代理

curl -X POST "$FOUNDRY_PROJECT_ENDPOINT/agents?api-version=v1" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -d '{
    "name": "file-search-structured",
    "definition": {
      "kind": "prompt",
      "model": "<MODEL_DEPLOYMENT>",
      "instructions": "You are a helpful assistant that searches product information.",
      "tools": [
        {
          "type": "file_search",
          "vector_store_ids": [
            "vs_base_kb",
            "{{tier_specific_kb}}"
          ]
        }
      ],
      "structured_inputs": {
        "tier_specific_kb": {
          "description": "Vector store ID for customer tier",
          "required": true,
          "schema": {"type": "string"}
        }
      }
    }
  }'

建立回應並附上向量存儲庫 ID

curl -X POST "$FOUNDRY_PROJECT_ENDPOINT/openai/v1/responses" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -d '{
    "agent_reference": {
      "type": "agent_reference",
      "name": "file-search-structured"
    },
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": "Tell me about Contoso products"
      }
    ],
    "structured_inputs": {
      "tier_specific_kb": "vs_premium_kb_2024"
    }
  }'

此範例結合了靜態向量儲存(vs_base_kb)與動態向量儲存({{tier_specific_kb}})。 範本佔位符會在執行時被替換,程序會自動移除陣列中空字串值。

透過結構化輸入,你可以在執行時動態設定 Azure AI 搜尋服務 工具的索引 filter。 在 OData 濾波器表達式中定義一個把手列範本,然後在建立回應時提供實際的濾波器值。 此模式可讓單一代理定義供查詢必須限定在索引不同子集內的使用者共用,而無需針對每個篩選值建立個別的代理版本。

在插入 OData 濾波器前,先驗證數值。 只允許預期值,跳脫 OData 特殊字元,且不接受來自不受信任使用者的完整過濾表達式。

import os
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
    AISearchIndexResource,
    AzureAISearchQueryType,
    AzureAISearchTool,
    AzureAISearchToolResource,
    PromptAgentDefinition,
    StructuredInputDefinition,
)
from azure.identity import DefaultAzureCredential

# Format: "https://resource_name.ai.azure.com/api/projects/project_name"
PROJECT_ENDPOINT = "your_project_endpoint"

# Create clients to call Foundry API
project = AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=DefaultAzureCredential())
openai = project.get_openai_client()

# Create the AI Search tool with a handlebar template inside the filter expression
tool = AzureAISearchTool(
    azure_ai_search=AzureAISearchToolResource(
        indexes=[
            AISearchIndexResource(
                project_connection_id=os.environ["AI_SEARCH_PROJECT_CONNECTION_ID"],
                index_name=os.environ["AI_SEARCH_INDEX_NAME"],
                query_type=AzureAISearchQueryType.SIMPLE,
                filter="search.ismatchscoring('{{userFilter}}')",
            ),
        ]
    )
)

# Create the agent with a structured input that supplies the filter value
agent = project.agents.create_version(
    agent_name="aisearch-agent-structured-input",
    definition=PromptAgentDefinition(
        model="gpt-5-mini",
        instructions=(
            "You are a helpful assistant. You must always provide citations for "
            "answers using the tool and render them as: "
            "`\u3010message_idx:search_idx\u2020source\u3011`."
        ),
        tools=[tool],
        structured_inputs={
            "userFilter": StructuredInputDefinition(
                description="The user's search filter",
                required=True,
                schema={"type": "string"},
            ),
        },
    ),
)
print(f"Agent created (id: {agent.id}, name: {agent.name}, version: {agent.version})")

# Supply the actual filter value at runtime
stream_response = openai.responses.create(
    stream=True,
    tool_choice="required",
    input="What outdoor gear do you have?",
    extra_body={
        "agent_reference": {"name": agent.name, "type": "agent_reference"},
        "structured_inputs": {"userFilter": "boots"},
    },
)

for event in stream_response:
    if event.type == "response.completed":
        print(f"Agent response: {event.response.output_text}")

預期產出

Agent created (id: <agent-id>, name: aisearch-agent-structured-input, version: 1)
Agent response: Based on the index, the available outdoor boots include ...

{{userFilter}} 表達式中的 filter 預留位置會在搜尋執行前替換為執行階段值 boots。 你可以為每個請求提供不同的篩選值,以限定結果範圍,而無需建立新的代理版本。

using System;
using Azure.AI.Projects;
using Azure.AI.Projects.Agents;
using Azure.AI.Extensions.OpenAI;
using Azure.Identity;
using OpenAI.Responses;

// Format: "https://resource_name.ai.azure.com/api/projects/project_name"
var projectEndpoint = "your_project_endpoint";
var searchConnectionName = "my-search-connection";
var searchIndexName = "my-search-index";

AIProjectClient projectClient = new(
    endpoint: new Uri(projectEndpoint),
    tokenProvider: new DefaultAzureCredential());

// Resolve the project connection ID from the connection name
AIProjectConnection aiSearchConnection =
    projectClient.Connections.GetConnection(connectionName: searchConnectionName);

// Define the search index with a handlebar template inside the filter expression
AzureAISearchToolIndex index = new()
{
    ProjectConnectionId = aiSearchConnection.Id,
    IndexName = searchIndexName,
    QueryType = AzureAISearchQueryType.Simple,
    Filter = "search.ismatchscoring('{{userFilter}}')"
};

// Create the agent with a structured input that supplies the filter value
DeclarativeAgentDefinition agentDefinition = new(model: "gpt-5-mini")
{
    Instructions = "You are a helpful assistant. You must always provide citations for "
        + "answers using the tool and render them as: "
        + "`\u3010message_idx:search_idx\u2020source\u3011`.",
    Tools = { new AzureAISearchTool(new AzureAISearchToolOptions(indexes: [index])) },
    StructuredInputs =
    {
        ["userFilter"] = new StructuredInputDefinition
            { Description = "The user's search filter", IsRequired = true }
    }
};
AgentVersion agent = projectClient.AgentAdministrationClient.CreateAgentVersion(
    agentName: "aisearch-agent-structured-input",
    options: new(agentDefinition));

// Supply the actual filter value at runtime
AgentReference agentRef = new(name: agent.Name, version: agent.Version);
ProjectResponsesClient responseClient =
    projectClient.ProjectOpenAIClient.GetProjectResponsesClientForAgent(agentRef);

CreateResponseOptions responseOptions = new()
{
    Input = [ResponseItem.CreateUserMessageItem("What outdoor gear do you have?")]
};
responseOptions.Patch.Set(
    "$.structured_inputs[\"userFilter\"]"u8,
    BinaryData.FromObjectAsJson("boots"));

ResponseResult response = responseClient.CreateResponse(responseOptions);
Console.WriteLine(response.GetOutputText());

// Clean up
projectClient.AgentAdministrationClient.DeleteAgentVersion(
    agentName: agent.Name, agentVersion: agent.Version);

預期產出

Based on the index, the available outdoor boots include ...

Filter上的AzureAISearchToolIndex屬性接受在執行階段解析的 handlebar 範本。 使用 Patch.Set on CreateResponseOptions 來透過 JSON 路徑提供篩選值 $.structured_inputs 。

import { DefaultAzureCredential } from "@azure/identity";
import { AIProjectClient } from "@azure/ai-projects";

// Format: "https://resource_name.ai.azure.com/api/projects/project_name"
const PROJECT_ENDPOINT = "your_project_endpoint";
const SEARCH_CONNECTION_NAME = "my-search-connection";
const SEARCH_INDEX_NAME = "my-search-index";

export async function main(): Promise<void> {
  const project = new AIProjectClient(PROJECT_ENDPOINT, new DefaultAzureCredential());
  const openai = project.getOpenAIClient();

  // Resolve the project connection ID from the connection name
  const aiSearchConnection = await project.connections.get(SEARCH_CONNECTION_NAME);

  // Create the agent with a handlebar template inside the filter expression
  const agent = await project.agents.createVersion("aisearch-agent-structured-input", {
    kind: "prompt",
    model: "gpt-5-mini",
    instructions:
      "You are a helpful assistant. You must always provide citations for " +
      "answers using the tool and render them as: `[message_idx:search_idx†source]`.",
    tools: [
      {
        type: "azure_ai_search",
        azure_ai_search: {
          indexes: [
            {
              project_connection_id: aiSearchConnection.id,
              index_name: SEARCH_INDEX_NAME,
              query_type: "simple",
              filter: "search.ismatchscoring('{{userFilter}}')",
            },
          ],
        },
      },
    ],
    structured_inputs: {
      userFilter: { description: "The user's search filter", required: true },
    },
  });
  console.log(`Agent created (id: ${agent.id}, name: ${agent.name}, version: ${agent.version})`);

  // Supply the actual filter value at runtime
  const response = await openai.responses.create(
    {
      input: "What outdoor gear do you have?",
      tool_choice: "required",
    },
    {
      body: {
        agent_reference: { name: agent.name, type: "agent_reference" },
        structured_inputs: { userFilter: "boots" },
      },
    },
  );
  console.log(response.output_text);

  // Clean up
  await project.agents.deleteVersion(agent.name, agent.version);
}

main().catch(console.error);

預期產出

Agent created (id: <agent-id>, name: aisearch-agent-structured-input, version: 1)
Based on the index, the available outdoor boots include ...
import com.azure.ai.agents.AgentsClient;
import com.azure.ai.agents.AgentsClientBuilder;
import com.azure.ai.agents.AgentsServiceVersion;
import com.azure.ai.agents.ResponsesClient;
import com.azure.ai.agents.models.AISearchIndexResource;
import com.azure.ai.agents.models.AgentReference;
import com.azure.ai.agents.models.AgentVersionDetails;
import com.azure.ai.agents.models.AzureAISearchQueryType;
import com.azure.ai.agents.models.AzureAISearchTool;
import com.azure.ai.agents.models.AzureAISearchToolResource;
import com.azure.ai.agents.models.AzureCreateResponseOptions;
import com.azure.ai.agents.models.PromptAgentDefinition;
import com.azure.ai.agents.models.StructuredInputDefinition;
import com.azure.core.util.BinaryData;
import com.azure.identity.DefaultAzureCredentialBuilder;
import com.openai.models.responses.Response;
import com.openai.models.responses.ResponseCreateParams;

import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.Map;

public class AzureAISearchStructuredInputExample {
    public static void main(String[] args) {
        // Format: "https://resource_name.ai.azure.com/api/projects/project_name"
        String projectEndpoint = "your_project_endpoint";
        String searchConnectionId = "your-search-connection-id";
        String searchIndexName = "my-search-index";

        AgentsClientBuilder builder = new AgentsClientBuilder()
            .credential(new DefaultAzureCredentialBuilder().build())
            .endpoint(projectEndpoint)
            .serviceVersion(AgentsServiceVersion.getLatest());

        AgentsClient agentsClient = builder.buildAgentsClient();
        ResponsesClient responsesClient = builder.buildResponsesClient();

        // Create the AI Search tool with a handlebar template inside the filter expression
        AzureAISearchTool tool = new AzureAISearchTool(
            new AzureAISearchToolResource(Arrays.asList(
                new AISearchIndexResource()
                    .setProjectConnectionId(searchConnectionId)
                    .setIndexName(searchIndexName)
                    .setQueryType(AzureAISearchQueryType.SIMPLE)
                    .setFilter("search.ismatchscoring('{{userFilter}}')")
            ))
        );

        Map<String, StructuredInputDefinition> inputDefs = new LinkedHashMap<>();
        inputDefs.put("userFilter",
            new StructuredInputDefinition()
                .setDescription("The user's search filter")
                .setRequired(true));

        AgentVersionDetails agent = agentsClient.createAgentVersion(
            "aisearch-agent-structured-input",
            new PromptAgentDefinition("gpt-5-mini")
                .setInstructions("You are a helpful assistant. Always provide citations.")
                .setTools(Arrays.asList(tool))
                .setStructuredInputs(inputDefs));

        // Supply the actual filter value at runtime
        Map<String, BinaryData> inputValues = new LinkedHashMap<>();
        inputValues.put("userFilter", BinaryData.fromObject("boots"));

        Response response = responsesClient.createAzureResponse(
            new AzureCreateResponseOptions()
                .setAgentReference(
                    new AgentReference(agent.getName()).setVersion(agent.getVersion()))
                .setStructuredInputs(inputValues),
            ResponseCreateParams.builder()
                .input("What outdoor gear do you have?"));

        System.out.println("Response: " + response.output());

        // Clean up
        agentsClient.deleteAgentVersion(agent.getName(), agent.getVersion());
    }
}

預期產出

Response: Based on the index, the available outdoor boots include ...

建立一個帶有動態 Azure AI 搜尋服務 濾鏡的代理

curl -X POST "$FOUNDRY_PROJECT_ENDPOINT/agents?api-version=v1" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  --data-binary @- <<EOF
{
    "name": "aisearch-agent-structured-input",
    "definition": {
      "kind": "prompt",
      "model": "<MODEL_DEPLOYMENT>",
      "instructions": "You are a helpful assistant. Always provide citations.",
      "tools": [
        {
          "type": "azure_ai_search",
          "azure_ai_search": {
            "indexes": [
              {
                "project_connection_id": "$AZURE_AI_SEARCH_CONNECTION_ID",
                "index_name": "$AI_SEARCH_INDEX_NAME",
                "query_type": "simple",
                "filter": "search.ismatchscoring('{{userFilter}}')"
              }
            ]
          }
        }
      ],
      "structured_inputs": {
        "userFilter": {
          "description": "The user's search filter",
          "required": true,
          "schema": {"type": "string"}
        }
      }
    }
}
EOF

用濾波器值建立回應

curl -X POST "$FOUNDRY_PROJECT_ENDPOINT/openai/v1/responses" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -d '{
    "agent_reference": {
      "type": "agent_reference",
      "name": "aisearch-agent-structured-input"
    },
    "input": [
      {
        "type": "message",
        "role": "user",
        "content": "What outdoor gear do you have?"
      }
    ],
    "structured_inputs": {
      "userFilter": "boots"
    },
    "tool_choice": "required"
  }'

執行時,該 filter 表達式會將範本替換 {{userFilter}} 為 boots。 未加引號的 heredoc 會在 curl 傳送 JSON 內容之前,先展開連線和索引環境變數。

在 MCP 伺服器中使用結構化輸入

透過結構化輸入,你可以動態配置非秘密的 MCP 伺服器屬性,例如伺服器 URL、伺服器標籤和路由標頭。 使用專案連線或其他受管理的認證機制來管理憑證。 透過此方法,單一代理定義可依上下文連接至不同的 MCP 伺服器。

以下 JSON 顯示了建立代理版本操作()的請求主體。POST /agents?api-version=v1 Agent 定義包含具有 Handlebar 範本預留位置的 MCP 工具屬性:

{
  "name": "mcp-dynamic-agent",
  "definition": {
    "kind": "prompt",
    "model": "gpt-4o",
    "instructions": "You are a development assistant for {{project_name}}.",
    "tools": [
      {
        "type": "mcp",
        "server_label": "{{server_label}}",
        "server_url": "{{server_url}}",
        "require_approval": "never",
        "headers": {"X-Project-ID": "{{project_id}}"}
      }
    ],
    "structured_inputs": {
      "project_name": {
        "description": "Project name",
        "required": true
      },
      "server_label": {
        "description": "MCP server label",
        "required": true,
        "schema": {"type": "string"}
      },
      "server_url": {
        "description": "MCP server URL",
        "required": true,
        "schema": {"type": "string"}
      },
      "project_id": {
        "description": "Project identifier",
        "required": true,
        "schema": {"type": "string"}
      }
    }
  }
}

執行時,請在請求主體中提供建立回應操作的實際伺服器設定值(POST /openai/v1/responses):

{
  "agent_reference": {
    "type": "agent_reference",
    "name": "mcp-dynamic-agent"
  },
  "input": [{"type": "message", "role": "user", "content": "List recent commits"}],
  "structured_inputs": {
    "project_name": "CloudSync API",
    "server_label": "cloudsync-repo",
    "server_url": "https://gitmcp.io/myorg/cloudsync-api",
    "project_id": "proj_12345"
  }
}

MCP 結構化輸入的 SDK 模式遵循前述範例所示的相同方法。 在 MCP 工具屬性中定義模板佔位符,在代理定義中宣告結構化輸入結構,並在執行時提供值。

以下 Python 範例展示了完整的模式:

from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
    MCPTool,
    PromptAgentDefinition,
    StructuredInputDefinition,
)
from azure.identity import DefaultAzureCredential

# Format: "https://resource_name.ai.azure.com/api/projects/project_name"
PROJECT_ENDPOINT = "your_project_endpoint"

# Create clients to call Foundry API
project = AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=DefaultAzureCredential())
openai = project.get_openai_client()

# Create MCP tool with template placeholders
tool = MCPTool(
    server_label="{{server_label}}",
    server_url="{{server_url}}",
    require_approval="never",
    headers={"X-Project-ID": "{{project_id}}"},
)

# Create agent with structured inputs for MCP configuration
agent = project.agents.create_version(
    agent_name="mcp-dynamic-agent",
    definition=PromptAgentDefinition(
        model="gpt-5-mini",
        instructions="You are a helpful development assistant for {{project_name}}.",
        tools=[tool],
        structured_inputs={
            "project_name": StructuredInputDefinition(
                description="Project name", required=True, schema={"type": "string"},
            ),
            "server_label": StructuredInputDefinition(
                description="MCP server label", required=True, schema={"type": "string"},
            ),
            "server_url": StructuredInputDefinition(
                description="MCP server URL", required=True, schema={"type": "string"},
            ),
            "project_id": StructuredInputDefinition(
                description="Project identifier", required=True, schema={"type": "string"},
            ),
        },
    ),
)

# Supply MCP server configuration at runtime
conversation = openai.conversations.create()
response = openai.responses.create(
    conversation=conversation.id,
    input="List recent commits",
    extra_body={
        "agent_reference": {"name": agent.name, "type": "agent_reference"},
        "structured_inputs": {
            "project_name": "CloudSync API",
            "server_label": "cloudsync-repo",
            "server_url": "https://gitmcp.io/myorg/cloudsync-api",
            "project_id": "proj_12345",
        },
    },
)
print(response.output_text)

以下 TypeScript 範例顯示了相同的模式:

import { DefaultAzureCredential } from "@azure/identity";
import { AIProjectClient } from "@azure/ai-projects";

// Format: "https://resource_name.ai.azure.com/api/projects/project_name"
const PROJECT_ENDPOINT = "your_project_endpoint";

export async function main(): Promise<void> {
  // Create clients to call Foundry API
  const project = new AIProjectClient(PROJECT_ENDPOINT, new DefaultAzureCredential());
  const openai = project.getOpenAIClient();

  // Create agent with structured inputs for MCP configuration. The MCP tool
  // is defined inline so TypeScript infers the literal "mcp" type instead of
  // widening it to string.
  const agent = await project.agents.createVersion("mcp-dynamic-agent", {
    kind: "prompt",
    model: "gpt-5-mini",
    instructions: "You are a helpful development assistant for {{project_name}}.",
    tools: [
      {
        type: "mcp",
        server_label: "{{server_label}}",
        server_url: "{{server_url}}",
        require_approval: "never",
        headers: {
          Authorization: "{{auth_token}}",
          "X-Project-ID": "{{project_id}}",
        },
      },
    ],
    structured_inputs: {
      project_name: {
        description: "Project name",
        required: true,
        schema: { type: "string" },
      },
      server_label: {
        description: "MCP server label",
        required: true,
        schema: { type: "string" },
      },
      server_url: {
        description: "MCP server URL",
        required: true,
        schema: { type: "string" },
      },
      auth_token: {
        description: "Authentication token",
        required: true,
        schema: { type: "string" },
      },
      project_id: {
        description: "Project identifier",
        required: true,
        schema: { type: "string" },
      },
    },
  });

  // Supply MCP server configuration at runtime
  const conversation = await openai.conversations.create();
  const response = await openai.responses.create(
    {
      conversation: conversation.id,
      input: "List recent commits",
    },
    {
      body: {
        agent_reference: { name: agent.name, type: "agent_reference" },
        structured_inputs: {
          project_name: "CloudSync API",
          server_label: "cloudsync-repo",
          server_url: "https://gitmcp.io/myorg/cloudsync-api",
          auth_token: "******",
          project_id: "proj_12345",
        },
      },
    },
  );
  console.log(response.output_text);
}

main().catch(console.error);

欲了解更多關於連接 MCP 伺服器的資訊,請參閱 「連接代理至 MCP 伺服器」。

請在回應 API 中使用結構化輸入

你可以直接在回應 API 呼叫中使用把手列範本,而不必在代理定義中定義它們。 此方法適用於回應層指令以及輸入陣列中的系統或開發者訊息。

結構化輸入的回應層級指令

在回應請求中同時傳遞結構化輸入 instructions 以參數化系統提示:

{
  "instructions": "You are assisting {{customerName}} from {{companyName}} located in {{location}}.",
  "input": [
    {
      "type": "message",
      "role": "user",
      "content": "Hello, who am I?"
    }
  ],
  "structured_inputs": {
    "customerName": "Bob Johnson",
    "companyName": "Tech Corp",
    "location": "San Francisco"
  },
  "model": "gpt-4o"
}

系統與開發者訊息,包含結構化輸入

在系統與開發者訊息內容中使用把手列範本,將執行時值注入對話情境中:

{
  "instructions": "You are a helpful assistant.",
  "input": [
    {
      "type": "message",
      "role": "system",
      "content": "The user's name is {{userName}} and they work in {{department}}."
    },
    {
      "type": "message",
      "role": "developer",
      "content": [
        {
          "type": "input_text",
          "text": "User role: {{userRole}}. Always be professional."
        }
      ]
    },
    {
      "type": "message",
      "role": "user",
      "content": "Hello, can you confirm my details?"
    }
  ],
  "structured_inputs": {
    "userName": "Sarah Connor",
    "department": "Engineering",
    "userRole": "Tech Lead"
  },
  "model": "gpt-4o"
}

在 SDK 程式碼中,透過前述範例所示的 extra_body(Python)、body(TypeScript)或 AzureCreateResponseOptions(Java/C#)模式來傳遞這些值。

以下 Python 範例展示了如何使用帶有結構化輸入的回應層級指令:

from azure.ai.projects import AIProjectClient
from azure.identity import DefaultAzureCredential

# Format: "https://resource_name.ai.azure.com/api/projects/project_name"
PROJECT_ENDPOINT = "your_project_endpoint"

# Create clients to call Foundry API
project = AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=DefaultAzureCredential())
openai = project.get_openai_client()

# Pass structured inputs with response-level instructions
response = openai.responses.create(
    model="gpt-5-mini",
    instructions="You are assisting {{customerName}} from {{companyName}} located in {{location}}.",
    input=[
        {
            "type": "message",
            "role": "user",
            "content": "Hello, who am I?",
        }
    ],
    extra_body={
        "structured_inputs": {
            "customerName": "Bob Johnson",
            "companyName": "Tech Corp",
            "location": "San Francisco",
        },
    },
)
print(response.output_text)

以下 TypeScript 範例顯示了相同的模式:

import { DefaultAzureCredential } from "@azure/identity";
import { AIProjectClient } from "@azure/ai-projects";

// Format: "https://resource_name.ai.azure.com/api/projects/project_name"
const PROJECT_ENDPOINT = "your_project_endpoint";

export async function main(): Promise<void> {
  // Create clients to call Foundry API
  const project = new AIProjectClient(PROJECT_ENDPOINT, new DefaultAzureCredential());
  const openai = project.getOpenAIClient();

  // Pass structured inputs with response-level instructions
  const response = await openai.responses.create(
    {
      model: "gpt-5-mini",
      instructions:
        "You are assisting {{customerName}} from {{companyName}} located in {{location}}.",
      input: [
        {
          type: "message",
          role: "user",
          content: "Hello, who am I?",
        },
      ],
    },
    {
      body: {
        structured_inputs: {
          customerName: "Bob Johnson",
          companyName: "Tech Corp",
          location: "San Francisco",
        },
      },
    },
  );
  console.log(response.output_text);
}

main().catch(console.error);

進階範本語法

結構化輸入支援完整的 Handlebars 模板語法,超越簡單的變數替換。 你可以使用條件句、迴圈和其他內建輔助工具,在單一代理定義內建立動態指令邏輯。

以下範例建立一個天氣助理,其行為會根據執行時輸入調整。 說明範本使用 {{#if}} 來處理條件區段,並使用 {{#each}} 來遍歷使用者偏好清單。

from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import PromptAgentDefinition, StructuredInputDefinition
from azure.identity import DefaultAzureCredential

# Format: "https://resource_name.ai.azure.com/api/projects/project_name"
PROJECT_ENDPOINT = "your_project_endpoint"

# Create clients to call Foundry API
project = AIProjectClient(endpoint=PROJECT_ENDPOINT, credential=DefaultAzureCredential())
openai = project.get_openai_client()

# Define instructions with conditionals and loops
instructions = """You are a weather assistant. Provide a helpful weather summary for the user.

The user asked about: {{location}}
Use the following units: {{units}}

{{#if includeForecast}}
Include a brief multi-day forecast in your response.
{{else}}
Focus only on the current conditions.
{{/if}}

{{#if preferences}}
The user has these additional preferences:
{{#each preferences}}
- {{this}}
{{/each}}
{{/if}}

Keep the final answer clear and easy to read."""

agent = project.agents.create_version(
    agent_name="weather-assistant",
    definition=PromptAgentDefinition(
        model="gpt-5-mini",
        instructions=instructions,
        structured_inputs={
            "location": StructuredInputDefinition(
                description="City or region to check weather for",
                required=True,
                schema={"type": "string"},
            ),
            "units": StructuredInputDefinition(
                description="Temperature units (Celsius or Fahrenheit)",
                default_value="Celsius",
                schema={"type": "string"},
            ),
            "includeForecast": StructuredInputDefinition(
                description="Whether to include a multi-day forecast",
                default_value="false",
                schema={"type": "boolean"},
            ),
            "preferences": StructuredInputDefinition(
                description="Additional user preferences",
                schema={"type": "array"},
            ),
        },
    ),
)

# Supply values at runtime — conditionals and loops resolve automatically
conversation = openai.conversations.create()
response = openai.responses.create(
    conversation=conversation.id,
    input="What's the weather like?",
    extra_body={
        "agent_reference": {"name": agent.name, "type": "agent_reference"},
        "structured_inputs": {
            "location": "Seattle, WA",
            "units": "Fahrenheit",
            "includeForecast": True,
            "preferences": ["Highlight UV index", "Include wind speed"],
        },
    },
)
print(response.output_text)

以下 TypeScript 範例顯示了相同的模式:

import { DefaultAzureCredential } from "@azure/identity";
import { AIProjectClient } from "@azure/ai-projects";

// Format: "https://resource_name.ai.azure.com/api/projects/project_name"
const PROJECT_ENDPOINT = "your_project_endpoint";

export async function main(): Promise<void> {
  // Create clients to call Foundry API
  const project = new AIProjectClient(PROJECT_ENDPOINT, new DefaultAzureCredential());
  const openai = project.getOpenAIClient();

  // Define instructions with conditionals and loops
  const instructions = `You are a weather assistant. Provide a helpful weather summary for the user.

The user asked about: {{location}}
Use the following units: {{units}}

{{#if includeForecast}}
Include a brief multi-day forecast in your response.
{{else}}
Focus only on the current conditions.
{{/if}}

{{#if preferences}}
The user has these additional preferences:
{{#each preferences}}
- {{this}}
{{/each}}
{{/if}}

Keep the final answer clear and easy to read.`;

  const agent = await project.agents.createVersion("weather-assistant", {
    kind: "prompt",
    model: "gpt-5-mini",
    instructions,
    structured_inputs: {
      location: {
        description: "City or region to check weather for",
        required: true,
        schema: { type: "string" },
      },
      units: {
        description: "Temperature units (Celsius or Fahrenheit)",
        default_value: "Celsius",
        schema: { type: "string" },
      },
      includeForecast: {
        description: "Whether to include a multi-day forecast",
        default_value: false,
        schema: { type: "boolean" },
      },
      preferences: {
        description: "Additional user preferences",
        schema: { type: "array" },
      },
    },
  });

  // Supply values at runtime — conditionals and loops resolve automatically
  const conversation = await openai.conversations.create();
  const response = await openai.responses.create(
    {
      conversation: conversation.id,
      input: "What's the weather like?",
    },
    {
      body: {
        agent_reference: { name: agent.name, type: "agent_reference" },
        structured_inputs: {
          location: "Seattle, WA",
          units: "Fahrenheit",
          includeForecast: true,
          preferences: ["Highlight UV index", "Include wind speed"],
        },
      },
    },
  );
  console.log(response.output_text);
}

main().catch(console.error);

在這些值下,解析後的指令變為:

你是氣象助理。 提供有用的天氣摘要給使用者。

該用戶詢問的地點:華盛頓州西雅圖

使用以下單位:華氏

在回覆中加入簡短的多日預報。

使用者有以下額外偏好:

  • 強調紫外線指數
  • 包含風速

保持最終答案清晰易讀。

下表總結了支援的 Handlebars 輔助功能:

助手 語法 描述
條件式 {{#if value}}...{{else}}...{{/if}} 根據真實值或虛假值來呈現內容
否定 {{#unless value}}...{{/unless}} 當某個數值是虛假時,渲染內容
迴圈 {{#each array}}{{this}}{{/each}} 遍歷陣列項目
最後一次物品檢查 {{#unless @last}}, {{/unless}} 迴圈項目間的分隔符條件渲染