터미널 AI 에이전트 구축 (v14)
터미널에서 작동하는 AI 에이전트는 현대 개발 워크플로우의 핵심 요소입니다. 이 가이드에서는 개발자가 실제로 사용할 수 있는 터미널 AI 에이전트를 구축하는 방법을 자세히 설명합니다.
1. CLI AI 에이전트 생태계
현재 터미널 AI 에이전트는 다양한 도구로 구성되어 있습니다:
Aider: GitHub Copilot과 유사한 기능을 제공하는 에이전트
Continue.dev: VS Code 확장 프로그램을 기반으로 한 터미널 지원 도구
OpenCode: 오픈소스 기반의 코드 생성 도구
# Aider 설치
pip install aider
# 사용 예시
aider --help
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
python convert.py mistral-7b-v0.1.Q4_K_M.gguf
# 로컬 API 서버 실행
./server -m mistral-7b-v0.1.Q4_K_M.gguf -c 2048 --host 127.0.0.1 --port 8080
3. 간단한 Python CLI 에이전트 구축
다음은 함수 호출 기능을 포함한 기본 CLI 에이전트입니다:
# terminal_agent.py
import openai
import json
import subprocess
import os
from typing import Dict, Any
class TerminalAgent:
def __init__(self):
self.client = openai.OpenAI(
base_url="http://localhost:8080/v1",
api_key="sk-no-key-required"
)
def call_function(self, function_name: str, arguments: Dict[str, Any]) -> str:
"""함수 호출"""
if function_name == "run_command":
return self.run_shell_command(arguments["command"])
elif function_name == "read_file":
return self.read_file(arguments["path"])
elif function_name == "write_file":
return self.write_file(arguments["path"], arguments["content"])
else:
return f"Unknown function: {function_name}"
def run_shell_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 subprocess.TimeoutExpired:
return "Command timed out"
def read_file(self, path: str) -> str:
"""파일 읽기"""
try:
with open(path, 'r') as f:
return f.read()
except Exception as e:
return f"Error reading file: {str(e)}"
def write_file(self, path: str, content: str) -> str:
"""파일 쓰기"""
try:
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, 'w') as f:
f.write(content)
return f"File written successfully to {path}"
except Exception as e:
return f"Error writing file: {str(e)}"
def chat(self, prompt: str) -> str:
"""AI와 대화"""
response = self.client.chat.completions.create(
model="local",
messages=[
{"role": "system", "content": """
You are a helpful terminal assistant. You can execute commands,
read/write files, and provide programming assistance.
Available functions:
- run_command(command): Execute shell commands
- read_file(path): Read file content
- write_file(path, content): Write content to file
Always respond in JSON format with 'function' and 'arguments' fields.
"""},
{"role": "user", "content": prompt}
],
temperature=0.7,
max_tokens=1024
)
return response.choices[0].message.content
# 실행 예시
if __name__ == "__main__":
agent = TerminalAgent()
while True:
user_input = input("Terminal Agent> ")
if user_input.lower() in ['exit', 'quit']:
break
response = agent.chat(user_input)
print(response)
4. tmux와의 통합
tmux를 활용해 에이전트를 터미널 세션과 통합합니다:
# tmux 세션 생성
tmux new-session -s ai_agent -d
# 세션에 명령어 전송
tmux send-keys -t ai_agent "python terminal_agent.py" Enter
# 세션에 명령어 전송 함수
function send_to_agent() {
tmux send-keys -t ai_agent "$1" Enter
}
# 사용 예시
send_to_agent "list files"
5. 사용자 정의 도구 개발
다음은 코드 검색 및 파일 작업 도구입니다:
# custom_tools.py
import os
import glob
import re
from typing import List
class CodeSearchTool:
def __init__(self, root_path: str = "."):
self.root_path = root_path
def search_code(self, pattern: str, file_extensions: List[str] = None) -> List[str]:
"""코드 검색"""
if file_extensions is None:
file_extensions = ['*.py', '*.js', '*.ts', '*.java', '*.cpp']
results = []
for ext in file_extensions:
search_path = os.path.join(self.root_path, '**', ext)
for file_path in glob.glob(search_path, recursive=True):
try:
with open(file_path, 'r') as f:
content = f.read()
if re.search(pattern, content, re.IGNORECASE):
results.append({
'path': file_path,
'matches': re.findall(pattern, content, re.IGNORECASE)
})
except Exception:
continue
return results
def get_git_status(self) -> str:
"""Git 상태 확인"""
try:
result = subprocess.run(
['git', 'status', '--porcelain'],
capture_output=True,
text=True,
cwd=self.root_path
)
return result.stdout
except Exception as e:
return f"Git error: {str(e)}"
# 파일 작업 도구
class FileOperationTool:
def __init__(self):
pass
def find_files_by_pattern(self, pattern: str, directory: str = ".") -> List[str]:
"""패턴 기반 파일 찾기"""
return glob.glob(os.path.join(directory, pattern), recursive=True)
def count_lines_in_file(self, file_path: str) -> int:
"""파일 줄 수 계산"""
try:
with open(file_path, 'r') as f:
return sum(1 for line in f)
except Exception:
return 0
6. 컨텍스트 윈도우 관리
대규모 코드베이스의 경우 컨텍스트 윈도우를 관리해야 합니다:
# context_manager.py
class ContextManager:
def __init__(self, max_tokens: int = 4096):
self.max_tokens = max_tokens
self.context = []
def add_to_context(self, content: str, role: str = "user"):
"""컨텍스트에 추가"""
self.context.append({
"role": role,
"content": content
})
def trim_context(self) -> str:
"""컨텍스트 자르기"""
current_tokens = 0
trimmed = []
# 최근 항목부터 검사
for item in reversed(self.context):
content_length = len(item["content"])
if current_tokens + content_length > self.max_tokens:
break
trimmed.append(item)
current_tokens += content_length
return list(reversed(trimmed))
def get_context_prompt(self) -> str:
"""현재 컨텍스트를 프롬프트로 반환"""
trimmed = self.trim_context()
return "\n".join([item["content"] for item in trimmed])
# 사용 예시
context = ContextManager(max_tokens=2048)
context.add_to_context("import os", "system")
context.add_to_context("def hello():\n print('hello')", "user")
prompt = context.get_context_prompt()
7. 비용/속도 최적화
로컬 vs API 모델의 최적화 전략:
python
# optimization.py
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
class ModelOptimizer:
def __init__(self
---
📥 **Get the full guide on Gumroad**: https://gumroad.com/l/auto ($5)
Top comments (0)