터미널 AI 에이전트 구축 (v9): 로컬 LLM 기반 개발자용 CLI AI 에이전트 만들기
터미널에서 직접 작동하는 AI 에이전트를 구축하는 것은 개발자에게 큰 생산성 향상을 제공합니다. 이번 가이드에서는 로컬 LLM을 기반으로 한 커스텀 CLI AI 에이전트를 구축하는 방법을 실습 중심으로 설명합니다.
1. CLI AI 에이전트 생태계 분석
현재 CLI AI 에이전트 시장에는 여러 솔루션이 존재합니다:
주요 도구들:
- Aider: GitHub Copilot 기반, 실시간 코드 수정 기능
- Continue.dev: VSCode 기반, 복잡한 작업 처리
- OpenCode: 오픈소스, 간단한 코딩 도움
- Custom Scripts: 직접 제작한 스크립트로 커스터마이징
현재 문제점:
- 대부분의 도구는 클라우드 API에 의존
- 로컬 실행 시 성능 저하
- 복잡한 툴링 기능 부족
- 비용 문제
2. 로컬 LLM API 엔드포인트 설정
로컬에서 LLM을 실행하려면 다음과 같은 단계를 따릅니다:
1. LM Studio 설치:
# macOS
brew install lm-studio
# 또는 직접 다운로드
wget https://github.com/lmstudio-ai/LMStudio/releases/latest/download/LMStudio-MacOS.dmg
2. 로컬 모델 실행:
# 모델 다운로드 후 실행
lm-studio --model "Nous-Hermes-2-Mistral-7B-DPO.Q4_K_M.gguf"
3. API 서버 설정:
# Ollama 설치
curl -fsSL https://ollama.com/install.sh | sh
# 모델 다운로드
ollama pull mistral
# API 서버 실행
ollama serve
3. 간단한 Python CLI 에이전트 구축
이제 기초적인 CLI 에이전트를 만들어보겠습니다:
# ai_agent.py
import os
import json
import subprocess
from typing import Dict, List, Any
import openai
class TerminalAIAgent:
def __init__(self, model="ollama/mistral"):
self.model = model
self.client = openai.OpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama"
)
self.conversation_history = []
def run_command(self, command: str) -> str:
"""명령어 실행 및 결과 반환"""
try:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True,
timeout=30
)
return result.stdout + result.stderr
except Exception as e:
return f"Error: {str(e)}"
def get_context(self) -> str:
"""현재 작업 디렉토리 정보 수집"""
pwd = os.getcwd()
files = os.listdir(pwd)
return f"Working directory: {pwd}\nFiles: {', '.join(files[:10])}"
def chat(self, user_input: str) -> str:
"""AI와 대화"""
self.conversation_history.append({
"role": "user",
"content": user_input
})
# 시스템 프롬프트
system_prompt = """
You are a helpful AI assistant that helps developers with coding tasks.
Your responses should be concise and actionable.
You can execute shell commands and modify files.
"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"Context: {self.get_context()}"},
] + self.conversation_history
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
temperature=0.3
)
ai_response = response.choices[0].message.content
self.conversation_history.append({
"role": "assistant",
"content": ai_response
})
return ai_response
# 사용법
if __name__ == "__main__":
agent = TerminalAIAgent()
print("AI Agent 시작 (종료는 'exit' 입력)")
while True:
user_input = input("\n> ")
if user_input.lower() == 'exit':
break
response = agent.chat(user_input)
print(response)
4. tmux와 통합
터미널 멀티플렉서와 통합하여 작업 흐름을 개선합니다:
# tmux 세션 생성
tmux new-session -d -s ai_agent
# 세션 내에서 에이전트 실행
tmux send-keys -t ai_agent "python ai_agent.py" Enter
tmux 스크립트:
# tmux_ai.sh
#!/bin/bash
SESSION="ai_agent"
# 세션 존재 여부 확인
if ! tmux has-session -t $SESSION 2>/dev/null; then
tmux new-session -d -s $SESSION
tmux send-keys -t $SESSION "python ai_agent.py" Enter
fi
tmux attach -t $SESSION
5. 사용자 정의 도구 개발
코드 검색 도구:
# tools/code_search.py
import os
import re
from typing import List, Dict
class CodeSearchTool:
def __init__(self, root_dir: str = "."):
self.root_dir = root_dir
def search_in_files(self, pattern: str, file_extensions: List[str] = None) -> List[Dict]:
"""파일 내에서 패턴 검색"""
results = []
if file_extensions is None:
file_extensions = ['.py', '.js', '.ts', '.java', '.cpp']
for root, dirs, files in os.walk(self.root_dir):
for file in files:
if any(file.endswith(ext) for ext in file_extensions):
file_path = os.path.join(root, file)
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
matches = re.finditer(pattern, content)
for match in matches:
results.append({
'file': file_path,
'line': content[:match.start()].count('\n') + 1,
'context': self.get_context(content, match.start())
})
except Exception:
continue
return results
def get_context(self, content: str, position: int, context_lines: int = 3) -> str:
"""문맥 추출"""
lines = content.split('\n')
line_num = content[:position].count('\n')
start = max(0, line_num - context_lines)
end = min(len(lines), line_num + context_lines + 1)
return '\n'.join(lines[start:end])
# 사용 예제
search_tool = CodeSearchTool()
results = search_tool.search_in_files(r"def\s+(\w+)\s*\(")
print(json.dumps(results, indent=2))
Git 도구:
# tools/git_tool.py
import subprocess
import json
from typing import Dict, List
class GitTool:
def get_status(self) -> Dict:
"""Git 상태 확인"""
try:
result = subprocess.run(['git', 'status', '--porcelain'],
capture_output=True, text=True)
return {
'status': result.stdout.strip(),
'has_changes': bool(result.stdout.strip())
}
except Exception as e:
return {'error': str(e)}
def get_branch_info(self) -> Dict:
"""브랜치 정보"""
try:
branch = subprocess.run(['git', 'branch', '--show-current'],
capture_output=True, text=True).stdout.strip()
return {'branch': branch}
except Exception as e:
return {'error': str(e)}
def commit_changes(self, message: str) -> Dict:
"""변경사항 커밋"""
try:
subprocess.run(['git', 'add', '.'], capture_output=True)
result = subprocess.run(['git', 'commit', '-m', message],
capture_output=True, text=True)
return {
'success': True,
'output': result.stdout,
'error': result.stderr
}
except Exception as e:
return {'success': False, 'error': str(e)}
# 사용 예제
git_tool = GitTool()
status = git_tool.get_status()
print(json.dumps(status, indent=2))
6. 컨텍스트 윈도우 관리
대규모 코드베이스를 처리하기 위한 컨텍스트 관리:
python
# context_manager.py
import os
import hashlib
from typing import List, Dict, Set
class ContextManager:
def __init__(self, max_tokens: int = 8000):
self.max_tokens = max_tokens
self.token_cache = {}
def calculate_tokens(self, text: str)
---
📥 **Get the full guide on Gumroad**: https://gumroad.com/l/auto ($5)
Top comments (0)