DEV Community

matias yoon
matias yoon

Posted on

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

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

터미널에서 직접 작동하는 AI 에이전트는 코드 개발의 핵심 도구로 자리 잡고 있습니다. 이 가이드에서는 실용적인 터미널 AI 에이전트 구축 방법을 다룹니다.

1. CLI AI 에이전트 생태계

현재 CLI AI 에이전트는 다음과 같은 주요 플랫폼으로 분류됩니다:

Aider

# 설치 및 기본 사용
pip install aider
aider --help
Enter fullscreen mode Exit fullscreen mode

Continue.dev

# VS Code 확장으로 설치 (터미널에서 사용 가능)
npm install -g continue
Enter fullscreen mode Exit fullscreen mode

OpenCode

# 직접 구축 가능한 오픈소스
git clone https://github.com/open-code/open-code
cd open-code && pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

커스텀 스크립트

가장 유연한 접근법으로, 자신의 필요에 맞춘 에이전트를 직접 개발할 수 있습니다.

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

로컬 LLM을 터미널에서 사용하기 위해 API 서버를 설정합니다:

# LM Studio 설치
git clone https://github.com/lm-sstudio/lm-studio.git
cd lm-studio
npm install
npm start

# 또는 llama.cpp를 통한 로컬 서버
git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
make
./server -m models/llama-2-7b-chat.Q4_K_M.gguf -c 2048 --host 127.0.0.1 --port 8080
Enter fullscreen mode Exit fullscreen mode
# API 엔드포인트 테스트
import requests
import json

def test_local_llm(prompt):
    response = requests.post(
        "http://127.0.0.1:8080/completion",
        json={
            "prompt": prompt,
            "n_predict": 100,
            "temperature": 0.7
        }
    )
    return response.json()['content']

# 테스트
result = test_local_llm("Python으로 factorial 함수를 구현하세요")
print(result)
Enter fullscreen mode Exit fullscreen mode

3. 간단한 Python CLI 에이전트 구축

함수 호출 기능을 갖춘 기초적인 CLI 에이전트를 구축합니다:

# aider_agent.py
import json
import subprocess
import requests
from typing import Dict, List

class TerminalAider:
    def __init__(self, api_url="http://127.0.0.1:8080"):
        self.api_url = api_url
        self.tools = {
            'run_command': self.run_command,
            'read_file': self.read_file,
            'write_file': self.write_file,
            'search_code': self.search_code,
        }

    def run_command(self, command: str) -> str:
        """명령어 실행"""
        try:
            result = subprocess.run(
                command, 
                shell=True, 
                capture_output=True, 
                text=True
            )
            return f"Output: {result.stdout}\nError: {result.stderr}"
        except Exception as e:
            return f"Error: {str(e)}"

    def read_file(self, filename: str) -> str:
        """파일 읽기"""
        try:
            with open(filename, 'r') as f:
                return f.read()
        except Exception as e:
            return f"Error reading file: {str(e)}"

    def write_file(self, filename: str, content: str) -> str:
        """파일 쓰기"""
        try:
            with open(filename, 'w') as f:
                f.write(content)
            return f"File {filename} written successfully"
        except Exception as e:
            return f"Error writing file: {str(e)}"

    def search_code(self, pattern: str) -> str:
        """코드 검색"""
        try:
            cmd = f"grep -r '{pattern}' . --exclude-dir=.git"
            result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
            return result.stdout
        except Exception as e:
            return f"Search error: {str(e)}"

    def call_function(self, function_name: str, args: Dict) -> str:
        """함수 호출"""
        if function_name in self.tools:
            return self.tools[function_name](**args)
        return f"Function {function_name} not found"

    def process_request(self, user_prompt: str, functions: List[Dict]) -> str:
        """요청 처리"""
        # LLM API 호출
        prompt = f"""
        User: {user_prompt}
        Available functions: {json.dumps(functions, indent=2)}
        Please respond with JSON format:
        {{
            "function": "function_name",
            "arguments": {{}}
        }}
        """

        response = requests.post(
            f"{self.api_url}/completion",
            json={
                "prompt": prompt,
                "n_predict": 200,
                "temperature": 0.3
            }
        )

        try:
            result = json.loads(response.json()['content'])
            return self.call_function(result['function'], result['arguments'])
        except:
            return "Failed to parse response"

# 사용법
agent = TerminalAider()
functions = [
    {"name": "run_command", "description": "명령어 실행"},
    {"name": "read_file", "description": "파일 읽기"},
    {"name": "write_file", "description": "파일 쓰기"},
    {"name": "search_code", "description": "코드 검색"}
]

# 예시 사용
result = agent.process_request(
    "README.md 파일을 읽고, Python 코드 예제를 추가해줘",
    functions
)
print(result)
Enter fullscreen mode Exit fullscreen mode

4. tmux와 통합

tmux 세션과 통합하여 더 효율적인 개발 환경을 제공합니다:

# tmux 설치
sudo apt install tmux  # Ubuntu/Debian
brew install tmux      # macOS

# 세션 생성
tmux new-session -s ai-dev -d
tmux attach -t ai-dev

# 세션 내에서 에이전트 실행
python aider_agent.py
Enter fullscreen mode Exit fullscreen mode
# tmux 통합 스크립트
import subprocess
import os

class TmuxIntegration:
    def __init__(self, session_name="ai-dev"):
        self.session_name = session_name

    def create_session(self):
        """새 tmux 세션 생성"""
        subprocess.run([
            'tmux', 'new-session', '-s', self.session_name, '-d'
        ])

    def send_command(self, command: str):
        """세션에 명령어 전송"""
        subprocess.run([
            'tmux', 'send-keys', '-t', self.session_name, command, 'Enter'
        ])

    def attach(self):
        """세션 연결"""
        subprocess.run(['tmux', 'attach', '-t', self.session_name])

# 사용 예시
tmux_integrator = TmuxIntegration("ai-dev")
tmux_integrator.create_session()
tmux_integrator.send_command("python aider_agent.py")
Enter fullscreen mode Exit fullscreen mode

5. 커스텀 도구 개발

다양한 개발 도구를 통합합니다:

# custom_tools.py
import subprocess
import os
from pathlib import Path

class CodeTools:
    @staticmethod
    def git_status():
        """Git 상태 확인"""
        try:
            result = subprocess.run(
                ['git', 'status', '--porcelain'],
                capture_output=True, 
                text=True
            )
            return result.stdout
        except:
            return "Not in a git repository"

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

    @staticmethod
    def file_tree(directory=".", max_depth=3):
        """디렉토리 트리 출력"""
        tree = []
        for root, dirs, files in os.walk(directory):
            level = root.replace(directory, '').count(os.sep)
            if level > max_depth:
                continue
            indent = ' ' * 2 * level
            tree.append(f"{indent}{os.path.basename(root)}/")
            subindent = ' ' * 2 * (level + 1)
            for file in files:
                tree.append(f"{subindent}{file}")
        return '\n'.join(tree)

    @staticmethod
    def find_python_files():
        """Python 파일 찾기"""
        try:
            result = subprocess.run(
                ['find', '.', '-name', '*.py', '-not', '-path', '*/.git/*'],
                capture_output=True,
                text=True
            )
            return result.stdout
        except:
            return "Error finding Python files"

# 통합 예시
tools = CodeTools()
print("Git Status:")
print(tools.git_status())
print("\nDirectory Tree:")
print(tools.file_tree())
Enter fullscreen mode Exit fullscreen mode

6. 컨텍스트 윈도우


📥 Get the full guide on Gumroad: https://gumroad.com/l/auto ($5)

Top comments (0)