Azure.AI.Agents.Persistent (.NET)
지속적인 AI 에이전트를 스레드, 메시지, 실행 및 도구와 함께 생성 및 관리하기 위한 저수준 SDK입니다.
설치
dotnet add package Azure.AI.Agents.Persistent --prerelease
dotnet add package Azure.Identity
현재 버전: 안정 v1.1.0, 미리보기 v1.2.0-beta.8
환경 변수
PROJECT_ENDPOINT=https://<resource>.services.ai.azure.com/api/projects/<project>
MODEL_DEPLOYMENT_NAME=gpt-4o-mini
AZURE_BING_CONNECTION_ID=<bing-connection-resource-id>
AZURE_AI_SEARCH_CONNECTION_ID=<search-connection-resource-id>
AZURE_TOKEN_CREDENTIALS=prod
인증
using Azure.AI.Agents.Persistent;
using Azure.Identity;
var projectEndpoint = Environment.GetEnvironmentVariable("PROJECT_ENDPOINT");
var credential = new DefaultAzureCredential(
DefaultAzureCredential.DefaultEnvironmentVariableName
);
PersistentAgentsClient client = new(projectEndpoint, credential);
클라이언트 계층 구조
PersistentAgentsClient
├── Administration → 에이전트 CRUD 작업
├── Threads → 스레드 관리
├── Messages → 메시지 작업
├── Runs → 실행 실행 및 스트리밍
├── Files → 파일 업로드/다운로드
└── VectorStores → 벡터 저장소 관리
핵심 워크플로
1. 에이전트 생성
var modelDeploymentName = Environment.GetEnvironmentVariable("MODEL_DEPLOYMENT_NAME");
PersistentAgent agent = await client.Administration.CreateAgentAsync(
model: modelDeploymentName,
name: "Math Tutor",
instructions: "You are a personal math tutor. Write and run code to answer math questions.",
tools: [new CodeInterpreterToolDefinition()]
);
2. 스레드 및 메시지 생성
PersistentAgentThread thread = await client.Threads.CreateThreadAsync();
await client.Messages.CreateMessageAsync(
thread.Id,
MessageRole.User,
"I need to solve the equation `3x + 11 = 14`. Can you help me?"
);
3. 에이전트 실행 (폴링)
ThreadRun run = await client.Runs.CreateRunAsync(
thread.Id,
agent.Id,
additionalInstructions: "Please address the user as Jane Doe."
);
할
{
await Task.Delay(TimeSpan.FromMilliseconds(500));
run = await client.Runs.GetRunAsync(thread.Id, run.Id);
}
while (run.Status == RunStatus.Queued || run.Status == RunStatus.InProgress);
await foreach (PersistentThreadMessage message in client.Messages.GetMessagesAsync(
threadId: thread.Id,
order: ListSortOrder.Ascending))
{
Console.Write($"{message.Role}: ");
foreach (MessageContent content in message.ContentItems)
{
if (content is MessageTextContent textContent)
Console.WriteLine(textContent.Text);
}
}
4. 스트리밍 응답
AsyncCollectionResult<StreamingUpdate> stream = client.Runs.CreateRunStreamingAsync(
thread.Id,
agent.Id
);
await foreach (StreamingUpdate update in stream)
{
if (update.UpdateKind == StreamingUpdateReason.RunCreated)
{
Console.WriteLine("--- Run started! ---");
}
else if (update is MessageContentUpdate contentUpdate)
{
Console.Write(contentUpdate.Text);
}
else if (update.UpdateKind == StreamingUpdateReason.RunCompleted)
{
Console.WriteLine("\n--- Run completed! ---");
}
}
5. 함수 호출
FunctionToolDefinition weatherTool = new(
name: "getCurrentWeather",
description: "Gets the current weather at a location.",
parameters: BinaryData.FromObjectAsJson(new
{
Type = "object",
Properties = new
{
Location = new { Type = "string", Description = "City and state, e.g. San Francisco, CA" },
Unit = new { Type = "string", Enum = new[] { "c", "f" } }
},
Required = new[] { "location" }
}, new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase })
);
PersistentAgent agent = await client.Administration.CreateAgentAsync(
model: modelDeploymentName,
name: "Weather Bot",
instructions: "You are a weather bot.",
tools: [weatherTool]
);
할
{
await Task.Delay(500);
run = await client.Runs.GetRunAsync(thread.Id, run.Id);
if (run.Status == RunStatus.RequiresAction
&& run.RequiredAction is SubmitToolOutputsAction submitAction)
{
List<ToolOutput> outputs = [];
foreach (RequiredToolCall toolCall in submitAction.ToolCalls)
{
if (toolCall is RequiredFunctionToolCall funcCall)
{
string result = ExecuteFunction(funcCall.Name, funcCall.Arguments);
outputs.Add(new ToolOutput(toolCall, result));
}
}
run = await client.Runs.SubmitToolOutputsToRunAsync(run, outputs, toolApprovals: null);
}
}
while (run.Status == RunStatus.Queued || run.Status == RunStatus.InProgress);
6. 벡터 저장소를 사용한 파일 검색
PersistentAgentFileInfo file = await client.Files.UploadFileAsync(
filePath: "document.txt",
purpose: PersistentAgentFilePurpose.Agents
);
PersistentAgentsVectorStore vectorStore = await client.VectorStores.CreateVectorStoreAsync(
fileIds: [file.Id],
name: "my_vector_store"
);
FileSearchToolResource fileSearchResource = new();
fileSearchResource.VectorStoreIds.Add(vectorStore.Id);
PersistentAgent agent = await client.Administration.CreateAgentAsync(
model: modelDeploymentName,
name: "Document Assistant",
instructions: "You help users find information in documents.",
tools: [new FileSearchToolDefinition()],
toolResources: new ToolResources { FileSearch = fileSearchResource }
);
7. Bing 접지
var bingConnectionId = Environment.GetEnvironmentVariable("AZURE_BING_CONNECTION_ID");
BingGroundingToolDefinition bingTool = new(
new BingGroundingSearchToolParameters(
[new BingGroundingSearchConfiguration(bingConnectionId)]
)
);
PersistentAgent agent = await client.Administration.CreateAgentAsync(
model: modelDeploymentName,
name: "Search Agent",
instructions: "Use Bing to answer questions about current events.",
tools: [bingTool]
);
8. Azure AI Search
AzureAISearchToolResource searchResource = new(
connectionId: searchConnectionId,
indexName: "my_index",
topK: 5,
filter: "category eq 'documentation'",
queryType: AzureAISearchQueryType.Simple
);
PersistentAgent agent = await client.Administration.CreateAgentAsync(
model: modelDeploymentName,
name: "Search Agent",
instructions: "Search the documentation index to answer questions.",
tools: [new AzureAISearchToolDefinition()],
toolResources: new ToolResources { AzureAISearch = searchResource }
);
9. 정리
await client.Threads.DeleteThreadAsync(thread.Id);
await client.Administration.DeleteAgentAsync(agent.Id);
await client.VectorStores.DeleteVectorStoreAsync(vectorStore.Id);
await client.Files.DeleteFileAsync(file.Id);
사용 가능한 도구
| 도구 | 클래스 | 용도 |
|---|
| 코드 인터프리터 | CodeInterpreterToolDefinition | Python 코드 실행, 시각화 생성 |
| 파일 검색 | FileSearchToolDefinition | 벡터 저장소를 통해 업로드된 파일 검색 |
| 함수 호출 | FunctionToolDefinition | 사용자 정의 함수 호출 |
| Bing 접지 | BingGroundingToolDefinition | Bing을 통한 웹 검색 |
| Azure AI Search | AzureAISearchToolDefinition | Azure AI Search 인덱스 검색 |
| OpenAPI | OpenApiToolDefinition | OpenAPI 사양을 통한 외부 API 호출 |
| Azure Functions | AzureFunctionToolDefinition | Azure Functions 호출 |
| MCP | MCPToolDefinition | 모델 컨텍스트 프로토콜 도구 |
| SharePoint | SharepointToolDefinition | SharePoint 콘텐츠 액세스 |
| Microsoft Fabric | MicrosoftFabricToolDefinition | Fabric 데이터 액세스 |
스트리밍 업데이트 유형
| 업데이트 유형 | 설명 |
|---|
StreamingUpdateReason.RunCreated | 실행 시작됨 |
StreamingUpdateReason.RunInProgress | 실행 처리 중 |
StreamingUpdateReason.RunCompleted | 실행 완료됨 |
StreamingUpdateReason.RunFailed | 실행 오류 발생 |
MessageContentUpdate | 텍스트 콘텐츠 청크 |
RunStepUpdate | 단계 상태 변경 |
주요 유형 참조
| 유형 | 용도 |
|---|
PersistentAgentsClient | 주요 진입점 |
PersistentAgent | 모델, 지침, 도구가 있는 에이전트 |
PersistentAgentThread | 대화 스레드 |
PersistentThreadMessage | 스레드의 메시지 |
ThreadRun | 스레드에 대한 에이전트 실행 |
RunStatus | Queued, InProgress, RequiresAction, Completed, Failed |
ToolResources | 결합된 도구 리소스 |
ToolOutput | 함수 호출 응답 |
모범 사례
- 항상 클라이언트를 삭제 —
using 문이나 명시적 삭제 사용
- 적절한 지연으로 폴링 — 상태 확인 간 500ms 권장
- 리소스 정리 — 작업 완료 후 스레드 및 에이전트 삭제
- 모든 실행 상태 처리 —
RequiresAction, Failed, Cancelled 확인
- 실시간 UX에는 스트리밍 사용 — 폴링보다 사용자 경험 향상
- ID를 객체가 아닌 저장 — 에이전트/스레드를 ID로 참조
- 비동기 메서드 사용 — 모든 작업은 비동기여야 함
오류 처리
using Azure;
try
{
var agent = await client.Administration.CreateAgentAsync(...);
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
Console.WriteLine("리소스를 찾을 수 없음");
}
catch (RequestFailedException ex)
{
Console.WriteLine($"오류: {ex.Status} - {ex.ErrorCode}: {ex.Message}");
}
관련 SDK
| SDK | 용도 | 설치 |
|---|
Azure.AI.Agents.Persistent | 저수준 에이전트 (이 SDK) | dotnet add package Azure.AI.Agents.Persistent |
Azure.AI.Projects | 고수준 프로젝트 클라이언트 | dotnet add package Azure.AI.Projects |
참조 링크