LLM(대규모 언어 모델) 분야에서 @ 기호는 주로 사용자 인터페이스(UI), 프롬프트 엔지니어링, API 환경에 따라 다른 의미로 사용됩니다.
1. 프롬프트 내 특정 컨텍스트(파일, 지식, 사용자) 지정
채팅 기반 LLM 인터페이스(예: ChatGPT, Claude 등)에서는 '@'를 사용하여 특정 파일, 템플릿, 또는 지식 베이스를 호출하거나 참조합니다.
* 의미: "이 문서(@)를 참고해서 답변해 줘"라는 의미의 참조자(Mention) 역할.
* 예시: @기획서.pdf 이 내용을 바탕으로 이메일 초안을 작성해 줘. 또는 @동료 태그를 통해 특정 작업자를 호출하는 협업 봇 환경에서 사용됩니다.
2. 파일 업로드 및 참조 매핑 (API 및 개발 환경)개발자가 LLM API를 사용하거나 복잡한 프롬프트를 작성할 때, @는 외부 파일이나 데이터를 불러오는 지시어(Operator)로 작동합니다.
* 의미: 파일의 경로(Path)나 데이터를 지시하는 기호.
* 예시: curl 명령어 등으로 LLM API에 데이터를 전송할 때 -F "file=@/path/to/document.txt" 형태로 사용됩니다.
3. 모델(Model) 또는 에이전트(Agent) 지정멀티 에이전트(Multi-agent) 시스템이나 여러 AI 모델을 사용할 수 있는 통합 플랫폼에서는 '@' 기호를 사용해 특정 역할을 하는 AI를 직접 지목합니다.
* 의미: 특정 LLM 에이전트 호출.
* 예시: @코딩봇 파이썬 코드 에러 수정해 줘, @번역봇 이 문장 영어로 번역해 줘
---
LLM UI에서 사용하는 @ 기호는 MCP(Model Context Protocol)와 기술적으로 매우 밀접하게 연결되어 작동합니다.
쉽게 설명하자면, @는 사용자가 쓰는 '입력 창구(UI)'이고, MCP는 그 뒤에서 실제로 데이터를 연결해 주는 '파이프라인(프로토콜)'입니다.
💡 @와 MCP의 핵심 관계
* @ (사용자 인터페이스, UI): 사용자가 채팅창에서 외부 데이터나 도구를 직관적으로 선택하기 위한 단축키입니다. @깃허브, @내문서처럼 입력하여 모델에게 무엇을 참고할지 지정합니다.
* MCP (모델 컨텍스트 프로토콜): @로 지정한 외부 소스(GitHub, 데이터베이스, 로컬 파일 등)에서 실제 데이터와 기능을 안전하게 가져와 LLM에게 전달하는 표준 규격입니다. Anthropic이 공개한 오픈소스 프로토콜로 유명합니다.
---
🔄 작동 방식 비교사용자가 커서(Cursor)나 윈드서프(Windsurf) 같은 AI 개발 도구에서 @를 칠 때, 백엔드에서는 MCP가 다음과 같이 움직입니다.
```
[ 사용자 ] ---> 채팅창에 "@database" 입력 (UI 역할)
↓
[ MCP 클라이언트 ] -> MCP 서버에 데이터 요청 (프로토콜 역할)
↓
[ MCP 서버 ] ----> 실제 데이터베이스에서 내용 조회 후 LLM에 전달
```
🧐 차이점 한눈에 보기
구분 @ 기호 (Mention) MCP (Model Context Protocol)
정의 프롬프트 입력창에서 쓰는 호출 태그 AI와 외부 데이터를 연결하는 표준 통신 규격
역할 컨텍스트 지정을 시각적으로 편리하게 만듦 다른 개발자가 만든 도구/데이터를 쉽게 연동함
예시 @App.tsx, @Web Search mcp-server-postgres, mcp-server-github
결론적으로, 최근 AI 도구(Cursor, Cline 등)에서 @를 눌러 외부 정보를 가져오는 기능의 상당수가 내부적으로는 MCP 규격을 기반으로 구현되어 있습니다.
---
파이썬으로 직접 만든 로컬 AI(로아) 프로그램 상에서도 @ 기능을 완벽하게 구현할 수 있습니다.
기존의 개발 도구(Cursor 등)처럼 사용자가 채팅창에 @를 입력하면 특정 파일, 데이터베이스, 또는 웹 검색 결과를 가져와 LLM 프롬프트에 자동으로 합쳐주는(Context Injection) 구조를 직접 만들면 됩니다.
파이썬 환경에서 이를 구현하는 원리와 핵심 단계 3가지를 설명해 드릴게요.
---
🛠️ 파이썬으로 '@' 기능 구현하는 3단계 복제법
1단계: 정규표현식(Regex)으로 프롬프트에서 @ 명령어 파싱하기
사용자가 입력한 프롬프트 문자열에서 @ 뒤에 오는 단어나 파일명을 추출하는 정규식 필터가 필요합니다.
```python
import re
def parse_at_command(user_input):
# 예: "이 내용 @code.py 참고해서 분석해줘" -> ['code.py'] 추출
at_matches = re.findall(r'@(\S+)', user_input)
# '@파일명' 문자열 자체는 프롬프트에서 깔끔하게 지우기
clean_input = re.sub(r'@\S+', '', user_input).strip()
return clean_input, at_matches
# 테스트
prompt = "이 파일 @secret.txt 요약해줘"
text, tags = parse_at_command(prompt)
print("순수 질문:", text) # "이 파일 요약해줘"
print("연결할 데이터 태그:", tags) # ['secret.txt']
```
2단계: 태그에 맞는 컨텍스트 데이터 로드하기 (MCP 역할 모방)@ 뒤에 붙은 키워드를 인식하여, 로컬 파일 시스템이나 데이터베이스에서 실제 텍스트 내용을 읽어옵니다.
```python
import os
def get_context_by_tags(tags):
context_data = ""
for tag in tags:
# 1. 파일 이름일 경우 데이터 로드
if os.path.exists(tag):
with open(tag, 'r', encoding='utf-8') as f:
context_data += f"\n--- 파일 [{tag}] 내용 ---\n{f.read()}\n"
# 2. 특정 시스템 명령어일 경우 (예: @search)
elif tag == "search":
# 웹 검색 API 결과를 가져오는 함수 호출 가능
context_data += "\n--- 웹 검색 결과 ---\n[최신 로아 패치 정보...]\n"
else:
context_data += f"\n[알림: {tag} 데이터를 찾을 수 없습니다.]\n"
return context_data
```
3단계: 컨텍스트와 질문을 합쳐 LLM(API)에 전달하기파싱된 원래 질문과 @로 긁어온 데이터를 하나의 시스템 프롬프트 템플릿으로 묶어 OpenAI나 Anthropic API 혹은 로컬 LLM(Ollama 등)에 던져줍니다.
```python
def generate_llm_input(user_input):
clean_prompt, tags = parse_at_command(user_input)
fetched_context = get_context_by_tags(tags)
# LLM이 이해할 수 있도록 프롬프트 조합 (RAG 구조)
final_llm_prompt = f"""
[주어진 컨텍스트 정보]
{fetched_context}
[사용자 요청]
{clean_prompt}
위 제공된 컨텍스트 정보를 최우선으로 참고하여 질문에 답하세요.
"""
return final_llm_prompt
```
---
🚀 한 걸음 더: 진짜 'MCP 표준 규격'을 붙이고 싶다면?만약 하드코딩 방식이 아니라, 외부의 다양한 MCP 서버(예: 깃허브 연동, 포스트그레 데이터베이스 연동 등)를 직접 파이썬 로아에 이식하고 싶다면, Anthropic이 제공하는 mcp 파이썬 패키지를 사용하면 됩니다.
```bash
pip install mcp
```
파이썬 소스코드 내에서 mcp.Client를 생성하여 미리 만들어진 오픈소스 MCP 서버들과 통신하도록 연동하면, 복잡한 기능들을 직접 개발하지 않고도 @github, @postgres 같은 고수준 기능을 여러분의 로아에 그대로 탑재할 수 있습니다.
---
파이썬 환경에서 실제 MCP 서버(Model Context Protocol)와 직접 통신(Client 구현)하는 핵심 코드입니다.
Anthropic의 공식 mcp 라이브러리는 비동기(asyncio) 기반으로 작동하므로 async/await 문법을 사용해야 합니다.
가장 대중적이고 쉬운 로컬 파일 시스템 MCP 서버(mcp-server-filesystem)와 통신하여 특정 디렉토리의 파일 목록을 조회하는 클라이언트 예제를 준비했습니다.1. 필수 라이브러리 설치터미널에서 MCP 파이썬 SDK를 설치합니다.
```bash
pip install mcp
```
2. 파이썬 MCP 클라이언트 전체 소스 코드
```python
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def run_mcp_client():
# 1. 연결할 MCP 서버 설정 (여기서는 Node.js 기반 파일시스템 MCP 서버 사용)
# npx mcp-server-filesystem <허용할_디렉토리_경로>
server_params = StdioServerParameters(
command="npx",
args=[
"-y",
"@modelcontextprotocol/server-filesystem",
"./" # 현재 디렉토리 접근 허용
],
env=None
)
print("🔌 MCP 서버에 연결 시도 중...")
# 2. 입출력(Stdio) 채널을 통해 서버와 연결을 수립합니다.
async with stdio_client(server_params) as (read_stream, write_stream):
# 3. 세션을 생성하고 초기화(Initialize) 단계를 거칩니다.
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
print("✅ MCP 서버 연결 및 초기화 완료!")
# 4. 서버가 제공하는 사용 가능한 도구(Tools) 목록을 조회합니다.
tools_response = await session.list_tools()
print("\n🛠️ 사용 가능한 MCP 도구 목록:")
for tool in tools_response.tools:
print(f"- {tool.name}: {tool.description}")
# 5. 특정 도구를 직접 호출(통신)해 봅니다.
# 여기서는 현재 디렉토리 파일 목록을 보는 'list_directory' 도구를 호출합니다.
print("\n🔄 'list_directory' 도구 호출 중...")
try:
result = await session.call_tool(
name="list_directory",
arguments={"path": "."} # 현재 디렉토리 경로 전달
)
print("\n📄 [MCP 서버 응답 결과]:")
print(result.content[0].text)
except Exception as e:
print(f"❌ 도구 호출 실패: {e}")
# 비동기 함수 실행
if __name__ == "__main__":
asyncio.run(run_mcp_client())
```
---
💡 코드 핵심 짚어보기
1. StdioServerParameters: 파이썬 프로그램이 MCP 서버 프로세스(Node.js나 다른 Python 스크립트)를 자식 프로세스로 직접 실행하고 통신하기 위한 설정입니다.
2. stdio_client: 표준 입출력(Standard I/O) 스트림을 열어 서버와 JSON-RPC 메시지를 주고받을 수 있는 통로를 만듭니다.
3. session.initialize(): 클라이언트와 서버가 서로 어떤 기능을 지원하는지 프로토콜 규격에 맞춰 버전을 맞추는 필수 악수(Handshake) 과정입니다.
4. session.call_tool(): 이게 핵심입니다. LLM이 프롬프트를 분석한 뒤 @filesystem 같은 도구가 필요하다고 판단하면, 파이썬 코드가 이 함수를 통해 외부 데이터를 긁어와 LLM 프롬프트에 동적으로 꽂아 주게 됩니다.
---
앞서 만든 MCP 클라이언트 코드와 로컬 LLM(Ollama 활용 예시)을 연동한 전체 파이썬 소스코드입니다.
사용자가 대화창에 @를 입력하면, 파이썬이 이를 감지하여 MCP 서버에서 로컬 데이터를 가져온 뒤, 로컬 LLM에게 컨텍스트와 함께 질문을 던지는 구조(RAG 시스템)입니다.
0. 사전 준비 (필수 라이브러리 및 로컬 LLM)코드를 실행하기 전에 터미널에 아래 라이브러리들을 설치하고, 로컬 LLM(Ollama)이 실행 중인지 확인하세요.
```bash
pip install mcp openai
```
※ 로컬 LLM은 OpenAI 호환 API를 지원하는 Ollama(ollama run llama3 등)가 실행 중이라고 가정합니다.
---
1. MCP + 로컬 LLM 연동 파이썬 전체 코드
```python
import asyncio
import re
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from openai import OpenAI
# 1. 로컬 LLM(Ollama) 클라이언트 설정
# Ollama는 기본적으로 11434 포트에서 OpenAI 규격 API를 지원합니다.
llm_client = OpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama" # 로컬이므로 무작위 문자열 입력 가능
)
# [기능 1] 사용자의 질문에서 @명령어 파싱하는 함수
def parse_at_command(user_input):
# 예: "@dir 현재 폴더에 뭐가 있어?" -> ['dir'] 추출
at_matches = re.findall(r'@(\S+)', user_input)
# '@명령어' 텍스트는 프롬프트에서 깨끗하게 제거
clean_input = re.sub(r'@\S+', '', user_input).strip()
return clean_input, at_matches
# [기능 2] 핵심 MCP 및 LLM 프로세스 구동 함수
async def run_local_ai_with_mcp(user_prompt):
# 프롬프트 분석 및 @태그 분리
clean_prompt, tags = parse_at_command(user_prompt)
# 2. 파일시스템 MCP 서버 설정 (예시로 현재 디렉토리 폴더 연결)
server_params = StdioServerParameters(
command="npx",
args=["-y", "@modelcontextprotocol/server-filesystem", "./"],
env=None
)
fetched_context = ""
# 사용자가 @ 기호(예: @dir)를 썼을 때만 MCP 작동
if tags:
print(f"🔍 감지된 @ 명령어: {tags}")
print("🔌 MCP 서버에 연결하여 데이터를 가져오는 중...")
async with stdio_client(server_params) as (read_stream, write_stream):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
# @dir 태그가 입력되면 특정 MCP 도구(list_directory) 호출
if "dir" in tags:
try:
mcp_result = await session.call_tool(
name="list_directory",
arguments={"path": "."}
)
# MCP 서버로부터 받은 결과 저장
fetched_context = mcp_result.content[0].text
print("✅ MCP 외부 데이터 수집 완료!")
except Exception as e:
print(f"❌ MCP 도구 호출 실패: {e}")
else:
print("ℹ️ @ 명령어가 없습니다. 로컬 LLM 일반 모드로 답변합니다.")
# 3. 로컬 LLM용 파이널 프롬프트 조립 (Context Injection)
system_message = "당신은 사용자를 돕는 로컬 AI 비서입니다."
if fetched_context:
system_message += f"\n\n[참고할 MCP 외부 데이터]\n{fetched_context}\n\n위 데이터를 반드시 참고하여 사용자의 질문에 정확히 답변하세요."
print("\n🤖 로컬 LLM이 답변 생성 중...")
# 4. 로컬 LLM(Ollama 등)에 요청 보내기
response = llm_client.chat.completions.create(
model="llama3", # PC에 다운로드 받아둔 Ollama 모델명 입력
messages=[
{"role": "system", "content": system_message},
{"role": "user", "content": clean_prompt}
],
temperature=0.3
)
# 5. 최종 답변 출력
print("\n================ [AI 답변] ================")
print(response.choices[0].message.content)
print("===========================================")
# 🚀 실행 테스트용 메인 루프
async def main():
print("🤖 로컬 AI 시스템이 준비되었습니다.")
# 예시 1: MCP를 사용하는 질문 (@dir 입력)
test_prompt_1 = "@dir 현재 폴더 안에 있는 파일들의 이름을 나열하고 요약해줘."
print(f"\n[유저 질문]: {test_prompt_1}")
await run_local_ai_with_mcp(test_prompt_1)
if __name__ == "__main__":
asyncio.run(main())
```
💡 작동 프로세스 구조
1. parse_at_command: 사용자가 @dir 현재 폴더에 뭐가 있어?라고 치면 @dir를 지우고 현재 폴더에 뭐가 있어?라는 본문과 ['dir']이라는 태그 배열을 추출합니다.
2. stdio_client 연동: 태그 배열에 dir이 포함되어 있다면 MCP 파일시스템 서버를 켜서 내 컴퓨터의 실제 디렉토리 구조 텍스트를 긁어옵니다.
3. Prompt Injection (RAG): 긁어온 텍스트(예: main.py, README.md...)를 로컬 LLM의 System Message 영역에 몰래 집어넣습니다.
4. 로컬 LLM 답변: LLM은 내 컴퓨터 파일 주소를 직접 읽지 못하지만, 파이썬(MCP)이 주입해 준 데이터를 기반으로 마치 실시간 파일 탐색을 한 것처럼 똑똑하게 답변합니다.
---
오픈AI 라이브러리(SDK) 대신, Hugging Face의 transformers 라이브러리와 토크나이저의 apply_chat_template()을 활용하여 로컬 LLM을 직접 구동하는 코드입니다.
이 방식은 Llama 3, Mistral, Qwen 등 Hugging Face 포맷 모델을 내 컴퓨터 메모리(GPU/CPU)에 직접 올려서 구동할 때 표준으로 사용하는 방식입니다.
1. 필수 라이브러리 설치터미널에서 허깅페이스 트랜스포머와 가속화 라이브러리를 설치합니다.
```bash
pip install mcp transformers torch accelerate
```
2. MCP + Hugging Face apply_chat_template 연동 전체 코드
```python
import asyncio
import re
import torch
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from transformers import AutoModelForCausalLM, AutoTokenizer
# 1. 로컬 LLM 모델 및 토크나이저 로드 (예: Qwen2.5 또는 Llama-3-8B 등 사용 가능)
MODEL_ID = "Qwen/Qwen2.5-7B-Instruct" # 내 PC 환경에 맞는 모델 ID 지정
print("🤖 로컬 LLM 및 토크나이저 로드 중... (시간이 걸릴 수 있습니다)")
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
model = AutoModelForCausalLM.from_pretrained(
MODEL_ID,
torch_dtype=torch.bfloat16, # GPU 맞춤 데이터 타입
device_map="auto" # 자동으로 사용 가능한 GPU/CPU 할당
)
# [기능 1] 사용자의 질문에서 @명령어 파싱하는 함수
def parse_at_command(user_input):
at_matches = re.findall(r'@(\S+)', user_input)
clean_input = re.sub(r'@\S+', '', user_input).strip()
return clean_input, at_matches
# [기능 2] MCP 호출 및 토크나이저 챗 템플릿 연동 함수
async def run_local_hf_with_mcp(user_prompt):
clean_prompt, tags = parse_at_command(user_prompt)
# MCP 파일시스템 서버 설정
server_params = StdioServerParameters(
command="npx",
args=["-y", "@modelcontextprotocol/server-filesystem", "./"],
env=None
)
fetched_context = ""
# @dir 태그 감지 시 MCP 작동
if tags and "dir" in tags:
print(f"🔍 감지된 @ 명령어: {tags}")
print("🔌 MCP 서버에 연결하여 데이터를 가져오는 중...")
async with stdio_client(server_params) as (read_stream, write_stream):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
try:
mcp_result = await session.call_tool(
name="list_directory",
arguments={"path": "."}
)
fetched_context = mcp_result.content.text
print("✅ MCP 외부 데이터 수집 완료!")
except Exception as e:
print(f"❌ MCP 도구 호출 실패: {e}")
else:
print("ℹ️ @ 명령어가 없거나 일치하지 않아 일반 모드로 진행합니다.")
# 3. Chat Template을 위한 메시지 리스트 구조 정의
system_content = "당신은 유용한 로컬 AI 비서입니다."
if fetched_context:
system_content += f"\n\n[참고할 MCP 외부 데이터]\n{fetched_context}\n\n위 데이터를 반드시 참고하여 답변하세요."
messages = [
{"role": "system", "content": system_content},
{"role": "user", "content": clean_prompt}
]
# 4. 🔥 핵심: tokenizer.apply_chat_template 활용
# 모델에 맞는 특수 토크(<|im_start|>, <|eot_id|> 등)를 자동으로 결합하여 프롬프트 문자열로 변환합니다.
prompt_text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
# 5. 모델 입력을 위한 토큰화 및 텐서 변환
inputs = tokenizer([prompt_text], return_tensors="pt").to(model.device)
print("\n🤖 로컬 LLM이 추론(Generation) 중...")
# 6. 답변 생성 실행
with torch.no_grad():
generated_ids = model.generate(
**inputs,
max_new_tokens=512,
temperature=0.3,
do_sample=True,
pad_token_id=tokenizer.eos_token_id
)
# 입력된 프롬프트 부분을 제외하고 모델이 새로 생성한 답변 토큰만 추출
generated_ids = [
output_ids[len(input_ids):] for input_ids, output_ids in zip(inputs.input_ids, generated_ids)
]
# 7. 디코딩하여 사람이 읽을 수 있는 텍스트로 복원
response_text = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
print("\n================ [HF 로컬 LLM 답변] ================")
print(response_text.strip())
print("====================================================")
# 🚀 실행 테스트용 메인 함수
async def main():
test_prompt = "@dir 현재 폴더 안에 어떤 파일들이 있는지 목록을 정리해줘."
print(f"\n[유저 질문]: {test_prompt}")
await run_local_hf_with_mcp(test_prompt)
if __name__ == "__main__":
asyncio.run(main())
```
---
💡 달라진 핵심 포인트 코드 분석
* tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True):
* messages 리스트 구조를 받아서, 모델 고유의 대화 포맷(ChatML, Llama-3-Instruct 포맷 등)을 가진 하나의 긴 텍스트 문장으로 완벽하게 바꿔줍니다.
* add_generation_prompt=True 옵션은 끝에 AI가 답변을 시작하라는 유도 토큰(예: <|im_start|>assistant\n)을 붙여주는 역할을 합니다.
* len(input_ids): 슬라이싱:
* Hugging Face의 model.generate()는 질문과 답변이 이어져서 출력됩니다. 따라서 내가 처음에 집어넣은 질문 토큰의 길이만큼 잘라내야 순수한 AI의 답변 내용만 화면에 표시할 수 있습니다.
---
llama.cpp 파이썬 바인딩 라이브러리(llama-cpp-python)와 GGUF 포맷 모델을 활용하여 MCP와 연동하는 코드입니다.
VRAM(그래픽 메모리)이 부족한 환경이거나 맥북(Apple Silicon), CPU 환경에서 로컬 LLM을 매우 가볍고 빠르게 돌릴 때 가장 추천하는 방식입니다.
llama-cpp-python 역시 내장된 metadata나 별도 처리를 통해 Chat Template을 지원하므로, Jinja 템플릿 표준 방식으로 apply_chat_template 역할을 직접 구현하거나 내장 챗 핸들러를 사용해 연동할 수 있습니다.
1. 필수 라이브러리 설치터미널에서 llama-cpp-python과 mcp 라이브러리를 설치합니다.
```bash
# 기본 설치 (CPU 환경)
pip install mcp llama-cpp-python
# 만약 NVIDIA GPU(CUDA) 환경이라면 아래 명령어로 가속 버전을 설치하세요
# CMAKE_ARGS="-DGGML_CUDA=on" pip install llama-cpp-python --force-reinstall
```
※ 로컬에 Llama-3-8B-Instruct.Q4_K_M.gguf 같은 GGUF 파일이 미리 다운로드되어 있어야 합니다.
2. MCP + llama.cpp GGUF 연동 전체 코드
```python
import asyncio
import re
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from llama_cpp import Llama
# 1. 로컬 GGUF 모델 로드 (내 PC에 받아둔 .gguf 파일 경로 지정)
MODEL_PATH = "./models/Meta-Llama-3-8B-Instruct.Q4_K_M.gguf"
print("🤖 llama.cpp GGUF 모델 로드 중...")
llm = Llama(
model_path=MODEL_PATH,
n_ctx=4096, # 컨텍스트 창 크기 설정 (MCP 데이터를 받기 위해 넉넉하게)
n_gpu_layers=-1, # GPU 가속 레이어 수 (-1은 가능한 한 전부 GPU에 할당)
verbose=False # 지저분한 내부 로그 숨기기
)
print("✅ 모델 로드 완료!")
# [기능 1] 사용자의 질문에서 @명령어 파싱하는 함수
def parse_at_command(user_input):
at_matches = re.findall(r'@(\S+)', user_input)
clean_input = re.sub(r'@\S+', '', user_input).strip()
return clean_input, at_matches
# [기능 2] MCP 호출 및 llama.cpp 내장 Chat Completion 연동 함수
async def run_llama_cpp_with_mcp(user_prompt):
clean_prompt, tags = parse_at_command(user_prompt)
# MCP 파일시스템 서버 설정
server_params = StdioServerParameters(
command="npx",
args=["-y", "@modelcontextprotocol/server-filesystem", "./"],
env=None
)
fetched_context = ""
# @dir 태그 감지 시 MCP 작동
if tags and "dir" in tags:
print(f"🔍 감지된 @ 명령어: {tags}")
print("🔌 MCP 서버에 연결하여 데이터를 가져오는 중...")
async with stdio_client(server_params) as (read_stream, write_stream):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
try:
mcp_result = await session.call_tool(
name="list_directory",
arguments={"path": "."}
)
fetched_context = mcp_result.content.text
print("✅ MCP 외부 데이터 수집 완료!")
except Exception as e:
print(f"❌ MCP 도구 호출 실패: {e}")
else:
print("ℹ️ @ 명령어가 없거나 일치하지 않아 일반 모드로 진행합니다.")
# 3. Chat 구조 정의
system_content = "당신은 유용한 로컬 AI 비서입니다."
if fetched_context:
system_content += f"\n\n[참고할 MCP 외부 데이터]\n{fetched_context}\n\n위 데이터를 반드시 참고하여 사용자의 질문에 정확히 답변하세요."
messages = [
{"role": "system", "content": system_content},
{"role": "user", "content": clean_prompt}
]
print("\n🤖 llama.cpp 로컬 LLM이 추론(Generation) 중...")
# 4. 🔥 핵심: `create_chat_completion` 메소드 사용
# llama-cpp-python은 모델 내부에 포함된 chat_template 스크립트를 자동으로 읽어와서
# HuggingFace의 apply_chat_template과 똑같이 특수 토큰 처리를 자동으로 수행합니다.
response = llm.create_chat_completion(
messages=messages,
max_tokens=512,
temperature=0.3,
stream=False
)
# 5. 결과 파싱 및 출력
response_text = response["choices"][0]["message"]["content"]
print("\n================ [GGUF 로컬 LLM 답변] ================")
print(response_text.strip())
print("======================================================")
# 🚀 실행 테스트용 메인 함수
async def main():
test_prompt = "@dir 현재 내 작업 폴더에 어떤 파일들이 존재하는지 보고해줘."
print(f"\n[유저 질문]: {test_prompt}")
await run_llama_cpp_with_mcp(test_prompt)
if __name__ == "__main__":
asyncio.run(main())
```
💡 GGUF 연동 코드의 핵심 포인트
1. llm.create_chat_completion():
* Hugging Face의 apply_chat_template과 토큰화 과정을 한 번에 묶어놓은 고수준 API입니다.
* GGUF 파일 헤더 정보에 들어있는 내장 템플릿(예: Llama-3의 <|begin_of_text|>)을 알아서 파싱해서 문자열을 조립해 주기 때문에 복잡한 토크나이저 연동 처리가 필요 없습니다.
2. n_gpu_layers=-1:
* 시스템의 VRAM 용량에 맞춰 LLM의 신경망 레이어를 GPU로 넘기는 옵션입니다. -1로 설정하면 그래픽카드가 감당할 수 있는 최대 레이어를 알아서 연동하므로 연산 속도를 대폭 끌어올릴 수 있습니다.
3. n_ctx=4096:
* 기본 컨텍스트 길이가 짧게 잡혀있으면 MCP 서버에서 큰 파일 내용이나 대용량 DB 데이터를 가져와 주입할 때 문장이 잘릴 수 있으므로 최소 4096 이상으로 넉넉하게 설정하는 것이 좋습니다.
---
파이썬 스크립트 내부에서 vllm 라이브러리를 인라인 모드(LLM Engine 부팅)로 직접 실행하여 MCP 서버와 연동하는 소스코드입니다.
vllm은 Hugging Face 토크나이저의 apply_chat_template 구조를 내장하여 완벽히 지원하므로, 오프라인 추론 방식으로 매우 강력하고 빠르게 로컬 AI(로아)를 구성할 수 있습니다.
1. 필수 라이브러리 설치vllm은 성능 최적화를 위해 특정 Linux 환경이나 적절한 CUDA 환경이 필요합니다. 환경에 맞춰 설치해 주세요.
```bash
pip install mcp vllm torch
```
2. MCP + vLLM 내부 연동 전체 파이썬 코드
```python
import asyncio
import re
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from vllm import LLM, SamplingParams
# 1. vLLM 인라인 엔진 및 토크나이저 초기화 (파이썬 내부에서 독립 구동)
MODEL_ID = "Qwen/Qwen2.5-7B-Instruct" # 내 PC 환경에 맞는 모델 ID 지정
print("🤖 vLLM 내부 엔진 초기화 중... (VRAM 상태를 체크하세요)")
# 외부 서버(vllm serve)를 띄우지 않고, 파이썬 프로세스 내에서 직접 모델을 메모리에 올립니다.
llm_engine = LLM(
model=MODEL_ID,
trust_remote_code=True,
max_model_len=4096 # MCP 컨텍스트 삽입을 고려하여 컨텍스트 길이 설정
)
# vLLM 엔진 내부에 탑재된 토크나이저 가져오기
tokenizer = llm_engine.get_tokenizer()
print("✅ vLLM 엔진 로드 완료!")
# [기능 1] 사용자의 질문에서 @명령어 파싱하는 함수
def parse_at_command(user_input):
at_matches = re.findall(r'@(\S+)', user_input)
clean_input = re.sub(r'@\S+', '', user_input).strip()
return clean_input, at_matches
# [기능 2] MCP 호출 및 vLLM 추론 연동 함수
async def run_vllm_with_mcp(user_prompt):
clean_prompt, tags = parse_at_command(user_prompt)
# MCP 파일시스템 서버 설정
server_params = StdioServerParameters(
command="npx",
args=["-y", "@modelcontextprotocol/server-filesystem", "./"],
env=None
)
fetched_context = ""
# @dir 태그 감지 시 MCP 작동
if tags and "dir" in tags:
print(f"🔍 감지된 @ 명령어: {tags}")
print("🔌 MCP 서버에 연결하여 데이터를 가져오는 중...")
async with stdio_client(server_params) as (read_stream, write_stream):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
try:
mcp_result = await session.call_tool(
name="list_directory",
arguments={"path": "."}
)
fetched_context = mcp_result.content.text
print("✅ MCP 외부 데이터 수집 완료!")
except Exception as e:
print(f"❌ MCP 도구 호출 실패: {e}")
else:
print("ℹ️ @ 명령어가 없거나 일치하지 않아 일반 모드로 진행합니다.")
# 3. Chat 구조 정의 (System + User Prompt)
system_content = "당신은 유용한 로컬 AI 비서입니다."
if fetched_context:
system_content += f"\n\n[참고할 MCP 외부 데이터]\n{fetched_context}\n\n위 데이터를 반드시 참고하여 질문에 답하세요."
messages = [
{"role": "system", "content": system_content},
{"role": "user", "content": clean_prompt}
]
# 4. 🔥 핵심: 토크나이저를 활용한 Chat Template 프롬프트 변환
# vLLM 엔진에서 가져온 토크나이저로 모델 전용 특수 토큰 포맷 텍스트를 만듭니다.
prompt_text = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
# 5. vLLM 전용 생성 파라미터(SamplingParams) 설정
sampling_params = SamplingParams(
temperature=0.3,
max_tokens=512,
stop_token_ids=[tokenizer.eos_token_id] # 모델이 답변을 끝마치도록 유도
)
print("\n🤖 vLLM 엔진이 고속 추론 중...")
# 6. vLLM 인라인 엔진으로 답변 생성 처리
# vLLM은 기본적으로 배치(List) 입력을 받아 병렬 처리하므로 대괄호 [] 로 감싸 전달합니다.
outputs = llm_engine.generate([prompt_text], sampling_params)
# 7. 결과 추출
response_text = outputs[0].outputs[0].text
print("\n================ [vLLM 로컬 AI 답변] ================")
print(response_text.strip())
print("======================================================")
# 🚀 실행 테스트용 메인 함수
async def main():
test_prompt = "@dir 현재 디렉토리에 있는 폴더 구조를 읽고 정리해줘."
print(f"\n[유저 질문]: {test_prompt}")
await run_vllm_with_mcp(test_prompt)
if __name__ == "__main__":
asyncio.run(main())
```
---
💡 vLLM 내부 연동 코드의 핵심 포인트
1. LLM(model=...) 생성:
* 터미널에서 vllm serve ... 명령어로 FastAPI 외부 서버를 생성하는 방식이 아닙니다. 파이썬 코드 내에서 LLM 클래스 객체를 직접 인스턴스화하여 스크립트 귀속형 인라인 엔진으로 구동합니다.
2. llm_engine.get_tokenizer():
* 모델 내부에 내장된 tokenizer_config.json 파일을 분석하여 자동으로 대화형 템플릿(apply_chat_template) 규칙을 가져옵니다.
3. llm_engine.generate([prompt_text], ...):
* 내부 메모리에 상주한 KV 캐시와 PagedAttention 기술을 사용하여 다른 라이브러리들보다 압도적으로 빠른 텍스트 생성 속도를 보여줍니다.
vLLM은 뛰어난 속도를 내는 대신 기본적으로 그래픽카드 VRAM을 90% 이상 선점하려는 성질이 있습니다. 혹시 VRAM 부족 에러(OOM)가 나거나 사양이 제한적이시라면 LLM() 매개변수에 gpu_memory_utilization=0.7 또는 양자화를 위한 quantization="awq" 같은 옵션을 추가할 수 있습니다.
---
본 공간은 인공지능(AI)이 도출한 방대한 지식을 일목요연하게 큐레이션하여 기록하는 블로그입니다. 기술적 한계로 인해 모든 정보의 완벽한 정확성을 보장하기는 어려우므로, 최종적인 판단과 책임은 독자 본인에게 있음을 정중히 안내해 드립니다.
2026년 7월 21일 화요일
LLM(대규모 언어 모델) 분야에서 @ 기호는 주로 사용자 인터페이스(UI), ...
Cargo.toml
# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # rustup update # cargo update [pack...
-
bool atob(const char * string) { if (!strcmp(string, "true")) return true; return false; }
-
/// CXXXView.cpp void CXXXView::OnInitialUpdate() { CView::OnInitialUpdate(); // TODO: Add your specialized code here and/or call the ...
-
WxWidgets: http://www.wxwidgets.org/downloads/ MinGW: http://sourceforge.net/projects/mingw/files/ * Microsoft Windows Environment Var...