2025년 3월 29일 토요일

딥시크(deep seek) 오픈소스 코드 및 구조 분석하기

앞서 AI에이전트 오픈 미노스를 분석해 보았는 데, 내친김에 그 동안 말많았던 딥시크(deep seek)를 분석해 보기로 한다. 개인적으로 언론의 기사를 잘 믿지는 않는다. 홍보성 퍼나른 기사가 많기도 하고, 특히 테크분야에서도 약장사분들? 많아, 어디까지 진실인지 아닌지 모르기 때문이다. 정말 대단한지, 아니면 지재권 완전 무시하고 기술 탈취?해 싼 제품 잘 만드는 중국 방식으로 개발된 것인지 알려진 자료에 기반해 팩트 확인해 보고자 한다.
딥시크 (theconversation.com, 2025)

참고로, 마누스 오픈소스에 관심 있다면 다음 링크를 참고한다. 

딥시크 분석 준비
다음 링크를 방문해 코드를 클론한다.
터미널에서 다음 명령을 실행한다. 
git clone https://github.com/deepseek-ai/DeepSeek-V3.git

폴더 및 파일 구조 분석 
vscode를 띄워 보니 폴더 구조는 다음과 같다. 
  - workflows: 워크플로우 관련 폴더
  - inference: 하위 폴더
    - configs: 설정 파일 폴더
    - convert.py: Python 파일, 4KB
    - fp8_cast_b16f.py: Python 파일, 5KB
    - generate.py: Python 파일, 8KB
    - kernel.py: Python 파일, 9KB
    - model.py: Python 파일, 8KB
    - requirements.txt: 텍스트 파일, 1KB


공개된 소스 코드를 보니 굳이 실행을 위한 패키지 설치는 할 필요 없을 것 같다. 일단, 오픈소스가 아니다. 단순히, inference 추론 코드만 공개되어 있다(어그로). 오픈소스라면, 최소한, train 학습 코드와 기본 데이터셋 정도는 공개되어야 한다(언론이 왜 오픈소스라 난리였는지 사실 이해가 안되는...). 

코드는 대부분 트랜스포머 구조를 그대로 사용한다. 트랜스포머스는 구글에서 이미 2017년 개발 공개된 LLM 모델 학습 메커니즘이다. 딥시크에서 사용한 상세한 기술을 알고 싶다면, 다음 링크를 참고하길 바란다.

소스 코드 분석
공개된 코드는 주로 추론을 위해 딥시크 측에서 공개한 학습된 가중치 모델 파일을 로딩해 사용하기 위한 model.py, 양자화로 성능 가속을 위한 fp8_cast_bf16.py, 질의 프롬프트에 대한 모델 출력을 생성하는 generate.py 정도가 분석할 필요가 있어 보인다. 

model.py 분석
일단, 사용하는 라이브러리 대부분이 미국 빅테크 기업 혹은 연구소에서 개발된 것들을 임포트에 사용하고 있다. 이 분야에서 모르면 간첩인 pytorch, 심지어 triton은 NVIDIA GPU 가속 최적화를 위해 사용하는 라이브러리를 직접 사용한다(NVIDIA 종속적). 

모델의 전체 구조는 트랜스포머를 그대로 따르며, 이미 오픈소스 공개된 코드에 나오는 키워드도 다음처럼 그대로 사용하고 있다.

model.forward를 확인해보자. 일반적인 트랜스포머스 forward 루틴으로 보여진다. 
    def forward(self, tokens: torch.Tensor, start_pos: int = 0):
        seqlen = tokens.size(1)
        h = self.embed(tokens)  # 1) 입력 임베딩
        freqs_cis = self.freqs_cis[start_pos:start_pos+seqlen]  # 2) # 위치 인코딩
        mask = None
        if seqlen > 1:              # 3) 마스킹
            mask = torch.full((seqlen, seqlen), float("-inf"), device=tokens.device).triu_(1)
        for layer in self.layers:   # 4) 트랜스포머스 레이어 실행 계산
            h = layer(h, start_pos, freqs_cis, mask)
        h = self.norm(h)[:, -1]   # 5) 출력 정규화
        logits = self.head(h)     # 6) 로짓 계산
        if world_size > 1:
            all_logits = [torch.empty_like(logits) for _ in range(world_size)]
            dist.all_gather(all_logits, logits)
            logits = torch.cat(all_logits, dim=-1)
        return logits

이 함수는 입력 토큰을 받아 로짓(예측값)을 계산하는 역할을 한다. 예측값은 미리 준비된 사전에서 예측된 단어를 선택할 때 역할을 한다(입력 토큰에 대한 다음 토큰 예측 생성과정). 주요 동작은 다음과 같다.
  1. embed: 입력 임베딩 처리: 입력으로 제공된 토큰 텐서를 임베딩 레이어를 통해 변환하여 초기 입력 표현을 생성한다. 
  2. freqs_cis: 로터리 임베딩 계산:  주파수 정보를 담고 있는 로터리 임베딩 텐서를 시퀀스 길이에 맞게 선택하여, 위치 정보를 모델에 제공한다. 위치임베딩이란 기법도 이미 트랜스포머스 논문(Google, 2017)에 구현된 것이다.
  3. mask: 시퀀스 길이가 1보다 클 경우, 미래 정보가 영향을 미치지 않도록 상삼각형 형태의 마스크를 생성한다. 마스크는 모델이 언어 생성 시 현재 시점 이전의 정보만을 활용하게 한다.
  4. Transformer 레이어 통과: 모델 내부의 여러 Transformer 레이어를 입력 데이터가 순차적으로 통과하며, 각 레이어에서 입력 표현이 갱신된다. 
  5. norm: 출력 정규화 및 최종 표현 추출. 마지막 Transformer 레이어의 출력을 정규화하고, 시퀀스의 마지막 토큰에 해당하는 표현을 추출한다. 
  6. logits: 로짓 계산. 추출된 최종 표현을 출력 레이어(헤드)에 전달하여 로짓, 즉 예측값을 계산한다. 이는 각 토큰에 대한 다음 단어 또는 출력값의 확률 분포를 나타낸다.
결과적으로, 이 메서드는 입력 토큰 시퀀스를 기반으로 각 토큰에 대한 예측값을 반환하며, 이는 주로 언어 모델링 및 자연어 처리 작업에 활용된다.

모델의 전체 구조는 다음과 같다. 대부분 파이토치 기반 트랜스포머스 코드(이미 많이 공개된 코드 조각)를 사용한다(딥시크 처음 언론 보도가 실제로 얼마나 차이가 있는 지 확인할 수 있음).
딥시크-V3 모델 구조(UML)

다만, 실행 속도 등 최적화를 위해 병렬처리, torch.einsum 함수를 이용해 GPU 연산을 직접 이용해 트랜스포머 어텐션 모델 QKV 코사인 유사도 계산하는 등의 노력을 하고 있다(이 또한 이미 알려진 것).
토큰 시퀀스 임베딩 벡터 간 유사도 스코어 계산 및 학습하는 부분(일부. 트랜스포머스 모델의 전형적인 루틴임. 여기서 bshd는 batch, source seqnce, heads, feature demension 의 약자로 입력 텐서의 모양-차원을 정의함)

kernel.py 분석
이 모듈은 주로 성능과 관련된 양자화를 다룬다. triton 라이브러리를 사용해 주어진 텐서를 양자화하여, 32비트 실수 연산을 8비트 실수 연산으로 처리할 수 있게 한다. 8비트 텐서 실수 연산을 위한 함수도 같이 구현되어 있다. 예를 들어, 다음 fp8_gemm 함수는 8비트 양자화된 a, b 텐서를 입력받아 행렬곱한 후 c를 리턴한다.

convert.py 분석
이 모듈은 모델 파일 포맷을 주어진 옵션에 맞게 단순히 체크포인트 파일로 변환하는 역할을 한다. 복잡한 내용은 별로 없어 상세 설명은 생략한다.

configs 파일 분석
이 폴더 내 모델의 구조를 정의하는 주요 변수가 정의되어 있다. 예를 들어, config_16B.json 파일은 다음과 같이 정의된다. 
의미는 다음과 같다. 
1. 모델 구조  
   - vocab_size: 어휘 크기 (102,400).  
   - dim: 임베딩 차원 (2048).  
   - inter_dim: FFN의 확장 차원 (10,944).  
2. MoE 관련  
   - n_routed_experts: 총 Expert 수 (64).  
   - n_activated_experts: 활성화 Expert 수 (6).  
   - moe_inter_dim: MoE Expert의 내부 FFN 차원 (1,408).  
3. Attention 관련  
   - n_layers: Transformer 레이어 수 (27).  
   - n_heads: Attention Head 수 (16).  
   - kv_lora_rank: 키/값 벡터의 LoRA 랭크 (512).  
   - qk_nope_head_dim: NOPE 기반 헤드 차원 (128).  
   - qk_rope_head_dim: RoPE 기반 헤드 차원 (64).  
4. 기타  
   - mscale: 모델 안정성을 위한 스케일 값 (0.707).  

분석해 본 결과, 사실 LLM에서 모델 구조, 추론 구현 부분 및 양자화 모듈만 대부분 공개되어 있다는 것을 알 수 있다. 

최소한 데이터셋 모듈이라도 공개되어야 어떤 식으로 데이터를 학습했는지 확인할 수 있지만, 이런 중요 모듈은 공개되어 있지 않아, 딥시크-V3는 오픈소스를 공개했다고 말하기 어렵다(가중치와 모델 모듈만 오픈. 이건 reddit에서도 까이고 있는데, 그냥 오픈웨이트 open weights 모델 코드임).

더 파보기
오픈소스라기에는 좀 실망이라, 무언가 더 없는 지 공개된 자료들을 파보기로 한다. 일단, 딥시크 개발사 github에서 최근 주목받고 있는 프로젝트만 다음처럼 정렬해본다.

이 중 체크한 부분이 먼가 있는 듯 하여, 들어가 확인해 본다. 
MIT 라이센스라 표시만 되어 있지, 코드가 없음
딥시크 기반 코더는 평가, 데모 코드만 있고, 파인튠은 학습 데이터셋 제공 없음 
평가 코드만 있음(MIT 라이센스 표시만. 오픈소스? 무슨 의미가?)
딥시크-V3 학습모델(가중치파일) 공개된 부부(허깅페이스)

더 파보았지만, 딥시크에서 주장하는 것은 오픈소스가 아닌 오픈웨이트 모델에 더 가까워보인다. 세계적인 홍보와 언론의 관심에 비해 무늬만 MIT라이센스 오픈소스가 아닌지 의문이다.

마무리
좀 시간을 내어 분석한 후, 확인 사살한 것은 다음과 같다. 
  1. 언론에서 말하는 것과는 상당한 차이가 있는 딥시크 기술 오픈소스였다. 대부분 이미 개발된 오픈소스를 가져다 쓴 것으로 보인다. 앞에 언급한 몇몇 성능 최적화 부분은 좋은 접근인 것이나, 메타(페북)의 라마(Llama)가 공개한 기술에 비하면 비교할 만한 것이 아니다.
  2. 중국은 확실히 홍보(x10배)에 천재적인 능력(약팔이)이 있다(진심으로). 
  3. 중국이 잘하는 선진국(미국) 기술 가져와 자국것으로 포장해 저가로 파는 기술은 세계 최고다. 
의문점은 한국 언론에서 다음과 같이 패닉성 기사를 쓸 때, 왜 남이 말한 것 받아 만 쓰고 팩트 확인하지 않았냐는 것인데... 좀 생각해보니 국내 딥시크 기사는 관련 컨텐츠를 해외에서 퍼온 검증도 안된 글을 기사로 정리한 것으로 이해된다. 사실, 첨단 기술을 팩트 체크할 리소스가 있는 언론이 많지는 않다고 생각한다. 그럼에도 파급격있는 채널은 뉴스를 전할때 항상 팩트 확인하려는 노력이 필요하다.
패닉성 딥시크 언론 보도(연합, 2025.1.27, 뉴스튜데이, 2025.3.28)

자극적 기사들로 얼마 전 정부 국회는 패닉되고, 급하게 만든 인공지능 진흥전략이 판을 치게 된 트리거 역할을 했다. 여론은 인공지능분야도 우리가 중국에 뒤쳐졌다는 것을 확인하는 계기는 되었다. 긍정적 효과도 있었다고 생각되나, 부작용도 있다. 예를 들어,불필요한 일들이 벌어지고(갑작스런 GPU전수조사? 등), 갑작스런 대규모 GPU 센터 개발 계획이 발표되고, 이로 인해 세금이 비과적으로 계획 투입되고, .. 이상한 방향으로 국가 첨단기술 연구개발 전략이 설정되고... 대규모 세금이 투입되지 않을 까라는 생각을 들게 만든다.

이 글에서 딥시크가 오픈소스 맞는지(거짓), 정말 중국 독자 기술로 개발했는지(거짓), 자국 GPU 사용해 개발했는 지(거짓. 기껏 추론 부분만 Google TPU같이 NPU 사용했을 가능성), 기술적 개선이 있었는지(성능 최적화 부분은 약간 인정), 정말 공개한 것은 무엇인지(모델만. 오픈웨이트) 등의 질문을 확인해 보았다. 

이 상황이면, GPT 학습 데이터를 증류해(카피해) 모델을 학습했다는 것이 더 신빙성 있어 보인다(가성비있게 실리콘밸리 테크 기술을 카피해 싸게 소프트웨어를 개발했다는 쪽이 더 맞는 듯. 물론 이것도 아무나 할 수 있는 건 아니다). 좀 더 시간이 있으면, 허깅페이스에 공개된 내용을 분석할 계획이다.
레퍼런스

2025년 3월 28일 금요일

인공지능 AI 에이전트 표준 프로토콜 MCP 분석 및 사용하기

이 글은 앤트로픽(Anthropic. 클로드 개발사)의 인공지능 AI 에이전트 표준 프로토콜 MCP(Model Context Protocol) 사용하는 방법을 간략히 설명한다. 

MCP는 애플리케이션이 LLM에 컨텍스트를 제공하는 방식을 표준화한 개방형 프로토콜이다. USB-C 포트처럼, 다양한 도구와 데이터를 LLM에 연결하는 통합된 인터페이스 역할을 한다. LLM 기반 에이전트와 워크플로우 구축을 지원하며, 유연한 통합, 데이터 보호, 공급업체 간 전환성을 제공한다.  
애트로픽 MCP 소개

이 글은 주로 다음 문서를 참고하였다.

아키텍처 구조
MCP는 클라이언트-서버 구조로 구성되며, 로컬 및 원격 데이터를 안전하게 연결할 수 있는 아키텍처를 따른다.
MCP 구조

  • MCP 호스트는 MCP 프로토콜을 통해 서비스에 액세스할 수 있는 애플리케이션이다. Claude 데스크톱 앱, AI 에이전트/CLI, 커서 IDE 등이 이에 해당하며, LLM(로컬 또는 원격)을 활용하여 다양한 작업을 수행한다.  
  • MCP 클라이언트는 MCP 서버와 연결하기 위해 호스트 애플리케이션과 통합된 클라이언트이다.  
  • MCP 서버는 MCP 프로토콜을 통해 특정 기능을 노출하는 응용 프로그램 또는 프로그램이다. 서버는 Docker 컨테이너, JVM, Node.js(UV/UVX) 프로세스에서 실행될 수 있으며, MCP 커뮤니티에서 제공하는 사전 구축된 서버를 활용할 수도 있다.  
  • 로컬 데이터 소스는 로컬 시스템에 존재하는 데이터베이스 또는 파일 시스템이다.  
  • 원격 서비스는 웹 API를 통해 액세스할 수 있는 GitHub, Brave Search와 같은 외부 리소스이다.

MCP를 이용하면, 서버, 클랑이언트, 로컬에 있는 파일, 폴더, 앱에 접근해 이를 LLM(Large Language Model)으로 컨트롤할 수 있다. 

MCP는 전형적인 클라이언드-서버 프로토콜(TCP/IP와 유사)을 따른다.

에이전트 오케스트레이션 
작업을 수행할 수 있는 올바른 에이전트를 전달한다. 예를 들어, 사용자가 텍스트를 스페인어로 번역을 요청하는 경우 사용자 요청을 완료하려면 요청을 스페인어 에이전트로 라우팅해야 한다. 다음은 OpenAI를 이용한 오케스트레이션을 보여준다.

## OpenAI Agent Usage: Agents as tools
##
from agents import Agent, Runner
import asyncio

spanish_agent = Agent(
    name="Spanish agent",
    instructions="You translate the user's message to Spanish",
)

french_agent = Agent(
    name="French agent",
    instructions="You translate the user's message to French",
)

orchestrator_agent = Agent(
    name="orchestrator_agent",
    instructions=(
        "You are a translation agent. You use the tools given to you to translate."
        "If asked for multiple traconvert this articlenslations, you call the relevant tools."
    ),
    tools=[
        spanish_agent.as_tool(
            tool_name="translate_to_spanish",
            tool_description="Translate the user's message to Spanish",
        ),
        french_agent.as_tool(
            too## OpenAI Agent SDKl_name="translate_to_french",
            tool_description="Translate the user's message to French",
        ),
    ],
)

async def main():
    result = await Runner.run(orchestrator_agent, input="Say 'Hello, how are you?' in Spanish.")
    print(result.final_output)

도구 검색 및 호출
MCP의 도구는 서버가 클라이언트 요청을 받아 실행 가능한 기능을 외부에 노출하고, LLM이 작업을 수행하는 데 활용할 수 있도록 설계된 요소이다. 도구는 클라이언트를 통해 검색 가능하며(`tools/list`), 작업 수행 요청은 `tools/call` 엔드포인트를 통해 전달된다. 

다음은 도구를 기술하는 메타데이터이다.
{
  name: string;          // Unique identifier for the tool
  description?: string;  // Human-readable description
  inputSchema: {         // JSON Schema for the tool's parameters
    type: "object",
    properties: { ... }  // Tool-specific parameters
  }
}
 
도구는 단순한 계산부터 복잡한 API 연동까지 다양할 수 있고, 고유한 이름과 설명을 통해 식별되고 사용된다.  

도구는 다음과 같이 정의, 호출된다. 
app = Server("example-server")

@app.list_tools()
async def list_tools() -> list[types.Tool]:
    return [
        types.Tool(
            name="calculate_sum",
            description="Add two numbers together",
            inputSchema={
                "type": "object",
                "properties": {
                    "a": {"type": "number"},
                    "b": {"type": "number"}
                },
                "required": ["a", "b"]
            }
        )
    ]

@app.call_tool()
async def call_tool(
    name: str,
    arguments: dict
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
    if name == "calculate_sum":
        a = arguments["a"]
        b = arguments["b"]
        result = a + b
        return [types.TextContent(type="text", text=str(result))]
    raise ValueError(f"Tool not found: {name}")

MCP 도구를 구현할 때는 다음과 같은 권장사항을 따르는 것이 좋다.  

도구는 명확한 이름과 설명을 갖추고, 매개변수는 JSON 스키마로 상세히 정의하며, 사용 예제를 포함해 모델이 이해하고 활용할 수 있도록 한다. 작업의 안정성과 신뢰성을 위해 오류 처리와 유효성 검사를 구현하고, 긴 작업은 진행 상황 보고를 포함하며, 원자성을 유지해야 한다.  
반환 값 구조는 문서화하고, 적절한 시간 초과와 리소스 사용 제한을 설정하며, 디버깅 및 모니터링을 위한 로깅 기능도 포함해야 한다.

파이썬 MCP Claude 기반 실습
파이썬 MCP Claude 기반 실습을 위해 다음 명령을 터미널에서 실행한다. 참고로, 미리 Claude 앱이 컴퓨터에 설치되어 있어야 한다.
git clone https://github.com/modelcontextprotocol/python-sdk.git
cd python-sdk
pip install mcp

vscode로 다음 server.py파일을 코딩한다. 
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Demo")

# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers"""
    return a + b

# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
    """Get a personalized greeting"""
    return f"Hello, {name}!"

다음과 같이 Claude 서버에 설치한다. 
mcp install server.py

MCP 검사기로 테스트한다.
mcp dev server.py

Ollama MCP-CLI 기반 실습
이 장은 Ollama, mcp-cli 도구를 이용해 MCP 서버에 등록된 도구를 호출하는 방법을 간략히 실습한다. 
터미널에서 다음 명령을 실행한다.

mcp서버 실헹에 필요한 UV를 설치한다.
pip install uv
uv sync --reinstall

다음과 같이 Ollama를 실행한다.
ollama run llama3.2

새로운 터미널 창에서 다음 명령을 실행한다.
uv run mcp-cli chat --server filesystem --provider ollama --model llama3.2

레퍼런스

오픈 마누스(manus) AI 에이전트 설치, 사용 및 구조 분석하기

한동안 회사 일 때문에 미뤄두었던, 딥시크(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일간 일정이 필요하다 말하고 있다. 

이에 대한 마누스 에이전트의 전체 큰 실행 구조는 다음과 같다.
  1. call main() # 메인 호출
  2. prompt = input() # 프롬프트 입력
  3. Manus.BaseAgent.run(prompt) # 프롬프트 입력에 따른 에이전트 도구들 실행
    1. update_memory() # 과거 입출력 저장
    2. max_steps 만큼 아래 루프 반복 # default max_steps = 20
    3. step_result = ReActAgent.step()  # 에이전트 도구 단계별 실행
      1. should_act = think() # 무슨 도구를 순서대로 호출할 지 LLM통해 정보얻음
        1. recent_messages = memory.messages[-3:]
        2. Manus.BrowserAgent.ToolCallAgent.think()  # 도구 선택 추론
          1. extract current browser page information  # 웹화면 정보 사용
          2. response = LLM.ask_tool()  # 추론 시 LLM 사용 
            1. check token limit  # 토큰 한계 체크
            2. response = ChatCompletion(params)  # LLM 호출
            3. return response[0].message  # 결과 리턴
          3. return response
      2. act()  # 에이전트 도구가 선택되었으니, 이를 실행
        1. tool_callls 에 담긴 도구 호출 명령에 따른 도구들 실행 루프 수행
          1. ToolCallAgent.execute_tool(command)  # 도구 실행
            1. args = json.loads(command) # 예. web_search. '7-day tour'
            2. ToolCollection.execute(args)  # 도구집합에서 해당도구실행
              1. BrowserUseTool.execute(args) # 쿼리검색 후 link 리턴
                1. _ensure_browser_initialized()  #브라우저 초기화
                2. links = WebSearch.execute(args.query) # 웹서치
                3. page = get_current_page()  # 페이지정보
                4. result = page.goto(url_to_navigate)  
                5. return ToolResult(args, result) # 검색결과 수집
            3. return observation(result)
          2. tool_msg = 도구 실행 명령 및 함수 정보
          3. memory.add_message(tool_msg)  # 메모리 업데이트
          4. results.append(result)
      3. return results  # 결과리턴
이를 좀 더 알기 쉽게 표현하면 다음같이 설명될 수 있다. 

1. 프로그램 시작: 메인 함수 호출
2. 프롬프트 입력: 사용자로부터 프롬프트 입력
3. 에이전트 실행: BaseAgent가 입력을 기반으로 동작 시작
4. 메모리 업데이트: 과거 입력/출력 내용을 memory에 저장
5. 에이전트 루프 실행 (기본 max_steps = 20)
    5.1. 단계 실행 (Step): ReActAgent가 현재 단계 처리 시작
    5.2. 다음 행동 판단 (Think)
        5.2.1. 최근 메시지 3개 불러오기
        5.2.2. LLM을 통해 다음 행동(도구 호출 여부 등) 추론
    5.3. Think: 도구 선택 판단
        5.3.1. BrowserAgent가 어떤 도구를 쓸지 결정
        5.3.2. 현재 브라우저 페이지 정보 추출
        5.3.3. 필요 시 LLM에 도구 사용 목적 질의 (ask_tool)
        5.3.4. 토큰 한계 체크
    5.4. LLM 호출 및 응답
        5.4.1. ChatCompletion으로 명령 생성
        5.4.2. 생성된 메시지 반환
    5.5. Act: 도구 실행 (Act)
        5.5.1. 도구 호출 명령(command)을 파싱 (예: JSON)
        반복 (모든 명령에 대한 도구 실행):
            5.5.2. 도구 실행 수행
                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. 도구 결과 처리
                5.5.3.1. ToolResult로 실행 결과 정리
                5.5.3.2. observation 형태로 결과 정리
    5.6. 메모리 및 결과 저장
        5.6.1. 도구 실행 정보 및 결과를 memory에 저장
        5.6.2. 결과 리스트에 추가
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."
think() 함수 동작 방식(일부)

현재 마누스 버전에서 프롬프트 템플릿은 다음처럼 정의되어 있다.
   
SYSTEM_PROMPT = (
    "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}"
)

NEXT_STEP_PROMPT = """
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 이 선택한 도구인 브라우저를 통해 정보를 얻고, 그 정보를 메모리에 업데이트하면서, 에이전트 도구를 실행해 가는 화면이다. 
에이전트 검색 결과
에이전트 도구의 리턴 결과(일부)

결론적으로 핵심만 요약해 보면, 다음과 같은 방식으로 에이전트가 실행되는 것을 확인 할 수 있다. 
  1. 사용자 프롬프트 입력
  2. LLM 이 프롬프트를 통해 어떤 에이전트 도구들을 실행할 지 결정. 도구 정보 반환
  3. 도구 호출 정보에 따라, 현재 등록된 도구들을 호출. 결과 파일은 workspace에 저장
  4. 도구 호출 결과는 메모리에 저장. 이는 LLM 이 도구를 호출할 때 참고 컨텐츠로 재사용
  5. 사용자 프롬프트 요구사항(목표)을 만족할 때까지 앞의 내용 반복
다음은 각 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 도 분석해볼 계획이다.

레퍼런스

2025년 3월 24일 월요일

기술로 감동을 주는 사람들

이 글은 기술로 감동을 주는 사람들에 대한 기록이다. 

나는 개발자이며 공학 오타쿠이며, 외적으로는 공학자, 연구자이다. 내가 내적, 외적으로 나를 분리해 보는 습관은 꾀 오래 된 것이다. 한국 연구 생태계에서는 이것이 Identify와 Brand를 지키는 몇 안되는 방법인 것 같다. 개인적으로 매우 많은 외적 시도를 해 보았고, 장단점을 알게 된 상황에서는 남은 인생은 전략적으로 살기로 했다. 

가끔, 내적 연구를 하다 보면, 정말 감탄하게 되는 분들을 만나게 된다. 내가 먹고 사는 분야인 BIM에서는 건축의 이스트만 교수님, VDC 마틴피셔 교수님, 토목의 밀러 교수님 같은 분들이다. 내가 공학의 내적 세계에서 우상으로 있는 분들은 이외 소프트웨어 공학, 컴퓨터 그래픽스 분야에도 우뚝 서 있다. 이 분들의 유산은 아낌없이 주는 나무처럼 기술적으로 나를 감동시킨다. 순수한 호기심과 열정으로 세상에 없던 것을 만들어 내는 것은 어느 평범한 누구와 같이 단기적 이익을 쫓는 정치하는 사람과는 비교할 수 없는 위치의 수준을 보게 된다. 

어차피 사람은 언젠가는 모두 죽게 되어 있다. 과학과 공학 분야에서 어떤 사람을 메모리얼하고 그리워하는 것은 그 분의 유산이 감동적이었기 때문이라 생각한다.
레퍼런스

2025년 3월 1일 토요일

최근 포인트 클라우드 세그먼테이션 동향

이 글은 최근 포인트 클라우드 세그먼테이션 동향에 관한 연구를 간략히 조사한것이다.


레퍼런스

2025년 2월 15일 토요일

대형언어모델 Gemma2 파인튜닝하기

대형 언어 모델(LLM)인 Gemma2-2B를 미세 조정하면 특정 작업에 대한 성능을 크게 향상시킬 수 있다. 이 가이드는 Google Colab을 활용하여 Gemma2-2B를 미세 조정하는 과정을 단계별로 설명한다.  

사전 준비 사항  
미세 조정을 진행하기 위해 다음과 같은 준비가 필요하다.  
- Google Colab(https://colab.research.google.com/) 계정이 있어야 한다. 혹은, NVIDIA GPU 환경(24GB 이상)이 구축된 컴퓨터가 있어야 한다.
- Python 및 머신러닝 기초 개념을 이해하고 있어야 한다.  

1단계: 환경 설정  
1. Google Colab 접속  
   - Google Colab(https://colab.research.google.com/)에 접속하여 새 노트북을 생성한다.  
2. GPU 설정  
   - 상단 메뉴에서 `편집(Edit) > 노트북 설정(Notebook settings)`으로 이동하여 하드웨어 가속기를 `GPU`로 변경한다.  
3. 필요한 패키지 설치  
   - 아래 명령어를 실행하여 필수 라이브러리를 설치한다.  
   !pip install transformers datasets accelerate

2단계: Gemma2-2B 모델 불러오기  
Hugging Face의 `transformers` 라이브러리를 사용하여 사전 학습된 Gemma2-2B 모델을 로드한다.  
from transformers import AutoModelForCausalLM, AutoTokenizer
model_name = "google/gemma2-2b"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)

3단계: 데이터셋 준비  
미세 조정을 위해 작업에 맞는 데이터셋이 필요하다. Hugging Face의 `datasets` 라이브러리를 사용하여 데이터를 로드하고 토큰화할 수 있다.  
from datasets import load_dataset
# 'your_dataset'을 원하는 데이터셋 이름 또는 경로로 변경해야 한다. 데이터셋 예시: lavita/ChatDoctor-HealthCareMagic-100k · Datasets at Hugging Face
dataset = load_dataset('your_dataset')
# 토큰화 함수 정의
def tokenize_function(examples):
    return tokenizer(examples['text'], padding="max_length", truncation=True)
# 데이터셋 토큰화 적용
tokenized_dataset = dataset.map(tokenize_function, batched=True)

4단계: 모델 미세 조정  
데이터셋을 준비한 후, 아래 코드로 모델을 미세 조정할 수 있다.  
from transformers import TrainingArguments, Trainer
training_args = TrainingArguments(
    output_dir="./results",
    evaluation_strategy="epoch",
    learning_rate=2e-5,
    per_device_train_batch_size=4,
    per_device_eval_batch_size=4,
    num_train_epochs=3,
    weight_decay=0.01,
)
trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset["train"],
    eval_dataset=tokenized_dataset["validation"],
)
trainer.train()

5단계: 미세 조정된 모델 저장  
학습이 완료된 모델을 저장하여 향후 사용할 수 있도록 한다.  
model.save_pretrained("./fine_tuned_gemma2_2b")
tokenizer.save_pretrained("./fine_tuned_gemma2_2b")

결론  
이 가이드를 따르면 Google Colab에서 Gemma2-2B 모델을 미세 조정하여 특정 작업에 최적화된 모델을 만들 수 있다. 미세 조정을 통해 모델의 성능을 향상시키고 특정 도메인 문제를 해결하는 데 도움을 줄 수 있다.  

참고 
대형 모델의 미세 조정은 많은 GPU 리소스(최소 24GB 이상)를 필요로 한다. Google Colab Pro 또는 TPU를 활용하면 더 원활한 학습이 가능하다. 

2025년 1월 26일 일요일

생성AI, LLM, AI Agent와 그래픽, 디자인, 미디어아트 관련 자료 소개

이 글은 생성AI, LLM, AI Agent와 그래픽, 디자인, 미디어아트에 관한 자료를 정리한 것이다. 관련 도구 및 예제는 다음 링크에 자세히 설명하였으니 참고한다.
프롬프트에서 생성된 그래픽스 예시

Blender LLM 기반 그래픽 모델링 관련 자료
LLM, ollama, Blender python library 등을 이용하면, 프롬프트를 입력해, 3차원 모델을 자동 생성할 수 있다. 다음은 관련 예시를 보여준다. 
Prompt: Create 100 cubes. The y position of each cube follows the cosine function along the x-axis with random color.

이를 이용해 다음과 같은 GPT 에이전트가 구현된다. 

상세한 동작 메커니즘은 다음 링크를 참고한다.

LLM과 컴퓨터 그래픽스
앞에서 사용한 방법과 동일하게, OpenGL, processing.org 등 3차원 가시화 도구를 이용해 실시간으로 프롬프트를 통해 컴퓨터 그래픽스 장면을 생성할 수 있다. 다음은 프롬프트를 통해 생성된 그래픽스를 보여준다. 

데이터 기반 그래픽스 렌더링 예시

생성된 그래픽스 코드는 다음과 같다. 
from p5 import *
import pandas as pd

# Load the dataset
data = pd.read_csv('input.csv')

def setup():
  size(720, 400)
  no_stroke()

def draw_cone(size_x, size_y, position):
  with push_matrix():
    translate(*position)
    cone(size_x, size_y)

def draw():
  background(20, 100, 24)
  lights()
  rotate_x(frame_count * 0.01)
  # rotate_y(frame_count * 0.01)
  blinn_phong_material()

  interval = 200
  for i, row in data.iterrows():
    x = (i % 3) * interval - interval
    y = 0
    z = (i // 3) * interval - interval
    draw_cone(row['energy'], row['temperature'], (x, y, z))

  locX = mouse_x - width/2
  locY = mouse_y - height/2
  light_specular(0, 0, 255)
  point_light(360, 360*1.5, 360, locX, locY, 400)

if __name__ == '__main__':
  run(mode='P3D')

LLM과 사운드 엔지니어링
동일한 원리로 사운드를 개발할 수 있다. 다음은 LLM을 통해 생성된 사운드 코드를 실행한 결과이다. 
사운드 생성 예

생성된 코드는 다음과 같다.
from psonic import *
import time
from threading import Thread, Condition

set_server_parameter_from_log("127.0.0.1")

def play_mozart(condition):
  while True:
    with condition:
      condition.notifyAll() # Message to threads      

    beat = 0.33

    melody = [
      E5, E5, F5, G5, G5, F5, E5, D5, C5, C5, D5, E5, E5, D5, D5,
      E5, E5, F5, G5, G5, F5, E5, D5, C5, C5, D5, E5, D5, C5, C5
    ]

    # Drum beat pattern
    def play_beat():
      sample(DRUM_HEAVY_KICK, amp=1.5)  # Strong kick drum
      sample(ELEC_CHIME, amp=1.2)  # Electric guitar sample
      sample(BD_ZOME, amp=1.5)
      sleep(beat / 2)

      sample(DRUM_CYMBAL_CLOSED, amp=1.2)  # Closed cymbal
      sample(ELEC_CHIME, amp=0.6)  
      sample(BD_ZOME, amp=0.6)
      sleep(beat / 2)

      sample(DRUM_SNARE_HARD, amp=1.3)  # Strong snare
      sample(ELEC_CHIME, amp=1.2)   
      sample(BD_ZOME, amp=1.3)
      sleep(beat / 2)
      
      sample(DRUM_CYMBAL_CLOSED, amp=1.2)
      sample(ELEC_CHIME, amp=0.6)  
      sample(BD_ZOME, amp=0.6)
      sleep(beat / 2)

    # Melody, Beat Channel Play 
    for note in melody:
      play(note, amp=1.0) # , release=0.2)  # Melody
      play_beat()  # Beat Pattern


condition = Condition()
mozart_thread = Thread(name='producer', target=play_mozart, args=(condition,))
mozart_thread.start()

input("Press Enter to continue...")

LLM과 피지컬 컴퓨팅
피지컬 컴퓨팅에 많이 사용되는 아두이노 등을 이용해, 프롬프트로 명령을 주면, 임베딩 컴퓨터가 명령을 실행할 수 있는 코드를 LLM이 생성해, 모터, 조명과 같은 액추에이터를 동작시킬 수 있다. 다음은 그 예를 보여준다. 

참고로, 아두이노의 경우, .ino 코드 파일을 실시간으로 컴파일해 아두이노보드로 전송하는 cli 도구가 설치 시 포함되어 있다. 이를 이용해, 컴파일 에이전트를 구현할 수 있다. 
Arduino CLI 도구

Ollama와 오픈소스 LLM 이용한 건축 이미지 프롬프트 역공학
말이 어렵지만, 사실 멀티모달을 지원하는 llama3.2-vision과 같은 모델이 저렴하게 공개되고 있는 상황이라, 이를 이용하면 쉽게 프롬프트 키워드 역공학해서, 얻은 프롬프트로 이미지를 생성할 수 있다. 

올라마(ollama) 설치 후 이미지를 준비하고, 다음을 실행한다.
ollama run llama3.2-vision

그리고, image 명령을 이용해 해당 파일 경로를 입력하고 설명하라 한다. 이후, 이 설명을 미드저니 프롬프트 키워드로 변경해 달라 하고, 텍스트-이미지 서비스에 역공학된 프롬프트를 입력하면 된다. 다음은 그 결과이다. 
건축가 자하하디드 스타일 건축물 사진 역공학 후 생성한 이미지 결과(참고)
생성된 영상(KREA)

레퍼런스
이 주제와 관련된 레퍼런스는 다음과 같다.

AI 에이전트
그래픽 모델링
사운드 엔지니어링
피지컬 컴퓨팅