13년차의 서버실

서버, 인프라, 홈랩 기술 블로그

[태그:] API

  • 로컬 LLM을 n8n 자동화에 연결하기 — llama-server API로 로그 분류기 만들기 (홈랩 CPU)

    1편에서 GPU 없이 로컬 LLM을 띄웠고, 2편에서 한국어엔 Qwen2.5-3B가 낫다는 걸 실측으로 확인했습니다. 이제 마지막 단계 — 이 로컬 LLM을 실제 자동화에 연결합니다. llama.cpp를 OpenAI 호환 API 서버로 띄우고, n8n 워크플로우에 붙여서 일을 시켜 봤습니다. 결론부터: n8n이 로컬 LLM을 호출해 nginx 에러 로그를 “ERROR”로 정확히 분류하는 데까지 성공했습니다. API 요금 0원, 전부 홈랩 안에서.

    1. llama-server로 OpenAI 호환 API 띄우기

    llama.cpp에는 llama-server라는 실행 파일이 함께 빌드됩니다(1편 참고). 이걸 띄우면 OpenAI의 /v1/chat/completions와 똑같은 형식의 API가 생깁니다.

    ./build/bin/llama-server \
      -m /root/models/Qwen2.5-3B-Instruct-Q4_K_M.gguf \
      -c 4096 -t 4 \
      --host 0.0.0.0 --port 8080

    여기서 OpenAI 호환이라는 점이 핵심입니다. 세상의 수많은 도구·라이브러리·자동화 노드가 이미 “OpenAI API 형식”을 표준으로 지원하니까, URL만 내 홈랩 서버로 바꾸면 그대로 붙습니다. 외부에 돈 내고 부르던 걸 로컬로 갈아끼우는 셈이죠. --host 0.0.0.0은 같은 네트워크의 다른 기기(n8n 등)에서 접근하게 열어 주는 옵션입니다.

    2. API가 진짜 되는지 먼저 확인

    워크플로우에 붙이기 전에 curl로 직접 찔러 봤습니다.

    curl http://127.0.0.1:8080/v1/chat/completions \
      -H "Content-Type: application/json" \
      -d '{
        "model": "qwen2.5-3b",
        "messages": [{"role":"user","content":"홈랩 자동화에 로컬 LLM을 쓰면 좋은 점 한 문장."}],
        "temperature": 0.3
      }'

    실제 응답(발췌)입니다.

    "content": "로컬 LLM은 ... 홈랩 로그의 특징을 정확하게 분류하는 데 유용할 수 있습니다.",
    "usage": { "prompt_tokens": 60, "completion_tokens": 50, "total_tokens": 110 }

    토큰 사용량까지 OpenAI와 똑같은 스키마로 돌아옵니다. 이제 이걸 자동화 도구에 물릴 차례입니다.

    3. n8n 설치 — 여기서 함정을 밟았다

    자동화 도구로는 오픈소스 워크플로우 툴 n8n을 골랐습니다. 그런데 설치가 한 번에 되지 않았습니다. 최신 Debian(13)에서 npm install -g n8n이 네이티브 모듈(isolated-vm) 빌드 단계에서 죽더군요.

    ModuleNotFoundError: No module named 'distutils'
    gyp ERR! configure error
    npm ERR! ... isolated-vm ... not ok  (exit 127)

    원인은 Python 3.12에서 distutils가 표준 라이브러리에서 제거됐기 때문입니다. 기본 저장소의 구버전 Node/node-gyp가 이걸 아직 참조해서 빌드가 깨진 거죠. 해결은 최신 Node로 교체하는 것이었습니다.

    # NodeSource로 Node 22 설치 (npm 10 / 최신 node-gyp 포함)
    curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
    apt-get install -y nodejs
    npm install -g n8n

    Node 22로 바꾸니 네이티브 모듈이 정상 빌드되고 n8n(2.35)이 깔렸습니다. 스펙표엔 안 나오는, 직접 깔아 봐야 아는 함정이라 그대로 남겨 둡니다 — 같은 에러를 만날 분이 분명 있을 테니까요.

    4. n8n 워크플로우 구성 — 로그 분류기

    실용적인 예로 “로그 한 줄을 INFO / WARN / ERROR로 분류”하는 워크플로우를 만들었습니다. 구조는 단순합니다.

    • Manual Trigger — 실행 시작
    • HTTP Request — 로컬 LLM 호출

    HTTP Request 노드 설정이 전부입니다.

    필드 값
    Method POST
    URL http://<llama-server-IP>:8080/v1/chat/completions
    Body JSON (아래)
    {
      "model": "qwen2.5-3b",
      "messages": [
        { "role": "system", "content": "너는 로그 분류기다. 입력 로그를 INFO/WARN/ERROR 중 하나로만 답하라." },
        { "role": "user", "content": "nginx: upstream timed out (110: Connection timed out) while reading response header" }
      ],
      "temperature": 0
    }

    n8n과 llama-server가 같은 호스트면 127.0.0.1, 다른 기기면 서버의 홈랩 IP를 넣으면 됩니다. system 메시지로 “분류기” 역할을 못 박고 temperature: 0으로 답을 고정한 게 포인트입니다.

    5. 실행 결과 — 로컬 LLM이 정확히 판단했다

    워크플로우를 실행했습니다. n8n의 실제 실행 결과(요약)입니다.

    status: "success"
    Local LLM 노드 → message.content: "ERROR"
    timings: prompt 46 tok/s, generation 13.65 tok/s (노드 실행 1.4초)

    nginx의 upstream 타임아웃 로그를 로컬 LLM이 정확히 “ERROR”로 분류했습니다. GPU도, 외부 API도, 요금도 없이 내 홈랩 안에서 자동화 파이프라인의 부품으로 로컬 LLM이 동작한 순간입니다. 이제 이 노드 앞뒤에 트리거·알림만 붙이면 실제 운영 자동화가 됩니다.

    6. 이걸로 뭘 할 수 있나

    • 로그·알림 분류: 서버 로그를 등급으로 분류해 ERROR만 텔레그램으로 즉시 알림
    • 요약: 긴 문서·메일·뉴스를 로컬에서 요약(데이터가 외부로 안 나감)
    • 정형화: 자유 텍스트를 JSON·태그로 구조화

    핵심 이점은 비용과 프라이버시입니다. 외부 LLM API는 호출마다 돈이 들고 데이터가 밖으로 나가지만, 로컬 LLM은 몇 번을 부르든 0원이고 데이터가 홈랩을 벗어나지 않습니다. 실시간 초고성능이 필요한 게 아니라 배치·자동화 용도라면, GPU 없는 홈랩 CPU로도 충분히 실전에서 굴릴 수 있습니다.

    시리즈를 마치며

    1편 설치 → 2편 모델 선택 → 3편 자동화 연동까지, GPU 없는 i5 미니 PC 한 대로 로컬 LLM을 실전에 투입하는 전 과정을 직접 해봤습니다. “로컬 AI는 그래픽카드 있어야 한다”는 편견은, 적어도 3B급 자동화 용도에선 사실이 아닙니다. 여러분의 홈랩에도 하나 올려 보시길 권합니다.