DEV Community

matias yoon
matias yoon

Posted on

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

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

터미널에서 작동하는 AI 에이전트는 현대 개발 워크플로우에 필수적인 도구입니다. 이 가이드는 개발자가 로컬 환경에서 효율적으로 작동하는 AI 에이전트를 구축하고 활용하는 방법을 실질적인 코드와 명령어로 설명합니다.

1. CLI AI 에이전트 생태계

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

Aider: GitHub Copilot을 기반으로 한 코드 생성 도구

pip install aider
aider --help
Enter fullscreen mode Exit fullscreen mode

Continue.dev: VS Code 확장에서 파생된 터미널 기반 에이전트

npm install -g continue
continue --help
Enter fullscreen mode Exit fullscreen mode

OpenCode: 오픈소스 CLI 에이전트 프레임워크

git clone https://github.com/open-code/open-code.git
cd open-code && pip install -r requirements.txt
Enter fullscreen mode Exit fullscreen mode

사용자 정의 스크립트: 최소한의 커스터마이징이 필요한 경우

#!/usr/bin/env python3
import subprocess
import sys

def run_command(cmd):
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    return result.stdout

if __name__ == "__main__":
    if len(sys.argv) > 1:
        output = run_command(' '.join(sys.argv[1:]))
        print(output)
Enter fullscreen mode Exit fullscreen mode

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

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

# Ollama 설치 (가장 간단한 방법)
curl -fsSL https://ollama.com/install.sh | sh

# 모델 다운로드
ollama pull llama3.2

# API 서버 실행
ollama serve
Enter fullscreen mode Exit fullscreen mode

API 엔드포인트 확인:

curl http://localhost:11434/api/tags
Enter fullscreen mode Exit fullscreen mode

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

함수 호출 기능을 포함한 기본 CLI 에이전트를 구축합니다:

#!/usr/bin/env python3
# ai_agent.py

import requests
import json
import subprocess
import sys
from typing import Dict, List, Any

class TerminalAI:
    def __init__(self, api_url="http://localhost:11434/api/generate"):
        self.api_url = api_url
        self.conversation_history = []

    def call_llm(self, prompt: str, system_prompt: str = "") -> str:
        """LLM 호출 함수"""
        messages = [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": prompt}
        ]

        payload = {
            "model": "llama3.2",
            "messages": messages,
            "stream": False
        }

        response = requests.post(
            self.api_url,
            json=payload,
            timeout=30
        )

        if response.status_code == 200:
            result = response.json()
            return result.get("response", "")
        else:
            raise Exception(f"LLM API Error: {response.status_code}")

    def code_review(self, code: str) -> str:
        """코드 리뷰 수행"""
        prompt = f"""
        다음 코드를 리뷰해 주세요:
        ```
{% endraw %}
python
        {code}
{% raw %}

        ```
        품질 향상을 위한 개선 제안을 제공해 주세요.
        """
        return self.call_llm(prompt, "You are a senior Python developer who reviews code quality")

    def run_command(self, command: str) -> str:
        """터미널 명령어 실행"""
        try:
            result = subprocess.run(
                command, 
                shell=True, 
                capture_output=True, 
                text=True,
                timeout=30
            )
            return result.stdout + result.stderr
        except subprocess.TimeoutExpired:
            return "Command timed out"
        except Exception as e:
            return f"Error: {str(e)}"

# 사용 예시
if __name__ == "__main__":
    agent = TerminalAI()

    if len(sys.argv) > 1:
        if sys.argv[1] == "review":
            # 현재 디렉토리의 Python 파일을 읽어와 리뷰
            with open("app.py", "r") as f:
                code = f.read()
            review = agent.code_review(code)
            print(review)
        else:
            # 일반 명령어 실행
            command = " ".join(sys.argv[1:])
            output = agent.run_command(command)
            print(output)
Enter fullscreen mode Exit fullscreen mode

실행 방법:

chmod +x ai_agent.py
python ai_agent.py review
python ai_agent.py "ls -la"
Enter fullscreen mode Exit fullscreen mode

4. tmux와의 통합

터미널 분할 환경에서 에이전트와 상호작용:

# tmux 세션 시작
tmux new-session -s ai_agent

# 새로운 창 생성
tmux new-window

# 창 1: 에이전트 실행
python ai_agent.py

# 창 2: 코드 편집
vim app.py
Enter fullscreen mode Exit fullscreen mode

에이전트의 출력을 tmux에 자동으로 전달하는 스크립트:

#!/usr/bin/env python3
# tmux_agent.py

import subprocess
import sys
import time

def send_to_tmux(window_name: str, content: str):
    """tmux 창에 내용 전송"""
    try:
        cmd = f"tmux send-keys -t {window_name} '{content}' Enter"
        subprocess.run(cmd, shell=True, check=True)
    except subprocess.CalledProcessError as e:
        print(f"Error sending to tmux: {e}")

# 사용 예시
if __name__ == "__main__":
    agent = TerminalAI()
    result = agent.call_llm("Hello, how are you?")
    send_to_tmux("ai_agent:0", result)
Enter fullscreen mode Exit fullscreen mode

5. 맞춤형 도구 개발

코드 검색 도구

#!/usr/bin/env python3
# code_search.py

import os
import re
from pathlib import Path

class CodeSearcher:
    def __init__(self, root_dir: str = "."):
        self.root_dir = Path(root_dir)
        self.ignore_patterns = [
            ".git", "__pycache__", ".venv", "node_modules"
        ]

    def search_function(self, func_name: str) -> List[Dict]:
        """함수 이름으로 검색"""
        results = []

        for file_path in self.root_dir.rglob("*.py"):
            if any(pattern in str(file_path) for pattern in self.ignore_patterns):
                continue

            try:
                with open(file_path, 'r') as f:
                    content = f.read()

                # 함수 정의 검색 (정규식)
                pattern = rf'def\s+{func_name}\s*\([^)]*\)'
                matches = re.finditer(pattern, content)

                for match in matches:
                    results.append({
                        'file': str(file_path),
                        'line': content[:match.start()].count('\n') + 1,
                        'context': self._get_context(content, match.start())
                    })
            except Exception as e:
                continue

        return results

    def _get_context(self, content: str, position: int, lines: int = 3) -> str:
        """주변 컨텍스트 추출"""
        lines_list = content.split('\n')
        start_line = max(0, content[:position].count('\n') - lines)
        end_line = min(len(lines_list), start_line + lines * 2 + 1)

        return '\n'.join(lines_list[start_line:end_line])

# 사용 예시
searcher = CodeSearcher()
results = searcher.search_function("main")
for result in results:
    print(f"Found in {result['file']}: line {result['line']}")
Enter fullscreen mode Exit fullscreen mode

Git 통합


python
#!/usr/bin/env python3
# git_integration.py

import subprocess
from datetime import datetime

class GitAgent:
    def __init__(self):
        self.repo_path = "."

    def get_recent_commits(self, count: int = 5) -> List[Dict]:
        """최근 커밋 목록 가져오기"""
        try:
            cmd = [
                "git", "-C", self.repo_path,
                "log", "--oneline", f"--{count}"
            ]
            result = subprocess.run(cmd, capture_output=True, text=True, check=True)

            commits = []
            for line in result.stdout.strip().split('\n'):
                if line:
                    sha, message = line.split(' ', 1)
                    commits.append({
                        'sha': sha,
                        'message': message,
                        'timestamp': datetime.now().isoformat()
                    })

            return commits
        except subprocess.CalledProcessError:
            return []

    def get_diff(self, file_path: str) -> str:
        """파일 변경사항 확인"""
        try:
            cmd = ["git", "-C",

---

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

Top comments (0)