4편 전체 목차
AI 자동화 아키텍처 설계 전략
AI 자동화는 단순히 “챗봇 만들기”가 아닙니다. 실제 운영 환경에서는 여러 도구를 조합해 사람이 개입하지 않아도 복잡한 작업을 완수하는 자율 시스템을 구축해야 합니다. 먼저 자동화 수준에 따라 올바른 도구를 선택하는 것이 중요합니다.
🗺️ 자동화 레이어별 도구 선택 매트릭스
| 자동화 수준 | 도구 | 특징 | 추천 대상 |
|---|---|---|---|
| L1. 노코드 자동화 | n8n | 드래그 앤 드롭, 500+ 통합, 빠른 구축 | 비개발자, 반복 업무 자동화 |
| L2. AI 앱 빌더 | Dify | RAG + 에이전트 + API 서버 올인원 | AI 서비스 내부 배포 |
| L3. 도구 프로토콜 | MCP | AI가 외부 도구를 표준화된 방식으로 호출 | Claude Desktop 고급 활용 |
| L4. 코드 에이전트 | LangChain/LangGraph | 완전한 프로그래밍 제어, 복잡한 로직 | Python 개발자 |
| L5. 멀티 에이전트 | AutoGen/CrewAI | 여러 AI가 협업해 복잡한 문제 해결 | 연구, 복잡한 업무 자동화 |
- 일상 업무 자동화 — n8n + Ollama + Open WebUI (슬랙 알림, 이메일 요약, 일정 관리)
- RAG 기반 AI 서비스 — Dify + Qdrant + nomic-embed-text (사내 지식 검색 봇)
- Claude Desktop 고급 에이전트 — MCP 커스텀 서버 + n8n API (로컬 파일 조작, DB 쿼리)
- 복잡한 리서치 에이전트 — LangGraph + Ollama + 웹 검색 + Qdrant RAG
- 자율 코딩 에이전트 — AutoGen + Ollama + Code Executor (자동 코드 작성·테스트·수정)
n8n — AI 워크플로우 자동화 완전 정복
n8n은 500개 이상의 앱과 통합되는 오픈소스 자동화 플랫폼입니다. AI 서버와 결합하면 슬랙 메시지가 오면 Ollama가 요약하고, 새 이메일이 도착하면 AI가 분류해 자동 응답하는 등의 인텔리전트 자동화가 가능합니다.
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n
restart: unless-stopped
ports:
- "5678:5678"
environment:
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=admin
- N8N_BASIC_AUTH_PASSWORD=your_secure_password_here
- GENERIC_TIMEZONE=Asia/Seoul
- N8N_HOST=n8n.yourdomain.com # Cloudflare 도메인
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://n8n.yourdomain.com
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=n8n_password
volumes:
- n8n_data:/home/node/.n8n
depends_on:
- postgres
networks:
- ai_net
postgres:
image: postgres:16-alpine
container_name: n8n_postgres
restart: unless-stopped
environment:
- POSTGRES_DB=n8n
- POSTGRES_USER=n8n
- POSTGRES_PASSWORD=n8n_password
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- ai_net
volumes:
n8n_data:
postgres_data:
networks:
ai_net:
external: true
name: ai_network🔗 n8n + Ollama 연동 설정
http://ollama:11434⚡ 실전 n8n AI 워크플로우 6종
| 워크플로우 | 트리거 | AI 처리 | 출력 |
|---|---|---|---|
| 이메일 AI 비서 | 새 Gmail 수신 | Ollama로 내용 분류·요약·초안 작성 | Slack 알림 + 초안 저장 |
| 블로그 자동 포스팅 | RSS 피드 변경 | 기사 요약 + 한국어 번역 + SEO 최적화 | WordPress 자동 발행 |
| 회의록 자동 정리 | 파일 업로드 웹훅 | Whisper 음성인식 + AI 요약 + 액션 아이템 추출 | Notion/Confluence 저장 |
| 소셜미디어 콘텐츠 | 매일 오전 9시 Cron | 트렌드 분석 + 콘텐츠 생성 + 이미지 생성(A1111) | Buffer/Hootsuite 예약 등록 |
| 고객 문의 자동 분류 | Webhook (폼 제출) | AI 카테고리 분류 + 감정 분석 + 자동 응답 생성 | 담당자 배정 + 메일 발송 |
| 코드 리뷰 봇 | GitHub PR 이벤트 | 코드 분석 + 개선 제안 + 버그 탐지 | GitHub 코멘트 자동 게시 |
// n8n Code 노드에서 Ollama API 직접 호출
const response = await $http.request({
method: 'POST',
url: 'http://ollama:11434/api/generate',
headers: { 'Content-Type': 'application/json' },
body: {
model: 'qwen2.5:14b',
prompt: `다음 이메일을 한국어로 요약하고 중요도를 High/Medium/Low로 분류해줘:\n\n${$json.emailBody}`,
stream: false,
options: {
temperature: 0.3,
num_predict: 500
}
}
});
return {
summary: response.response,
originalEmail: $json.emailBody,
processedAt: new Date().toISOString()
};Dify — 프라이빗 AI 앱 빌더 완전 구축
Dify는 RAG, 에이전트, 채팅봇, 워크플로우를 노코드로 구성할 수 있는 오픈소스 AI 앱 빌더입니다. 완성된 앱은 REST API나 웹 인터페이스로 즉시 배포됩니다. Ollama와 연동하면 완전한 프라이빗 환경에서 ChatGPT급 AI 서비스를 구축할 수 있습니다.
# Dify 공식 docker-compose 클론 cd ~/ai-server/automation git clone https://github.com/langgenius/dify.git cd dify/docker # 환경 설정 cp .env.example .env # 핵심 환경변수 수정 (.env 파일) sed -i "s/SECRET_KEY=.*/SECRET_KEY=$(openssl rand -hex 32)/" .env sed -i "s/CONSOLE_API_URL=.*/CONSOLE_API_URL=https:\/\/dify.yourdomain.com/" .env # 실행 (포트 3001에서 서비스) docker compose up -d # 초기 관리자 계정 생성 (최초 1회) docker compose exec api flask db upgrade docker compose exec api flask reset-email-and-password
🤖 Dify + Ollama 연동 설정
http://ollama:11434 → 연결 테스트 → 모델 목록 자동 로드- 사내 지식 검색봇 — 사내 문서 Knowledge Base → 직원이 질문하면 정확한 문서 위치와 내용 제공
- 고객 지원 챗봇 — 제품 매뉴얼 + FAQ Knowledge Base → 24시간 자동 고객 응대
- 코드 리뷰 에이전트 — Agent 앱 + GitHub 도구 → 코드 분석 + 개선안 자동 제시
- 데이터 분석 워크플로우 — Workflow 앱 → CSV 입력 → AI 분석 → 리포트 생성 → 이메일 발송
MCP 서버 — AI 에이전트 도구 생태계 구축
MCP(Model Context Protocol)는 Anthropic이 설계한 AI 에이전트 표준 프로토콜입니다. AI가 파일 시스템 접근, 데이터베이스 쿼리, API 호출, 코드 실행 등의 외부 도구를 표준화된 방식으로 사용할 수 있게 합니다. Claude Desktop과 완벽하게 통합되며 커스텀 서버를 직접 개발해 AI 서버의 모든 기능을 도구로 노출할 수 있습니다.
🔧 커스텀 MCP 서버 개발 (n8n 연동)
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import httpx
import asyncio
app = Server("ai-server-mcp")
N8N_BASE_URL = "http://192.168.1.253:5678"
OLLAMA_URL = "http://192.168.1.253:11434"
@app.list_tools()
async def list_tools() -> list[types.Tool]:
return [
types.Tool(
name="generate_image",
description="AI 이미지 생성 (ComfyUI/A1111 사용)",
inputSchema={
"type": "object",
"properties": {
"prompt": {"type": "string", "description": "이미지 생성 프롬프트"},
"width": {"type": "integer", "default": 1024},
"height": {"type": "integer", "default": 1024},
},
"required": ["prompt"]
}
),
types.Tool(
name="trigger_n8n_workflow",
description="n8n 워크플로우 트리거",
inputSchema={
"type": "object",
"properties": {
"workflow_id": {"type": "string"},
"data": {"type": "object"}
},
"required": ["workflow_id"]
}
),
types.Tool(
name="query_ollama",
description="로컬 Ollama LLM에 직접 질문",
inputSchema={
"type": "object",
"properties": {
"model": {"type": "string", "default": "qwen2.5:14b"},
"prompt": {"type": "string"}
},
"required": ["prompt"]
}
),
]
@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
async with httpx.AsyncClient(timeout=120) as client:
if name == "generate_image":
resp = await client.post(
"http://192.168.1.253:7860/sdapi/v1/txt2img",
json={
"prompt": arguments["prompt"],
"width": arguments.get("width", 1024),
"height": arguments.get("height", 1024),
"steps": 20,
}
)
return [types.TextContent(type="text",
text=f"이미지 생성 완료. 결과: {resp.json()['images'][0][:50]}...")]
elif name == "trigger_n8n_workflow":
resp = await client.post(
f"{N8N_BASE_URL}/webhook/{arguments['workflow_id']}",
json=arguments.get("data", {})
)
return [types.TextContent(type="text",
text=f"워크플로우 실행: {resp.status_code} - {resp.text[:200]}")]
elif name == "query_ollama":
resp = await client.post(
f"{OLLAMA_URL}/api/generate",
json={
"model": arguments.get("model", "qwen2.5:14b"),
"prompt": arguments["prompt"],
"stream": False
}
)
return [types.TextContent(type="text",
text=resp.json()["response"])]
async def main():
async with stdio_server() as streams:
await app.run(*streams, app.create_initialization_options())
if __name__ == "__main__":
asyncio.run(main())⚙️ Claude Desktop config.json 설정
{
"mcpServers": {
"ai-server": {
"command": "python",
"args": ["/path/to/ai_server_mcp.py"],
"env": {
"AI_SERVER_IP": "192.168.1.253"
}
},
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem",
"/Volumes/data", "/Volumes/storage"]
},
"n8n": {
"command": "npx",
"args": ["-y", "n8n-mcp"],
"env": {
"N8N_API_URL": "http://192.168.1.253:5678",
"N8N_API_KEY": "your_n8n_api_key"
}
}
}
}LangChain & LangGraph — 코드 기반 AI 에이전트
LangChain은 LLM 기반 애플리케이션 개발 프레임워크입니다. LangGraph는 LangChain 위에서 상태 머신(State Machine) 방식으로 복잡한 에이전트 워크플로우를 구현합니다. Ollama와 조합하면 완전한 오프라인 AI 에이전트를 개발할 수 있습니다.
pip install langchain langchain-community langgraph \
langchain-ollama chromadb \
tavily-python duckduckgo-search🤖 ReAct 에이전트 — 웹 검색 + RAG + 코드 실행
from langchain_ollama import ChatOllama from langchain.agents import create_react_agent, AgentExecutor from langchain_community.tools import DuckDuckGoSearchRun from langchain_community.tools.python.tool import PythonREPLTool from langchain_community.vectorstores import Chroma from langchain_ollama import OllamaEmbeddings from langchain.tools.retriever import create_retriever_tool from langchain import hub # 로컬 Ollama LLM 설정 llm = ChatOllama( base_url="http://192.168.1.253:11434", model="qwen2.5:14b", temperature=0.1 ) # 임베딩 모델 embeddings = OllamaEmbeddings( base_url="http://192.168.1.253:11434", model="nomic-embed-text" ) # 지식 베이스 (ChromaDB) vectorstore = Chroma( persist_directory="./knowledge_base", embedding_function=embeddings ) retriever = vectorstore.as_retriever(search_kwargs={"k": 5}) # 에이전트 도구 정의 tools = [ DuckDuckGoSearchRun(name="web_search", description="최신 정보나 사실 확인이 필요할 때 사용"), PythonREPLTool(name="python_repl", description="Python 코드 실행, 계산, 데이터 분석에 사용"), create_retriever_tool( retriever, "knowledge_search", "내부 지식베이스에서 관련 문서 검색" ), ] # ReAct 에이전트 생성 prompt = hub.pull("hwchase17/react") agent = create_react_agent(llm, tools, prompt) executor = AgentExecutor( agent=agent, tools=tools, verbose=True, max_iterations=10, handle_parsing_errors=True ) # 실행 예시 result = executor.invoke({ "input": "2026년 최신 AI 모델 트렌드를 조사하고, " "우리 지식베이스와 비교해서 차이점을 Python으로 분석해줘" }) print(result["output"])
🔀 LangGraph — 복잡한 에이전트 상태 머신
from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated, List
import operator
class ResearchState(TypedDict):
topic: str
searches: Annotated[List[str], operator.add]
findings: Annotated[List[str], operator.add]
report: str
step: int
def search_node(state: ResearchState) -> dict:
"""웹 검색 수행"""
search = DuckDuckGoSearchRun()
query = f"{state['topic']} 최신 동향 2026"
result = search.run(query)
return {"searches": [result], "step": state["step"] + 1}
def analyze_node(state: ResearchState) -> dict:
"""검색 결과 분석"""
prompt = f"""다음 검색 결과를 분석하고 핵심 인사이트를 추출해:
{' '.join(state['searches'][-3:])}"""
result = llm.invoke(prompt)
return {"findings": [result.content], "step": state["step"] + 1}
def report_node(state: ResearchState) -> dict:
"""최종 리포트 작성"""
prompt = f"""다음 분석 내용을 바탕으로 전문적인 리포트를 작성해:
주제: {state['topic']}
분석: {' '.join(state['findings'])}"""
result = llm.invoke(prompt)
return {"report": result.content}
def should_continue(state: ResearchState) -> str:
"""검색 3회 후 분석으로 전환"""
return "analyze" if state["step"] >= 3 else "search"
# 그래프 구성
graph = StateGraph(ResearchState)
graph.add_node("search", search_node)
graph.add_node("analyze", analyze_node)
graph.add_node("report", report_node)
graph.set_entry_point("search")
graph.add_conditional_edges("search", should_continue, {
"search": "search",
"analyze": "analyze"
})
graph.add_edge("analyze", "report")
graph.add_edge("report", END)
app = graph.compile()
result = app.invoke({
"topic": "AI 서버 구축 최신 기술 트렌드",
"searches": [], "findings": [], "report": "", "step": 0
})
print(result["report"])AutoGen & CrewAI — 멀티 에이전트 시스템
단일 AI가 해결하기 어려운 복잡한 작업은 여러 AI 에이전트가 역할을 분담해 협업하는 멀티 에이전트 아키텍처가 필요합니다. AutoGen은 Microsoft가 개발한 멀티 에이전트 프레임워크로, 에이전트들이 대화를 통해 문제를 해결합니다.
import autogen # Ollama 로컬 모델 설정 config_list = [{ "model": "qwen2.5:14b", "base_url": "http://192.168.1.253:11434/v1", "api_key": "ollama", "api_type": "openai" }] llm_config = { "config_list": config_list, "temperature": 0.1, "timeout": 180 } # 에이전트 역할 정의 user_proxy = autogen.UserProxyAgent( name="ProductManager", system_message="제품 요구사항을 정의하고 팀을 조율하는 PM입니다.", human_input_mode="TERMINATE", code_execution_config={"work_dir": "/tmp/autogen"} ) architect = autogen.AssistantAgent( name="SoftwareArchitect", llm_config=llm_config, system_message="""당신은 시니어 소프트웨어 아키텍트입니다. 요구사항을 분석하고 최적의 시스템 설계를 제안합니다. 코드를 직접 작성하지 않고 설계 방향을 제시합니다.""" ) developer = autogen.AssistantAgent( name="Developer", llm_config=llm_config, system_message="""당신은 풀스택 개발자입니다. 아키텍트의 설계를 바탕으로 실제 Python 코드를 작성합니다. 코드는 반드시 ```python 블록으로 감싸서 제공하세요.""" ) reviewer = autogen.AssistantAgent( name="CodeReviewer", llm_config=llm_config, system_message="""당신은 시니어 코드 리뷰어입니다. 작성된 코드의 품질, 보안, 성능을 검토하고 개선점을 제시합니다.""" ) # 그룹 채팅으로 협업 groupchat = autogen.GroupChat( agents=[user_proxy, architect, developer, reviewer], messages=[], max_round=15, speaker_selection_method="round_robin" ) manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config) # 작업 시작 user_proxy.initiate_chat( manager, message=""" 다음 기능을 구현해주세요: - Ollama API에서 사용 가능한 모델 목록을 가져오는 함수 - 각 모델의 크기와 최근 사용 시간을 포함 - 결과를 pandas DataFrame으로 반환 - 단위 테스트 포함 """ )
⚓ CrewAI — 역할 기반 AI 팀 구성
from crewai import Agent, Task, Crew, Process
from crewai_tools import SerperDevTool, WebsiteSearchTool
from langchain_ollama import ChatOllama
ollama_llm = ChatOllama(
base_url="http://192.168.1.253:11434",
model="qwen2.5:14b"
)
# AI 팀 구성
researcher = Agent(
role="수석 리서처",
goal="정확하고 최신의 기술 정보를 수집·검증한다",
backstory="10년 경력의 기술 리서처. 허위 정보를 절대 허용하지 않는다.",
llm=ollama_llm,
tools=[SerperDevTool()],
verbose=True
)
writer = Agent(
role="기술 블로그 작가",
goal="복잡한 기술 내용을 쉽고 흥미롭게 설명하는 글을 쓴다",
backstory="개발자 출신 테크 라이터. SEO와 가독성을 동시에 추구한다.",
llm=ollama_llm,
verbose=True
)
editor = Agent(
role="편집장",
goal="글의 품질, 정확성, 일관성을 최종 검토한다",
backstory="20년 경력 편집장. 오탈자, 논리 오류, 사실 오류를 절대 놓치지 않는다.",
llm=ollama_llm,
verbose=True
)
# 작업 정의
research_task = Task(
description="2026년 로컬 AI 서버 구축 트렌드를 조사. GPU 선택, 모델 트렌드, 비용 분석 포함.",
agent=researcher,
expected_output="5개 이상의 핵심 인사이트가 담긴 리서치 리포트"
)
writing_task = Task(
description="리서치 결과를 바탕으로 3000자 이상의 기술 블로그 포스트 작성. 실전 코드 예시 포함.",
agent=writer,
expected_output="Markdown 형식의 완성된 블로그 포스트"
)
editing_task = Task(
description="작성된 블로그 포스트를 검토하고 최종 편집. SEO 키워드 최적화 포함.",
agent=editor,
expected_output="최종 편집 완료된 블로그 포스트"
)
# 크루 실행
crew = Crew(
agents=[researcher, writer, editor],
tasks=[research_task, writing_task, editing_task],
process=Process.sequential,
verbose=True
)
result = crew.kickoff()
print(result)✅ 글 4 완료! n8n 자동화부터 LangGraph 에이전트, AutoGen 멀티에이전트까지 AI 자동화 전체 스택이 완성됐습니다. 글 5에서는 벡터DB·RAG 파이프라인·GPU 모니터링·트러블슈팅으로 AI 서버 운영의 마지막 조각을 완성합니다.
개인 생산성 혁신 — 연구·학습·창작 AI 활용
🔑 개인 생산성 향상을 위한 핵심 프롬프트 템플릿
## 논문 요약 프롬프트 다음 논문을 분석해줘. 구성: 1. 핵심 기여(Contribution) — 3문장 2. 방법론 요약 — 5~7문장 3. 실험 결과 핵심 수치 4. 한계점 및 향후 연구 방향 5. 실무 적용 가능성 (내 분야: [분야 입력]) [논문 텍스트 붙여넣기] ## 회의 준비 프롬프트 내일 [주제] 회의에 참석합니다. 배경 정보: [컨텍스트] 회의 목적: [목적] 다음을 준비해줘: - 예상 의제 5가지 - 각 의제별 내가 준비해야 할 질문 2개 - 주의해야 할 반대 의견과 대응 방법 - 회의 전 확인해야 할 사항 체크리스트 ## 학습 자료 생성 프롬프트 [주제]를 처음 배우는 사람을 위한 학습 계획을 만들어줘. 내 배경: [현재 수준] 목표: [달성하고 싶은 것] 가용 시간: 하루 [X]시간, 총 [N]주 출력 형식: - 주차별 학습 목표 - 각 주제별 추천 학습 순서 - 실습 프로젝트 아이디어 3개 - 학습 체크포인트 (스스로 평가 방법)
소상공인 · 1인 창업자 AI 비즈니스 자동화
from fastapi import FastAPI
from pydantic import BaseModel
import httpx, asyncio
app = FastAPI()
class ProductRequest(BaseModel):
product_name: str
category: str
price: int
features: list[str]
target: str = "일반 소비자"
@app.post("/generate-description")
async def generate_product_description(req: ProductRequest):
"""상품 설명 5가지 플랫폼별 자동 생성"""
prompt = f"""다음 상품의 판매 설명을 5개 플랫폼별로 작성해줘.
상품명: {req.product_name}
카테고리: {req.category}
가격: {req.price:,}원
주요 특징: {', '.join(req.features)}
타겟 고객: {req.target}
JSON 형식으로 출력:
{{
"naver_smart_store": "네이버 스마트스토어용 (500자 내외, SEO 키워드 포함)",
"coupang": "쿠팡 상세페이지용 (300자 내외, 혜택 강조)",
"instagram": "인스타그램 캡션 (150자 내외, 해시태그 10개 포함, 이모지 활용)",
"kakao_channel": "카카오채널 메시지 (100자 내외, 친근한 말투)",
"blog_intro": "블로그 포스팅 도입부 (200자 내외, 스토리텔링)",
"seo_keywords": ["핵심 키워드 10개"]
}}"""
async with httpx.AsyncClient(timeout=60) as client:
resp = await client.post(
"http://ollama:11434/api/generate",
json={"model": "qwen2.5:14b", "prompt": prompt, "stream": False,
"options": {"temperature": 0.8}}
)
import json, re
raw = resp.json()["response"]
json_match = re.search(r'\{.*\}', raw, re.DOTALL)
result = json.loads(json_match.group()) if json_match else {"raw": raw}
return {"product": req.product_name, "descriptions": result}
# FastAPI 실행: uvicorn main:app --host 0.0.0.0 --port 8500
# n8n HTTP Request 노드: POST http://ai-server:8500/generate-description개발자 · 엔지니어 AI 워크플로우
🔍 Open WebUI System Prompt — 코딩 전문가 페르소나
당신은 10년 경력의 시니어 풀스택 개발자입니다. 주요 스택: Python, Docker, Kubernetes, PostgreSQL, React 답변 원칙: 1. 코드는 항상 실행 가능한 완전한 형태로 제공 2. 보안 취약점과 엣지 케이스를 먼저 언급 3. 성능 최적화 관점에서 개선점 제안 4. 대안적인 접근 방법 1~2가지 함께 제시 5. 코드에는 반드시 한국어 주석 포함 6. 복잡한 로직은 단계별로 설명 응답 형식: - 핵심 답변 (3~5문장) - 코드 (완전한 실행 가능 형태) - 주의사항 및 개선 포인트 - 참고 사항 (관련 라이브러리, 문서 링크)
🤖 GitHub PR 자동 코드 리뷰 설정
from fastapi import FastAPI, Request
import httpx, asyncio
app = FastAPI()
@app.post("/github-webhook")
async def handle_pr_webhook(request: Request):
"""GitHub PR 생성/업데이트 시 자동 AI 코드 리뷰"""
payload = await request.json()
if payload.get("action") not in ["opened", "synchronize"]:
return {"status": "skipped"}
pr = payload["pull_request"]
pr_title = pr["title"]
pr_body = pr.get("body", "")
diff_url = pr["diff_url"]
comments_url = pr["comments_url"]
# PR diff 가져오기
async with httpx.AsyncClient() as client:
diff_resp = await client.get(
diff_url,
headers={"Authorization": f"token {GITHUB_TOKEN}"}
)
diff_text = diff_resp.text[:8000] # 토큰 한도
# AI 코드 리뷰 생성
review_prompt = f"""다음 Pull Request를 시니어 개발자 관점에서 리뷰해줘.
PR 제목: {pr_title}
PR 설명: {pr_body}
변경 코드 (diff):
{diff_text}
리뷰 항목:
1. 🐛 잠재적 버그 및 오류 (심각도: 높음/중간/낮음)
2. 🔒 보안 취약점 (SQL Injection, XSS, 인증 우회 등)
3. ⚡ 성능 이슈 (N+1 쿼리, 불필요한 루프, 메모리 누수)
4. 📖 코드 가독성 및 유지보수성
5. ✅ 잘된 점 (긍정적 피드백 필수)
6. 💡 개선 제안 (선택적)
각 항목은 구체적인 라인 번호나 코드 예시와 함께."""
async with httpx.AsyncClient(timeout=120) as client:
ai_resp = await client.post(
"http://ollama:11434/api/generate",
json={"model": "qwen2.5:14b", "prompt": review_prompt, "stream": False}
)
review = ai_resp.json()["response"]
# GitHub에 리뷰 코멘트 게시
await client.post(
comments_url,
headers={"Authorization": f"token {GITHUB_TOKEN}",
"Content-Type": "application/json"},
json={"body": f"## 🤖 AI 코드 리뷰\n\n{review}\n\n---\n*AI 리뷰는 참고용입니다.*"}
)
return {"status": "review_posted"}
GITHUB_TOKEN = "your_github_token"📝 개발자 AI 활용 시나리오 총정리
| 시나리오 | AI 도구 | 시간 절감 | 구현 복잡도 |
|---|---|---|---|
| PR 코드 리뷰 자동화 | Qwen2.5:14b + GitHub Webhook | 30분/PR → 0분 | 중간 |
| API 문서 자동 생성 | LLM + FastAPI OpenAPI | 2시간 → 10분 | 낮음 |
| 에러 로그 자동 분석 | n8n + Ollama + Slack | 즉시 원인 파악 | 중간 |
| 단위 테스트 자동 생성 | vLLM + LangChain | 1시간 → 5분 | 중간 |
| 코드 마이그레이션 보조 | RAG (기존 코드베이스) | 40% 속도 향상 | 높음 |
| 리팩토링 제안 | Open WebUI + 코드 업로드 | 즉시 피드백 | 낮음 |
| 보안 취약점 스캔 | LLM + 정적 분석 결합 | 보안 감사 70% 자동화 | 높음 |
중소기업 AI 도입 — 사내 지식 관리 & 업무 자동화
중소기업에서 AI 서버 도입이 가장 빠른 ROI를 내는 영역은 사내 문서 검색·고객 지원·보고서 작성·데이터 분석입니다. 외부 API에 기밀 문서를 보낼 필요 없이 내부망에서 완전히 처리됩니다.
👥 멀티유저 AI 서버 구성 — 부서별 접근 제어
| 부서 | 접근 허용 Knowledge Base | 사용 모델 | 특수 기능 |
|---|---|---|---|
| 인사팀 | 인사규정, 급여체계, 복리후생 | Qwen2.5:7b (빠름) | 개인정보 필터링 활성화 |
| 개발팀 | 기술문서, API 명세, 코드 가이드 | Qwen2.5:14b (고품질) | 코드 실행 허용 |
| 영업팀 | 제품 카탈로그, 가격표, 계약 템플릿 | Qwen2.5:7b | 고객사 정보 격리 |
| 경영진 | 전체 Knowledge Base | API 연결 가능 (Claude) | 모든 권한 |
프롬프트 엔지니어링 실전 완전 가이드
같은 LLM이라도 프롬프트 품질에 따라 결과가 10배 이상 달라집니다. 로컬 모델은 클라우드 API보다 더 명확하고 구체적인 프롬프트를 요구합니다.
🧠 핵심 프롬프트 기법 6가지
| 기법 | 언제 사용 | 효과 | 예시 |
|---|---|---|---|
| Role Prompting | 전문 지식 필요 시 | 도메인 특화 답변 | “당신은 10년 경력 Python 보안 전문가입니다” |
| Chain-of-Thought | 복잡한 추론 문제 | 정확도 30~60%↑ | “단계별로 생각하면서 답해줘. 먼저…” |
| Few-shot | 특정 형식 출력 필요 | 형식 정확도↑ | 입력/출력 예시 2~3개 제공 |
| 구조화된 출력 | 파싱·자동화 연동 | 코드 처리 가능 | “반드시 JSON 형식으로만 출력해” |
| 제약 조건 명시 | 범위 제한 필요 | 할루시네이션↓ | “제공된 정보 외 추측 금지” |
| 반복 정제 | 품질 개선 | 점진적 향상 | “위 답변을 더 간결하게 다시 작성해” |
## 📋 구조화된 분석 프롬프트 (Chain-of-Thought + 구조화 출력) [역할] 당신은 비즈니스 전략 컨설턴트입니다. [작업] 다음 상황을 분석하고 전략을 제안해줘. [상황] {상황 설명} [분석 단계 — 반드시 순서대로 수행] Step 1: 핵심 문제 정의 (1~2문장) Step 2: 주요 원인 분석 (3가지) Step 3: 선택 가능한 전략 (3가지, 각각 장단점) Step 4: 최적 전략 추천 및 근거 Step 5: 실행 계획 (30일/90일/1년) [제약 조건] - 실행 예산: {예산} - 팀 규모: {규모} - 주어진 기간: {기간} [출력 형식] 마크다운 형식으로 각 Step을 헤더로 구분 --- ## 🔄 Few-shot 예시 — 감정 분석 + 응대 초안 다음은 고객 메시지를 분석하는 예시야: 입력: "배송이 3일이나 늦었어요. 너무 실망입니다." 출력: {{"감정": "실망/불만", "긴급도": "높음", "카테고리": "배송문제", "추천응대": "먼저 사과 후 보상 제안"}} 입력: "상품 색상이 사진과 달라요." 출력: {{"감정": "불만", "긴급도": "중간", "카테고리": "상품불일치", "추천응대": "환불 또는 교환 안내"}} 입력: "{실제 고객 메시지}" 출력:
⚡ Open WebUI에서 프롬프트 템플릿 관리
/ 입력 시 빠른 검색으로 불러오기.{{topic}}, {{language}} 같은 플레이스홀더를 포함하면 프롬프트 불러올 때 자동으로 입력창이 뜹니다.AI 서버 ROI 분석 & 비용 절감 계산
AI 서버 구축 비용이 아깝지 않으려면 명확한 ROI 계산이 필요합니다. 실제 사용 패턴을 기반으로 클라우드 API 대비 절감액을 계산해봅니다.
💰 클라우드 API vs AI 서버 비용 비교 (월간 기준)
🎯 월 절감액: 약 33만원 (75% 절감)
350만원 초기 투자 → 손익분기점: 약 10.6개월
이후 월 33만원 × 12개월 = 연 396만원 순절감. 2년 총 절감: 800만원+
5명 팀이 무제한 사용해도 비용 동일. 클라우드는 사람 수 × 사용량만큼 비용 증가.
📈 사용량 증가 시 절감 효과 (팀 규모별)
| 팀 규모 | 월 클라우드 API 예상 비용 | AI 서버 비용 | 월 절감액 | 연 절감액 |
|---|---|---|---|---|
| 1인 (개인) | $100~200 (14~28만원) | 10.6만원 | 4~17만원 | 50~200만원 |
| 3~5인 팀 | $400~800 (56~112만원) | 10.6만원 | 45~100만원 | 540~1,200만원 |
| 10~20인 팀 | $1,500~3,000 (210~420만원) | 15~20만원 | 190~400만원 | 2,300~4,800만원 |
| 50인+ 기업 | $10,000+ (1,400만원+) | 50~80만원 | 1,300만원+ | 1.5억원+ |
- 이미지 생성 무제한화 — DALL-E 비용 절감이 가장 빠른 ROI. 마케팅팀에 ComfyUI 도입 즉시 효과
- Whisper 회의록 자동화 — 회의 1시간 녹음 → 10분 내 회의록 자동 완성. 인당 주 2~3시간 절감
- 사내 문서 RAG 검색 — 신입 온보딩 시간 50% 단축. 반복 질문 80% 자동 처리
- 코드 리뷰 자동화 — PR 처리 속도 향상 + 시니어 개발자 리뷰 부담 감소
- n8n 업무 자동화 — 반복 업무 자동화로 인당 주 5~10시간 회복
Open WebUI 전체 기능 맵 & Admin 완전 정복
Open WebUI는 지속적으로 기능이 추가되어 2026년 기준 단순 채팅 인터페이스를 훨씬 넘어섭니다. Admin Panel에만 50개 이상의 설정 항목이 있으며, 대부분의 사용자가 기본값으로만 사용합니다. 아래 설정들을 제대로 구성하면 완전히 다른 수준의 AI 플랫폼이 됩니다.
⚙️ 반드시 변경해야 할 Admin 핵심 설정
| 설정 위치 | 항목 | 권장값 | 이유 |
|---|---|---|---|
| General | Default User Role | pending | 신규 가입자 관리자 승인 후 사용 |
| General | Enable Community Sharing | OFF | 내부 서버에서 외부 공유 차단 |
| General | Enable Message Rating | ON | 응답 품질 피드백 수집 |
| General | Enable Channels | ON | Slack형 채널로 팀 협업 |
| Models | Default Model | qwen2.5:14b | 신규 대화 기본 모델 지정 |
| Audio | STT/TTS Engine | OpenAI 호환 (로컬) | Whisper + Kokoro 연동 |
| Images | Image Generation Engine | AUTOMATIC1111/ComfyUI | 로컬 이미지 생성 활성화 |
| Search | Web Search Engine | SearXNG (self-hosted) | 프라이빗 웹 검색 |
| Security | JWT Token Expiry | 24h | 보안 강화 (기본값 너무 김) |
| Security | Enable API Key Auth | ON | 외부 스크립트 API 접근 |
📦 Open WebUI 고급 환경변수 완전 가이드
open-webui:
image: ghcr.io/open-webui/open-webui:main
environment:
## ── 핵심 설정 ────────────────────────────────
- OLLAMA_BASE_URL=http://ollama:11434
- WEBUI_SECRET_KEY=생성한_32자_랜덤_키
- WEBUI_NAME=My Private AI # 브랜딩명
- WEBUI_URL=https://ai.yourdomain.com
## ── 데이터베이스 (기본은 SQLite, 프로덕션 권장) ─
- DATABASE_URL=postgresql://user:pass@postgres/openwebui
## ── 사용자 인증 ──────────────────────────────
- ENABLE_SIGNUP=false # 초기 설정 후 차단
- DEFAULT_USER_ROLE=pending
- JWT_EXPIRES_IN=86400 # 24시간 (초)
- ENABLE_OAUTH_SIGNUP=true
## ── OAuth / Google 로그인 ───────────────────
- GOOGLE_CLIENT_ID=your_google_client_id
- GOOGLE_CLIENT_SECRET=your_google_secret
- OAUTH_MERGE_ACCOUNTS_BY_EMAIL=true
## ── RAG 설정 ─────────────────────────────────
- VECTOR_DB=qdrant
- QDRANT_URI=http://qdrant:6333
- QDRANT_API_KEY=your_qdrant_key
- RAG_EMBEDDING_MODEL=BAAI/bge-m3 # 한국어 최강
- RAG_EMBEDDING_ENGINE=ollama
- RAG_OLLAMA_BASE_URL=http://ollama:11434
- CHUNK_SIZE=1000
- CHUNK_OVERLAP=100
- RAG_TOP_K=5
- RELEVANCE_THRESHOLD=0.35 # 낮을수록 많이 검색
- ENABLE_RAG_HYBRID_SEARCH=true # 하이브리드 검색 ON
- RAG_RERANKING_MODEL=cross-encoder/ms-marco-MiniLM-L-6-v2
## ── 이미지 생성 ──────────────────────────────
- IMAGE_GENERATION_ENGINE=comfyui
- COMFYUI_BASE_URL=http://comfyui:8188
- IMAGE_SIZE=1024x1024
- IMAGE_STEPS=20
## ── 음성 ─────────────────────────────────────
- AUDIO_STT_ENGINE=openai
- AUDIO_STT_OPENAI_API_BASE_URL=http://whisper-api:8000/v1
- AUDIO_STT_OPENAI_API_KEY=any
- AUDIO_STT_MODEL=large-v3-turbo
- AUDIO_TTS_ENGINE=openai
- AUDIO_TTS_OPENAI_API_BASE_URL=http://kokoro-tts:8880/v1
- AUDIO_TTS_OPENAI_API_KEY=any
- AUDIO_TTS_MODEL=kokoro
- AUDIO_TTS_VOICE=af_sarah
## ── 웹 검색 ──────────────────────────────────
- ENABLE_RAG_WEB_SEARCH=true
- RAG_WEB_SEARCH_ENGINE=searxng
- SEARXNG_QUERY_URL=http://searxng:8080/search?q=<query>&format=json
- RAG_WEB_SEARCH_RESULT_COUNT=5
## ── 외부 API 연결 ────────────────────────────
- OPENAI_API_BASE_URL=https://api.openai.com/v1
- OPENAI_API_KEY=sk-your-key # 클라우드 폴백용
## ── 성능 & 로깅 ──────────────────────────────
- WEBUI_AUTH_TRUSTED_EMAIL_HEADER=X-Forwarded-Email
- ENABLE_ADMIN_CHAT_ACCESS=true # Admin이 모든 대화 확인
- ENABLE_ADMIN_EXPORT=truePipelines — 메시지 전처리·후처리 완전 제어
Pipelines는 Open WebUI의 가장 강력하면서도 덜 알려진 기능입니다. 모든 채팅 메시지가 LLM에 도달하기 전·후에 파이썬 코드로 가로채 처리할 수 있습니다. 콘텐츠 필터링, 자동 번역, 컨텍스트 주입, 응답 후처리, 외부 API 라우팅 등 거의 모든 것이 가능합니다.
services:
pipelines:
image: ghcr.io/open-webui/pipelines:main
container_name: owui_pipelines
restart: unless-stopped
ports:
- "9099:9099"
volumes:
- pipelines_data:/app/pipelines
environment:
- PIPELINES_API_KEY=your_pipeline_secret_key
networks:
- ai_net
volumes:
pipelines_data:
networks:
ai_net:
external: true
name: ai_network"""
파일명: korean_context_filter.py
기능: 메시지 언어 감지 → 한국어 시 시스템 프롬프트 강화
+ 개인정보(전화번호·이메일·주민번호) 자동 마스킹
"""
from typing import Optional
from pydantic import BaseModel
import re
class Filter:
class Valves(BaseModel):
priority: int = 0
enable_pii_masking: bool = True
enable_language_detection: bool = True
korean_system_suffix: str = "답변은 반드시 한국어로 작성하세요."
def __init__(self):
self.valves = self.Valves()
def inlet(self, body: dict, user: Optional[dict] = None) -> dict:
"""메시지가 LLM에 도달하기 전 처리 (입력 필터)"""
messages = body.get("messages", [])
for msg in messages:
if msg.get("role") == "user":
content = msg.get("content", "")
# 1. PII 마스킹
if self.valves.enable_pii_masking:
content = self._mask_pii(content)
# 2. 한국어 감지 → 시스템 프롬프트 강화
if self.valves.enable_language_detection:
if self._is_korean(content):
self._inject_korean_context(body)
msg["content"] = content
return body
def outlet(self, body: dict, user: Optional[dict] = None) -> dict:
"""LLM 응답 후처리 (출력 필터)"""
# 응답에서 불필요한 패턴 정리
messages = body.get("messages", [])
for msg in messages:
if msg.get("role") == "assistant":
content = msg.get("content", "")
# 과도한 이모지 정리, 특수문자 정규화 등
content = self._clean_response(content)
msg["content"] = content
return body
def _mask_pii(self, text: str) -> str:
"""개인정보 마스킹"""
# 전화번호
text = re.sub(r'01[0-9]-?\d{3,4}-?\d{4}', '010-****-****', text)
# 이메일
text = re.sub(r'[\w\.-]+@[\w\.-]+\.\w+',
lambda m: m.group()[0] + '***@***.***', text)
# 주민번호
text = re.sub(r'\d{6}-[1-4]\d{6}', '******-*******', text)
return text
def _is_korean(self, text: str) -> bool:
korean_chars = sum(1 for c in text if '\uAC00' <= c <= '\uD7A3')
return korean_chars / max(len(text), 1) > 0.3
def _inject_korean_context(self, body: dict):
"""시스템 메시지에 한국어 지시 추가"""
messages = body.get("messages", [])
for msg in messages:
if msg.get("role") == "system":
if self.valves.korean_system_suffix not in msg["content"]:
msg["content"] += f"\n\n{self.valves.korean_system_suffix}"
return
# 시스템 메시지 없으면 추가
body["messages"].insert(0, {
"role": "system",
"content": self.valves.korean_system_suffix
})
def _clean_response(self, text: str) -> str:
# 연속 빈 줄 3개 이상 → 2개로 정리
text = re.sub(r'\n{3,}', '\n\n', text)
return text.strip()"""
파일명: claude_manifold.py
기능: Anthropic Claude API를 Open WebUI 모델 목록에 추가
→ 로컬 Ollama 모델과 함께 선택 가능
"""
from typing import List, Union, Generator, Iterator
from pydantic import BaseModel
import anthropic
class Pipe:
class Valves(BaseModel):
ANTHROPIC_API_KEY: str = ""
def __init__(self):
self.valves = self.Valves()
self.client = None
def pipes(self) -> List[dict]:
"""Open WebUI 모델 목록에 추가할 모델 정의"""
return [
{"id": "claude-opus-4-5", "name": "Claude Opus 4.5 (Cloud)"},
{"id": "claude-sonnet-4-5", "name": "Claude Sonnet 4.5 (Cloud)"},
{"id": "claude-haiku-4-5-20251001", "name": "Claude Haiku 4.5 (Cloud, 빠름)"},
]
def pipe(self, body: dict) -> Union[str, Generator, Iterator]:
"""실제 API 호출"""
if not self.valves.ANTHROPIC_API_KEY:
return "오류: Anthropic API Key가 설정되지 않았습니다."
client = anthropic.Anthropic(api_key=self.valves.ANTHROPIC_API_KEY)
# 모델 ID 추출
model_id = body["model"].split(".", 1)[-1]
# 시스템 프롬프트 분리
system_msg = ""
messages = []
for msg in body.get("messages", []):
if msg["role"] == "system":
system_msg = msg["content"]
else:
messages.append(msg)
# 스트리밍 응답
with client.messages.stream(
model=model_id,
max_tokens=body.get("max_tokens", 2048),
system=system_msg,
messages=messages,
) as stream:
for text in stream.text_stream:
yield textFunctions & Tools — AI 에이전트 도구 생태계
Open WebUI의 Tools는 AI가 채팅 중에 직접 호출할 수 있는 함수입니다. AI가 날씨를 실시간으로 조회하거나, 데이터베이스를 쿼리하거나, 파일을 생성하는 행동을 채팅 맥락 안에서 자연스럽게 수행합니다. MCP와 유사하지만 Open WebUI 내장 방식으로 더 간단하게 구현됩니다.
"""
파일명: ai_server_tools.py
Admin Panel → Tools → + New Tool 에서 코드 붙여넣기
"""
import subprocess
import httpx
from datetime import datetime
from pydantic import BaseModel
class Tools:
def get_gpu_status(self) -> str:
"""
현재 GPU 상태와 메모리 사용량을 확인합니다.
:return: GPU 상태 정보 문자열
"""
try:
result = subprocess.run(
["nvidia-smi",
"--query-gpu=name,temperature.gpu,utilization.gpu,memory.used,memory.total,power.draw",
"--format=csv,noheader,nounits"],
capture_output=True, text=True, timeout=10
)
if result.returncode != 0:
return "GPU 정보를 가져올 수 없습니다."
lines = result.stdout.strip().split('\n')
statuses = []
for i, line in enumerate(lines):
parts = [p.strip() for p in line.split(',')]
if len(parts) >= 6:
statuses.append(
f"GPU {i}: {parts[0]}\n"
f" 온도: {parts[1]}°C | 사용률: {parts[2]}%\n"
f" VRAM: {parts[3]}MB / {parts[4]}MB\n"
f" 전력: {parts[5]}W"
)
return "\n".join(statuses)
except Exception as e:
return f"GPU 상태 조회 실패: {e}"
def get_ollama_models(self) -> str:
"""
현재 Ollama에 설치된 AI 모델 목록을 조회합니다.
:return: 모델 목록과 크기 정보
"""
try:
resp = httpx.get("http://ollama:11434/api/tags", timeout=10)
models = resp.json().get("models", [])
if not models:
return "설치된 모델이 없습니다."
lines = [f"설치된 모델 ({len(models)}개):"]
for m in models:
size_gb = m.get("size", 0) / 1e9
lines.append(f" - {m['name']} ({size_gb:.1f}GB)")
return "\n".join(lines)
except Exception as e:
return f"모델 목록 조회 실패: {e}"
def get_service_health(self) -> str:
"""
AI 서버의 핵심 서비스 상태를 확인합니다.
:return: 각 서비스의 헬스 상태
"""
services = {
"Ollama": "http://ollama:11434/api/tags",
"Qdrant": "http://qdrant:6333/healthz",
"n8n": "http://n8n:5678/healthz",
"ComfyUI": "http://comfyui:8188/",
}
results = [f"서비스 상태 ({datetime.now().strftime('%H:%M:%S')})"]
for name, url in services.items():
try:
resp = httpx.get(url, timeout=3)
status = "✅ 정상" if resp.status_code < 400 else f"⚠️ {resp.status_code}"
except:
status = "❌ 연결 실패"
results.append(f" {name}: {status}")
return "\n".join(results)
def calculate(self, expression: str) -> str:
"""
수학 계산을 수행합니다.
:param expression: 계산할 수식 (예: '2 ** 10', 'sum([1,2,3,4,5])')
:return: 계산 결과
"""
try:
allowed = {
"__builtins__": {},
"sum": sum, "max": max, "min": min,
"abs": abs, "round": round, "len": len,
"range": range, "list": list,
}
result = eval(expression, allowed)
return f"{expression} = {result}"
except Exception as e:
return f"계산 오류: {e}"
def get_current_time(self) -> str:
"""
현재 한국 시간과 날짜를 반환합니다.
:return: 현재 날짜시간 정보
"""
from datetime import timezone, timedelta
kst = timezone(timedelta(hours=9))
now = datetime.now(kst)
return (f"현재 시간: {now.strftime('%Y년 %m월 %d일 %H시 %M분 %S초')}\n"
f"요일: {['월','화','수','목','금','토','일'][now.weekday()]}요일\n"
f"Unix Timestamp: {int(now.timestamp())}")🔗 Tool 등록 및 모델에 연결하는 방법
멀티유저 관리 & 권한 설계
팀이나 기업에서 Open WebUI를 운영할 때 사용자 관리와 권한 설계가 핵심입니다. 잘못된 권한 설정은 민감한 Knowledge Base가 모든 직원에게 노출되거나, 고비용 모델을 무제한 사용하게 만듭니다.
👥 역할(Role) 체계 설계
| 역할 | 모델 접근 | Knowledge Base | Tool 사용 | 이미지 생성 | 관리 기능 |
|---|---|---|---|---|---|
| Admin | 전체 | 전체 (생성/삭제) | 전체 | 무제한 | 전체 |
| User (고급) | 14B+ 모델 | 할당된 KB | 승인된 Tool | 일 50장 | 자기 관리 |
| User (기본) | 7B 모델만 | 공개 KB만 | 기본 Tool | 일 10장 | 없음 |
| Pending | 없음 | 없음 | 없음 | 없음 | 없음 |
🔐 Google OAuth 연동 설정 (팀 계정으로 자동 로그인)
# Google Cloud Console에서 OAuth 2.0 자격증명 생성 후 # Authorized redirect URI: https://ai.yourdomain.com/oauth/google/callback # docker-compose 환경변수 추가 - ENABLE_OAUTH_SIGNUP=true - OAUTH_MERGE_ACCOUNTS_BY_EMAIL=true - GOOGLE_CLIENT_ID=123456789-abcdefg.apps.googleusercontent.com - GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxx # 특정 도메인 계정만 허용 (예: company.com 직원만) # Admin Panel → Auth → OAuth 설정에서 Allowed Email Domain: company.com # 처음 OAuth 로그인 시 자동으로 pending 상태로 생성됨 # Admin이 Admin Panel → Users에서 승인 (Role을 user로 변경)
📊 사용량 모니터링 & 비용 추적
import httpx from collections import defaultdict WEBUI_URL = "http://localhost:3000" ADMIN_KEY = "your_admin_api_key" # Admin Panel → Account → API Key def get_usage_stats() -> dict: """사용자별 채팅 사용량 통계""" headers = {"Authorization": f"Bearer {ADMIN_KEY}"} # 전체 채팅 목록 (관리자 권한) resp = httpx.get(f"{WEBUI_URL}/api/v1/chats/all/db", headers=headers, timeout=30) chats = resp.json() stats = defaultdict(lambda: {"chats": 0, "messages": 0, "models": set()}) for chat in chats: uid = chat.get("user_id", "unknown") msgs = chat.get("chat", {}).get("messages", []) model = chat.get("chat", {}).get("models", ["?"])[0] stats[uid]["chats"] += 1 stats[uid]["messages"] += len([m for m in msgs if m.get("role") == "user"]) stats[uid]["models"].add(model) return dict(stats) stats = get_usage_stats() for user_id, data in sorted(stats.items(), key=lambda x: x[1]["messages"], reverse=True)[:10]: models = ", ".join(list(data["models"])[:3]) print(f"사용자: {user_id[:8]}..." f" | 채팅: {data['chats']}개" f" | 메시지: {data['messages']}개" f" | 모델: {models}")
모델 라우터 & 폴백 전략
모든 쿼리에 14B 대형 모델을 쓸 필요가 없습니다. “안녕”이나 “감사합니다” 같은 간단한 메시지는 7B 모델이 충분하고, 복잡한 코딩 문제는 특화 모델이 더 정확합니다. 지능형 모델 라우터로 속도와 품질을 동시에 최적화합니다.
"""
파일명: smart_router_pipe.py
기능: 쿼리 복잡도·유형에 따라 최적 모델 자동 선택
단순 질문 → qwen2.5:7b (빠름)
코딩 문제 → deepseek-coder:6.7b (전문)
복잡한 추론 → qwen2.5:14b (고품질)
이미지 관련 → gemma3:12b (Vision)
"""
from typing import Union, Generator, Iterator
from pydantic import BaseModel
import httpx, re
class Pipe:
class Valves(BaseModel):
OLLAMA_URL: str = "http://ollama:11434"
SIMPLE_MODEL: str = "qwen2.5:7b"
CODING_MODEL: str = "deepseek-r1:8b"
COMPLEX_MODEL: str = "qwen2.5:14b"
VISION_MODEL: str = "gemma3:12b"
MIN_TOKENS_FOR_COMPLEX: int = 200
def __init__(self):
self.valves = self.Valves()
def pipes(self):
return [{"id": "smart-router", "name": "🧠 Smart Router (자동 모델 선택)"}]
def _detect_intent(self, text: str) -> str:
"""쿼리 의도 분류"""
text_lower = text.lower()
code_keywords = ["코드","함수","클래스","python","javascript","sql",
"def ","class ","import ","error","bug","디버그","구현"]
complex_keywords = ["분석","비교","설계","아키텍처","전략","최적화",
"장단점","차이점","원인","메커니즘","심층"]
# 이미지 포함 여부 (Vision)
has_image = any(isinstance(c, dict) and c.get("type") == "image_url"
for c in ([text] if isinstance(text, str) else text))
if has_image:
return "vision"
if any(kw in text_lower for kw in code_keywords):
return "coding"
if (any(kw in text_lower for kw in complex_keywords)
or len(text) > self.valves.MIN_TOKENS_FOR_COMPLEX):
return "complex"
return "simple"
def pipe(self, body: dict) -> Union[str, Generator, Iterator]:
messages = body.get("messages", [])
last_user = next((m["content"] for m in reversed(messages)
if m["role"] == "user"), "")
intent = self._detect_intent(
last_user if isinstance(last_user, str)
else str(last_user)
)
model_map = {
"simple": self.valves.SIMPLE_MODEL,
"coding": self.valves.CODING_MODEL,
"complex": self.valves.COMPLEX_MODEL,
"vision": self.valves.VISION_MODEL,
}
selected_model = model_map[intent]
print(f"[SmartRouter] intent={intent} → model={selected_model}")
# 선택된 모델로 요청 전달
body["model"] = selected_model
with httpx.stream(
"POST",
f"{self.valves.OLLAMA_URL}/api/chat",
json=body,
timeout=180
) as response:
for line in response.iter_lines():
if line:
import json
data = json.loads(line)
if content := data.get("message", {}).get("content"):
yield content
if data.get("done"):
breakRAG 고급 설정 & Knowledge Base 최적화
🌐 웹 크롤링 자동화 — URL 지정으로 실시간 RAG 구성
import httpx, asyncio
WEBUI_URL = “http://localhost:3000”
API_KEY = “your_user_api_key”
async def add_url_to_knowledge(collection_id: str, url: str) -> dict:
“””웹 URL을 Knowledge Base에 자동 추가 (크롤링 + 임베딩)”””
async with httpx.AsyncClient(timeout=120) as client:
resp = await client.post(
f”{WEBUI_URL}/api/v1/knowledge/{collection_id}/file/add”,
headers={“Authorization”: f”Bearer {API_KEY}”},
json={“url”: url}
)
return resp.json()
async def batch_add_urls(collection_id: str, urls: list[str]):
“””여러 URL 배치 추가”””
for url in urls:
print(f”인덱싱 중: {url}”)
result = await add_url_to_knowledge(collection_id, url)
print(f” → {result.get(‘status’, ‘unknown’)}”)
await asyncio.sleep(2) # 서버 부하 방지
# 사용 예시 — 블로그 글 전체 자동 RAG 인덱싱
urls_to_index = [
“https://agibop.com/ai-server-guide-1”,
“https://agibop.com/docker-complete-guide”,
“https://agibop.com/qdrant-vector-db”,
]
asyncio.run(batch_add_urls(“your_collection_id”, urls_to_index))📺 유튜브 자막 RAG — 영상 내용을 지식베이스로
from youtube_transcript_api import YouTubeTranscriptApi # pip install youtube-transcript-api from qdrant_client import QdrantClient from qdrant_client.models import PointStruct from sentence_transformers import SentenceTransformer import uuid, re embedder = SentenceTransformer("BAAI/bge-m3") qdrant = QdrantClient(host="192.168.1.253", port=6333, api_key="your_key") def youtube_to_rag(video_url: str, collection: str = "ai_knowledge_base"): """유튜브 영상 자막을 RAG 지식베이스로 자동 변환""" # 영상 ID 추출 video_id = re.search(r'(?:v=|/)([A-Za-z0-9_-]{11})', video_url) if not video_id: raise ValueError("올바른 유튜브 URL을 입력하세요") vid_id = video_id.group(1) # 자막 가져오기 (한국어 우선, 영어 폴백) try: transcript = YouTubeTranscriptApi.get_transcript(vid_id, languages=['ko', 'en']) except Exception as e: print(f"자막 없음: {e}") return # 자막을 30초 단위로 청킹 CHUNK_SEC = 30 chunks = [] current = {"text": "", "start": 0} for entry in transcript: current["text"] += " " + entry["text"] if entry["start"] - current["start"] >= CHUNK_SEC: if current["text"].strip(): chunks.append({ "content": current["text"].strip(), "start_time": current["start"], "source": video_url, "type": "youtube_transcript" }) current = {"text": "", "start": entry["start"]} if current["text"].strip(): chunks.append({"content": current["text"].strip(), "start_time": current["start"], "source": video_url, "type": "youtube_transcript"}) # 임베딩 & Qdrant 삽입 texts = [c["content"] for c in chunks] vectors = embedder.encode(texts, normalize_embeddings=True).tolist() points = [ PointStruct( id=str(uuid.uuid4()), vector=vectors[i], payload={ "content": chunks[i]["content"], "source": chunks[i]["source"], "start_time": f"{int(chunks[i]['start_time']//60)}:{int(chunks[i]['start_time']%60):02d}", "type": "youtube_transcript", "category": "video" } ) for i in range(len(chunks)) ] qdrant.upsert(collection_name=collection, points=points) print(f"✅ 유튜브 자막 RAG 완료: {len(chunks)}개 청크 인덱싱") # 사용 예시 youtube_to_rag("https://www.youtube.com/watch?v=example_video_id") # → Open WebUI에서 "영상에서 RAG 설정 방법 설명해줘" 로 검색 가능
- 모든 채팅이 한국어 자동 감지 → 시스템 프롬프트 강화 + PII 마스킹 자동 처리
- 채팅에서 “GPU 상태 확인해줘” → AI가 직접 서버 상태 조회 후 분석 답변
- Claude Opus 4.5와 로컬 Qwen 모델이 같은 UI에서 선택 가능
- 쿼리 유형에 따라 최적 모델 자동 선택 → 속도·품질 동시 최적화
- 팀원별 권한·사용량 관리 + Google 계정으로 간편 로그인
- 유튜브 영상·웹페이지를 즉시 Knowledge Base에 추가해 RAG 검색
🚀 실전 워크플로우 완전 모음 — 바로 쓰는 n8n 자동화 20선
아래 20개 워크플로우는 모두 홈랩 AI 서버(Ollama + n8n)와 연동되는 실전 예제입니다. 각 워크플로우의 JSON을 n8n에서 Import → 환경변수만 수정하면 바로 동작합니다. Ollama URL: http://ollama:11434
🗂️ WF-01 — Telegram → AI 질문답변 봇
흐름: Telegram Trigger → Ollama Chat → Telegram 답장 용도: 어디서나 로컬 LLM에 질문 설정: - Telegram Bot Token: @BotFather에서 발급 - Ollama URL: http://ollama:11434 - 모델: qwen2.5:14b (한국어 최적) - System Prompt: "당신은 친절한 AI 어시스턴트입니다. 한국어로 답하세요." 핵심 노드: [Telegram Trigger] → [Ollama: /api/chat POST] → [Telegram: sendMessage]
📄 WF-02 — URL 입력 → 웹 요약 → Obsidian 저장
흐름: Telegram "요약 https://..." → Firecrawl 크롤링 → Ollama 요약 → Obsidian REST API 저장
용도: 읽고 싶은 아티클을 AI가 요약해 내 지식 베이스에 자동 저장
설정:
- Firecrawl URL: http://firecrawl:3002
- Obsidian Local REST API: http://192.168.1.100:27123
- 저장 경로: /vault/.raw/web/{{날짜}}_{{제목}}.md
프롬프트:
"다음 웹페이지 내용을 한국어로 요약하세요.
형식: YAML 프론트매터(title, url, date, tags) + 핵심 요점 5개 + 상세 요약"
🎤 WF-03 — 회의 녹음 → STT → 회의록 → Notion 저장
흐름: 파일 드롭(mp3/wav) → Whisper STT → Ollama 회의록 작성 → Notion API 저장 용도: 회의 후 자동으로 회의록·액션아이템 정리 Whisper 설정: - URL: http://whisper:9000/asr - 언어: ko (한국어) - 모델: large-v3 Ollama 프롬프트: "다음 회의 녹취록에서 추출하세요: 1. 회의 제목 및 일시 2. 참석자 목록 3. 주요 논의 사항 (번호 목록) 4. 결정된 사항 5. 액션 아이템 (담당자, 기한 포함) 6. 다음 회의 안건"
📊 WF-04 — 주식 뉴스 자동 수집 → AI 분석 → 리포트
흐름: Cron(매일 07:00) → RSS/API 뉴스 수집 → Ollama 감성분석 → Telegram 리포트
용도: 관심 종목 뉴스를 매일 아침 AI가 분석해서 알림
뉴스 소스:
- 한국경제TV RSS: https://www.wowtv.co.kr/NewsCenter/RSS
- 네이버 금융 API
- KIS Developers (주가 데이터)
Ollama 프롬프트:
"다음 뉴스들에서 {{종목명}} 관련 내용을 분석하세요.
출력: 긍정/부정/중립 판단, 핵심 이슈, 투자 시사점 (3줄 이내)"
📧 WF-05 — 이메일 자동 분류 & 요약 답장 초안 생성
흐름: Gmail Trigger(새 메일) → Ollama 분류/요약 → 카테고리별 레이블 → 답장 초안 → Telegram 알림 용도: 중요 이메일 놓치지 않고, 답장 초안 자동 생성 분류 카테고리: [긴급/업무/광고/구독/개인] 프롬프트: "다음 이메일을 분석하세요: 1. 카테고리: [긴급/업무/광고/구독/개인] 중 선택 2. 한 줄 요약 3. 필요한 경우 한국어 답장 초안 (200자 이내) 4. 긴급 여부 (true/false)"
🔬 WF-06 — 논문/PDF → AI 분석 → 지식 베이스 자동 구축
흐름: 폴더 감시(새 PDF) → PyMuPDF 텍스트 추출 → Ollama 논문 분석 → Obsidian 위키 생성 용도: 논문 읽을 때마다 자동으로 개인 지식 베이스 구축 Ollama 프롬프트: "다음 논문을 분석해 Obsidian 마크다운 형식으로 정리하세요: --- type: source source_type: paper title: [논문 제목] authors: [저자] year: [연도] tags: [핵심 키워드 3~5개] --- ## 핵심 기여 ## 방법론 ## 실험 결과 ## 한계점 ## 내 생각 ## 관련 개념 [[링크]]"
🛒 WF-07 — 쇼핑몰 리뷰 자동 수집 & 감성분석 리포트
흐름: Cron(매일) → 쇼핑 API 리뷰 수집 → Ollama 감성분석 → Meilisearch 저장 → 대시보드 용도: 소상공인 상품 리뷰 자동 모니터링 & 개선점 도출 지원 플랫폼: 쿠팡·네이버스마트스토어·G마켓 API 분석 항목: - 긍정/부정 비율 - 자주 언급되는 키워드 - 개선 요구사항 Top 5 - 경쟁 제품 언급 감지
✍️ WF-08 — 키워드 입력 → SEO 블로그 포스트 자동 생성
흐름: Telegram "블로그 [키워드]" → Meilisearch 기존 글 검색 → Ollama 포스트 작성 → WordPress API 임시저장
용도: 블로그 콘텐츠 반자동화 (초안 생성 → 사람이 검토 후 발행)
설정:
- WordPress REST API: https://agibop.com/wp-json/wp/v2/posts
- 상태: draft (바로 발행 안 함)
프롬프트:
"다음 키워드로 한국어 블로그 포스트를 작성하세요.
키워드: {{keyword}}
형식: HTML (WordPress용)
구조: 서론 → H2 섹션 4~6개 → 결론
분량: 2000~3000자
SEO: 키워드를 자연스럽게 포함, 관련 LSI 키워드 활용"
🔔 WF-09 — 서버 이상 감지 → AI 진단 → 자동 알림
흐름: Cron(5분마다) → Prometheus API 메트릭 수집 → 이상치 감지 → Ollama 원인 분석 → Telegram 알림
용도: 서버 이상 시 원인과 해결책을 AI가 자동 분석해서 알림
감지 조건:
- GPU 온도 > 85°C
- 메모리 사용률 > 90%
- 컨테이너 재시작 횟수 증가
- 디스크 사용률 > 85%
Ollama 프롬프트:
"다음 서버 메트릭 이상 상황을 분석하세요:
{{metrics_json}}
1. 예상 원인
2. 즉시 조치 사항
3. 장기 해결 방안"
🎓 WF-10 — YouTube 영상 → 자막 추출 → 학습 노트 자동화
흐름: Telegram "유튜브 https://youtube.com/..." → yt-dlp 자막 추출 → Whisper STT(자막없을때) → Ollama 학습노트 → Obsidian 저장
용도: 유튜브 강의·컨퍼런스 영상을 구조화된 학습 노트로 자동 변환
yt-dlp 명령:
yt-dlp --write-auto-sub --sub-lang ko,en --skip-download -o /tmp/%(id)s {{url}}
Ollama 프롬프트:
"다음 영상 자막을 학습 노트 형식으로 정리하세요:
## 핵심 개념 (3~5개)
## 타임스탬프별 주요 포인트
## 내가 배운 것
## 실천할 것
## 관련 자료 추천"
🏪 WF-11 — 고객 문의 자동 1차 응답 시스템
흐름: 이메일/폼 문의 수신 → Qdrant FAQ 검색 → Ollama 답변 생성 → 자동 이메일 발송 → 미해결 시 담당자 알림
용도: 반복 문의는 AI가 처리, 복잡한 문의만 사람에게 전달
RAG 설정:
- Qdrant에 FAQ·제품설명·정책 문서 임베딩
- 유사도 임계값: 0.8 이상 = 자동 답변, 미만 = 담당자 전달
프롬프트:
"당신은 {{회사명}} 고객 서비스 담당자입니다.
다음 FAQ를 참고해 고객 문의에 정중하게 답변하세요.
FAQ: {{context}}
문의: {{query}}
답변은 200자 이내, 공손하게, 해결 불가 시 '담당자 연결 안내'"
📱 WF-12 — SNS 콘텐츠 자동 생성 & 예약 발행
흐름: Cron(매일 08:00) → 트렌드 수집(Google Trends API) → Ollama 포스트 작성 → Buffer/Meta API 예약 발행 용도: SNS 일일 콘텐츠 반자동화 플랫폼별 형식: Instagram: 해시태그 30개 포함, 1200자 이내, 이모지 활용 X(Twitter): 280자 이내, 링크 포함, 스레드 구성 LinkedIn: 전문적 톤, 인사이트 중심, 1500자 블로그: HTML 2000자 이상, SEO 최적화
📝 WF-13 — 코드 리뷰 봇 (GitHub PR 자동 검토)
흐름: GitHub Webhook(PR 생성) → 변경 파일 diff 수집 → Ollama 코드리뷰 → PR 코멘트 자동 게시
용도: PR 올릴 때마다 AI가 코드 품질·버그·보안 이슈 1차 검토
Ollama 프롬프트:
"다음 코드 변경사항을 리뷰하세요.
언어: {{language}}
diff: {{diff}}
검토 항목:
1. 잠재적 버그 및 오류
2. 성능 개선 제안
3. 보안 취약점
4. 코드 가독성 개선
5. 테스트 커버리지 제안
형식: 마크다운, 심각도(🔴/🟡/🟢) 표시"
🌐 WF-14 — 다국어 문서 자동 번역 & 용어집 관리
흐름: 파일 감시(새 문서) → Ollama 번역 → 용어집 일관성 검사 → 번역 파일 저장
용도: 기술 문서·매뉴얼 자동 다국어화
지원 언어쌍: 영→한, 한→영, 영→일, 영→중
용어집 관리:
- Meilisearch에 도메인별 용어집 저장
- 번역 전 용어집 검색 → 일관된 번역어 사용
- 새 용어 발견 시 용어집 자동 추가
프롬프트:
"다음 기술 문서를 {{대상언어}}로 번역하세요.
용어집: {{glossary}}
원문: {{source}}
주의: 용어집에 있는 단어는 반드시 정의된 번역어 사용"
📅 WF-15 — 일정 관리 AI 비서 (Google Calendar 연동)
흐름: Telegram "내일 일정?" → Google Calendar API → Ollama 일정 요약 & 준비사항 → Telegram 답장
추가 기능:
- "회의 추가: 내일 2시 팀미팅 30분" → 파싱 → Calendar 이벤트 생성
- 매일 아침 7시 당일 일정 브리핑 자동 발송
- 회의 전 30분 Telegram 알림 + 안건 준비사항 AI 생성
프롬프트:
"다음 일정들을 바탕으로 오늘 하루를 브리핑하세요:
{{events_json}}
포함 사항: 시간순 일정, 준비할 것, 이동 시간, 여유 시간 분석"
🔍 WF-16 — 경쟁사 모니터링 & AI 분석 리포트
흐름: Cron(주 1회) → 경쟁사 웹사이트 크롤링(Firecrawl) → 변경사항 감지(diff) → Ollama 분석 → 리포트 이메일
용도: 경쟁사 신제품·가격 변경·공지사항 자동 모니터링
모니터링 항목:
- 메인 페이지 변경
- 가격 페이지 변경
- 블로그/공지 신규 포스팅
- LinkedIn 채용 공고 (전략 방향 파악)
Ollama 분석:
"다음 경쟁사 웹사이트 변경사항을 분석하세요:
이전: {{old_content}}
현재: {{new_content}}
분석: 변경의 의미, 우리에게 미치는 영향, 대응 방안"
📦 WF-17 — 재고 관리 AI 자동화 (소상공인용)
흐름: 판매 데이터 수집(Google Sheets) → Ollama 수요 예측 → 발주 시점 계산 → Telegram 발주 알림
용도: 소규모 쇼핑몰 재고 부족·과잉 방지
분석 요소:
- 최근 30일 판매 트렌드
- 계절성 패턴
- 현재 재고 수준
- 납기 기간
Ollama 프롬프트:
"다음 재고·판매 데이터를 분석해 발주 추천을 해주세요:
{{inventory_data}}
출력: 발주 필요 품목, 추천 발주량, 긴급 여부"
🎵 WF-18 — 텍스트 → AI 음악 생성 자동화 (ACE-Step 연동)
흐름: Telegram "음악생성 [설명]" → Ollama 프롬프트 최적화 → ACE-Step API → 완성 MP3 → Telegram 전송 용도: 텍스트로 AI 음악 자동 생성 ACE-Step 설정: - URL: http://ace-step:7865/api/generate - 모델: ACE-Step 1.5 Turbo - 파라미터: duration=120, batch_size=4 Ollama 역할: 사용자의 자연어 요청을 ACE-Step 전용 스타일 프롬프트로 변환 예: "신나는 운동 음악" → "upbeat EDM, punchy drums, 128 BPM, energetic, no vocals"
🧪 WF-19 — A/B 테스트 콘텐츠 자동 생성 & 결과 분석
흐름: 캠페인 설정 → Ollama 변형 콘텐츠 N개 생성 → 플랫폼 배포 → 성과 수집 → Ollama 승자 분석
용도: 이메일·광고·랜딩페이지 자동 A/B 테스트
Ollama 역할 1 (생성):
"다음 광고 문구의 A/B 테스트 변형 4개를 만드세요.
원본: {{original}}
변형 전략: 제목 변경, CTA 변경, 감성 톤 변경, 길이 변경"
Ollama 역할 2 (분석):
"A/B 테스트 결과를 분석하세요:
{{results_json}}
출력: 승자 및 이유, 통계적 유의성, 다음 테스트 제안"
🤖 WF-20 — AI 에이전트 팀 오케스트레이션 (멀티에이전트)
흐름: 복잡한 태스크 입력 → 오케스트레이터 LLM이 서브태스크 분해 → 각 에이전트 병렬 실행 → 결과 통합
구성:
오케스트레이터: qwen2.5:32b (태스크 분해·할당·통합)
리서치 에이전트: qwen2.5:14b + Firecrawl (웹 검색·수집)
분석 에이전트: qwen2.5:14b (데이터 분석·인사이트)
작성 에이전트: qwen2.5:14b (문서·보고서 작성)
검증 에이전트: qwen2.5:7b (사실 확인·품질 검수)
n8n 구현:
[입력] → [오케스트레이터: 태스크 분해 JSON] → [Switch 노드]
→ [에이전트1 HTTP] ──┐
→ [에이전트2 HTTP] ──┤→ [Merge] → [오케스트레이터: 통합] → [출력]
→ [에이전트3 HTTP] ──┘
① 모든 워크플로우에 에러 핸들러 노드를 추가해 실패 시 Telegram 알림 받기
② n8n 환경변수로 API URL을 관리 → 서버 IP 변경 시 일괄 수정 가능
③ 개발 완료 후 n8n Export → GitHub에 JSON 백업
④ 프로덕션 워크플로우는 실행 로그를 7일 보존 설정 (n8n Settings)
