[LangChain.js] 2. 모델과 프롬프트
LangChain.js 카테고리에 포함된 포스트들에서는 React/JS 를 이용해서 LangChain 을 구현하는 예제들을 포함하고 있습니다.
여기서는 LangChain 의 javascript 구현체를 기반으로 내용이 구성되어 있습니다. LangChain 아키텍처 자체에 대해서는 python 을 기반으로 한 강좌에서 더욱 자세히 다루고 있습니다. 아래 링크의 강좌를 참고하세요.
이번 포스트에서는 예제에서 사용된 model 과 prompt 에 대해서 더 자세히 알아봅니다.
Model & Prompt
이번 포스트에서 사용하는 예제는 아래에서 다운로드 받을 수 있습니다.
Chap 1 에서 사용한 예제처럼 번역 화면을 출력합니다. 하지만 이번에는 사용자가 입력한 텍스트를 원하는 언어로 번역할 수 있도록 언어를 선택하는 콤보박스가 추가되었습니다.

원하는 언어로 변환하기 위해서는 LLM 모델에게 어떤 언어로 번역할지 알려줘야 합니다. 이번 예제는 Prompt 를 이용해서 이걸 어떻게 처리하는지 보여줍니다.
아울러 앞서 사용했던 OpenAI 의 gpt 모델 대신 DeepSeek 의 모델을 사용하도록 변경하면서 모델 사용법에 대해서도 살펴보겠습니다.
UI 의 변경 내용은 여기서는 다루지 않습니다. App.tsx 파일을 참고하세요.
DeepSeek 모델 사용
DeepSeek 를 사용하기 위해서는 package.json 에 @langchain/deepseek 를 추가해야 합니다. 그리고 아래 명령으로 패키지를 install 해주세요.
- npm install
"dependencies": { "@langchain/core": "^0.3.28", "@langchain/openai": "^0.3.16", "@langchain/deepseek": "^0.0.1", "langchain": "^0.3.11", "react": "^18.3.1", "react-dom": "^18.3.1" },
DeepSeek API 를 사용하기 위해서는 DeepSeek platform 에 가입 후 API key 를 생성하고 Billing 을 추가해야 합니다.
API key 가 준비되었다면 프로젝트 root 폴더에 .env 파일을 생성하고 VITE_CHATMODEL_API_KEY 항목에 값을 넣어줍니다.
VITE_CHATMODEL_API_KEY=<your_deepseek_api_key>
여기까지 준비되었다면 npm run start 로 실행해서 번역기능을 테스트 해볼 수 있습니다.
우리가 분석할 LLM 호출과 번역기능 코드를 살펴보겠습니다. 관련 코드는 모두 chatService.ts 에 있습니다.
import { ChatDeepSeek } from '@langchain/deepseek' const apiKey = import.meta.env.VITE_CHATMODEL_API_KEY if (!apiKey) { throw new Error('API key is not defined in environment variables') } // 1. OpenAI 모델 대신 DeepSeek 모델을 사용합니다. // const model = new ChatOpenAI({ model: 'gpt-4o-mini', temperature: 0, apiKey }) const model = new ChatDeepSeek({ model: 'deepseek-chat', temperature: 0, maxTokens: 10000, maxRetries: 2, apiKey, })
코드를 보면 Chap 1 에서 사용했던 ChatOpenAI 가 주석처리되고, 대신 ChatDeepSeek 가 사용되었습니다. LangChain 에서 제공하는 LLM 모델 클래스는 이름이 Chat 으로 시작합니다.
클래스만 바뀌었을 뿐 클래스에 사용되는 속성은 표준화되어 있어서 동일하게 사용됩니다. 위 코드에서는 model, temperature, maxTokens, maxRetries, apiKey 등이 사용되었습니다.
대부분의 속성은 이름만으로도 기능이 이해가 갈 것입니다. 다만 temperature 가 궁금할 수 있겠습니다. temperature 는 AI 의 창의성을 제어하는 수치로 값이 낮을수록 정확한 답변을 요구합니다. 1에 가까울수록 AI 는 창의적이고 예측할 수 없는 답변을 합니다.
챗 모델에 사용할 수 있는 속성들은 아래 링크에 자세히 소개되어 있습니다. (“표준 매개변수” 참고)

이렇게 생성된 model 인스턴스의 invoke 또는 stream 메서드를 호출하면 LLM API 를 통해 입력한 프롬프트에 대한 응답을 출력해줍니다.
Prompt 설정
이제 사용자가 입력한 텍스트를 선택한 언어로 번역해야 합니다.
즉, LLM 모델을 호출할 때 사용자가 선택한 언어와 번역할 문장을 포함한 Prompt 를 구성해서 넘겨줘야 합니다. 이 과정이 streamChatResponse() 함수에 포함되어 있습니다.
export async function streamChatResponse( targetLanguage: string, userMessage: string, onMessage: (message: string) => void, ) { // 2. 템플릿을 생성합니다. const systemTemplate = 'Translate the following from Korean into {language}' const promptTemplate = ChatPromptTemplate.fromMessages([ ['system', systemTemplate], ['user', '{text}'], ]) // 3. 프롬프트를 생성합니다. const prompt = await promptTemplate.invoke({ language: targetLanguage, text: userMessage, }) // 3-1. 동일한 기능을 하는 다른 코드 /* const prompt = await promptTemplate.formatMessages({ language: 'English', text: userMessage, }) */ // 4. 프롬프트를 모델에 전달하여 대화를 생성합니다. const stream = await model.stream(prompt) // 5. 대화 스트림을 이용하여 메시지를 처리합니다. const chunks = [] for await (const chunk of stream) { const content = parseContent(chunk.content) chunks.push(content) onMessage(content) } // 6. 대화 스트림이 종료되면 결과를 출력합니다. console.log(chunks.join('')) }
코드를 분석하기 전 LangChain 의 message 구조를 알아두는 것이 좋습니다.
LangChain 에서는 LLM 모델과의 통신에 사용되는 기본 단위를 메시지(message) 라고 부릅니다. 메시지는 다음의 정보들을 포함하고 있습니다.
- 역할(Role): 메시지의 역할(예: “user”, “system”, “assistant” …)
- 내용(Content): 메시지의 내용(예: 텍스트, 다중 모드 데이터)
- 추가 메타데이터: ID, 이름, 토큰 사용량 및 기타 모델별 메타데이터
- 참고자료 링크
우리는 LLM 에게 번역할 문장과 함께 특정 언어로 번역해 달라고 요청하는 프롬프트를 작성해야 합니다. 이걸 메시지를 이용해서 표현하면 다음과 같습니다.
- Prompt
- Message 1 (role: system)
- LLM 이 어떤 역할을 수행해야 하는지를 지정
- content: 텍스트 (번역할 언어를 {language} 변수로 포함)
- Message 2 (role: user)
- 사용자가 입력한 텍스트
- content: 텍스트 (사용자가 입력한 텍스트를 {text} 변수로 포함)
- Message 1 (role: system)
이 구조를 코드로 작성한 부분이 [2], [3] 입니다.
- 2. ChatPromptTemplate 을 이용해서 프롬프트 템플릿을 작성합니다.
- 이 템플릿은 system, user 메시지를 포함하고 있습니다.
- system, user 메시지는 language, text 변수를 포함하고 있습니다.
- 3. 템플릿에 변수값을 지정해서 invoke 메서드를 호출하면 LLM 에게 전달할 프롬프트가 작성됩니다.
- 사실 프롬프트 템플릿은 streamChatResponse() 함수 호출때마다 생성할 필요가 없습니다. 이름처럼 템플릿을 생성해두고 필요할 때마다 invoke() 를 호출해서 사용하면 됩니다.
- 4. LLM API 호출
- 5. stream 처리
LangChain 의 장점
LLM 마다 특성이 다르고 지원하는 기능도 천차만별입니다. 따라서 다양한 LLM 모델을 서비스에 접합하기 위해서는 LLM 특성에 맞는 코드를 작성해야 하는 부담이 생기기 마련입니다. LangChain 은 이런 상황에서 다양한 LLM 을 서비스에 접목하는 표준적인 방법을 제시해줍니다.
당장은 모델과 메시지와 같은 기본적인 구성요소를 이용해서 LangChain 의 유용함을 맛봤지만, 앞으로는 LangChain 이 가진 더 강력한 기능들을 하나씩 살펴볼 것입니다.