DEV Community

matias yoon
matias yoon

Posted on

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

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

터미널에서 작동하는 AI 에이전트를 직접 구축하는 것은 개발자에게 매우 실용적인 도구입니다. 이 가이드에서는 로컬 LLM을 활용한 터미널 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
Enter fullscreen mode Exit fullscreen mode

OpenCode: 오픈소스, 로컬 실행 가능한 에이전트

git clone https://github.com/open-code/open-code.git
cd open-code && python -m pip install -e .
Enter fullscreen mode Exit fullscreen mode

사용자 정의 스크립트: 최대한의 커스터마이징이 가능

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

로컬 LLM을 위한 API 서버를 구축하여 비용과 보안 문제를 해결합니다.

LM Studio 설치

# macOS
brew install lm-studio

# 또는 직접 다운로드
curl -L https://github.com/lm-s Studio/lm-studio/releases/latest/download/LM-Studio-Mac.dmg -o lm-studio.dmg
Enter fullscreen mode Exit fullscreen mode

LocalAI 설치 (대안)

git clone https://github.com/go-skynet/LocalAI.git
cd LocalAI
docker build -t localai .
docker run -p 8080:8080 -v $(pwd)/models:/models localai
Enter fullscreen mode Exit fullscreen mode

테스트 명령

curl http://localhost:8080/v1/models
curl http://localhost:8080/v1/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama3",
    "prompt": "Hello, how are you?",
    "max_tokens": 100
  }'
Enter fullscreen mode Exit fullscreen mode

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

다음은 기능 호출을 사용하는 간단한 CLI 에이전트입니다:

# ai_agent.py
import openai
import subprocess
import json
import os
from typing import List, Dict, Any

class TerminalAgent:
    def __init__(self, api_key: str = None):
        self.client = openai.OpenAI(
            base_url="http://localhost:8080/v1",
            api_key="none"
        )
        self.tools = [
            {
                "type": "function",
                "function": {
                    "name": "execute_shell",
                    "description": "Shell 명령어 실행",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "command": {
                                "type": "string",
                                "description": "실행할 명령어"
                            }
                        },
                        "required": ["command"]
                    }
                }
            }
        ]

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

    def run(self, prompt: str) -> str:
        """AI 에이전트 실행"""
        messages = [
            {
                "role": "user", 
                "content": prompt
            }
        ]

        # 함수 호출
        response = self.client.chat.completions.create(
            model="llama3",
            messages=messages,
            tools=self.tools,
            tool_choice="auto"
        )

        # 결과 처리
        tool_calls = response.choices[0].message.tool_calls
        if tool_calls:
            for tool_call in tool_calls:
                if tool_call.function.name == "execute_shell":
                    args = json.loads(tool_call.function.arguments)
                    output = self.execute_shell(args["command"])
                    messages.append({
                        "role": "tool",
                        "content": output,
                        "tool_call_id": tool_call.id
                    })

            # 최종 응답 요청
            final_response = self.client.chat.completions.create(
                model="llama3",
                messages=messages
            )
            return final_response.choices[0].message.content

        return response.choices[0].message.content

# 사용법
if __name__ == "__main__":
    agent = TerminalAgent()
    result = agent.run("시스템 정보를 확인해주세요")
    print(result)
Enter fullscreen mode Exit fullscreen mode

4. tmux와 통합

터미널 multiplexer와 통합하여 에이전트를 더 효율적으로 사용합니다:

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

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

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

Python 스크립트에서 tmux 통합:

# tmux_integration.py
import subprocess
import json

class TmuxAgent(TerminalAgent):
    def __init__(self, session_name: str = "ai_agent"):
        super().__init__()
        self.session_name = session_name

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

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

    def get_session_output(self):
        """세션 출력 가져오기"""
        result = subprocess.run([
            "tmux", "capture-pane", "-p", "-t", self.session_name
        ], capture_output=True, text=True)
        return result.stdout

# 사용법
agent = TmuxAgent("my_ai")
agent.create_session()
agent.send_command("ls -la")
Enter fullscreen mode Exit fullscreen mode

5. 사용자 정의 도구 개발

코드 검색 도구

# 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.supported_extensions = {'.py', '.js', '.ts', '.java', '.cpp', '.h'}

    def search_patterns(self, pattern: str, file_pattern: str = "*") -> List[Dict]:
        """정규식 패턴으로 코드 검색"""
        results = []

        for file_path in self.root_dir.rglob(file_pattern):
            if file_path.suffix in self.supported_extensions:
                try:
                    with open(file_path, 'r', encoding='utf-8') as f:
                        content = f.read()
                        matches = re.finditer(pattern, content)
                        for match in matches:
                            results.append({
                                'file': str(file_path),
                                'line': content[:match.start()].count('\n') + 1,
                                'content': match.group()
                            })
                except Exception:
                    continue
        return results

    def search_function(self, function_name: str) -> List[Dict]:
        """함수 정의 검색"""
        pattern = rf'def\s+{function_name}\s*\('
        return self.search_patterns(pattern)
Enter fullscreen mode Exit fullscreen mode

Git 통합 도구

# git_tools.py
import subprocess
import json
from typing import List, Dict

class GitTools:
    @staticmethod
    def get_git_status() -> str:
        """Git 상태 확인"""
        try:
            result = subprocess.run(
                ['git', 'status', '--porcelain'],
                capture_output=True, text=True
            )
            return result.stdout.strip()
        except:
            return "Git repository not found"

    @staticmethod
    def get_recent_commits(limit: int = 5) -> List[Dict]:
        """최근 커밋 정보"""
        try:
            result = subprocess.run([
                'git', 'log', '--oneline', f'-{limit}'
            ], capture_output=True, text=True)

            commits = []
            for line in result.stdout.strip().split('\n'):
                if line.strip():
                    parts = line.split(' ', 1)
                    commits.append({
                        'hash': parts[0],
                        'message': parts[1] if len(parts) > 1 else ''
                    })
            return commits
        except:
            return []

    @staticmethod
    def get_changed_files() -> List[str]:
        """변경된 파일 목록"""
        try:
            result = subprocess.run([
                'git', 'diff', '--name-only', 'HEAD~1'
            ], capture_output=True, text=True)
            return result.stdout.strip().split('\n')
        except:
            return []
Enter fullscreen mode Exit fullscreen mode

6. 컨텍스트 윈도우 관리

대규모 코드


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

Top comments (0)