DEV Community

matias yoon
matias yoon

Posted on

터미널 AI 에이전트 구축 (v37)

터미널 AI 에이전트 구축 (v37)

터미널에서 AI 에이전트를 구축하는 것은 개발자에게 매우 실용적인 도구를 제공합니다. 이 가이드는 로컬 LLM을 활용한 CLI AI 에이전트를 구축하고, 실전 워크플로우에 적용하는 방법을 단계별로 설명합니다.

1. CLI AI 에이전트 생태계

현재 CLI AI 에이전트는 여러 형태로 존재합니다:

Aider: GitHub에서 개발된 코드 생성 도구로, 실제 파일에 직접 수정을 적용하는 기능이 강점입니다.

Continue.dev: VSCode 확장 프로그램이지만, 터미널에서도 사용 가능한 커스터마이징 가능한 에이전트입니다.

OpenCode: 직접 구축한 AI 에이전트로, 빠르고 간단한 커스터마이징이 가능합니다.

커스텀 스크립트: 가장 유연한 접근 방식으로, 특정 워크플로우에 맞춘 로직을 직접 구현할 수 있습니다.

2. 로컬 LLM API 엔드포인트 설정

먼저 로컬 LLM 서버를 실행해야 합니다. 이 예제에서는 LLaMA.cpp를 사용하겠습니다:

# 1. LLaMA.cpp 설치
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make

# 2. 모델 다운로드 및 변환
wget https://huggingface.co/TheBloke/Mistral-7B-v0.1-GGUF/resolve/main/mistral-7b-v0.1.Q4_K_M.gguf

# 3. 로컬 서버 시작
./server -m mistral-7b-v0.1.Q4_K_M.gguf -c 2048 --host 127.0.0.1 --port 1234
Enter fullscreen mode Exit fullscreen mode

API 엔드포인트를 테스트하기 위해 curl 명령어를 사용합니다:

curl http://localhost:1234/v1/completions \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Write a Python function that calculates fibonacci numbers",
    "max_tokens": 200,
    "temperature": 0.7
  }'
Enter fullscreen mode Exit fullscreen mode

3. 간단한 Python CLI 에이전트 만들기

다음은 함수 호출 기능을 포함한 기초적인 Python CLI 에이전트입니다:

# agent.py
import requests
import json
import subprocess
import sys

class TerminalAgent:
    def __init__(self, api_url="http://localhost:1234/v1/completions"):
        self.api_url = api_url

    def call_model(self, prompt, max_tokens=300):
        """LLM API 호출"""
        headers = {"Content-Type": "application/json"}
        data = {
            "prompt": prompt,
            "max_tokens": max_tokens,
            "temperature": 0.3
        }

        response = requests.post(self.api_url, headers=headers, data=json.dumps(data))
        return response.json()['choices'][0]['text'].strip()

    def execute_command(self, command):
        """명령어 실행 및 결과 반환"""
        try:
            result = subprocess.run(
                command, 
                shell=True, 
                capture_output=True, 
                text=True, 
                check=True
            )
            return result.stdout
        except subprocess.CalledProcessError as e:
            return f"Error: {e.stderr}"

    def run(self, task):
        """주어진 작업을 실행"""
        print(f"작업 요청: {task}")

        # 작업 분석 및 분할
        analysis_prompt = f"""
        다음 작업을 분석하고 필요한 단계를 나열해주세요:
        {task}

        단계별로 JSON 형식으로 응답해주세요:
        {{
            "steps": ["step1", "step2", ...],
            "summary": "작업 요약"
        }}
        """

        analysis = self.call_model(analysis_prompt, 150)
        print(f"분석 결과: {analysis}")

        # 각 단계별 실행
        for i, step in enumerate(json.loads(analysis).get("steps", [])):
            print(f"\n단계 {i+1}: {step}")
            result = self.execute_command(step)
            print(f"결과: {result}")

if __name__ == "__main__":
    agent = TerminalAgent()
    task = "Python으로 주어진 디렉토리 내 모든 .py 파일을 찾아서 'print('Hello World')'를 추가해주세요"
    agent.run(task)
Enter fullscreen mode Exit fullscreen mode

실행 방법:

python agent.py
Enter fullscreen mode Exit fullscreen mode

4. tmux와 통합

tmux를 사용하여 에이전트가 작업을 수행하는 동안 터미널 세션을 유지하고, 다른 작업을 병행할 수 있습니다:

# tmux 세션 생성
tmux new-session -s ai_agent -d

# 에이전트 실행
tmux send-keys -t ai_agent "python agent.py" Enter

# 세션에 연결
tmux attach -t ai_agent
Enter fullscreen mode Exit fullscreen mode

다음은 tmux 세션을 관리하는 스크립트입니다:

# tmux_helper.py
import subprocess
import os

class TmuxHelper:
    def __init__(self, session_name="ai_agent"):
        self.session_name = session_name

    def create_session(self):
        """새 tmux 세션 생성"""
        cmd = f"tmux new-session -s {self.session_name} -d"
        subprocess.run(cmd, shell=True, check=True)

    def send_command(self, command):
        """세션에 명령어 전송"""
        cmd = f"tmux send-keys -t {self.session_name} '{command}' Enter"
        subprocess.run(cmd, shell=True, check=True)

    def attach(self):
        """세션 연결"""
        cmd = f"tmux attach -t {self.session_name}"
        subprocess.run(cmd, shell=True, check=True)

    def kill_session(self):
        """세션 종료"""
        cmd = f"tmux kill-session -t {self.session_name}"
        subprocess.run(cmd, shell=True, check=True)

# 사용 예시
if __name__ == "__main__":
    helper = TmuxHelper("my_ai")
    helper.create_session()
    helper.send_command("python agent.py")
Enter fullscreen mode Exit fullscreen mode

5. 커스텀 도구 개발

다음은 코드 검색, git 연동, 파일 작업을 위한 커스텀 도구들입니다:

# tools.py
import os
import subprocess
import json
import re

class CodeSearchTool:
    @staticmethod
    def find_files(directory, extension=".py"):
        """지정된 확장자 파일 찾기"""
        files = []
        for root, dirs, filenames in os.walk(directory):
            for filename in filenames:
                if filename.endswith(extension):
                    files.append(os.path.join(root, filename))
        return files

    @staticmethod
    def grep_in_files(pattern, files):
        """파일 내에서 패턴 검색"""
        results = {}
        for file_path in files:
            try:
                with open(file_path, 'r') as f:
                    content = f.read()
                    matches = re.findall(pattern, content)
                    if matches:
                        results[file_path] = matches
            except Exception as e:
                print(f"Error reading {file_path}: {e}")
        return results

class GitTool:
    @staticmethod
    def get_git_status():
        """Git 상태 확인"""
        result = subprocess.run(["git", "status", "--porcelain"], 
                              capture_output=True, text=True)
        return result.stdout.strip()

    @staticmethod
    def git_diff():
        """Git diff 출력"""
        result = subprocess.run(["git", "diff"], 
                              capture_output=True, text=True)
        return result.stdout

class FileOperationTool:
    @staticmethod
    def create_directory(path):
        """디렉토리 생성"""
        os.makedirs(path, exist_ok=True)
        return f"Directory {path} created"

    @staticmethod
    def read_file(path):
        """파일 읽기"""
        try:
            with open(path, 'r') as f:
                return f.read()
        except Exception as e:
            return f"Error reading {path}: {e}"

    @staticmethod
    def write_file(path, content):
        """파일 쓰기"""
        try:
            with open(path, 'w') as f:
                f.write(content)
            return f"File {path} written successfully"
        except Exception as e:
            return f"Error writing {path}: {e}"

# 사용 예시
if __name__ == "__main__":
    search_tool = CodeSearchTool()
    files = search_tool.find_files(".", ".py")
    print(f"Found {len(files)} Python files")

    git_tool = GitTool()
    print("Git status:", git_tool.get_git_status())
Enter fullscreen mode Exit fullscreen mode

6. 컨텍스트 윈도우 관리

대규모 코드베이스에서 성능을 최적화하기 위해 컨텍스트 윈도우를 관리해야 합니다:




---

📥 **Get the full guide on Gumroad**: https://gumroad.com/l/auto ($5)
Enter fullscreen mode Exit fullscreen mode

Top comments (0)