최근 인공지능(AI) 기술의 비약적인 발전과 함께, 대형 언어 모델(LLM)인 ChatGPT와 Claude를 활용한 다양한 서비스가 등장하고 있습니다. 특히, 시스템 프롬프트(System Prompt)를 효과적으로 설계함으로써 복잡한 코드 없이도 고성능의 AI 서비스를 구현할 수 있는 가능성이 주목받고 있습니다. 본 글에서는 시스템 프롬프트의 역할과 그 진화, 그리고 LLAMI 팀이 제안하는 멀티 에이전트 시스템을 통한 혁신적인 접근법을 상세히 알아봅니다.
시스템 프롬프트란 무엇인가?
시스템 프롬프트는 AI 모델의 초기 지시사항으로, 모델의 응답 방식을 정의하는 중요한 요소입니다. 초기에는 단순한 지시어(“차분히 생각하세요”, “단계별로 접근하세요”)로 시작했으나, GPT-4와 같은 고성능 LLM의 등장으로 더욱 정교한 지시어가 필요하게 되었습니다. 이제 시스템 프롬프트는 단순한 역할 부여를 넘어, 전문가 페르소나를 정의하고, 구체적인 행동 지시어를 포함하는 복잡한 컨테이너로 발전했습니다.
시스템 프롬프트의 진화
매직 프롬프트에서 행동 지시어로
초기 시스템 프롬프트는 단순한 지시어로 AI의 성능을 향상시키는 역할을 했습니다. 그러나 고성능 LLM의 등장으로 시스템 프롬프트는 전문가 페르소나를 정의하고, 특정 상황에서의 응답 방식을 세부적으로 규정하는 도구로 진화했습니다. 이는 AI가 특정 도메인 지식을 바탕으로 일관된 응답을 제공하도록 돕는 중요한 발전 단계였습니다.
시스템 프롬프트의 딜레마
LLM의 성능이 향상됨에 따라 시스템 프롬프트는 더욱 복잡해졌습니다. 복잡한 지시 사항이 추가될수록 AI의 행동 예측이 어려워졌고, 강력한 제약어(“절대로”, “반드시”)를 사용해도 AI가 이를 무시하는 문제가 발생했습니다. 이는 시스템 프롬프트의 복잡성이 증가할수록 AI의 일관성과 신뢰성이 저하되는 딜레마를 초래했습니다.
RAG의 한계: 정보 검색만으로는 부족하다
첫 번째 해결책으로 시도된 RAG(Retrieval-Augmented Generation)는 시스템 프롬프트의 일부를 필요할 때마다 검색하여 참조하는 방식이었습니다. 그러나 시스템 프롬프트의 복잡한 행동 지시어들은 단순한 정보 검색으로는 해결할 수 없었고, 규칙 간의 긴밀한 상호작용을 처리하기에는 한계가 있었습니다.
시스템 프롬프트의 모듈화: 마이크로소프트 AutoGen에서 영감을 받은 접근
LLAMI 팀은 마이크로소프트의 AutoGen 프로젝트에서 영감을 받아 시스템 프롬프트를 여러 전문 에이전트로 분할하는 방식을 도입했습니다. 이는 복잡한 코드를 여러 함수로 나누어 관리하듯, 시스템 프롬프트도 여러 에이전트가 분담하여 처리함으로써 이행률을 크게 향상시켰습니다.
멀티 에이전트 시스템의 가능성
멀티 에이전트 시스템은 여러 AI 에이전트가 서로 대화하며 복잡한 문제를 해결하는 구조입니다. LLAMI 팀은 이를 통해 시스템 프롬프트를 명확한 직무로 분할하고, 각 에이전트가 특정 역할을 수행하도록 설계했습니다. 이로써 시스템 프롬프트 지시 사항 이행률을 90% 이상으로 끌어올리는 성과를 거두었습니다.
맥락 과부하의 해결
시스템 프롬프트가 복잡해질수록 LLM은 더 많은 맥락을 처리해야 하며, 이는 성능 저하로 이어질 수 있습니다. LLAMI 팀은 프롬프트를 여러 에이전트에 분산 처리함으로써 개별 에이전트의 인지 부하를 줄이고, 장기적인 대화에서도 일관성과 신뢰성을 유지할 수 있었습니다.
통제된 협업의 설계
LLAMI의 멀티 에이전트 시스템은 명확한 규칙과 체계를 기반으로 각 에이전트가 책임과 권한을 가지고 협업하도록 설계되었습니다. 이러한 구조는 책임소재의 명확화, 예측 가능한 동작, 효과적인 디버깅 등의 이점을 제공하여 시스템의 신뢰성을 크게 향상시켰습니다.
프로그래밍적 구현: GroupChatManager와 ConversableAgent
LLAMI 팀은 시스템 프롬프트의 모듈화를 위해 두 가지 핵심 컴포넌트인 `GroupChatManager`와 `ConversableAgent`를 도입했습니다. 이를 통해 에이전트 간의 효율적인 메시지 처리와 응답 생성을 구현할 수 있었습니다.
GroupChatManager
`GroupChatManager`는 대화의 기록을 관리하고, 각 에이전트가 정상적으로 활동하는지 모니터링하며, 메시지가 정확히 전달되도록 보장합니다. 주요 메서드인 `processMessage`는 메시지를 히스토리에 기록하고, 대화의 종료 조건을 확인한 후 적절한 에이전트로 메시지를 전달합니다.
class GroupChatManager {
protected history: Message[] = [];
protected agents: Map<string, ConversableAgent> = new Map();
protected async processMessage(message: Message): Promise<Message> {
this.history.push(message);
if (this.shouldEndConversation(message, this.history)) {
return message;
}
const currentAgent = this.agents.get(message.receiver);
if (!currentAgent) {
throw new Error(`Agent ${message.receiver} not found`);
}
const fullPrompt = await this.contextStrategy(this.history, message);
const responseMessage = await currentAgent.answer({
sender: message.sender,
receiver: currentAgent.name,
content: fullPrompt,
}, this.history);
return this.processMessage(responseMessage);
}
}
핵심 기능
- 히스토리 관리: 모든 메시지를 기록하여 대화의 흐름을 추적합니다.
- 에이전트 전달: 메시지를 적절한 에이전트로 전달하여 응답을 생성합니다.
- 대화 종료 조건: 특정 조건에 도달하면 대화를 종료합니다.
ConversableAgent
`ConversableAgent`는 모든 대화 참여자의 기본 설계도로, 각 에이전트는 응답 내용을 생성하고 다음 대화 상대를 결정합니다. 이를 통해 LLAMI의 분산형 의사결정을 가능하게 합니다.
abstract class ConversableAgent {
abstract readonly name: string;
protected manager!: GroupChatManager;
async answer(message: Message, history: Message[]): Promise<Message> {
const { content, nextReceiver } = await this.processAnswer(message, history);
return {
sender: this.name,
receiver: nextReceiver,
content,
};
}
protected abstract processAnswer(message: Message, history: Message[]): Promise<{ content: string; nextReceiver: string; }>;
}
핵심 기능
- 응답 생성: 메시지에 대한 응답 내용을 생성합니다.
- 다음 수신자 결정: 다음 대화 상대를 결정하여 대화의 흐름을 관리합니다.
Human-in-the-Loop: 인간과 AI의 자연스러운 협업
LLAMI 팀은 인간 사용자가 AI 시스템의 자연스러운 일부로 참여할 수 있도록 `UserProxy`라는 인터페이스를 도입했습니다. 이는 인간이 다른 AI 에이전트들과 동등하게 대화에 참여할 수 있게 하여, 진정한 의미의 human-in-the-loop 협업을 실현했습니다.
UserProxy: 인간 참여자를 위한 인터페이스
`UserProxy`는 사용자의 입력을 비동기적으로 처리하며, 사용자의 차례일 때만 입력을 받을 수 있도록 설계되었습니다.
export class UserProxy extends ConversableAgent {
readonly name = "user";
private resolveInput: ((value: string) => void) | null = null;
private _isMyTurn: boolean = true;
async processAnswer(message: Message): Promise<{ content: string; nextReceiver: string; }> {
this.manager.resetTurns();
this.setTurn(true);
return new Promise<{ content: string; nextReceiver: string; }>((resolve) => {
this.resolveInput = (input: string) => {
this.setTurn(false);
resolve({
content: input,
nextReceiver: "dialogue"
});
};
});
}
handleInput(input: string) {
if (this.resolveInput && this._isMyTurn) {
this.resolveInput(input);
this.resolveInput = null;
}
}
}
핵심 기능
- 비동기 입력 처리: 사용자의 입력을 비동기적으로 기다립니다.
- 차례 관리: 사용자의 차례를 관리하여 입력 시점을 제어합니다.
UI와의 통합
LLAMI 팀은 `UserProxy`와 `GroupChatManager`를 React 컴포넌트와 자연스럽게 통합하여 사용자 인터페이스를 구현했습니다. 이는 사용자와 AI 에이전트 간의 원활한 상호작용을 가능하게 합니다.
ChatInterface
`ChatInterface`는 사용자 입력을 처리하고, AI 에이전트의 응답을 표시하는 React 컴포넌트입니다.
export const ChatInterface = () => {
const [isUserTurn, setIsUserTurn] = React.useState(true);
const [input, setInput] = React.useState("");
// UserProxy의 턴 변경 감지
React.useEffect(() => {
const unsubscribe = userAgent.onTurnChanged((isMyTurn) => {
setIsUserTurn(isMyTurn);
});
return () => unsubscribe();
}, []);
// 사용자 입력 처리
const handleSubmit = async (e: React.SyntheticEvent) => {
e.preventDefault();
if (!input.trim() || !isUserTurn) return;
const userMessage: Message = {
sender: "user",
receiver: "dialogue",
content: input,
};
setInput("");
if (isFirst.current) {
isFirst.current = false;
await groupChatManager.chatStart(userMessage);
} else {
userAgent.handleInput(input);
}
};
return (
<form onSubmit={handleSubmit}>
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder={isUserTurn ? "메시지를 입력하세요..." : "AI가 응답하는 중입니다..."}
disabled={!isUserTurn}
/>
<Button
type="submit"
disabled={!isUserTurn || !input.trim()}
>
전송
</Button>
</form>
);
};
핵심 기능
- 턴 관리: `isUserTurn` 상태를 통해 사용자의 차례를 관리합니다.
- 입력 처리: 사용자의 입력을 `UserProxy`에 전달하여 대화를 진행합니다.
- 비동기 응답: AI 에이전트의 응답을 비동기적으로 처리하여 사용자에게 표시합니다.
실제 적용 사례와 효과
LLAMI 팀은 멀티 에이전트 시스템을 AI 제목 생성 프로젝트에 적용하여, 단일 프롬프트 방식에서 발생하던 복잡성을 해결하고 시스템 프롬프트 이행률을 90% 이상으로 향상시켰습니다. 각 에이전트는 특정 직무에 집중함으로써 시스템의 신뢰성과 확장성을 크게 높일 수 있었다고 합니다.
적용된 에이전트 역할
- 서비스 안내자: 사용자와의 첫 대화를 시작하고 전체 맥락을 파악합니다.
- 창의적 사고 촉진자: 사용자의 의도를 구체화하고 다양한 가능성을 탐색합니다.
- 제목 생성기: 효과적인 제목을 생성하고 평가 기준에 따라 검증합니다.
- 사용자 에이전트: 인간 사용자의 입력을 시스템에 자연스럽게 통합합니다.
결론
대형 언어 모델의 발전은 AI 기반 서비스의 새로운 가능성을 열었지만, 시스템 프롬프트의 복잡성 증가는 그 한계점도 드러냈습니다. LLAMI 팀의 멀티 에이전트 시스템은 이러한 문제를 효과적으로 해결하며, 시스템 프롬프트를 코드처럼 모듈화하여 관리할 수 있는 새로운 패러다임을 제시했습니다. 이 접근법은 LLM 기반 서비스의 신뢰성과 확장성을 한 단계 더 높일 수 있는 혁신적인 해결책으로 주목받고 있습니다.
참고 자료 마이크로소프트 AutoGen 프로젝트: AutoGen GitHub