LangChain-Upstage 패키지

김동준·2025년 10월 28일

LangChain-Upstage 패키지 완벽 가이드

📚 목차

  1. 개요
  2. Upstage 소개
  3. 설치 및 설정
  4. 핵심 컴포넌트
  5. 사용 가능한 모델
  6. 실전 활용 예제
  7. 다른 LLM 제공자와 비교
  8. 요금 정책
  9. 트러블슈팅
  10. 참고 자료

개요

langchain-upstage는 한국 AI 기업 Upstage의 Solar 모델 시리즈를 LangChain 프레임워크에서 원활하게 사용할 수 있도록 제공하는 공식 통합 패키지입니다.

주요 특징

  • LangChain 네이티브 통합: LangChain의 모든 기능과 완벽 호환
  • 한국어 최적화: 한국어 처리 성능이 뛰어난 Solar 모델
  • 다양한 기능: LLM, 임베딩, 문서 파싱, Groundedness Check 지원
  • 비용 효율적: OpenAI 대비 경제적인 가격
  • 빠른 응답 속도: 경량화된 모델로 빠른 추론

Upstage 소개

회사 정보

  • 설립: 2020년
  • 창업자: 김성훈 교수 (홍콩과기대 교수, 전 네이버 Clova AI 헤드)
  • 미션: "Making AI Beneficial"
  • 주요 제품: Solar LLM, Document AI, Groundedness Check

Solar 모델의 특징

  1. Depth Up-Scaling (DUS): 작은 모델을 효율적으로 확장하는 기술
  2. 한국어 특화: 한국어 벤치마크에서 우수한 성능
  3. 경량화: 동급 성능 대비 작은 모델 크기
  4. 실용성: 실제 서비스에 바로 적용 가능한 기능들

설치 및 설정

1. 패키지 설치

# 기본 설치
pip install langchain-upstage

# 특정 버전 설치
pip install langchain-upstage==0.2.0

# 개발 환경 설치 (추가 도구 포함)
pip install langchain-upstage[dev]

2. API 키 발급

단계별 가이드:

  1. Upstage Console 접속
  2. 회원가입 또는 로그인
  3. 좌측 메뉴에서 "API Keys" 클릭
  4. "Create API Key" 버튼 클릭
  5. API 키 이름 입력 후 생성
  6. 생성된 키 복사 (한 번만 표시됨!)

3. 환경 변수 설정

방법 1: .env 파일 사용

# .env 파일 생성
UPSTAGE_API_KEY=your-api-key-here
from dotenv import load_dotenv
import os

load_dotenv()
api_key = os.getenv("UPSTAGE_API_KEY")

방법 2: 직접 전달

from langchain_upstage import ChatUpstage

llm = ChatUpstage(
    api_key="your-api-key-here"  # 보안상 권장하지 않음
)

방법 3: 환경 변수 export

export UPSTAGE_API_KEY="your-api-key-here"

핵심 컴포넌트

1. ChatUpstage - LLM 대화 모델

기본 사용법

from langchain_upstage import ChatUpstage
from langchain_core.messages import HumanMessage, SystemMessage

# 모델 초기화
llm = ChatUpstage(
    model="solar-pro",
    temperature=0.7,
    max_tokens=1000
)

# 단순 호출
response = llm.invoke("파이썬의 장점을 3가지 알려줘")
print(response.content)

# 메시지 리스트 사용
messages = [
    SystemMessage(content="너는 친절한 AI 어시스턴트야"),
    HumanMessage(content="LangChain이 뭐야?")
]
response = llm.invoke(messages)

스트리밍

# 실시간 스트리밍
for chunk in llm.stream("긴 이야기를 들려줘"):
    print(chunk.content, end="", flush=True)

비동기 사용

import asyncio

async def async_chat():
    response = await llm.ainvoke("비동기로 대화하기")
    return response

# 실행
asyncio.run(async_chat())

2. UpstageEmbeddings - 임베딩 모델

문서 임베딩

from langchain_upstage import UpstageEmbeddings

embeddings = UpstageEmbeddings(
    model="solar-embedding-1-large"
)

# 여러 문서 임베딩
docs = [
    "LangChain은 LLM 애플리케이션 개발 프레임워크입니다.",
    "Upstage는 한국의 AI 스타트업입니다.",
    "Solar는 Upstage의 LLM 모델입니다."
]

doc_vectors = embeddings.embed_documents(docs)
print(f"벡터 차원: {len(doc_vectors[0])}")  # 4096

쿼리 임베딩

# 검색 쿼리 임베딩 (다른 최적화 적용)
query = "LangChain이란 무엇인가요?"
query_vector = embeddings.embed_query(query)

유사도 검색 예제

import numpy as np
from numpy.linalg import norm

def cosine_similarity(a, b):
    return np.dot(a, b) / (norm(a) * norm(b))

# 쿼리와 문서 간 유사도 계산
for i, doc in enumerate(docs):
    doc_vec = doc_vectors[i]
    similarity = cosine_similarity(query_vector, doc_vec)
    print(f"문서 {i+1} 유사도: {similarity:.4f}")

3. UpstageDocumentParseLoader - 문서 파싱

PDF 파싱

from langchain_upstage import UpstageDocumentParseLoader

# PDF 파일 파싱
loader = UpstageDocumentParseLoader(
    file_path="document.pdf",
    split="page",  # 페이지별 분할
    use_ocr=True,   # OCR 사용 (이미지 텍스트 추출)
    output_format="html"  # 또는 "text", "markdown"
)

documents = loader.load()
for doc in documents:
    print(f"페이지: {doc.metadata['page_number']}")
    print(f"내용: {doc.page_content[:200]}...")

이미지 파싱

# 이미지에서 텍스트 추출
image_loader = UpstageDocumentParseLoader(
    file_path="image.png",
    use_ocr=True
)
text_from_image = image_loader.load()

레이아웃 분석

from langchain_upstage import UpstageLayoutAnalysisLoader

# 문서 레이아웃 분석 (표, 그림, 텍스트 구분)
layout_loader = UpstageLayoutAnalysisLoader(
    file_path="complex_document.pdf",
    output_type="json"  # 구조화된 JSON 출력
)

layout_analysis = layout_loader.load()

4. UpstageGroundednessCheck - 답변 검증

기본 사용법

from langchain_upstage import UpstageGroundednessCheck

# Groundedness 검증기 초기화
checker = UpstageGroundednessCheck()

# 컨텍스트와 답변 준비
context = """
LangChain은 Harrison Chase가 2022년 10월에 만든
오픈소스 프레임워크입니다. LLM 애플리케이션 개발을
쉽게 만들어주는 도구입니다.
"""

answer = "LangChain은 2022년 10월에 만들어진 LLM 프레임워크입니다."

# 검증 수행
result = checker.check_groundedness(
    context=context,
    answer=answer
)

print(f"Grounded: {result['is_grounded']}")
print(f"Score: {result['score']}")

RAG 시스템과 통합

def verify_rag_response(question, context, answer):
    """RAG 응답의 신뢰도 검증"""
    checker = UpstageGroundednessCheck()

    result = checker.check_groundedness(
        context=context,
        answer=answer
    )

    if result['score'] < 0.8:
        return f"⚠️ 신뢰도 낮음 ({result['score']:.2f}): {answer}"
    return f"✅ 검증됨: {answer}"

사용 가능한 모델

LLM 모델

모델명용도컨텍스트 길이특징
solar-pro고성능 대화4,096최고 성능, 복잡한 작업
solar-1-mini-chat경량 대화4,096빠른 응답, 일반 대화
solar-1-mini-chat-ja일본어 특화4,096일본어 최적화

임베딩 모델

모델명차원컨텍스트 길이용도
solar-embedding-1-large4,0964,096범용 임베딩
solar-embedding-1-large-query4,0964,096쿼리 특화
solar-embedding-1-large-passage4,0964,096문서 특화

모델 선택 가이드

# 용도별 모델 선택 예시

# 1. 복잡한 추론이 필요한 경우
complex_llm = ChatUpstage(model="solar-pro")

# 2. 빠른 응답이 중요한 경우
fast_llm = ChatUpstage(model="solar-1-mini-chat")

# 3. RAG 시스템 구축
embeddings = UpstageEmbeddings(model="solar-embedding-1-large")

# 4. 검색 쿼리 최적화
query_embeddings = UpstageEmbeddings(model="solar-embedding-1-large-query")

# 5. 문서 인덱싱
doc_embeddings = UpstageEmbeddings(model="solar-embedding-1-large-passage")

실전 활용 예제

1. 완전한 RAG 시스템 구축

from langchain_upstage import ChatUpstage, UpstageEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate

# 1. 문서 로드 및 분할
documents = [...]  # 문서 로드
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200
)
chunks = text_splitter.split_documents(documents)

# 2. 임베딩 및 벡터 저장소 생성
embeddings = UpstageEmbeddings(model="solar-embedding-1-large")
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"
)

# 3. LLM 설정
llm = ChatUpstage(
    model="solar-pro",
    temperature=0.1,
    max_tokens=1000
)

# 4. 프롬프트 템플릿
template = """주어진 컨텍스트를 바탕으로 질문에 답변해주세요.
컨텍스트에 없는 내용은 모른다고 답변하세요.

컨텍스트: {context}

질문: {question}

답변:"""

prompt = PromptTemplate(
    template=template,
    input_variables=["context", "question"]
)

# 5. RAG 체인 생성
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=vectorstore.as_retriever(search_kwargs={"k": 3}),
    chain_type_kwargs={"prompt": prompt}
)

# 6. 질의응답
question = "LangChain의 주요 기능은 무엇인가요?"
answer = qa_chain.run(question)
print(answer)

2. 대화형 챗봇 구축

from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain

# 대화 메모리 설정
memory = ConversationBufferMemory(
    memory_key="chat_history",
    return_messages=True,
    output_key="answer"
)

# 대화형 RAG 체인
conversational_chain = ConversationalRetrievalChain.from_llm(
    llm=llm,
    retriever=vectorstore.as_retriever(),
    memory=memory,
    return_source_documents=True
)

# 대화 시작
chat_history = []
while True:
    user_input = input("질문: ")
    if user_input.lower() == 'quit':
        break

    result = conversational_chain({
        "question": user_input,
        "chat_history": chat_history
    })

    print(f"답변: {result['answer']}\n")
    chat_history.append((user_input, result['answer']))

3. 문서 요약 파이프라인

from langchain.chains.summarize import load_summarize_chain
from langchain_upstage import UpstageDocumentParseLoader

# PDF 로드
loader = UpstageDocumentParseLoader("long_document.pdf")
docs = loader.load()

# 요약 체인 생성
summarize_chain = load_summarize_chain(
    llm=ChatUpstage(model="solar-pro"),
    chain_type="map_reduce"  # 또는 "stuff", "refine"
)

# 요약 실행
summary = summarize_chain.run(docs)
print(f"요약: {summary}")

4. 스트리밍 웹 서버 (FastAPI)

from fastapi import FastAPI, StreamingResponse
from fastapi.responses import StreamingResponse
import asyncio

app = FastAPI()

llm = ChatUpstage(model="solar-1-mini-chat")

@app.post("/chat/stream")
async def stream_chat(question: str):
    async def generate():
        async for chunk in llm.astream(question):
            yield f"data: {chunk.content}\n\n"

    return StreamingResponse(
        generate(),
        media_type="text/event-stream"
    )

# 실행: uvicorn main:app --reload

다른 LLM 제공자와 비교

성능 비교

제공자모델한국어 성능속도비용컨텍스트
UpstageSolar-pro⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐4K
OpenAIGPT-4⭐⭐⭐⭐⭐⭐⭐⭐⭐8K-128K
AnthropicClaude 3⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐200K
GoogleGemini Pro⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐32K

코드 비교

OpenAI에서 Upstage로 마이그레이션

# Before (OpenAI)
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

llm = ChatOpenAI(model="gpt-3.5-turbo")
embeddings = OpenAIEmbeddings()

# After (Upstage)
from langchain_upstage import ChatUpstage, UpstageEmbeddings

llm = ChatUpstage(model="solar-1-mini-chat")  # 유사한 성능, 더 저렴
embeddings = UpstageEmbeddings(model="solar-embedding-1-large")

요금 정책

현재 가격 (2024년 기준)

서비스모델입력 (1M 토큰)출력 (1M 토큰)
Chatsolar-pro$3.00$15.00
Chatsolar-1-mini-chat$0.50$1.50
Embeddingsolar-embedding-1-large$0.10-
Document Parse-$0.01/페이지-
Groundedness Check-$0.05/검사-

비용 최적화 팁

# 1. 캐싱 사용
from langchain.cache import InMemoryCache
import langchain
langchain.llm_cache = InMemoryCache()

# 2. 배치 처리
embeddings.embed_documents(docs)  # 한 번에 처리

# 3. 모델 선택
# 간단한 작업: solar-1-mini-chat
# 복잡한 작업만: solar-pro

# 4. 스트리밍 활용
# 전체 응답 대기 대신 스트리밍으로 빠른 피드백

트러블슈팅

자주 발생하는 오류와 해결법

1. API 키 오류

# 오류: "Invalid API Key"
# 해결:
import os
print(os.getenv("UPSTAGE_API_KEY"))  # 키 확인
# None이면 .env 파일 확인 또는 환경변수 설정

2. Rate Limit 오류

# 오류: "Rate limit exceeded"
# 해결: 재시도 로직 추가
from tenacity import retry, wait_exponential, stop_after_attempt

@retry(
    wait=wait_exponential(multiplier=1, min=4, max=10),
    stop=stop_after_attempt(3)
)
def call_llm(prompt):
    return llm.invoke(prompt)

3. 타임아웃 오류

# 오류: "Request timeout"
# 해결: 타임아웃 증가
llm = ChatUpstage(
    model="solar-pro",
    request_timeout=60  # 60초로 증가
)

4. 토큰 제한 초과

# 오류: "Maximum token limit exceeded"
# 해결: 청크 분할
from langchain.text_splitter import TokenTextSplitter

splitter = TokenTextSplitter(
    chunk_size=3000,  # Solar 모델 한계 내
    chunk_overlap=100
)

디버깅 팁

# 1. 상세 로깅 활성화
import logging
logging.basicConfig(level=logging.DEBUG)

# 2. 응답 메타데이터 확인
response = llm.invoke("테스트")
print(response.response_metadata)  # 토큰 사용량 등

# 3. 스트림 디버깅
for chunk in llm.stream("테스트"):
    print(f"Chunk: {chunk}")
    print(f"Type: {type(chunk)}")

모범 사례 (Best Practices)

1. 환경별 설정 분리

# config.py
import os
from enum import Enum

class Environment(Enum):
    DEV = "development"
    PROD = "production"

def get_llm_config(env: Environment):
    if env == Environment.DEV:
        return {
            "model": "solar-1-mini-chat",
            "temperature": 0.7,
            "max_tokens": 500
        }
    else:  # PROD
        return {
            "model": "solar-pro",
            "temperature": 0.1,
            "max_tokens": 2000
        }

2. 에러 핸들링

from typing import Optional
import logging

logger = logging.getLogger(__name__)

def safe_llm_call(prompt: str) -> Optional[str]:
    """안전한 LLM 호출"""
    try:
        response = llm.invoke(prompt)
        return response.content
    except Exception as e:
        logger.error(f"LLM 호출 실패: {e}")
        return None

3. 성능 모니터링

import time
from functools import wraps

def monitor_performance(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        duration = time.time() - start

        # 로깅 또는 메트릭 수집
        print(f"{func.__name__} 실행 시간: {duration:.2f}초")

        return result
    return wrapper

@monitor_performance
def generate_response(prompt):
    return llm.invoke(prompt)

고급 활용

1. 커스텀 프롬프트 엔지니어링

from langchain.prompts import FewShotPromptTemplate, PromptTemplate

# Few-shot 예제
examples = [
    {"input": "파이썬이 뭐야?", "output": "파이썬은 프로그래밍 언어입니다."},
    {"input": "LangChain이 뭐야?", "output": "LangChain은 LLM 애플리케이션 개발 프레임워크입니다."}
]

example_prompt = PromptTemplate(
    input_variables=["input", "output"],
    template="입력: {input}\n출력: {output}"
)

few_shot_prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    prefix="다음 예제를 참고하여 답변하세요:\n",
    suffix="\n입력: {input}\n출력:",
    input_variables=["input"]
)

2. 멀티모달 처리

# 이미지 + 텍스트 처리
from langchain_upstage import UpstageDocumentParseLoader

def process_multimodal_document(file_path):
    # 1. 문서에서 텍스트와 이미지 추출
    loader = UpstageDocumentParseLoader(
        file_path=file_path,
        use_ocr=True,
        extract_images=True
    )

    docs = loader.load()

    # 2. 각 요소 처리
    for doc in docs:
        if doc.metadata.get("type") == "image":
            # 이미지 설명 생성
            description = llm.invoke(f"이 이미지를 설명해줘: {doc.page_content}")
        else:
            # 텍스트 요약
            summary = llm.invoke(f"요약: {doc.page_content}")

    return docs

3. 파인튜닝 데이터 준비

import json

def prepare_finetuning_data(qa_pairs):
    """Solar 모델 파인튜닝용 데이터 준비"""
    training_data = []

    for question, answer in qa_pairs:
        training_data.append({
            "messages": [
                {"role": "user", "content": question},
                {"role": "assistant", "content": answer}
            ]
        })

    # JSONL 형식으로 저장
    with open("training_data.jsonl", "w", encoding="utf-8") as f:
        for item in training_data:
            f.write(json.dumps(item, ensure_ascii=False) + "\n")

    return "training_data.jsonl"

참고 자료

공식 문서

튜토리얼 및 예제

커뮤니티

관련 논문

유용한 도구


부록: 빠른 참조

환경 설정 체크리스트

✅ pip install langchain-upstage
✅ export UPSTAGE_API_KEY="your-key"
✅ python -c "from langchain_upstage import ChatUpstage"

기본 코드 템플릿

from langchain_upstage import ChatUpstage, UpstageEmbeddings
from dotenv import load_dotenv

# 환경 변수 로드
load_dotenv()

# LLM 초기화
llm = ChatUpstage(model="solar-pro")

# 임베딩 초기화
embeddings = UpstageEmbeddings(model="solar-embedding-1-large")

# 사용
response = llm.invoke("Hello, Solar!")
vectors = embeddings.embed_documents(["Document"])
profile
Story Engineer

0개의 댓글