DEV Community

matias yoon
matias yoon

Posted on

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

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

터미널에서 작동하는 AI 에이전트는 개발자에게 매우 가치 있는 도구입니다. 이 가이드에서는 실제 개발 환경에서 사용할 수 있는 터미널 AI 에이전트 구축 방법을 설명합니다.

1. CLI AI 에이전트 생태계

현재 터미널 AI 에이전트는 여러 플랫폼으로 구성되어 있습니다:

주요 도구들

Aider: Git 기반 코드 수정을 위한 간단한 에이전트

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

Continue.dev: VSCode와 연동된 고급 에이전트

npm install -g continue
Enter fullscreen mode Exit fullscreen mode

OpenCode: Python 기반 커스터마이징 가능한 에이전트

pip install opencode
Enter fullscreen mode Exit fullscreen mode

커스텀 스크립트: 직접 구현한 빠른 프로토타입

# aider-like agent
import subprocess
import sys

def aider_like_agent(prompt):
    cmd = ["aider", "--yes", "--no-stream", f"--prompt={prompt}"]
    result = subprocess.run(cmd, capture_output=True, text=True)
    return result.stdout
Enter fullscreen mode Exit fullscreen mode

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

로컬 LLM을 터미널에서 사용하려면 API 서버를 구축해야 합니다.

llama.cpp 서버 시작

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

# 모델 다운로드 및 서버 실행
wget https://huggingface.co/TheBloke/Mistral-7B-v0.1-GGUF/resolve/main/mistral-7b-v0.1.Q4_K_M.gguf
./server -m mistral-7b-v0.1.Q4_K_M.gguf -c 2048 --port 8080
Enter fullscreen mode Exit fullscreen mode

Python API 클라이언트

import requests
import json

class LocalLLMClient:
    def __init__(self, base_url="http://localhost:8080"):
        self.base_url = base_url

    def generate(self, prompt, max_tokens=200):
        response = requests.post(
            f"{self.base_url}/completion",
            json={
                "prompt": prompt,
                "max_tokens": max_tokens,
                "temperature": 0.7,
                "stop": ["\n\n"]
            }
        )
        return response.json()['content']
Enter fullscreen mode Exit fullscreen mode

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

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

#!/usr/bin/env python3
# ai_agent.py
import argparse
import json
import os
import subprocess
from typing import List, Dict
from local_llm_client import LocalLLMClient

class TerminalAgent:
    def __init__(self):
        self.client = LocalLLMClient()
        self.tools = {
            "code_search": self.search_code,
            "git_status": self.git_status,
            "file_operations": self.file_operations,
            "system_info": self.system_info
        }

    def execute_tool(self, tool_name: str, **kwargs) -> str:
        if tool_name in self.tools:
            return self.tools[tool_name](**kwargs)
        return f"Unknown tool: {tool_name}"

    def search_code(self, pattern: str, file_types: List[str] = None) -> str:
        cmd = ["find", ".", "-type", "f"]
        if file_types:
            extensions = " -o ".join([f"-name '*.{ext}'" for ext in file_types])
            cmd.extend(["-exec", f"grep -l '{pattern}' {{}} \\;", "(", extensions, ")", "-o"])
        else:
            cmd.extend(["-exec", f"grep -l '{pattern}' {{}} \\;"])

        try:
            result = subprocess.run(cmd, capture_output=True, text=True, check=True)
            return result.stdout
        except subprocess.CalledProcessError:
            return "No matches found"

    def git_status(self) -> str:
        try:
            result = subprocess.run(["git", "status", "--porcelain"], 
                                  capture_output=True, text=True, check=True)
            return result.stdout
        except subprocess.CalledProcessError:
            return "Not a git repository"

    def file_operations(self, operation: str, path: str, content: str = None) -> str:
        if operation == "read":
            try:
                with open(path, 'r') as f:
                    return f.read()
            except Exception as e:
                return f"Error reading file: {str(e)}"
        elif operation == "write":
            try:
                with open(path, 'w') as f:
                    f.write(content)
                return f"File written to {path}"
            except Exception as e:
                return f"Error writing file: {str(e)}"
        return "Unknown operation"

    def system_info(self) -> str:
        try:
            result = subprocess.run(["uname", "-a"], capture_output=True, text=True, check=True)
            return result.stdout
        except:
            return "System info not available"

    def run(self, prompt: str, tools: List[str] = None):
        if not tools:
            tools = ["code_search", "git_status", "file_operations", "system_info"]

        # 도구 정보 생성
        tool_info = "\n".join([
            f"{name}: {func.__doc__}" 
            for name, func in self.tools.items() 
            if name in tools
        ])

        # 프롬프트 구성
        full_prompt = f"""
You are a terminal AI assistant. Use the following tools when needed:
{tool_info}

User request: {prompt}

Respond with JSON format:
{{"action": "tool_call", "tool": "tool_name", "args": {{}}}}
or
{{"action": "generate", "content": "your response"}}

Available tools: {', '.join(tools)}
"""

        response = self.client.generate(full_prompt, max_tokens=500)

        try:
            json_resp = json.loads(response)
            if json_resp.get("action") == "tool_call":
                tool_result = self.execute_tool(
                    json_resp["tool"], 
                    **json_resp.get("args", {})
                )
                return tool_result
            elif json_resp.get("action") == "generate":
                return json_resp["content"]
        except:
            return response

def main():
    parser = argparse.ArgumentParser(description="Terminal AI Agent")
    parser.add_argument("prompt", help="Prompt to send to AI agent")
    parser.add_argument("--tools", nargs="*", default=None, help="Available tools")
    args = parser.parse_args()

    agent = TerminalAgent()
    result = agent.run(args.prompt, args.tools)
    print(result)

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

4. tmux와 통합

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

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

# 세션 내에서 명령 실행
tmux send-keys -t ai_agent "python3 ai_agent.py 'fix this bug'" Enter

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

tmux 통합 스크립트

# tmux_agent.py
import subprocess
import os

def create_tmux_session(session_name: str, command: str):
    # 새로운 세션 생성
    subprocess.run(["tmux", "new-session", "-d", "-s", session_name])

    # 명령 실행
    subprocess.run(["tmux", "send-keys", "-t", session_name, command, "Enter"])

    return session_name

def attach_to_session(session_name: str):
    subprocess.run(["tmux", "attach", "-t", session_name])
Enter fullscreen mode Exit fullscreen mode

5. 커스텀 도구 개발

코드 검색 도구

def search_code(pattern: str, file_extensions: List[str] = None) -> str:
    """코드 내 특정 패턴 검색"""
    cmd = ["grep", "-r", "-n", pattern, "."]
    if file_extensions:
        cmd.extend(["--include", f"*.{file_extensions[0]}"])

    try:
        result = subprocess.run(cmd, capture_output=True, text=True, check=True)
        return result.stdout
    except subprocess.CalledProcessError:
        return f"No matches found for '{pattern}'"
Enter fullscreen mode Exit fullscreen mode

Git 도구


python
def git_operations(operation: str, *args) -> str:
    """Git 작업 수행"""
    if operation == "log":
        cmd = ["git", "log", "--oneline", "-10"]
    elif operation == "diff":
        cmd = ["git", "diff"]
    elif operation == "status":
        cmd = ["git", "status", "--porcelain"]
    else:
        return "Unknown git operation"

    try:
        result = subprocess.run(cmd, capture_output=True, text=True, check=True)
        return result.stdout
    except subprocess.CalledProcessError as e:
        return f

---

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

Top comments (0)