이 문서에서는 Microsoft Agent Framework에서 워크플로를 에이전트로 사용하는 방법에 대한 개요를 제공합니다.
개요
경우에 따라 여러 에이전트, 사용자 지정 실행기 및 복잡한 논리를 사용하여 정교한 워크플로를 빌드했지만 다른 에이전트와 마찬가지로 사용하려고 합니다. 이것이 바로 워크플로 에이전트가 수행할 수 있는 작업입니다. 워크플로를 Agent로 래핑하면 간단한 채팅 에이전트에서 사용하는 익숙한 API를 통해 상호작용할 수 있습니다.
주요 이점
- 통합 인터페이스: 단순 에이전트와 동일한 API를 사용하여 복잡한 워크플로와 상호 작용
- API 호환성: 에이전트 인터페이스를 지원하는 기존 시스템과 워크플로 통합
- 구성성: 더 큰 에이전트 시스템 또는 기타 워크플로에서 워크플로 에이전트를 구성 요소로 사용
- 세션 관리: 대화 상태 및 재개에 에이전트 세션 활용
- 스트리밍 지원: 워크플로가 실행됨에 따라 실시간 업데이트 가져오기
작동 방식
워크플로를 에이전트로 변환하는 경우:
- 워크플로의 유효성을 검사하여 시작 실행기가 필요한 입력 형식을 수락할 수 있는지 확인합니다.
- 대화 상태를 관리하기 위한 세션이 만들어집니다.
- 입력 메시지는 워크플로의 시작 실행기로 라우팅됩니다.
- 워크플로 이벤트가 에이전트 응답 업데이트로 변환됩니다.
- 외부 입력 요청(원본
RequestInfoExecutor)이 함수 호출로 표시됩니다.
요구 사항
워크플로를 에이전트로 사용하려면 워크플로의 시작 실행기가 입력으로 처리 IEnumerable<ChatMessage> 할 수 있어야 합니다. 로 만든 AsAIAgent에이전트 기반 실행기를 사용할 때 자동으로 충족됩니다.
워크플로 에이전트 만들기
확장 메서드를 AsAIAgent() 사용하여 호환되는 워크플로를 에이전트로 변환합니다.
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Workflows;
using Microsoft.Extensions.AI;
// Create agents
AIAgent researchAgent = chatClient.AsAIAgent("You are a researcher. Research and gather information on the given topic.");
AIAgent writerAgent = chatClient.AsAIAgent("You are a writer. Write clear, engaging content based on research.");
AIAgent reviewerAgent = chatClient.AsAIAgent("You are a reviewer. Review the content and provide a final polished version.");
// Build a sequential workflow
var workflow = new WorkflowBuilder(researchAgent)
.AddEdge(researchAgent, writerAgent)
.AddEdge(writerAgent, reviewerAgent)
.Build();
// Convert the workflow to an agent
AIAgent workflowAgent = workflow.AsAIAgent(
id: "content-pipeline",
name: "Content Pipeline Agent",
description: "A multi-agent workflow that researches, writes, and reviews content"
);
AsAIAgent 매개 변수
| 매개 변수 | 유형 | Description |
|---|---|---|
id |
string? |
에이전트에 대한 선택적 고유 식별자입니다. 제공되지 않은 경우 자동으로 생성됩니다. |
name |
string? |
에이전트의 선택적 표시 이름입니다. |
description |
string? |
에이전트의 용도에 대한 선택적 설명입니다. |
executionEnvironment |
IWorkflowExecutionEnvironment? |
선택적 실행 환경입니다. 기본값은 워크플로 구성에 따라 InProcessExecution.OffThread 또는 InProcessExecution.Concurrent로 설정됩니다. |
includeExceptionDetails |
bool |
이면 true오류 내용에 예외 메시지가 포함됩니다. 기본값은 false입니다. |
includeWorkflowOutputsInResponse |
bool |
이 경우 true 출력된 워크플로를 에이전트 응답의 콘텐츠로 변환합니다. 기본값은 false입니다. |
워크플로 에이전트 사용
세션 만들기
워크플로 에이전트와의 각 대화에는 상태를 관리하는 세션이 필요합니다.
// Create a new session for the conversation
AgentSession session = await workflowAgent.CreateSessionAsync();
스트리밍이 아닌 실행
전체 응답을 원하는 간단한 사용 사례의 경우:
var messages = new List<ChatMessage>
{
new(ChatRole.User, "Write an article about renewable energy trends in 2025")
};
AgentResponse response = await workflowAgent.RunAsync(messages, session);
foreach (ChatMessage message in response.Messages)
{
Console.WriteLine($"{message.AuthorName}: {message.Text}");
}
스트리밍 실행
워크플로가 실행됨에 따라 실시간 업데이트의 경우:
var messages = new List<ChatMessage>
{
new(ChatRole.User, "Write an article about renewable energy trends in 2025")
};
await foreach (AgentResponseUpdate update in workflowAgent.RunStreamingAsync(messages, session))
{
// Process streaming updates from each agent in the workflow
if (!string.IsNullOrEmpty(update.Text))
{
Console.Write(update.Text);
}
}
외부 입력 요청 처리
워크플로에 외부 입력(사용 RequestInfoExecutor)을 요청하는 실행기가 포함된 경우 이러한 요청은 에이전트 응답에서 함수 호출로 표시됩니다.
await foreach (AgentResponseUpdate update in workflowAgent.RunStreamingAsync(messages, session))
{
// Check for function call requests
foreach (AIContent content in update.Contents)
{
if (content is FunctionCallContent functionCall)
{
// Handle the external input request
Console.WriteLine($"Workflow requests input: {functionCall.Name}");
Console.WriteLine($"Request data: {functionCall.Arguments}");
// Provide the response in the next message
}
}
}
세션 직렬화 및 재개
워크플로 에이전트 세션은 지속성을 위해 직렬화되고 나중에 다시 시작될 수 있습니다.
// Serialize the session state
JsonElement serializedSession = await workflowAgent.SerializeSessionAsync(session);
// Store serializedSession to your persistence layer...
// Later, resume the session
AgentSession resumedSession = await workflowAgent.DeserializeSessionAsync(serializedSession);
// Continue the conversation
await foreach (var update in workflowAgent.RunStreamingAsync(newMessages, resumedSession))
{
Console.Write(update.Text);
}
요구 사항
워크플로를 에이전트로 사용하려면 워크플로의 시작 실행기가 메시지 입력을 처리할 수 있어야 합니다.
Agent 또는 에이전트 기반 실행기를 사용할 때 자동으로 충족됩니다.
워크플로 에이전트 만들기
호환되는 워크플로를 호출 as_agent() 하여 에이전트로 변환합니다.
from agent_framework.foundry import FoundryChatClient
from agent_framework.orchestrations import SequentialBuilder
from azure.identity import AzureCliCredential
# Create your chat client and agents
client = FoundryChatClient(
project_endpoint="<your-endpoint>",
model="<your-deployment>",
credential=AzureCliCredential(),
)
researcher = client.as_agent(
name="Researcher",
instructions="Research and gather information on the given topic.",
)
writer = client.as_agent(
name="Writer",
instructions="Write clear, engaging content based on research.",
)
# Build a sequential workflow
workflow = SequentialBuilder(participants=[researcher, writer]).build()
# Convert the workflow to an agent
workflow_agent = workflow.as_agent(name="Content Pipeline Agent")
as_agent 매개 변수
| 매개 변수 | 유형 | Description |
|---|---|---|
name |
str | None |
에이전트의 선택적 표시 이름입니다. 제공되지 않은 경우 자동으로 생성됩니다. |
워크플로 에이전트 사용
세션 만들기
필요에 따라 세션을 만들어 여러 번 대화 상태를 관리할 수 있습니다.
# Create a new session for the conversation
session = await workflow_agent.create_session()
비고
세션은 선택 사항입니다.
session를 run()에 전달하지 않으면, 에이전트가 내부적으로 상태를 처리합니다.
workflow.as_agent()가 context_providers 없이 생성될 경우, 프레임워크는 기본적으로 InMemoryHistoryProvider()를 추가하여 멀티턴 기록이 자동으로 작동합니다.
명시적으로 context_providers를 전달하면 해당 목록이 그대로 사용됩니다.
스트리밍이 아닌 실행
전체 응답을 원하는 간단한 사용 사례의 경우:
# You can pass a plain string as input
response = await workflow_agent.run("Write an article about AI trends")
for message in response.messages:
print(f"{message.author_name}: {message.text}")
스트리밍 실행
워크플로가 실행됨에 따라 실시간 업데이트의 경우:
async for update in workflow_agent.run(
"Write an article about AI trends",
stream=True,
):
if update.text:
print(update.text, end="", flush=True)
외부 입력 요청 처리
워크플로에 외부 입력(사용 request_info)을 요청하는 실행기가 포함된 경우 이러한 요청은 에이전트 응답에서 함수 호출로 표시됩니다. 함수 호출은 다음 이름을 WorkflowAgent.REQUEST_INFO_FUNCTION_NAME사용합니다.
from agent_framework import Content, Message, WorkflowAgent
response = await workflow_agent.run("Process my request")
# Look for function calls in the response
human_review_function_call = None
for message in response.messages:
for content in message.contents:
if content.name == WorkflowAgent.REQUEST_INFO_FUNCTION_NAME:
human_review_function_call = content
보류 중인 요청에 대한 응답 제공
외부 입력 요청 후 워크플로 실행을 계속하려면 함수 결과를 만들고 다시 보냅니다.
if human_review_function_call:
# Parse the request arguments
request = WorkflowAgent.RequestInfoFunctionArgs.from_json(
human_review_function_call.arguments
)
# Create a response (your custom response type)
result_data = MyResponseType(approved=True, feedback="Looks good")
# Create the function call result
function_result = Content.from_function_result(
call_id=human_review_function_call.call_id,
result=result_data,
)
# Send the response back to continue the workflow
response = await workflow_agent.run(Message("tool", [function_result]))
완성된 예시
다음은 스트리밍 출력이 있는 워크플로 에이전트를 보여주는 전체 예제입니다.
import asyncio
import os
from agent_framework.foundry import FoundryChatClient
from agent_framework.orchestrations import SequentialBuilder
from azure.identity import AzureCliCredential
async def main():
# Set up the chat client
client = FoundryChatClient(
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
model=os.environ["FOUNDRY_MODEL"],
credential=AzureCliCredential(),
)
# Create specialized agents
researcher = client.as_agent(
name="Researcher",
instructions="Research the given topic and provide key facts.",
)
writer = client.as_agent(
name="Writer",
instructions="Write engaging content based on the research provided.",
)
reviewer = client.as_agent(
name="Reviewer",
instructions="Review the content and provide a final polished version.",
)
# Build a sequential workflow
workflow = SequentialBuilder(participants=[researcher, writer, reviewer]).build()
# Convert to a workflow agent
workflow_agent = workflow.as_agent(name="Content Creation Pipeline")
# Run the workflow
print("Starting workflow...")
print("=" * 60)
current_author = None
async for update in workflow_agent.run(
"Write about quantum computing",
stream=True,
):
# Show when different agents are responding
if update.author_name and update.author_name != current_author:
if current_author:
print("\n" + "-" * 40)
print(f"\n[{update.author_name}]:")
current_author = update.author_name
if update.text:
print(update.text, end="", flush=True)
print("\n" + "=" * 60)
print("Workflow completed!")
if __name__ == "__main__":
asyncio.run(main())
이벤트 변환 이해
워크플로가 에이전트로 실행되면 워크플로 이벤트가 에이전트 응답으로 변환됩니다. 응답 유형은 다음을 호출 run()하는 방법에 따라 달라집니다.
-
run(): 워크플로가 완료된 후 전체 결과를 포함하는AgentResponse을 반환 -
run(..., stream=True): 워크플로가 실행되면 개체의AgentResponseUpdate비동기 반복 가능 항목을 반환하여 실시간 업데이트를 제공합니다.
실행하는 동안 내부 워크플로 이벤트는 다음과 같이 에이전트 응답에 매핑됩니다.
| 워크플로 이벤트 | 에이전트 응답 |
|---|---|
event.type == "output" |
(스트리밍)으로 AgentResponseUpdate 전달되거나 (비 스트리밍)으로 AgentResponse 집계됨 |
event.type == "request_info" |
를 사용하여 함수 호출 콘텐츠로 변환 WorkflowAgent.REQUEST_INFO_FUNCTION_NAME |
| 기타 이벤트 | 무시됨(워크플로 내부 전용) |
이 변환을 사용하면 필요할 때 자세한 워크플로 정보에 액세스할 수 있는 동시에 표준 에이전트 인터페이스를 사용할 수 있습니다.
사용 사례
1. 복잡한 에이전트 파이프라인
다중 에이전트 워크플로를 애플리케이션에서 사용할 단일 에이전트로 래핑합니다.
User Request --> [Workflow Agent] --> Final Response
|
+-- Researcher Agent
+-- Writer Agent
+-- Reviewer Agent
2. 에이전트 구성
더 큰 시스템에서 워크플로 에이전트를 구성 요소로 사용합니다.
- 워크플로 에이전트는 다른 에이전트가 도구로 사용할 수 있습니다.
- 여러 워크플로 에이전트를 함께 오케스트레이션할 수 있습니다.
- 워크플로 에이전트는 다른 워크플로 내에 중첩될 수 있습니다.
3. API 통합
표준 에이전트 인터페이스를 예상하는 API를 통해 복잡한 워크플로를 노출하고, 이를 활용할 수 있도록 합니다.
- 정교한 백 엔드 워크플로를 사용하는 채팅 인터페이스
- 기존 에이전트 기반 시스템과 통합
- 간단한 에이전트에서 복잡한 워크플로로 점진적 마이그레이션