한동안 회사 일 때문에 미뤄두었던, 딥시크(
DeekSeek)와 더불어 많이 많은 마누스(
manus.im)에서 영감받아 개발된 오픈마누스(
open manus) 오픈소스 AI 에이전트를 설치, 사용 및 분석한다. 오픈마누스는 MetaGPT란 이름으로 활동 중인 중국인 개발자가 공개한 AI에이전트이다. 개발자는 오픈마누스가 연결된 다양한 도구들을 LLM으로 조율하고, 실행할 수 있고 주장하고 있다. 깃허브 등에 설명된 오픈 마누스는 다음과 같은 기능을 지원한다.
- 로컬에서 AI 에이전트 실행
- 여러 도구 및 API 통합: 외부 API, 로컬 모델 및 자동화 도구를 연결, 호출
- 워크플로우 사용자 지정: AI가 복잡한 다단계 상호 작용을 효율적으로 처리
- 여러 LLM 지원: LLaMA, Mistral 및 Mixtral과 같은 인기 있는 개방형 모델 모델과 호환
- 자동화 향상: 내장 메모리 및 계획 기능을 통해 OpenManus는 코딩, 문서 처리, 연구 등을 지원
다음 그림은 이 에이전트가 지원하는 기능 중 일부이다.
prompt: Create a basic Three.js endless runner game with a cube as the player and procedurally generated obstacles. Make sure to run it only in browser. If possible also launch it in the browser automatically after creating the game.
오픈 마누스는 이전 중국에서 개발된 마누스의 관심을 오픈소소로 옮겨지는 데 성공했다. 오픈 마누스는 현재 github에서 40.6k란 매우 높은 좋아요 관심을 받고 있다.
오픈 마누스(현재 시점. 40.6k stars)
개인적으로 오픈마누스에 대한 관심도가 높았던 것은, 구현된 기술보다는 에이전트 분야에서 크게 알려진 마누스에 대한 관심, 오픈소스 버전의 AI에이전트 코드 공개가 더 크게 작용했다고 생각한다. 이제 설치 사용해 보고, 성능 품질을 확인해 보자. 그리고, 코드 실행 메커니즘을 분석해 본다.
오픈마누스 설치
개발환경은 이미 컴퓨터에 NVIDIA, CUDA, PyTorch 등이 설치되어 있다고 가정한다. 이제, 다음 명령을 터미널에서 실행해 설치한다.
conda create -n open_manus python=3.12
conda activate open_manus
cd OpenManus
pip install -r requirements.txt
playwright install
오픈마누스가 설치하는 패키지를 보면, 많은 경우, 기존에 잘 만들어진 LLM, AI Agent 라이브러리를 사용하는 것을 알 수 있다. 여기서 사용하는 주요 라이브러리는 다음과 같다.
pydantic, openai, fastapi, tiktoken, html2text, unicorn, googlesearch-python, playwright, docker
config/config.toml 설정 파일을 수정한다. api_key에 OpenAI의 API 키 등을 입력한다(만약, API 키 유출 등이 불안하다면, Ollama 오픈소스 LLM 모델로 설정한다).
# Global LLM configuration
[llm]
model = "gpt-4o"
base_url = "https://api.openai.com/v1"
api_key = "sk-..." # Replace with your actual API key
max_tokens = 4096
temperature = 0.0
# Optional configuration for specific LLM models
[llm.vision]
model = "gpt-4o"
base_url = "https://api.openai.com/v1"
api_key = "sk-..." # Replace with your actual API key
실행
일단, 예제를 간단히 실행해 본다.
python main.py
적절한 프롬프트를 입력해 본다.
create PDF file about BIM(building information modeling).
마누스는 이 프롬프트에 응답해, LLM에 입력하여, 마누스에 등록된 도구를 호출하는 정보와 스크립트를 생성한다. 그리고, 이를 통해 각 도구들을 적절히 호출해 실행한다.
다음은 각 프롬트에 대한 그 예를 보여준다.
prompt: Create a basic Three.js endless runner game with a cube as the player and procedurally generated obstacles. Make sure to run it only in browser. If possible also launch it in the browser automatically after creating the game.
prompt: I need a 7-day Japan itinerary for April 15-23 from Seattle, with a $2500-5000 budget for my fiancée and me. We love historical sites, hidden gems, and Japanese culture (kendo, tea ceremonies, Zen meditation). We want to see Nara's deer and explore cities on foot. I plan to propose during this trip and need a special location recommendation. Please provide a detailed itinerary and a simple HTML travel handbook with maps, attraction descriptions, essential Japanese phrases, and travel tips we can reference throughout our journey.
prompt: create PDF file about ConTech in construction
실행결과는 많이 알려진 프롬프트를 제외하고는 그다지 품질이 좋지는 않다. 그럼에도, 나름 많은 스타를 깃허브에서 얻고 있는 오픈 마누스의 에이전트의 구조를 분석하는 것은 의미가 있어 보여, 좀 더 자세히 코드를 확인해 본다.
코드 동적 구조 분석
동적 구조는 실행 흐름을 타고 가며 확인한다. 참고로, 이 구조는 다음 프롬프트일때 실행되는 구조이다.
I need a 7-day Japan itinerary for April 15-23 from Seattle, with a $2500-5000 budget for my fiancée and me. We love historical sites, hidden gems, and Japanese culture (kendo, tea ceremonies, Zen meditation). We want to see Nara's deer and explore cities on foot. I plan to propose during this trip and need a special location recommendation. Please provide a detailed itinerary and a simple HTML travel handbook with maps, attraction descriptions, essential Japanese phrases, and travel tips we can reference throughout our journey.
프롬프트는 일본 여행 기간을 명시하고 7일간 일정이 필요하다 말하고 있다.
이에 대한 마누스 에이전트의 전체 큰 실행 구조는 다음과 같다.
- call main() # 메인 호출
- prompt = input() # 프롬프트 입력
- Manus.BaseAgent.run(prompt) # 프롬프트 입력에 따른 에이전트 도구들 실행
- update_memory() # 과거 입출력 저장
- max_steps 만큼 아래 루프 반복 # default max_steps = 20
- step_result = ReActAgent.step() # 에이전트 도구 단계별 실행
- should_act = think() # 무슨 도구를 순서대로 호출할 지 LLM통해 정보얻음
- recent_messages = memory.messages[-3:]
- Manus.BrowserAgent.ToolCallAgent.think() # 도구 선택 추론
- extract current browser page information # 웹화면 정보 사용
- response = LLM.ask_tool() # 추론 시 LLM 사용
- check token limit # 토큰 한계 체크
- response = ChatCompletion(params) # LLM 호출
- return response[0].message # 결과 리턴
- return response
- act() # 에이전트 도구가 선택되었으니, 이를 실행
- tool_callls 에 담긴 도구 호출 명령에 따른 도구들 실행 루프 수행
- ToolCallAgent.execute_tool(command) # 도구 실행
- args = json.loads(command) # 예. web_search. '7-day tour'
- ToolCollection.execute(args) # 도구집합에서 해당도구실행
- BrowserUseTool.execute(args) # 쿼리검색 후 link 리턴
- _ensure_browser_initialized() #브라우저 초기화
- links = WebSearch.execute(args.query) # 웹서치
- page = get_current_page() # 페이지정보
- result = page.goto(url_to_navigate)
- return ToolResult(args, result) # 검색결과 수집
- return observation(result)
- tool_msg = 도구 실행 명령 및 함수 정보
- memory.add_message(tool_msg) # 메모리 업데이트
- results.append(result)
- return results # 결과리턴
이를 좀 더 알기 쉽게 표현하면 다음같이 설명될 수 있다.
2. 프롬프트 입력: 사용자로부터 프롬프트 입력
3. 에이전트 실행: BaseAgent가 입력을 기반으로 동작 시작
4. 메모리 업데이트: 과거 입력/출력 내용을 memory에 저장
5. 에이전트 루프 실행 (기본 max_steps = 20)
5.1. 단계 실행 (Step): ReActAgent가 현재 단계 처리 시작
5.2.2. LLM을 통해 다음 행동(도구 호출 여부 등) 추론
5.3.1. BrowserAgent가 어떤 도구를 쓸지 결정
5.3.3. 필요 시 LLM에 도구 사용 목적 질의 (ask_tool)
5.4.1. ChatCompletion으로 명령 생성
5.5.1. 도구 호출 명령(command)을 파싱 (예: JSON)
5.5.2.1. ToolCollection에서 해당 도구 실행
5.5.2.2. 브라우저 초기화 (_ensure_browser_initialized)
5.5.2.3. 웹 검색 수행 (WebSearch.execute)
5.5.2.4. 페이지 이동 및 정보 추출 (page.goto)
5.5.3.1. ToolResult로 실행 결과 정리
5.5.3.2. observation 형태로 결과 정리
5.6.1. 도구 실행 정보 및 결과를 memory에 저장
6. 최종 결과 반환: 누적된 결과 또는 마지막 응답을 사용자에게 반환
이 중에 핵심 실행 단계만 확인해 보자.
5번 단계의 think는 LLM을 이용해 사용자 프롬프트를 기반으로 다음과 같이 적절한 도구를 순서대로 선택하도록 명령하고 있다. 이런 이유로, 도구에 대한 프로토타입을 LLM 호출 시 컨텐츠로 전달해 두어야 한다.
"Based on user needs, proactively select the most appropriate tool or combination of tools. For complex tasks, you can break down the problem and use different tools step by step to solve it. After using each tool, clearly explain the execution results and suggest the next steps."
현재 마누스 버전에서 프롬프트 템플릿은 다음처럼 정의되어 있다.
"You are OpenManus, an all-capable AI assistant, aimed at solving any task presented by the user. You have various tools at your disposal that you can call upon to efficiently complete complex requests. Whether it's programming, information retrieval, file processing, or web browsing, you can handle it all."
"The initial directory is: {directory}"
Based on user needs, proactively select the most appropriate tool or combination of tools. For complex tasks, you can break down the problem and use different tools step by step to solve it. After using each tool, clearly explain the execution results and suggest the next steps.
LLM을 호출하는 부분은 위 템플릿을 이용해 시스템 프롬프트와 함께 사용자 질의를 입력하는 부분으로 구성될 것이다. 다음은 해당 정보를 보여준다.
prompt: create input.txt file and copy it to output.txt
본인의 경우, gpt-4o LLM 을 사용했다. messages의 1번에는 사용자 프롬프트가 입력되어 있고, 이 목표를 달성하기 위해 적절한 도구를 선택하라 명령하고 있다. tools에 함수 프로토타입이 저장된 것을 확인할 수 있다. 이를 근거로, LLM은 목표를 달성하기 위한 적절한 함수 호출 시퀀스를 생성한다.
브라우저 화면의 검색 정보가 직접 필요한 경우가 있다. playwright를 이용해 해당 정보를 얻는 부분이 think()에서 사용되는 경우도 있을 수 있다. 다음 그림은 사용자 프롬프트 질의에 따라 LLM 이 선택한 도구인 브라우저를 통해 정보를 얻고, 그 정보를 메모리에 업데이트하면서, 에이전트 도구를 실행해 가는 화면이다.
에이전트 검색 결과
에이전트 도구의 리턴 결과(일부)
결론적으로 핵심만 요약해 보면, 다음과 같은 방식으로 에이전트가 실행되는 것을 확인 할 수 있다.
- 사용자 프롬프트 입력
- LLM 이 프롬프트를 통해 어떤 에이전트 도구들을 실행할 지 결정. 도구 정보 반환
- 도구 호출 정보에 따라, 현재 등록된 도구들을 호출. 결과 파일은 workspace에 저장
- 도구 호출 결과는 메모리에 저장. 이는 LLM 이 도구를 호출할 때 참고 컨텐츠로 재사용
- 사용자 프롬프트 요구사항(목표)을 만족할 때까지 앞의 내용 반복
다음은 각 step별로 에이전트가 호출되어 파일이 생성될 경우 저장된 workspace 폴더와 예시를 보여주다.
AI 에이전트 도구에 의해 생성된 파일(우: 게임 코드, 좌하: 일본여행일정)
분석해 보면, 사실, 대단한 메커니즘은 아니다. 이는 기존 OpenAI LLM 플랫폼 도구, LangChain과 같은 RAG, Ollama 같은 LLM Agent 도구에도 있었던 것이다. 좀 다른 것은 다음과 같은 기능이 기본으로 구현되어 있다는 정도로 보이는 데, 이도 다른 유명 LLM, 에이전트 플랫폼에서 하고 있는 것이라 큰 차이라 보기가 어렵다.
1. 웹브라우저를 통해 인터넷 컨텐츠 정보로 적극 사용한 것. 화면 자체에서 정보를 얻는 기능
2. 파일 및 폴더, MCP(Model Control Procotol), 파이썬, 터미널 조작 등 지원
오픈마누스의 가장 큰 장점은 오픈소스로 누구나 그 메커니즘을 확인하고, 분석하는 재미와 기여하며 커가는 커뮤니티 연대 정도로 생각할 수 있겠다.
코드 정적 구조 분석
코드 정적 구조 분석을 위해 폴더부터 분석해 본다. 구조는 다음과 같다.
OpenManus/
├── app/ # 애플리케이션 핵심 코드
│ ├── agent/ # 에이전트 로직 (예: BaseAgent, ReActAgent)
│ ├── flow/ # 실행 흐름 제어 (workflow, step control)
│ ├── mcp/ # Model Control Procotol
│ ├── prompt/ # 프롬프트 템플릿 관련
│ ├── sandbox/ # 실행 격리 환경 (보호된 실행 공간)
│ └── tool/ # 실행 가능한 다양한 도구 모음
│ ├── bash.py # Bash 명령 도구
│ ├── browser_use_tool.py # 브라우저 연동 도구
│ ├── create_chat_completion.py # LLM 호출 지원
│ ├── file_operators.py # 파일 입출력 도구
│ ├── file_saver.py # 파일 저장 도구
│ ├── mcp.py # 제어 관련 도구
│ ├── planning.py # 계획 생성 도구
│ ├── python_execute.py # 파이썬 코드 실행 도구
│ ├── str_replace_editor.py # 문자열 편집 도구
│ ├── terminal.py # 터미널 명령 실행 도구
│ ├── terminate.py # 실행 종료 도구
│ ├── tool_collection.py # 전체 도구 관리자
│ └── web_search.py # 웹 검색 도구
├── assets/ # 에셋, 리소스 파일
├── config/ # 설정 파일들
├── examples/ # 예시 실행 계획들
│ └── japan-travel-plan/ # 예: 여행 계획 샘플
├── logs/ # 실행 로그 저장
├── tests/ # 테스트 코드
│ └── sandbox/ # 샌드박스 테스트
└── workspace/ # 임시 실행 또는 작업 파일 저장소
설치된 폴더 구조 (일부)
각 코드를 정적 분석해, 핵심 클래스만 UML로 분석해 보겠다. 마누스의 주요 클래스 구조는 다음과 같다.
오픈 마누스 클래스 다이어그램(UML)
소프트웨어 공학적으로는 디자인패턴 중 strategy pattern (ToolCollection, BaseTool) 을 사용하고 있다. 나머진 일반적인 OOAD 구조이다.
BaseTool 클래스는 execute 메서드를 공통으로 가지며, 이를 상속한 각 도구 클래스들(Terminal, FileSaver, MCPClientTool, WebSearch, DomService, BrowserUseTool 등)은 시스템 명령 실행, 파일 저장, 브라우저 제어 등 특정 기능을 담당한다. 각 도구는 ToolCollection에 집합되어 있으며, tool_map을 통해 관리되고 execute를 통해 실행된다.
ToolCallAgent는 think 메서드를 통해 어떤 도구를 사용할지 판단하고, 판단 결과를 ToolCollection에 전달하여 해당 도구를 실행한다. ReActAgent는 step, think, act 메서드를 통해 LLM 기반 추론과 도구 실행 흐름을 단계적으로 처리하며, BaseAgent는 이를 상속받아 step 단위의 실행 흐름을 제공한다. Manus 객체는 최상위 제어자로서 전체적인 에이전트의 동작을 통제하며 think 메서드를 통해 추론을 담당한다. BrowserAgent는 BrowserUseTool과 관련된 think 역할을 수행한다.
BrowserUseTool은 WebSearch와 DomService를 포함하며 웹 페이지 탐색, 클릭, 입력 등의 브라우저 상의 조작을 담당한다. DomService는 클릭, 스크롤, 탭 전환 등 구체적인 DOM 제어 명령을 담당하며, 오른쪽 enum 박스는 이 DomService가 수행할 수 있는 구체적인 명령어 목록을 나열한 것이다.
LLM 클래스는 ask_tool, ask_with_images, ask 등의 메서드를 제공하며, 도구 선택 판단 또는 일반 자연어 추론을 위한 언어 모델 호출 기능을 수행한다. LLM이 사용하는 모델은 gpt-4-vision, gpt-4.0, claude-3 계열 등으로 구성된 멀티모달 모델 리스트에 명시되어 있다.
전체 구조는 에이전트가 사용자 입력을 받아 LLM을 통해 판단하고, 적절한 도구를 선택하여 실행하며, 이를 반복적으로 수행하는 다단계 추론 및 실행 체계를 중심으로 구성되어 있다.
마무리
이 글을 통해 오픈마누스를 분석해 보았다. 개발 시작한 지 얼마 안되는 따끈따끈한 코드라서 그런지, 아직 코드 리팩토링이 잘 안되어 있고, 구조도 멀티 에이전트라 하기에는 좀 부족하고 확장성에 문제가 있는 것들이 있다. 에이전트 선택 및 호출하는 부분은 막코딩(?) 같은 부분이 있어 구조적으로 깔끔하지 못하다(습작 느낌). LangChain처럼 많은 개발자가 참여하면 크게 복잡해져 입력-결과를 예측하기 어려워지거나, 버전업에 되면서 빅스텝(과거와의 단절)이 될 수 있을 것 같다.
에이전트의 핵심기술은 결국 추론 능력을 가진 LLM을 어떻게 잘 활용하는 가이다. 이런 점에서 마누스(최근 해킹되어 코드 확인해 보았더니)나 오픈마누스는 기존 LLM과 프롬프트 템플릿을 복잡하게 wrapping 해 놓은 모듈이란 말이 나올 수 밖에 없다.
좀 더 깃허브를 살펴보니, 이를 주도하는 개발자는 심천에 있는 중국인이며. 이외, 지장에 있는 개발자, 학생들 6명 정도가 주축으로 개발하고 있는 것 같다(소프트웨어 공학적으로는 약간 아마추어 느낌).
RL 모듈은 UIUC에 다니는 중국인 대학원생, 홍콩과기대 학생 등이 주축이되고 있다(참 열심히 개발하는 느낌).
그럼에도 불구하고, 열심히 개발 중인 오픈소스 구조를 살펴보고 여러 구현 아이디어를 보는 것은 즐거운 것이다. 이런 이유로, 이들이 본인이 개발하는 코드를 공개하고, 고민을 공유하는 것은 브랭딩 전략이란 점을 제외하더라도 의미있는 행위라 생각한다. 시간이 된다면,
OpenManus-RL 도 분석해볼 계획이다.
레퍼런스