LangChain 챗봇3장 · LangChain 기본 구조와 LCEL12 / 21← 이전목차다음 →MetaContents

3장. LangChain 기본 구조와 LCEL

RunnablePassthrough·RunnableLambda·RunnableParallel 로 체인 넓히기

주방의 벨트가 한 줄만 있으면 한 번에 한 가지 요리만 나옵니다. 큰 식당은 주문서를 복사해 국 담당과 반찬 담당에게 동시에 보내고, 끝에 쟁반 하나에 모아 냅니다. 주문서 원본은 계산대에 그대로 넘깁니다. LangChain 에도 이렇게 벨트를 나누고, 그대로 넘기고, 내 손으로 한 가지 일을 끼워 넣는 부품이 있습니다.

내 함수를 부품으로 만드는 RunnableLambda, 입력을 그대로 넘기는 RunnablePassthrough, 여러 갈래를 한 번에 돌리는 RunnableParallel 의 비교 그림

세 상자가 체인을 넓히는 세 부품입니다. RunnableLambda 는 내 함수를 벨트에 세우고, RunnablePassthrough 는 받은 것을 그대로 넘기고, RunnableParallel 은 같은 입력을 여러 갈래에 동시에 넣어 결과를 사전 하나로 모읍니다. 여기서 주방에 새로 세운 직원이 RunnableLambda, 계산대로 가는 원본이 RunnablePassthrough, 국과 반찬을 동시에 만드는 두 갈래 벨트가 RunnableParallel 입니다. 비유와 다른 점은, 주방은 갈래마다 다른 주문서를 쓸 수 있지만 RunnableParallel 은 모든 갈래에 똑같은 입력을 넣는다는 것입니다.

세 부품

부품하는 일예결과
RunnableLambda(함수)보통 함수를 부품으로RunnableLambda(len)함수의 결과
RunnablePassthrough()입력을 그대로 넘긴다갈래 하나에 원래 질문을 남길 때입력 그대로
RunnablePassthrough.assign(이름=부품)입력 사전에 열쇠를 하나 더한다질문에 낱말 수를 붙일 때입력 사전 + 새 열쇠
RunnableParallel(이름=부품, …)같은 입력을 여러 부품에 넣는다요약과 키워드를 한 번에{이름: 결과, …} 사전

assign 은 "몫을 정해 주다"라는 뜻입니다. 체인 안에서는 RunnableParallel(a=…, b=…) 대신 {"a": …, "b": …} 처럼 사전을 그대로 적어도 같은 뜻으로 읽힙니다.

짧은 예시

Python
from langchain_core.runnables import RunnableLambda, RunnableParallel, RunnablePassthrough

# 앞뒤 빈칸을 지우는 작은 함수를 부품으로 만든다. lambda 는 이름 없는 한 줄 함수
clean = RunnableLambda(lambda text: text.strip())

# 같은 입력을 세 갈래에 넣고 결과를 사전 하나로 모은다
both = RunnableParallel(original=RunnablePassthrough(), cleaned=clean, length=RunnableLambda(len))
print(both.invoke("  환불되나요? "))

# assign: 입력 사전은 그대로 두고 words 열쇠를 더한다
add = RunnablePassthrough.assign(words=lambda d: len(d["question"].split()))
print(add.invoke({"question": "예약 날짜를 바꿀 수 있나요?"}))
출력
{'original': '  환불되나요? ', 'cleaned': '환불되나요?', 'length': 9}
{'question': '예약 날짜를 바꿀 수 있나요?', 'words': 5}

세 갈래가 같은 입력 " 환불되나요? " 를 받았습니다. original 은 빈칸까지 그대로, cleaned 는 빈칸을 지운 글, length 는 빈칸을 포함한 글자 수 9 입니다. assign 은 원래 질문을 지우지 않고 words 를 옆에 붙였습니다. 실습 5에서 이 부품으로 손님 글의 요약과 키워드를 한 번에 뽑습니다.

코드가 의미하는 것

이 코드는 주문서를 세 갈래로 복사해 넘기고, 원본에 메모를 덧붙이는 일을 흉내 낸 것입니다. 내 함수를 부품으로 만들고, 같은 입력을 세 갈래에 넣고, 원래 사전에 열쇠를 하나 더합니다.

코드하는 일챗봇에서 뜻하는 것
RunnableLambda(lambda text: text.strip())앞뒤 빈칸을 지우는 함수를 부품으로 만든다손님 글을 모델에 넣기 전에 다듬는 일처럼, 모델이 아닌 작은 일을 체인에 끼웁니다
RunnableParallel(original=…, cleaned=…, length=…)같은 입력을 세 부품에 넣고 결과를 사전 하나로 모은다한 질문에서 여러 정보를 한 번에 뽑을 때 씁니다. 이름표가 사전의 열쇠가 됩니다
RunnablePassthrough()입력을 그대로 넘긴다다듬기 전의 원래 글을 결과에 남겨 둡니다
RunnablePassthrough.assign(words=…)입력 사전에 새 열쇠를 더한다원래 질문은 지우지 않고 계산한 값을 옆에 붙입니다. 다음 부품이 둘을 함께 쓸 수 있습니다

결과에서 읽을 것은 두 가지입니다.

  • 세 갈래가 같은 입력을 받았습니다. 첫 줄의 original, cleaned, length 가 모두 " 환불되나요? " 에서 나왔습니다.
  • assign 은 더하기만 합니다. 둘째 줄에 원래의 question 이 그대로 있고 words 5 가 옆에 붙었습니다.

주의할 점

  • RunnableParallel 의 갈래들은 동시에 돌기 때문에, 진짜 모델이 갈래마다 있으면 요청이 한꺼번에 여러 개 나갑니다. 요금은 갈래 수만큼 듭니다.
  • RunnableLambda 에 넣는 함수는 입력을 하나만 받습니다. 값이 여러 개 필요하면 사전 하나로 받아 안에서 꺼냅니다.
← 이전 절3장 · 다양한 프롬프트 2: 퓨샷과 단계별 지시다음 절 →3장 · 실습 지도