터미널 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)
Top comments (0)