
일반적인 AI Agent에 Plan 모드와 Todo 관리를 추가해 보기 - MS Agent Framework (C#)
요약
Microsoft Agent Framework의 HarnessAgent를 활용하여 AI 에이전트에 Plan 모드와 Todo 관리 기능을 구현하는 방법을 다룹니다. 기본 인스트럭션과 사용자 정의 지시사항을 병합하여 에이전트의 페르소나를 유지하면서도 계획적인 동작을 유도하는 기술적 상세 내용을 설명합니다.
핵심 포인트
- HarnessAgent의 기본 인스트럭션과 사용자 정의 지시사항 병합 방법
- ChatOptions.Instructions를 통한 에이전트 페르소나 설정 및 확장
- Plan 및 Todo 기능을 위한 시스템 프롬프트 구성 원리
- 모델 성능에 따른 에이전트 계획 수립 능력 확인
서론
이전 기사에서 「Plan 모드와 Todo 관리에 대응하는 Agent를 만들자 - Microsoft Agent Framework (C#)」라는 기사를 작성했습니다. 거기서는 Microsoft Agent Framework의 HarnessAgent를 사용하여 간단하게 구현할 수 있다는 내용을 다루었습니다.
여기서는 HarnessAgent의 내부 구현을 살펴본 뒤, 조금 더 자세히 동작을 확인해 보고자 합니다.
gpt-5.6-luna라도 괜찮습니다
이전 기사에서는 Plan과 Todo를 능숙하게 사용하도록 하기 위해 gpt-5.6-luna가 아닌 gpt-5.6-sol을 사용했습니다. 이는 luna를 사용해도 괜찮습니다. 사실 HarnessAgent에는 기본 인스트럭션(Instruction)이 있으며, HarnessInstructions 프로퍼티에 값을 설정하지 않으면 그것이 사용됩니다. 지난번 코드에서는 다음과 같이 고양이처럼 행동하도록 하는 지시를 설정했기 때문에 기본 인스트럭션을 덮어쓰고 있었습니다.
// HarnessAgent를 생성한다
var harnessAgent = chatClient.AsHarnessAgent(new()
{
...
사실 HarnessAgent의 기본 인스트럭션은 다음과 같은 내용으로 되어 있습니다. (영어 원문이지만, 여기서는 일본어로 번역되어 있습니다)
/// <summary>
/// <see cref="ChatOptions.Instructions"/>가 설정되지 않은 경우 사용되는 내장 기본 시스템 지시사항입니다.
/// </summary>
...
왠지 이것만으로도 Plan이나 Todo를 잘 사용할 수 있을 것 같은 느낌이 드네요. 그렇다면 이것을 사용하도록 하면서, 자신의 에이전트 특징(이번 경우에는 고양이)을 추가하는 방법은 ChatOptions 프로퍼티의 Instructions에 지시를 설정하면, HarnessAgent의 인스트럭션과 병합(Merge)된 것이 시스템 프롬프트(System Prompt)로 사용됩니다.
따라서 다음과 같이 하면 고양이이면서, 적절하게 생각하고 행동해 주는 지시가 포함된 상태가 됩니다.
// HarnessAgent를 생성한다
var harnessAgent = chatClient.AsHarnessAgent(new()
{
...
조금 더 세부적으로 말하자면, HarnessInstructions에서 지정한 프롬프트에 줄바꿈을 두 번 넣고 ChatOptions의 Instructions가 연결된 것이 시스템 프롬프트가 됩니다. 즉, 이번 경우에는 다음과 같은 시스템 프롬프트가 됩니다. 엄밀히 말하면 앞부분은 영어로 되어 있지만, 이번에는 분위기를 파악하기 위해 기사 내에서는 일본어 번역본을 사용합니다.
도구를 사용하여 태스크를 완료하는 유용한 AI 어시스턴트입니다.
## 일반적인 가이드라인
- 행동하기 전에 태스크에 대해 깊이 생각하세요. 복잡한 작업은 명확한 절차로 분해하세요.
...
이 상태에서 gpt-5.6-luna를 지정해 본 실행 결과는 다음과 같았습니다.
3개 도시의 날씨를 동시에 확인하고, 비교하기 쉬운 표로 정리하는 계획이다냥. 먼저 각 도시의 최신 정보를 가져오겠다냥.
날씨 취득 계획은 다음과 같다냥.
1. 도쿄·히로시마·교토의 오늘 날씨를 확인한다냥
...
보시는 바와 같이 gpt-5.6-luna라도 괜찮았습니다. 따라서 기본 기능을 사용할 경우에는 HarnessInstructions가 아니라 ChatOptions의 Instructions를 사용하는 것이 좋아 보이네요. HarnessInstructions를 새로 작성하는 경우에는 도구 사용에 관한 커스터마이징(Customizing)도 함께 해두는 것이 좋을 것 같습니다.
HarnessAgent를 사용하지 않는 케이스
다음은, HarnessAgent를 사용하면 간단하게 Plan과 Todo(Plan과 Todo뿐만이 아니지만)를 사용할 수 있지만, 일반적인 AIAgent를 사용하고 있어서 쉽게 HarnessAgent로 교체할 수 없는... 상황이 있는 케이스를 생각하고 있습니다.
HarnessAgent
는, 그 안에 대량의 기능이 구현되어 있는 것이 아니라 Microsoft.Agents.AI 패키지 내의 Harness 폴더 (Harness 폴더에 들어있지만 네임스페이스는 Microsoft.Agents.AI임)에 있는 부품군을 모아서 사용하기 쉽게 패키징한 것이 HarnessAgent입니다. 따라서 HarnessAgent가 가진 기능의 거의 모든 기능은 일반적인 AIAgent에도 추가할 수 있습니다. 한번 해봅시다.
포인트는 AIContextProviders에 AgentModeProvider와 TodoProvider를 설정하고 있는 부분입니다.
// IChatClient로부터 일반적인 AIAgent를 생성한다
var harnessAgent = chatClient.AsAIAgent(new ChatClientAgentOptions
{
...
이렇게 실행하면 Plan 모드와 Todo 관리를 하는 에이전트가 됩니다. 실행 결과는 이전과 큰 차이가 없지만, 다음과 같이 되었습니다. 계획(Plan)에 따른 실행과 계획을 통한 Todo 생성이 제대로 이루어지고 있네요.
현재 모드: plan
다음 단계로 진행할게냥.
1. 도쿄, 히로시마, 교토의 날씨 정보를 가져올게냥
...
AgentModeProvider를 살펴보자
결과적으로 Plan 모드와 Todo 관리는 AgentModeProvider와 TodoProvider로 구현되어 있다는 것을 알 수 있었습니다. HarnessAgent에서는 기본적으로 AIContextProvider에 이러한 Provider들이 추가되어 있으며, DisableXXXXX와 같은 프로퍼티로 명시적으로 비활성화하면 해당 Provider가 사용되지 않는 방식입니다. 파일 액세스는 기본적으로 비활성화되어 있거나, Provider가 아닌 Middleware 등도 추가되어 있지만, 이번에는 일단 대상에서 제외하겠습니다.
AgentModeProvider에서는 plan과 execute라는 모드가 자동으로 설정됩니다. 이 AgentModeProvider를 추가하면, 시스템 프롬프트(System Prompt)에 자동으로 다음과 같은 인스트럭션(Instruction)이 추가됩니다.
private const string DefaultInstructions =
"""
## 에이전트 모드
...
모드를 의식하며 동작하도록 하는 지시가 들어있네요. 그리고 기본적으로는 다음과 같은 plan과 execute 모드가 정의되어 있습니다.
private static readonly IReadOnlyList<AgentModeProviderOptions.AgentMode> s_defaultModes =
[
new(
...
그리고 DefaultInstructions에서 사용하도록 안내된 mode_set과 mode_get 도구(Tool)도 추가됩니다. 참고로, 이것들은 어디까지나 기본 지시와 모드입니다. 이 모드는 커스터마이징할 수도 있습니다.
AgentModeProvider의 생성자에는 AgentModeProviderOptions라는 클래스를 받는 오버로드(Overload)가 있으며, 이를 사용함으로써 위의 지시나 모드를 교체할 수 있습니다.
시도해 봅시다. 다음과 같은 코드를 작성해 보았습니다.
using Azure.AI.Projects;
using Azure.Identity;
using Microsoft.Agents.AI;
...
포인트는 에이전트 정의를 하고 있는 다음 부분의 AIContextProviders입니다.
// IChatClient로부터 일반적인 AIAgent를 생성한다
var catAgent = chatClient.AsAIAgent(new ChatClientAgentOptions
{
...
여기서 다음 두 가지 모드를 정의하고 있습니다.
agent모드: 일반적인 에이전트로서 행동한다.echo모드: 말을 그대로 따라 한다(Echo).
그리고 기본값을 echo
모드로 설정되어 있습니다. 그 상태에서 다음과 같이 3턴의 대화를 진행하고 있습니다.
// echo 모드로 실행
Console.WriteLine($"현재 모드: {await agentModeProvider.GetModeAsync(session)}");
var response = await catAgent.RunAsync("子子子子子子子子子子子子ってどういう意味?", session);
...
실행 결과는 다음과 같습니다. echo와 agent가 제대로 전환되며 동작하고 있음을 확인할 수 있습니다.
현재 모드: echo
子子子子子子子子子子子子ってどういう意味にゃん?
------------------
...
DefaultInstructions를 덮어쓸 수도 있지만, 여기서는 딱히 덮어쓸 의미가 별로 없을 것 같다는 생각이 듭니다. 만약 내용을 바꾸고 싶다면 AgentModeProviderOptions의 Instructions 속성을 사용하여 교체할 수 있습니다.
TodoProvider 살펴보기
TodoProvider는 Todo의 상태를 관리할 뿐만 아니라, Todo를 조작하기 위한 도구(Tool)와 에이전트에게 이러한 도구들을 구분해서 사용하도록 전달하는 인스트럭션(Instruction)도 제공합니다.
먼저 TodoProvider 안에 있는 DefaultInstructions를 살펴보겠습니다. 영어로 작성된 내용을 한국어로 번역하면 다음과 같습니다.
private const string DefaultInstructions =
"""
## Todo 항목
...
여러 단계의 절차가 필요한 의뢰만 Todo에 등록하고, 단순한 의뢰는 그대로 처리하도록 안내하고 있습니다.
또한, 계획에 대한 사용자의 피드백이나 도중에 의뢰 내용이 변경된 경우에는 Todo를 추가하거나 삭제하도록 되어 있습니다.
이 DefaultInstructions에서 안내하는 TodoProvider의 도구는 다음 5가지입니다.
todos_add: 1개 또는 여러 개의 Todo 항목을 추가합니다. 각 항목에는 제목과 선택적인 설명을 설정할 수 있습니다.todos_complete: ID를 지정하여 1개 또는 여러 개의 Todo 항목을 완료 상태로 표시합니다. 완료한 이유도 지정합니다.todos_remove: ID를 지정하여 1개 또는 여러 개의 Todo 항목을 삭제합니다.todos_get_remaining: 완료되지 않은 Todo 항목만 가져옵니다.todos_get_all: 완료된 항목과 완료되지 않은 Todo 항목을 모두 가져옵니다.
이처럼 TodoProvider는 Todo 리스트를 유지할 뿐만 아니라, 에이전트가 작업 진행 상황에 맞춰 스스로 리스트를 업데이트할 수 있도록 조작용 도구도 함께 제공합니다.
TodoProvider는 개인적으로 크게 커스텀할 일은 없을 것 같지만, Todo의 상태를 가져오는 메서드가 정의되어 있으므로 이를 사용하여 Todo 상황을 UI에 표시하는 등의 작업은 가능합니다.
GetAllTodosAsync: 세션에 저장된 완료된 항목과 완료되지 않은 모든 Todo 항목을 가져옵니다.GetRemainingTodosAsync: 세션에 저장된 완료되지 않은 Todo 항목만 가져옵니다.
메서드 시그니처는 다음과 같습니다.
public async Task<IReadOnlyList<TodoItem>> GetAllTodosAsync(
AgentSession session,
CancellationToken cancellationToken = default)
...
TodoProvider의 예시는 앞서 설명한 "HarnessAgent를 사용하지 않는 케이스"에서 다루었으므로 여기서는 새로운 샘플을 만들지 않겠지만, TodoProvider를 넣는 것만으로 에이전트가 Todo 관리를 수행하게 된다는 점은 매우 매력적입니다.
요약
지금까지 Todo와 AgentMode라는 두 가지 프로바이더를 살펴보았습니다. HarnessAgent는 편리하지만 사실 일반적인 AIAgent
에도 HarnessAgent가 가지고 있는 기능을 추가할 수 있습니다. HarnessAgent를 사용하는 것이 어렵더라도, 본인의 기존 AIAgent에 이러한 기능들을 추가하는 것은 간단하므로 기회가 된다면 시도해 보시기 바랍니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기