DEV Community

matias yoon
matias yoon

Posted on

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

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

터미널에서 작동하는 AI 에이전트를 구축하면 개발자들이 코드를 더 빠르고 효율적으로 작성할 수 있습니다. 이 가이드에서는 실제 사용 가능한 터미널 AI 에이전트를 구축하는 방법을 단계별로 설명합니다.

1. CLI AI 에이전트 랜드스케이프

현재 CLI AI 에이전트 시장에는 여러 선택지가 있습니다:

Aider: Git 기반 코드 변경을 위한 자동화 도구로, 터미널에서 직접 작동합니다.

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

Continue.dev: VSCode와 연동된 AI 코드 작성 도구.

npm install -g continue
Enter fullscreen mode Exit fullscreen mode

OpenCode: GitHub에서 직접 제공하는 CLI 도구.

# GitHub에서 설치
git clone https://github.com/openai/open-code.git
Enter fullscreen mode Exit fullscreen mode

커스텀 스크립트: 직접 제작한 간단한 에이전트. 가장 유연한 접근입니다.

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

로컬 LLM을 위한 API 서버를 구축하려면 llama.cpp를 사용하는 것이 좋습니다:

# llama.cpp 설치
git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
make

# 모델 다운로드 및 변환
wget https://huggingface.co/TheBloke/Mistral-7B-v0.1-GGUF/resolve/main/mistral-7b-v0.1.Q4_K_M.gguf
./convert-hf-to-gguf.py mistral-7b-v0.1.Q4_K_M.gguf

# API 서버 실행
./server -m mistral-7b-v0.1.Q4_K_M.gguf -c 2048 --host 127.0.0.1 --port 8080
Enter fullscreen mode Exit fullscreen mode

API 엔드포인트를 사용하여 테스트:

curl -X POST http://127.0.0.1:8080/completion \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Write a Python function that calculates factorial",
    "max_tokens": 100,
    "temperature": 0.7
  }'
Enter fullscreen mode Exit fullscreen mode

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

기본적인 CLI 에이전트를 구현해봅니다:

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

import os
import json
import requests
import argparse
from typing import Dict, List

class TerminalAgent:
    def __init__(self, api_url: str = "http://127.0.0.1:8080"):
        self.api_url = api_url

    def generate_code(self, prompt: str, context: str = "") -> str:
        """코드 생성"""
        payload = {
            "prompt": f"{context}\n\nPrompt: {prompt}\n\nCode:",
            "max_tokens": 500,
            "temperature": 0.7,
            "stop": ["\n\n"]
        }

        try:
            response = requests.post(
                f"{self.api_url}/completion",
                json=payload,
                timeout=30
            )
            return response.json()['content']
        except Exception as e:
            return f"Error: {str(e)}"

    def explain_code(self, code: str) -> str:
        """코드 설명"""
        prompt = f"Explain the following Python code:\n\n{code}"
        return self.generate_code(prompt, "Explain code:")

    def fix_errors(self, code: str, error: str) -> str:
        """코드 오류 수정"""
        prompt = f"Fix the following Python error in the code:\n\nCode:\n{code}\n\nError:\n{error}"
        return self.generate_code(prompt, "Fix error:")

def main():
    parser = argparse.ArgumentParser(description="Terminal AI Agent")
    parser.add_argument("--generate", "-g", help="Generate code from prompt")
    parser.add_argument("--explain", "-e", help="Explain code")
    parser.add_argument("--fix", "-f", help="Fix code errors")
    parser.add_argument("--context", "-c", help="Additional context")

    args = parser.parse_args()

    agent = TerminalAgent()

    if args.generate:
        result = agent.generate_code(args.generate, args.context or "")
        print(result)
    elif args.explain:
        result = agent.explain_code(args.explain)
        print(result)
    elif args.fix:
        result = agent.fix_errors(args.fix, args.context or "")
        print(result)
    else:
        print("Usage: python agent.py --generate 'prompt' [--context 'context']")

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

실행 방법:

# 코드 생성
python agent.py --generate "Write a function to sort a list of dictionaries by a key"

# 코드 설명
python agent.py --explain "def bubble_sort(arr): n = len(arr); for i in range(n): for j in range(0, n-i-1): if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j]"

# 오류 수정
python agent.py --fix "import pandas as pd; df = pd.DataFrame({'a': [1, 2], 'b': [3, 4]}); print(df.colums)" --context "AttributeError: 'DataFrame' object has no attribute 'colums'"
Enter fullscreen mode Exit fullscreen mode

4. tmux와 통합

터미널 세션을 관리하기 위해 tmux와 연동합니다:

# tmux 세션 생성
tmux new-session -d -s ai-agent

# 세션 내부에 에이전트 실행
tmux send-keys -t ai-agent "python agent.py --generate 'create a Flask route for user login'" Enter

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

tmux 스크립트를 사용한 자동화:

#!/bin/bash
# tmux-agent.sh

SESSION="ai-agent"

# 세션 존재 여부 확인
if ! tmux has-session -t $SESSION 2>/dev/null; then
    tmux new-session -d -s $SESSION
fi

# 현재 세션에서 새로운 윈도우 생성
tmux new-window -t $SESSION -n "code"
tmux new-window -t $SESSION -n "chat"

# 세션에 연결
tmux attach -t $SESSION
Enter fullscreen mode Exit fullscreen mode

5. 커스텀 도구 개발

기본적인 도구들을 개발해보겠습니다:


python
# tools.py

import os
import subprocess
import json
from pathlib import Path

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

    def search_files(self, pattern: str, file_types: list = None) -> list:
        """파일 검색"""
        cmd = ["find", str(self.project_path), "-name", f"*{pattern}*"]
        if file_types:
            type_args = []
            for ext in file_types:
                type_args.extend(["-o", "-name", f"*.{ext}"])
            cmd.extend(["(", *type_args[1:], ")"])

        result = subprocess.run(cmd, capture_output=True, text=True)
        return result.stdout.strip().split('\n') if result.stdout.strip() else []

    def search_code(self, term: str, file_types: list = None) -> dict:
        """코드 검색"""
        files = self.search_files(term, file_types)
        results = {}

        for file_path in files:
            try:
                with open(file_path, 'r') as f:
                    content = f.read()
                    if term in content:
                        results[file_path] = {
                            "line_count": len(content.split('\n')),
                            "contains": term
                        }
            except Exception as e:
                continue

        return results

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

    def get_changed_files(self) -> list:
        """변경된 파일 목록"""
        result = subprocess.run(
            ["git", "diff", "--name-only", "HEAD~1", "HEAD"],
            cwd=self.repo_path,
            capture_output=True,
            text=True
        )
        return result.stdout.strip().split('\n') if result.stdout.strip() else []

    def get_branch_info(self) -> dict:
        """브랜치 정보"""
        result = subprocess.run(
            ["git", "branch", "--show-current"],
            cwd=self.repo_path,
            capture_output=True,
            text=True
        )
        return {
            "current_branch": result.stdout.strip()
        }

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

    @

---

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

Top comments (0)