DEV Community

matias yoon
matias yoon

Posted on

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

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

터미널에서 작동하는 AI 에이전트를 구축하여 개발 생산성을 극대화하는 방법을 알아봅니다. 이 가이드에서는 오픈소스 도구와 커스텀 솔루션을 사용해 실용적인 터미널 AI 에이전트를 구현하는 방법을 설명합니다.

1. CLI AI 에이전트 생태계

현재 터미널 AI 에이전트는 여러 플랫폼으로 나뉩니다:

주요 도구 비교

# Aider: 코드 생성 및 수정
pip install aider

# Continue.dev: VS Code 확장 + CLI
npm install -g @continue_dev/cli

# OpenCode: GitHub 기반
pip install opencode

# 커스텀 스크립트: 최대한의 커스터마이즈
Enter fullscreen mode Exit fullscreen mode

Aider는 가장 널리 사용되는 터미널 기반 에이전트로, 코드 생성과 수정에 강점을 가집니다. 그러나 복잡한 작업에는 한계가 있습니다.

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

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

# docker-compose.yml
version: '3.8'
services:
  llama-server:
    image: ghcr.io/ggerganov/llama.cpp:latest
    command: |
      --model models/llama-3-8b-instruct.Q4_K_M.gguf
      --port 8080
      --host 0.0.0.0
      --n-gpu-layers 35
    volumes:
      - ./models:/models
    ports:
      - "8080:8080"
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
Enter fullscreen mode Exit fullscreen mode
# API 서버 시작
docker-compose up -d

# 테스트 명령어
curl -X POST http://localhost:8080/completion \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Write a Python function to calculate Fibonacci numbers",
    "n_predict": 100
  }'
Enter fullscreen mode Exit fullscreen mode

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

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

class TerminalAIAgent:
    def __init__(self, api_base="http://localhost:8080"):
        self.client = openai.OpenAI(
            base_url=api_base,
            api_key="EMPTY"
        )

    def call_function(self, function_name: str, args: dict) -> str:
        """함수 호출"""
        if function_name == "execute_command":
            return self.execute_command(args["command"])
        elif function_name == "read_file":
            return self.read_file(args["filepath"])
        elif function_name == "write_file":
            return self.write_file(args["filepath"], args["content"])
        return "Unknown function"

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

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

    def write_file(self, filepath: str, content: str) -> str:
        """파일 쓰기"""
        try:
            os.makedirs(os.path.dirname(filepath), exist_ok=True)
            with open(filepath, 'w') as f:
                f.write(content)
            return f"File written to {filepath}"
        except Exception as e:
            return f"Error writing file: {str(e)}"

    def process_request(self, user_prompt: str) -> str:
        """사용자 요청 처리"""
        messages = [
            {"role": "system", "content": "You are a helpful coding assistant. Use available functions to help the user."},
            {"role": "user", "content": user_prompt}
        ]

        # 함수 호출 정의
        tools = [
            {
                "type": "function",
                "function": {
                    "name": "execute_command",
                    "description": "Execute shell commands",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "command": {"type": "string", "description": "Shell command to execute"}
                        },
                        "required": ["command"]
                    }
                }
            },
            {
                "type": "function",
                "function": {
                    "name": "read_file",
                    "description": "Read file content",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "filepath": {"type": "string", "description": "Path to file"}
                        },
                        "required": ["filepath"]
                    }
                }
            },
            {
                "type": "function",
                "function": {
                    "name": "write_file",
                    "description": "Write content to file",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "filepath": {"type": "string", "description": "Path to file"},
                            "content": {"type": "string", "description": "Content to write"}
                        },
                        "required": ["filepath", "content"]
                    }
                }
            }
        ]

        response = self.client.chat.completions.create(
            model="local-model",
            messages=messages,
            tools=tools,
            tool_choice="auto"
        )

        return response.choices[0].message.content

# 사용법
if __name__ == "__main__":
    agent = TerminalAIAgent()
    while True:
        prompt = input("AI Agent> ")
        if prompt.lower() in ['quit', 'exit']:
            break
        result = agent.process_request(prompt)
        print(result)
Enter fullscreen mode Exit fullscreen mode

4. tmux와 통합

터미널 multiplexer와 통합하여 작업 환경을 개선:

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

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

# 세션에 파일 전송
tmux send-keys -t ai_session "cat main.py" Enter
Enter fullscreen mode Exit fullscreen mode
# tmux 스크립트
#!/bin/bash
# ai_tmux.sh

SESSION_NAME="ai_dev"
WINDOW_NAME="agent"

# 세션이 존재하는지 확인
if ! tmux has-session -t $SESSION_NAME 2>/dev/null; then
    # 새 세션 생성
    tmux new-session -d -s $SESSION_NAME
    tmux new-window -t $SESSION_NAME:$WINDOW_NAME
fi

# 윈도우로 전환
tmux select-window -t $SESSION_NAME:$WINDOW_NAME

# 작업 디렉토리 설정
tmux send-keys -t $SESSION_NAME:$WINDOW_NAME "cd ~/projects/myapp" Enter
tmux send-keys -t $SESSION_NAME:$WINDOW_NAME "export PYTHONPATH=." Enter

echo "AI session ready in tmux"
Enter fullscreen mode Exit fullscreen mode

5. 커스텀 도구 개발


python
# custom_tools.py
import os
import subprocess
import re
from typing import List

class CodeSearchTool:
    """코드 검색 도구"""

    @staticmethod
    def search_code(pattern: str, directory: str = ".") -> List[str]:
        """정규 표현식으로 코드 검색"""
        results = []
        try:
            cmd = f"find {directory} -name '*.py' -type f -exec grep -l '{pattern}' {{}} \\;"
            output = subprocess.check_output(cmd, shell=True, text=True)
            files = output.strip().split('\n')
            for file in files:
                if file:
                    results.append(file)
        except:
            pass
        return results

    @staticmethod
    def grep_content(pattern: str, directory: str = ".") -> List[str]:
        """내용 검색"""
        try:
            cmd = f"find {directory} -name '*.py' -type f -exec grep -n '{pattern}' {{}} \\;"
            output = subprocess.check_output(cmd, shell=True, text=True)
            return output.strip().split('\n')
        except:
            return []

class GitTool:
    """Git 도구"""

    @staticmethod
    def get_recent_commits(n: int = 5) -> str:
        """최근 커밋 목록 가져오기"""
        try:
            cmd = f"git log --oneline -{n}"
            output = subprocess.check_output(cmd, shell=True, text=True)
            return output.strip()
        except:
            return "No git repository"

    @staticmethod
    def get_status() -> str:
        """Git 상태"""
        try:
            cmd = "git status

---

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

Top comments (0)