본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 26. 12:24

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

요약

로컬 환경에서 작동하는 가벼운 터미널 AI 에이전트 구축 방법을 다룹니다. LM Studio를 활용해 로컬 LLM API를 설정하고, Python을 사용하여 코드 리뷰 및 프로젝트 탐색이 가능한 CLI 도구를 만드는 과정을 설명합니다.

핵심 포인트

  • 기존 솔루션(Aider, Continue.dev)의 한계 분석
  • LM Studio를 이용한 로컬 LLM API 서버 구축
  • Python 기반의 커스텀 CLI 에이전트 구현 방법
  • 코드 리뷰 및 자동화를 위한 프롬프트 활용

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

터미널에서 작동하는 AI 에이전트는 개발자들에게 강력한 도구가 되지만, 대부분의 기존 솔루션은 복잡하거나 클라우드 기반으로 의존합니다. 이 가이드는 로컬에서 작동하는 가벼운 AI 에이전트를 구축하여 코드 리뷰, 자동완성, 프로젝트 탐색을 수행하는 실용적인 방법을 설명합니다.

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

기존 솔루션 비교

Aider: GitHub에서 개발한 코드 에이전트로, 코드 변경을 직접 수정합니다. 하지만 GUI 기반으로 구조화되어 있어 터미널에서 사용하기 어려움.

Continue.dev: VSCode 확장 기반의 AI 에이전트. 터미널에서 사용하려면 복잡한 설정 필요.

OpenCode: 코드 기반 LLM 도구로, 로컬 모델 사용 가능하지만 커스터마이즈가 어려움.

사용자 정의 스크립트: 터미널에서 사용 가능한 가장 유연한 방식으로, 필요한 기능만 포함 가능.

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

LM Studio를 통한 로컬 LLM 실행

# LM Studio 설치 (macOS)
brew install --cask lm-studio

# 또는 직접 다운로드
# https://lmstudio.ai/

# 로컬 서버 시작 (기본 포트 1234)
lm-studio-server --port 1234

API 서버 테스트

# 테스트 요청
curl -X POST http://localhost:1234/v1/completions \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Hello, how are you?",
    "max_tokens": 100
  }'

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

기본 에이전트 스크립트

# aider_agent.py
import os
import json
import requests
import argparse
from typing import Dict, List, Any

class TerminalAgent:
    def __init__(self, api_url: str = "http://localhost:1234/v1/completions"):
        self.api_url = api_url
        self.headers = {"Content-Type": "application/json"}

    def call_model(self, prompt: str) -> str:
        """로컬 LLM API 호출"""
        payload = {
            "prompt": prompt,
            "max_tokens": 500,
            "temperature": 0.7
        }

        try:
            response = requests.post(
                self.api_url,
                headers=self.headers,
                json=payload,
                timeout=30
            )
            response.raise_for_status()
            return response.json()['choices'][0]['text']
        except Exception as e:
            return f"에러 발생: {str(e)}"

    def code_review(self, file_path: str) -> str:
        """코드 리뷰 요청"""
        with open(file_path, 'r') as f:
            code = f.read()

        prompt = f"""
        다음 코드를 분석하고, 개선 제안을 제공해주세요:

        {code}

        요청사항:
        1. 버그나 문제점
        2. 성능 개선 제안
        3. 코드 스타일 개선
        """

        return self.call_model(prompt)

    def generate_docstring(self, function_code: str) -> str:
        """함수 문서화 생성"""
        prompt = f"""
        다음 함수의 문서화를 생성해주세요:

        {function_code}

        문서화 형식:
        - 함수 설명
        - 파라미터 설명
        - 반환값 설명
        """

        return self.call_model(prompt)

def main():
    parser = argparse.ArgumentParser(description="터미널 AI 에이전트")
    parser.add_argument("--review", help="리뷰할 파일 경로")
    parser.add_argument("--docstring", help="문서화할 함수 코드")

    args = parser.parse_args()

    agent = TerminalAgent()

    if args.review:
        result = agent.code_review(args.review)
        print("코드 리뷰 결과:")
        print(result)

    if args.docstring:
        result = agent.generate_docstring(args.docstring)
        print("문서화 결과:")
        print(result)

if __name__ == "__main__":
    main()

실행 방법

# 코드 리뷰
python aider_agent.py --review src/main.py

# 문서화 생성
python aider_agent.py --docstring "def hello(name): return f'Hello {name}'"

4. tmux/터미널 멀티플렉서 통합

tmux 세션에 에이전트 통합

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

# 세션에 명령어 실행
tmux send-keys -t ai_agent "python aider_agent.py --review src/main.py" Enter

# 세션에 명령어 실행 (대화형)
tmux send-keys -t ai_agent "python aider_agent.py" Enter

tmux 스크립트 설정

# ai_session.sh
#!/bin/bash
SESSION="ai_dev"

# 새로운 세션 생성
tmux new-session -d -s $SESSION

# 첫 번째 윈도우: 코드 리뷰
tmux new-window -t $SESSION -n "review"
tmux send-keys -t $SESSION:0 "python aider_agent.py --review" Enter

# 두 번째 윈도우: 코딩
tmux new-window -t $SESSION -n "coding"
tmux send-keys -t $SESSION:1 "vim" Enter

# 세션에 연결
tmux attach -t $SESSION

5. 사용자 정의 도구 개발

코드 검색 도구

# code_search.py
import os
import re
from pathlib import Path
from typing import List, Dict

class CodeSearcher:
    def __init__(self, project_root: str):
        self.project_root = Path(project_root)
        self.ignore_patterns = [
            '.git', '__pycache__', '.venv', '.env'
        ]

    def search_functions(self, pattern: str, file_extensions: List[str] = None) -> List[Dict]:
        """함수 검색"""
        if file_extensions is None:
            file_extensions = ['.py', '.js', '.ts']

        results = []

        for file_path in self.project_root.rglob('*'):
            if file_path.is_file() and file_path.suffix in file_extensions:
                if any(ignore in str(file_path) for ignore in self.ignore_patterns):
                    continue

                try:
                    with open(file_path, 'r') as f:
                        content = f.read()

                    # 함수 정의 찾기
                    function_pattern = rf'def\s+(\w+)\s*\([^)]*\)'
                    functions = re.findall(function_pattern, content)

                    if pattern.lower() in file_path.name.lower():
                        results.append({
                            'file': str(file_path),
                            'functions': functions,
                            'line_count': len(content.split('\n'))
                        })

                except Exception:
                    continue

        return results

    def search_imports(self, module_name: str) -> List[str]:
        """모듈 검색"""
        results = []
        for file_path in self.project_root.rglob('*.py'):
            if any(ignore in str(file_path) for ignore in self.ignore_patterns):
                continue

            try:
                with open(file_path, 'r') as f:
                    content = f.read()

                if f'import {module_name}' in content or f'from {module_name}' in content:
                    results.append(str(file_path))

            except Exception:
                continue

        return results

# 사용 예시
searcher = CodeSearcher('.')
functions = searcher.search_functions('database')
print(json.dumps(functions, indent=2))

Git 연동 도구


python
# git_tools.py
import subprocess
import json
from datetime import datetime

class GitTools:
    @staticmethod
    def get_recent_commits(limit: int = 5) -> List[Dict]:
        """최근 커밋 정보 가져오기"""
        try:
            result = subprocess.run(
                ['git', 'log', f'--max-count={limit}', '--format=%H|%an|%ae|%s|%ad'],
                capture_output=True,
                text=True,
                check=True
            )

            commits = []
            for line in result.stdout.strip().split('\n'):
                if line:
                    parts = line.split('|')
                    commits.append({
                        'hash': parts[0],
                        'author': parts[1],
                        'email': parts[2],
                        'message': parts[3],
                        'date': parts[4]
                    })

            return commits
        except subprocess.CalledProcessError:
            return []

    @staticmethod
    def get_branch_status() -> Dict:
        """브랜치 상태 정보"""
        try:
            #

---

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

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0