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

3장. LangChain 기본 구조와 LCEL

Runnable 과 invoke·batch·stream

커피 전문점의 기계는 회사마다 생김새가 달라도 버튼은 비슷합니다. "한 잔", "여러 잔 연속", 그리고 우유 거품처럼 조금씩 나오는 것을 지켜보는 기능이 있습니다. 새 기계로 바꿔도 직원은 같은 버튼을 누르면 됩니다. LangChain 의 부품도 모두 같은 버튼, 곧 같은 손잡이를 가집니다.

invoke, batch, stream 세 손잡이를 주문 한 건, 여러 건, 나오는 대로 받기에 견준 비교 그림

세 상자가 모든 러너블에 달린 세 손잡이입니다. invoke 는 입력 하나로 결과 하나를, batch 는 입력 목록으로 결과 목록을, stream 은 결과를 조각조각 받습니다. 여기서 커피 기계가 러너블이고, 버튼이 손잡이입니다. 비유와 다른 점은, 커피 기계는 버튼마다 만드는 것이 다르지만 러너블의 세 손잡이는 결과가 같고 받는 방식만 다르다는 것입니다.

세 손잡이

손잡이넣는 것받는 것어울리는 때
invoke(입력)입력 하나결과 하나질문 하나에 답 하나
batch([입력, …])입력 목록같은 차례의 결과 목록손님 질문 여러 개를 한꺼번에 시험할 때
stream(입력)입력 하나결과의 조각을 차례로챗봇 화면에 답이 타자 치듯 나오게 할 때

프롬프트 템플릿, 모델, 파서, 체인이 모두 이 셋을 가집니다. 그래서 가짜 모델로 시험하던 코드에 진짜 모델을 끼워도 부르는 줄은 바꿀 필요가 없습니다.

짧은 예시

글자 수를 세는 파이썬 함수 len 을 러너블로 바꿔 세 손잡이를 눌러 봅니다. 모델의 stream 은 가짜 모델로 봅니다.

Python
from langchain_core.language_models.fake_chat_models import FakeListChatModel
from langchain_core.runnables import RunnableLambda

# RunnableLambda: 보통 함수를 러너블로 바꾼다. 이제 invoke, batch, stream 을 쓸 수 있다
count = RunnableLambda(len)
print(count.invoke("제주도"))
print(count.batch(["제주도", "강릉", "부산 해운대"]))

# 가짜 모델의 stream 은 답을 한 글자씩 조각(chunk)으로 내놓는다
model = FakeListChatModel(responses=["동쪽 해안을 추천합니다."])
for chunk in model.stream("어디로 갈까요?"):
    print(repr(chunk.content), end=" ")
print()
print(type(chunk).__name__)
출력
3
[3, 2, 6]
'동' '쪽' ' ' '해' '안' '을' ' ' '추' '천' '합' '니' '다' '.' 
AIMessageChunk

batch 는 넣은 차례 그대로 [3, 2, 6] 을 돌려줍니다. stream 의 조각은 AIMessageChunk(chunk 는 "덩어리, 조각")라는 꼴이고, 조각마다 .content 에 글이 조금씩 들어 있습니다. 가짜 모델은 한 글자씩 자르지만, 진짜 모델은 토큰 몇 개씩 묶어 보냅니다.

코드가 의미하는 것

이 코드는 커피 기계의 세 버튼을 차례로 눌러 보는 일을 흉내 낸 것입니다. 보통 함수 len 에 세 버튼을 달아 invoke 와 batch 를 누르고, 가짜 모델에서 stream 을 누릅니다.

코드하는 일챗봇에서 뜻하는 것
RunnableLambda(len)보통 함수를 러너블로 바꾼다내가 쓴 함수도 세 손잡이를 가진 부품이 됩니다. 체인 사이에 끼워 넣을 수 있습니다
count.invoke("제주도")입력 하나로 결과 하나를 받는다질문 하나에 답 하나를 받는 가장 흔한 부르기입니다
count.batch([...])입력 목록으로 결과 목록을 받는다손님 질문 여러 개를 한꺼번에 시험할 때 누르는 버튼입니다
model.stream(...)결과를 조각으로 차례차례 내놓는다챗봇 화면에 답이 타자 치듯 나오게 하는 버튼입니다. 7장의 웹 화면에서 씁니다
chunk.content조각 하나에 든 글을 꺼낸다조각마다 글이 조금씩 들어 있어, 화면에 이어 붙여 보여 줍니다

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

  • 같은 부품에 버튼만 다릅니다. invoke 는 3 하나를, batch 는 [3, 2, 6] 목록을 돌려줬습니다. 계산은 같고 받는 방식만 다릅니다.
  • stream 은 빈칸까지 조각으로 옵니다. 셋째 줄에서 ' ' 도 조각 하나로 왔습니다. 화면에 보여 줄 때는 조각을 고치지 않고 그대로 이어 붙입니다.
  • 조각의 꼴은 AIMessageChunk 입니다. 마지막 줄처럼 모델의 stream 은 AIMessage 의 조각을 내놓습니다. 파서를 이으면 글 조각으로 바뀌는데, 실습 5에서 봅니다.

주의할 점

  • batch 는 여러 입력을 동시에(나란히) 처리합니다. 진짜 모델이라면 요청이 한꺼번에 여러 개 나가므로, 계정의 분당 요청 한도를 넘지 않게 config={"max_concurrency": 2} 처럼 동시에 보낼 수를 줄일 수 있습니다. concurrency 는 "동시에 일어남"이라는 뜻입니다.
  • stream 은 조각을 내놓는 "발전기(generator)"를 돌려줍니다. for 로 돌려야 조각이 나오고, 한 번 다 돌면 다시 쓸 수 없습니다.
← 이전 절3장 · 체인과 LCEL다음 절 →3장 · PromptTemplate