THE DEVLOG

scribbly.

LangChain JS 치트시트

2025.07.05 20:14:53

ollama서버를 이용하여 간단한 챗봇을 구현해본다.

먼저 터미널에서 ollama serve를 입력하여 ollama 로컬 서버를 실행시킨다.

 

ollama-js 시작하기

npm install ollama로 ollama를 설치한다.

ollama 모델 관리

list, pull, delete를 이용해 ollama 모델이 설치되어 있는지 확인하거나 모델을 mount할 수 있다.

// 모델이 설치되어 있는지 확인하는 함수
async function ensureModelExists() {
  try {
    const models = await ollama.list();
    const modelExists = models.models.some(model => model.name === MODEL_NAME);
    
    if (!modelExists) {
      console.log(`모델 ${MODEL_NAME}을 다운로드 중...`);
      await ollama.pull({ model: MODEL_NAME });
      console.log(`모델 ${MODEL_NAME} 다운로드 완료`);
    }
  } catch (error) {
    console.error('모델 확인/다운로드 중 에러:', error);
    throw new Error('모델을 준비할 수 없습니다.');
  }
}

 

응답 관리

채팅에서의 응답은 기본, 스트리밍, json 등 다양한 형태를 지원한다.

기본 채팅

const response = await ollama.chat({
  model: 'llama3.1',
  messages: [
    { role: 'system', content: '당신은 도움이 되는 AI 어시스턴트입니다.' },
    { role: 'user', content: '안녕하세요!' }
  ]
});

console.log(response.message.content);

스트리밍 채팅

const stream = await ollama.chat({
  model: 'llama3.1',
  messages: [{ role: 'user', content: '긴 이야기를 해주세요' }],
  stream: true
});

for await (const part of stream) {
  process.stdout.write(part.message.content);
}

JSON 형식 응답

const response = await ollama.chat({
  model: 'llama3.1',
  messages: [{ role: 'user', content: '사용자 정보를 JSON으로 반환해주세요' }],
  format: 'json'
});

 

텍스트 생성

ollama.generate()에서는 chat과 달리 role, assistant 같은 기능이 없이 문장을 생성할 때 사용한다.

const response = await ollama.generate({
  model: 'llama3.1',
  prompt: '다음 문장을 완성해주세요: 오늘 날씨가'
});

console.log(response.response);

시스템 프롬프트 설정

const response = await ollama.generate({
  model: 'llama3.1',
  prompt: '사용자 질문에 답변해주세요',
  system: '당신은 전문적인 상담사입니다.'
});

템플릿 사용

const response = await ollama.generate({
  model: 'llama3.1',
  prompt: '{{.Input}}',
  template: '다음 질문에 답변해주세요: {{.Input}}'
});

 

임베딩 생성

const embeddings = await ollama.embed({
  model: 'mxbai-embed-large',
  input: 'Llamas are members of the camelid family',
});

console.log(embeddings.embeddings); // 벡터 배열

모델 정보 조회

const modelInfo = await ollama.show({ model: 'llama3.1' });
console.log(modelInfo.parameters); // 모델 파라미터
console.log(modelInfo.template);   // 프롬프트 템플릿
console.log(modelInfo.system);     // 시스템 프롬프트

 

Routes Handler를 이용한 챗봇

import { NextRequest, NextResponse } from 'next/server';
import ollama from 'ollama';

// Ollama 모델 설정
const MODEL_NAME = "hf.co/rippertnt/HyperCLOVAX-SEED-Text-Instruct-1.5B-Q4_K_M-GGUF:Q4_K_M";

// 모델이 설치되어 있는지 확인하는 함수
async function ensureModelExists() {
  try {
    const models = await ollama.list();
    const modelExists = models.models.some(model => model.name === MODEL_NAME);
    
    if (!modelExists) {
      console.log(`모델 ${MODEL_NAME}을 다운로드 중...`);
      await ollama.pull({ model: MODEL_NAME });
      console.log(`모델 ${MODEL_NAME} 다운로드 완료`);
    }
  } catch (error) {
    console.error('모델 확인/다운로드 중 에러:', error);
    throw new Error('모델을 준비할 수 없습니다.');
  }
}

// 대화 기록을 저장할 배열 (실제 프로덕션에서는 데이터베이스나 세션 스토리지를 사용해야 함)
let messages = [
  { role: "system", content: "너는 사용자를 도와주는 상담사야." }, // 초기 시스템 메시지
];

export async function POST(request: NextRequest) {
  try {
    const { userInput } = await request.json();

    // 사용자 입력이 없거나 "exit"인 경우 처리
    if (!userInput || userInput === "exit") {
      return NextResponse.json({ 
        message: "대화가 종료되었습니다.",
        aiResponse: null 
      });
    }

    // 모델이 설치되어 있는지 확인
    await ensureModelExists();

    // 사용자 메시지를 대화 기록에 추가
    messages.push({ role: "user", content: userInput });

    // 대화 기록을 기반으로 AI 응답 가져오기
    const response = await ollama.chat({
      model: MODEL_NAME,
      messages: messages,
    });
    
    // AI 응답을 대화 기록에 추가
    messages.push({ role: "assistant", content: response.message.content });

    const embedding = await ollama.embed({
        model: MODEL_NAME,
        input: ["안녕하세요. 너는 누구야?", "너는 누구야?"],
      });
      console.log(embedding);

    return NextResponse.json({
      message: "성공적으로 응답을 생성했습니다.",
      aiResponse: response.message.content,
      userInput: userInput
    });

  } catch (error) {
    console.error('API 에러:', error);
    return NextResponse.json(
      { error: '서버 에러가 발생했습니다.' },
      { status: 500 }
    );
  }
}

해당 Route Handler가 실행되기 전에 ollama serve를 이용하여 ollama를 실행시켜두어야 한다.

ensureModelExists 함수를 이용해 모델을 pull한다.

이후에는 openAI 라이브러리와 유사한 인터페이스로 chatbot을 사용할 수 있다.