DEV Community

matias yoon
matias yoon

Posted on

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

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

터미널에서 AI 코드 보조 도구를 직접 구축하는 실전 가이드

1. CLI AI 에이전트 생태계

현재 CLI AI 에이전트 시장은 다음과 같은 주요 플랫폼들로 구성되어 있습니다:

Aider: GitHub Copilot과 유사하지만 오픈소스 버전. aider --help 명령으로 간단히 시작 가능합니다.

Continue.dev: VSCode 확장 프로그램이지만 터미널에서 사용할 수 있는 라이브러리도 제공. continue 명령을 통해 실행합니다.

OpenCode: 오픈소스 코드 생성 도구. opencode --help로 도움말을 확인할 수 있습니다.

커스텀 스크립트: 가장 유연한 접근 방식. Python 스크립트를 직접 작성하여 원하는 기능을 구현.

# 예시: 간단한 Aider 설치
pip install aider
# 사용 예시
aider --help
Enter fullscreen mode Exit fullscreen mode

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

로컬 LLM 서버를 설정하여 비용과 보안 문제를 해결합니다:

# LM Studio 설치 (macOS)
brew install lm-studio

# 또는 Ollama 사용
curl -fsSL https://ollama.com/install.sh | sh

# Ollama로 모델 다운로드
ollama pull mistral:7b

# 로컬 서버 시작
ollama serve
Enter fullscreen mode Exit fullscreen mode

API 엔드포인트 설정:

# config.yaml
model: mistral:7b
port: 11434
host: localhost
timeout: 30
Enter fullscreen mode Exit fullscreen mode

3. Python CLI 에이전트 구축

기본적인 Python CLI 에이전트를 구현합니다:

# ai_agent.py
import openai
import json
import sys
import os
from pathlib import Path

class TerminalAgent:
    def __init__(self, model="mistral:7b"):
        self.model = model
        self.client = openai.OpenAI(
            base_url="http://localhost:11434/v1",
            api_key="ollama"
        )

    def call_function(self, function_name, args):
        """함수 호출을 처리합니다"""
        if function_name == "create_file":
            return self.create_file(args['path'], args.get('content', ''))
        elif function_name == "run_command":
            return self.run_command(args['command'])
        elif function_name == "git_add":
            return self.git_add(args['files'])

    def create_file(self, path, content):
        """파일 생성"""
        path = Path(path)
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(content)
        return f"Created {path}"

    def run_command(self, command):
        """명령어 실행"""
        import subprocess
        result = subprocess.run(
            command, shell=True, capture_output=True, text=True
        )
        return {
            "stdout": result.stdout,
            "stderr": result.stderr,
            "returncode": result.returncode
        }

    def git_add(self, files):
        """Git 추가"""
        import subprocess
        for file in files:
            subprocess.run(["git", "add", file])
        return f"Added {len(files)} files to git"

# 메인 실행 로직
if __name__ == "__main__":
    agent = TerminalAgent()

    # 예시: 함수 호출
    result = agent.call_function("create_file", {
        "path": "test.py",
        "content": "print('Hello, World!')"
    })
    print(result)
Enter fullscreen mode Exit fullscreen mode

4. tmux와 통합

터미널 멀티플렉서와 통합하여 작업 흐름 개선:

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

# 세션에 명령어 전달
tmux send-keys -t ai_agent "python ai_agent.py --mode chat" Enter

# 세션에 파일 추가
tmux send-keys -t ai_agent "vim main.py" Enter
Enter fullscreen mode Exit fullscreen mode

Python 스크립트에서 tmux 통합:

# tmux_integration.py
import subprocess
import os

class TmuxAgent:
    def __init__(self, session_name="ai_session"):
        self.session_name = session_name
        self._ensure_session()

    def _ensure_session(self):
        """세션 존재 여부 확인"""
        result = subprocess.run(
            ["tmux", "has-session", "-t", self.session_name],
            capture_output=True
        )
        if result.returncode != 0:
            subprocess.run([
                "tmux", "new-session", "-s", self.session_name, "-d"
            ])

    def send_to_session(self, command, pane=0):
        """세션에 명령어 전송"""
        subprocess.run([
            "tmux", "send-keys", "-t", f"{self.session_name}:{pane}", 
            command, "Enter"
        ])

    def create_new_pane(self):
        """새로운 파인 생성"""
        subprocess.run([
            "tmux", "split-window", "-h", "-t", self.session_name
        ])
Enter fullscreen mode Exit fullscreen mode

5. 커스텀 도구 개발

자신만의 코드 검색 및 Git 도구 개발:

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

class CodeSearchTool:
    def __init__(self, project_root):
        self.project_root = Path(project_root)

    def search_patterns(self, patterns, file_extensions=None):
        """코드 패턴 검색"""
        results = []
        if file_extensions is None:
            file_extensions = ['.py', '.js', '.ts', '.java']

        for root, dirs, files in os.walk(self.project_root):
            for file in files:
                if any(file.endswith(ext) for ext in file_extensions):
                    file_path = Path(root) / file
                    try:
                        with open(file_path, 'r', encoding='utf-8') as f:
                            content = f.read()
                            for pattern in patterns:
                                matches = re.finditer(pattern, content)
                                for match in matches:
                                    results.append({
                                        'file': str(file_path),
                                        'line': content[:match.start()].count('\n') + 1,
                                        'match': match.group()
                                    })
                    except Exception as e:
                        continue
        return results

class GitTool:
    def __init__(self):
        self.repo_path = Path(".")

    def git_status(self):
        """Git 상태 조회"""
        result = subprocess.run(
            ["git", "status", "--porcelain"],
            capture_output=True, text=True
        )
        return result.stdout.strip().split('\n') if result.stdout else []

    def git_diff(self, file_path):
        """Git 차이점 조회"""
        result = subprocess.run(
            ["git", "diff", file_path],
            capture_output=True, text=True
        )
        return result.stdout

# 사용 예제
search_tool = CodeSearchTool(".")
results = search_tool.search_patterns([r"def.*\(.*\)"])
print("검색 결과:", results)
Enter fullscreen mode Exit fullscreen mode

6. 컨텍스트 윈도우 관리

대규모 코드베이스를 위한 컨텍스트 윈도우 관리:

# context_manager.py
import os
import json
from pathlib import Path

class ContextManager:
    def __init__(self, max_tokens=4096, context_limit=10000):
        self.max_tokens = max_tokens
        self.context_limit = context_limit
        self.context_cache = {}

    def get_context(self, file_path, lines_before=5, lines_after=5):
        """지정된 파일의 컨텍스트 얻기"""
        file_path = Path(file_path)
        if not file_path.exists():
            return ""

        with open(file_path, 'r') as f:
            lines = f.readlines()

        # 현재 커서 위치 찾기 (간단한 예시)
        start_line = max(0, 0 - lines_before)
        end_line = min(len(lines), 0 + lines_after)

        context = "".join(lines[start_line:end_line])
        return context

    def build_prompt(self, files, additional_context=""):
        """프롬프트 빌드"""
        prompt = additional_context + "\n\n"

        for file_path in files:
            file_context = self.get_context(file_path)
            prompt += f"File: {file_path}\n{file_context}\n\n"

        return prompt[:self.context_limit]
Enter fullscreen mode Exit fullscreen mode

7. 비용/속도 최적화

로컬 vs API 모델의 비용과 성능 비교:


python
# optimization.py
import time
import subprocess
import json

class ModelOptimizer:
    def __init__(self):
        self.local_models = {
            "mistral": {"size": "7b", "speed": "fast", "cost": "free"},
            "llama": {"size": "7b", "speed": "medium", "cost": "free"},
            "phi": {"size": "

---

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

Top comments (0)