터미널 AI 에이전트 구축 (v5)
터미널 기반 AI 에이전트는 개발자에게 매우 실용적인 도구로 자리 잡았습니다. 다양한 CLI 기반 AI 도구들 중에서 가장 효율적인 방식으로 개발자 워크플로우를 개선할 수 있는 방법을 소개합니다.
1. CLI AI 에이전트 생태계
현재 CLI AI 에이전트 시장은 다음과 같은 주요 도구들로 구성되어 있습니다:
Aider
pip install aider
aider --help
Continue.dev
npm install -g continue
OpenCode
git clone https://github.com/opencode-dev/opencode
cd opencode && pip install -e .
이들 도구들은 모두 자체적으로 파일 편집, 코드 생성, git 통합 기능을 제공하지만, 커스터마이징과 성능 최적화에 있어 한계가 있습니다.
2. 로컬 LLM API 엔드포인트 설정
로컬 LLM을 사용하면 보안성과 성능을 높일 수 있습니다:
Ollama 설치
# Ubuntu/Debian
curl -fsSL https://ollama.com/install.sh | sh
# macOS
brew install ollama
# 시작
ollama serve
모델 다운로드 및 실행
# llama3.2 모델 다운로드
ollama pull llama3.2
# 로컬 API 시작
ollama run llama3.2
API 테스트
# curl로 테스트
curl http://localhost:11434/api/generate \
-H "Content-Type: application/json" \
-d '{
"model": "llama3.2",
"prompt": "Hello, how are you?",
"stream": false
}'
3. 간단한 Python CLI 에이전트 구축
# aider_agent.py
import openai
import json
import subprocess
import os
from typing import List, Dict
class TerminalAgent:
def __init__(self, model="llama3.2"):
self.model = model
self.client = openai.OpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama"
)
self.context = []
def call_llm(self, prompt: str) -> str:
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}],
temperature=0.7
)
return response.choices[0].message.content
def execute_command(self, command: str) -> str:
try:
result = subprocess.run(
command,
shell=True,
capture_output=True,
text=True
)
return result.stdout + result.stderr
except Exception as e:
return f"Error: {str(e)}"
def get_file_content(self, filepath: str) -> str:
try:
with open(filepath, 'r') as f:
return f.read()
except Exception as e:
return f"Error reading file: {str(e)}"
def save_file(self, filepath: str, content: str) -> bool:
try:
with open(filepath, 'w') as f:
f.write(content)
return True
except Exception as e:
print(f"Error saving file: {str(e)}")
return False
# 사용 예시
if __name__ == "__main__":
agent = TerminalAgent()
# 코드 생성 예시
prompt = """
Create a Python function that calculates the fibonacci sequence up to n terms.
Return the list of numbers.
"""
response = agent.call_llm(prompt)
print("Generated code:")
print(response)
4. tmux와의 통합
터미널 에이전트는 tmux와 함께 사용될 때 더욱 강력합니다:
# tmux 세션 생성
tmux new-session -s ai_agent -d
# 세션에 명령 실행
tmux send-keys -t ai_agent "python aider_agent.py" Enter
# 세션에 파일 생성
tmux send-keys -t ai_agent "touch test.py" Enter
# 세션 정보 확인
tmux list-sessions
tmux 자동화 스크립트
#!/bin/bash
# setup_tmux.sh
SESSION_NAME="ai_dev"
tmux new-session -s $SESSION_NAME -d
# 메인 창 생성
tmux new-window -t $SESSION_NAME:1 -n "main"
tmux send-keys -t $SESSION_NAME:1 "cd ~/projects/myproject" Enter
# 터미널 창 생성
tmux new-window -t $SESSION_NAME:2 -n "terminal"
tmux send-keys -t $SESSION_NAME:2 "python aider_agent.py" Enter
# 에이전트 창 생성
tmux new-window -t $SESSION_NAME:3 -n "agent"
tmux send-keys -t $SESSION_NAME:3 "watch -n 1 'ls -la'" Enter
# 세션에 연결
tmux attach -t $SESSION_NAME
5. 커스텀 도구 개발
코드 검색 도구
# tools/code_search.py
import os
import re
class CodeSearchTool:
def __init__(self, project_root: str):
self.project_root = project_root
def search_in_files(self, pattern: str, file_extensions: list = None) -> List[Dict]:
results = []
if file_extensions is None:
file_extensions = ['.py', '.js', '.ts', '.java', '.cpp']
for root, dirs, files in os.walk(self.project_root):
for file in files:
if any(file.endswith(ext) for ext in file_extensions):
filepath = os.path.join(root, file)
try:
with open(filepath, 'r') as f:
content = f.read()
matches = re.finditer(pattern, content)
for match in matches:
results.append({
'file': filepath,
'line': content[:match.start()].count('\n') + 1,
'context': self.get_context(content, match.start())
})
except Exception as e:
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])
# 사용 예시
searcher = CodeSearchTool("/path/to/project")
results = searcher.search_in_files(r"def.*function_name")
Git 통합 도구
# tools/git_tool.py
import subprocess
import json
class GitTool:
def __init__(self):
pass
def get_status(self) -> Dict:
result = subprocess.run(['git', 'status', '--porcelain'],
capture_output=True, text=True)
return {"status": result.stdout.strip()}
def get_diff(self) -> str:
result = subprocess.run(['git', 'diff'],
capture_output=True, text=True)
return result.stdout
def commit_changes(self, message: str) -> bool:
try:
subprocess.run(['git', 'add', '.'], check=True)
subprocess.run(['git', 'commit', '-m', message], check=True)
return True
except subprocess.CalledProcessError:
return False
def get_branch_info(self) -> Dict:
result = subprocess.run(['git', 'branch', '--show-current'],
capture_output=True, text=True)
return {"branch": result.stdout.strip()}
# 사용 예시
git_tool = GitTool()
status = git_tool.get_status()
print(json.dumps(status, indent=2))
6. 컨텍스트 윈도우 관리
대규모 코드베이스에서는 컨텍스트 윈도우 관리가 중요합니다:
python
# context_manager.py
import tiktoken
from typing import List, Dict
class ContextManager:
def __init__(self, model_name: str = "gpt-4"):
self.encoding = tiktoken.encoding_for_model(model_name)
self.max_tokens = 8192 # 8K 토큰 제한
def count_tokens(self, text: str) -> int:
return len(self.encoding.encode(text))
def truncate_context(self, context: List[Dict], max_tokens: int = None) -> List[Dict]:
if max_tokens is None:
max_tokens = self.max_tokens
truncated = []
current_tokens = 0
# 최근 항목부터 처리
for item in reversed(context):
item_tokens = self.count_tokens(str(item))
if current_tokens + item_tokens <= max_tokens:
truncated.append(item)
current_tokens += item_tokens
else:
break
return list(reversed(truncated))
def add_context
---
📥 **Get the full guide on Gumroad**: https://gumroad.com/l/auto ($5)
Top comments (0)