LCEL (LangChain Expression Language) 3

Chat History 관리

from langchain_community.chat_message_histories import SQLChatMessageHistory

def respond(session_id: str, human_message: str) -> str:
    chat_message_history = SQLChatMessageHistory(
        session_id = session_id,
        connection = "sqlite:///sqlite.db",
    )
    messages = chat_message_history.get_messages()

    ai_message = chain.invoke({
        "chat_history": messages,
        "human_message": human_message,
    })

    chat_message_history.add_user_message(human_message)
    chat_message_history.add_ai_message(ai_message)

    return ai_message

# 호출
from uuid import uuid4

session_id = uuid4().hex
output1 = respond(session_id=session_id, human_message="안녕하세요. 제 이름은 나뭇잎입니다.")
print(output1)

output2 = respond(session_id=session_id, human_message="내 이름이 뭘까?")
print(output2)

지원하는 데이터베이스

SQLite 말고 다른 데이터베이스의 통합도 제공합니다:

  • 인메모리
  • SQLAlchemy가 지원하는 각종 관계형 데이터베이스
  • Redis
  • DynamoDB
  • CosmosDB
  • Momento 등

메모리

대화 이력에 대한 고급 처리를 구현하고 싶은 경우 메모리를 사용합니다. 예를 들어 최근 k개의 대화 이력만 포함하고 싶은 경우. ConversationBufferWindowMemory나 ConversationSummaryMemory를 해당 컴포넌트로 사용할 수 있습니다.

LangServe

LangChain의 러너블을 간편하게 REST API로 만들기 위한 패키지입니다.

📚 추가로 알아볼 내용

1. 고급 Runnable 패턴들

RunnableGenerator (스트리밍 생성기):

from langchain_core.runnables import RunnableGenerator

def streaming_splitter(input: Iterator[str]) -> Iterator[str]:
    buffer = ""
    for chunk in input:
        buffer += chunk
        # 문장 단위로 분할하여 yield
        while '. ' in buffer:
            sentence, buffer = buffer.split('. ', 1)
            yield sentence + '. '

    if buffer:
        yield buffer

streaming_chain = model | RunnableGenerator(streaming_splitter)

RunnableRetry (재시도 로직):

from langchain_core.runnables import RunnableRetry

retry_chain = RunnableRetry(
    bound=model,
    max_attempt_number=3,
    wait_exponential_jitter=True,
    stop_after_delay=30
)

RunnableWithMessageHistory (대화 이력 관리):

from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain_community.chat_message_histories import SQLChatMessageHistory

def get_session_history(session_id: str):
    return SQLChatMessageHistory(session_id, "sqlite:///memory.db")

chain_with_history = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key="input",
    history_messages_key="chat_history",
)

2. 복잡한 라우팅 전략

Multi-Modal Routing:

from typing import Literal

class RouteInput(BaseModel):
    query: str
    data_type: Literal["text", "image", "code"] = "text"

def route_by_type(input: RouteInput):
    if input.data_type == "image":
        return vision_chain
    elif input.data_type == "code":
        return code_analysis_chain
    else:
        return general_chain

routing_chain = RunnableLambda(route_by_type)

Semantic Routing:

from langchain_community.utils.math import cosine_similarity

def semantic_router(query: str, route_embeddings: dict):
    query_embedding = embeddings.embed_query(query)

    similarities = {}
    for route, embedding in route_embeddings.items():
        sim = cosine_similarity([query_embedding], [embedding])[0][0]
        similarities[route] = sim

    best_route = max(similarities, key=similarities.get)
    return route_chains[best_route]