DEV Community

matias yoon
matias yoon

Posted on

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

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

개발자용 CLI AI 에이전트 구축 가이드

터미널에서 작동하는 AI 에이전트는 개발자의 생산성을 높이는 강력한 도구입니다. 이 가이드에서는 실제 개발자들이 필요로 하는 3-7달러 범위의 실용적 CLI AI 에이전트를 구축하는 방법을 설명합니다.

1. CLI AI 에이전트 생태계 분석

현재 선택지 비교

Aider: GitHub Copilot 기반의 코드 생성 도구로, 현재 가장 인기 있는 선택입니다.

# Aider 설치
pip install aider
# 사용 예시
aider --model llama3:8b
Enter fullscreen mode Exit fullscreen mode

Continue.dev: VSCode 확장으로 시작했지만 CLI 버전도 제공됩니다.

# Continue CLI 설치
npm install -g @continue-dev/cli
Enter fullscreen mode Exit fullscreen mode

Custom Scripts: 직접 구축한 스크립트로 완전한 제어권 확보

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

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

Ollama 설치 및 실행

# Ollama 설치 (macOS)
curl -fsSL https://ollama.com/install.sh | sh

# Ollama 서버 시작
ollama serve

# 모델 다운로드
ollama pull llama3:8b
ollama pull codellama:7b

# 서버 상태 확인
ollama list
Enter fullscreen mode Exit fullscreen mode

API 엔드포인트 테스트

# test_api.py
import requests
import json

def test_local_llm():
    response = requests.post(
        'http://localhost:11434/api/generate',
        json={
            'model': 'llama3:8b',
            'prompt': 'Hello, how are you?',
            'stream': False
        }
    )
    print(response.json()['response'])

if __name__ == "__main__":
    test_local_llm()
Enter fullscreen mode Exit fullscreen mode

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

# ai_agent.py
#!/usr/bin/env python3
import requests
import json
import sys
from typing import Dict, List, Any

class TerminalAgent:
    def __init__(self, model="llama3:8b", base_url="http://localhost:11434"):
        self.model = model
        self.base_url = base_url
        self.history = []

    def call_llm(self, prompt: str, context: str = "") -> str:
        full_prompt = f"{context}\n\n{prompt}"

        response = requests.post(
            f"{self.base_url}/api/generate",
            json={
                'model': self.model,
                'prompt': full_prompt,
                'stream': False,
                'options': {
                    'temperature': 0.3,
                    'top_p': 0.9
                }
            }
        )

        if response.status_code == 200:
            return response.json()['response']
        else:
            raise Exception(f"API Error: {response.status_code}")

    def process_request(self, task: str) -> str:
        return self.call_llm(task, self.get_context())

    def get_context(self) -> str:
        # 현재 디렉토리와 파일 정보 추가
        import subprocess
        try:
            files = subprocess.check_output(['ls', '-la']).decode()
            return f"Current directory files:\n{files}"
        except:
            return ""

def main():
    if len(sys.argv) < 2:
        print("Usage: python ai_agent.py \"task description\"")
        sys.exit(1)

    agent = TerminalAgent()
    task = " ".join(sys.argv[1:])

    try:
        result = agent.process_request(task)
        print(result)
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

4. tmux 통합

터미널 세션 관리를 위한 tmux 통합:

# tmux 세션 생성 및 관리 스크립트
# tmux_agent.sh
#!/bin/bash

SESSION_NAME="ai_agent"
if ! tmux has-session -t $SESSION_NAME 2>/dev/null; then
    tmux new-session -d -s $SESSION_NAME
fi

# 에이전트 실행
tmux send-keys -t $SESSION_NAME "python ai_agent.py 'Write a Python function to sort a list'" Enter
Enter fullscreen mode Exit fullscreen mode
# enhanced_agent.py
#!/usr/bin/env python3
import subprocess
import os
import sys

class EnhancedTerminalAgent(TerminalAgent):
    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"

    def get_file_content(self, filename: str) -> str:
        """파일 내용 읽기"""
        try:
            with open(filename, 'r') as f:
                return f.read()
        except FileNotFoundError:
            return f"File {filename} not found"

    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: {e}"

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

    # 파일 내용 확인
    if len(sys.argv) > 1:
        command = sys.argv[1]
        if command == "read_file":
            print(agent.get_file_content(sys.argv[2]))
        elif command == "write_file":
            content = sys.argv[2]
            filename = sys.argv[3]
            print(agent.write_file(filename, content))
        else:
            print(agent.process_request(command))
Enter fullscreen mode Exit fullscreen mode

5. 사용자 정의 도구 개발

코드 검색 도구

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

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

    def search_code(self, pattern: str, file_types: list = None) -> list:
        """코드 검색"""
        if file_types is None:
            file_types = ['*.py', '*.js', '*.ts', '*.java', '*.cpp']

        results = []
        for file_type in file_types:
            try:
                cmd = f"find {self.project_root} -name '{file_type}' -type f"
                files = subprocess.check_output(cmd, shell=True, text=True).strip().split('\n')

                for file_path in files:
                    if file_path.strip():
                        with open(file_path, 'r') as f:
                            content = f.read()
                            if pattern in content:
                                results.append({
                                    'file': file_path,
                                    'line': self._find_pattern_line(content, pattern),
                                    'context': self._get_context(content, pattern)
                                })
            except Exception as e:
                print(f"Search error: {e}")

        return results

    def _find_pattern_line(self, content: str, pattern: str) -> int:
        lines = content.split('\n')
        for i, line in enumerate(lines):
            if pattern in line:
                return i + 1
        return -1

    def _get_context(self, content: str, pattern: str, context_lines: int = 3) -> str:
        lines = content.split('\n')
        for i, line in enumerate(lines):
            if pattern in line:
                start = max(0, i - context_lines)
                end = min(len(lines), i + context_lines + 1)
                return '\n'.join(lines[start:end])
        return ""

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

Git 통합 도구


python
# git_tool.py
import subprocess
import json

class GitTool:
    def __init__(self):
        pass

    def get_git_status(self) -> dict:
        """Git 상태 확인"""
        try:
            status = subprocess.check_output(['git', 'status', '--porcelain'], text=True)
            return {'status': status.strip()}
        except:
            return {'error': 'Not a git repository'}

    def get_last_commit(self) -> dict:
        """최근 커밋 정보"""
        try:
            commit = subprocess.check_output(['git', 'log', '-1', '--format=%H,%an,%ae,%s'], text=True)
            parts = commit.strip().split(',')
            return {
                'hash': parts[0],
                'author': parts[1],
                'email': parts[2],
                'message': parts[3]
            }
        except:
            return {'error':

---

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

Top comments (0)