[LangChain] 표준 인터페이스, 비동기 인터페이스 (Standard Interfaces, Async Interfaces in LangChain)
이번 포스팅에서는 LangChain 에서 LLM 체인을 호출할 때 사용하는 인터페이스에 대해서 소개하겠습니다. LangChain의 인터페이스는 크게 아래처럼 2가지로 구분할 수 있습니다.
(1) Standard Interface: invoke(), stream(), batch()
(2) Async Interface: ainvoke(), astream(), abatch(), astream_log()
(1) Standard Interface: invoke(), stream(), batch()
표준 인터페이스에는 invoke(), stream(), batch()가 있습니다. 표준 인터페이스는 LLM 모델 체인을 정의하고 표준 방식으로 호출(call a chain in a standard way)하는 것을 쉽게 만들어줍니다.
먼저, 터미널에서 pip install을 사용해서 openai, langchain 모듈을 설치해줍니다.
! pip install openai langchain
필요한 모듈을 importing하고, OpenAI의 LLM 모델을 API로 사용하기 위해 OPENAI_API_KEY를 환경변수로 등록해줍니다.
import os
from langchain.llms import OpenAI
from langchain_core.output_parsers import StrOutputParser
os.environ["OPENAI_API_KEY"]="sk-xxxx...." # set with yours
llm = OpenAI()
parser = StrOutputParser()
chain = llm | parser
각 인터페이스에 대해 하나씩 예를 들어보겠습니다. 굳이 추가적인 설명이 필요치 않아서 제목과 예시를 보면 되겠습니다.
(1-1) invoke(): 입력에 대해 체인을 호출함
# invoke(): call the chain on an input
chain.invoke("What are some colors of rainbow?")
# The colors of the rainbow are red, orange, yellow, green, blue, indigo, and violet.
(1-2) stream(): 응답의 청크(chunk)를 스트리밍함
# stream(): stream back chunks of the response
for chunk in chain.stream(
"What are some colors of rainbow? Only answer the colors one by one per a line."):
print(chunk, end="", flush=True)
# Red
# Orange
# Yellow
# Green
# Blue
# Indigo
# Violet
참고로, flush=True를 설정하면 응답 텍스트가 출력되자마자 버퍼를 비워서 즉시 화면에 출력됩니다. 설정하지 않으면 파이썬은 자체적으로 적절한 시점에서 버퍼를 비울 때까지 데이터를 버퍼에 저장합니다. 이를 통해 프로그램이 실행되는 동안 실시간으로 데이터를 출력하거나 로깅을 할 때 유용하게 사용할 수 있습니다.
(1-3) batch(): 입력 리스트 (a list of inputs)에 대해 체인을 호출함
# batch(): call the chain on a list of inputs
chain.batch([
"What are some colors of rainbow?",
"Where is the capital city of South Korea?",
"When did the World War II happen?"
])
# ['\n\nThe colors of the rainbow are red, orange, yellow, green, blue, indigo, and violet.',
# '\n\nThe capital city of South Korea is Seoul.', '
# \n\nWorld War II began on September 1, 1939, when Nazi Germany invaded Poland.']
(2) Async Interface: ainvoke(), astream(), abatch(), astream_log()
"async" 키워드는 비동기 프로그래밍(Asynchronous programming)을 말합니다. 이 함수는 비동기 함수로 정의되었으며, 이 함수 안에서 "await" 키워드를 사용하여 다른 비동기 함수가 완료될 때까지 기다릴 수 있습니다. 이를 통해 동시성 및 병렬성을 활용하여 더 효율적인 프로그램을 작성할 수 있습니다.
예를 들어, 네트워크 요청이나 파일 입출력과 같은 I/O 작업을 수행할 때 비동기 프로그래밍은 프로그램이 블록되지 않고 다른 작업을 수행할 수 있게 해줍니다.
Python 3.5부터 "async"와 "await" 키워드가 도입되어 비동기 프로그래밍을 지원하며, 이를 통해 asyncio 모듈과 같은 도구를 사용하여 비동기 코드를 작성할 수 있습니다.
(2-1) ainvoke(): 입력에 대해 체인을 비동기적으로 호출함
# ainvoke(): call the chain on an input async
await chain.ainvoke("What are some colors of rainbow?")
# '\n\nThe colors of the rainbow are red, orange, yellow, green, blue, indigo, and violet.'
(2-2) astream(): 응답의 청크를 비동기적으로 스트리밍함
비동기적으로 처리하고 바로 바로 스트리밍 하기 때문에 중간에 공백 라인이 생겼습니다.
# astream(): stream back chunks of the response async
async for chunk in chain.astream(
"What are some colors of rainbow? Only answer the colors one by one per a line."):
print(chunk)
#
#
# Red
#
#
# Orange
#
#
# Yellow
#
#
# Green
#
# Blue
# Indigo
# Violet
(2-3) abatch(): 입력 리스트(a list of inputs)에 대해 체인을 비동기적으로 호출함
# abatch(): call the chain on a list of inputs async
await chain.abatch([
"What are some colors of rainbow?",
"Where is the capital city of South Korea?",
"When did the World War II happen?"
])
# ['\n\n-Red\n-Orange\n-Yellow\n-Green\n-Blue\n-Indigo\n-Violet',
# '\n\nThe capital city of South Korea is Seoul.',
# '\n\nWorld War II began on September 1, 1939, when Nazi Germany invaded Poland.']
(2-4) astream_log(): 최종 응답뿐만 아니라 중간 단계 로그를 그때 그때 스트리밍함
중간 단계의 세부 로그 데이터를 확인할 수 있습니다.
# astream_log(): stream back intermediate steps as they happen, in addition to the final response
async for chunk in chain.astream_log(
"What are some colors of rainbow? Only answer the colors one by one per a line."):
print("---" * 20)
print(chunk)
# ------------------------------------------------------------
# RunLogPatch({'op': 'replace',
# 'path': '',
# 'value': {'final_output': None,
# 'id': '98250f70-4772-4afe-9e3e-e815b1c0ca78',
# 'logs': {},
# 'streamed_output': []}})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add',
# 'path': '/logs/OpenAI',
# 'value': {'end_time': None,
# 'final_output': None,
# 'id': '7b2ca22e-71e0-4a03-9775-801f6c92f3d6',
# 'metadata': {},
# 'name': 'OpenAI',
# 'start_time': '2024-01-06T12:08:35.661',
# 'streamed_output_str': [],
# 'tags': ['seq:step:1'],
# 'type': 'llm'}})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add',
# 'path': '/logs/StrOutputParser',
# 'value': {'end_time': None,
# 'final_output': None,
# 'id': 'abebbbcd-7c1c-4af3-8a47-54c67df34bb8',
# 'metadata': {},
# 'name': 'StrOutputParser',
# 'start_time': '2024-01-06T12:08:36.061',
# 'streamed_output_str': [],
# 'tags': ['seq:step:2'],
# 'type': 'parser'}})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '\n'},
# {'op': 'replace', 'path': '/final_output', 'value': '\n'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/logs/OpenAI/streamed_output_str/-', 'value': '\n'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '\n'},
# {'op': 'replace', 'path': '/final_output', 'value': '\n\n'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/logs/OpenAI/streamed_output_str/-', 'value': '\n'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': 'Red'},
# {'op': 'replace', 'path': '/final_output', 'value': '\n\nRed'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/logs/OpenAI/streamed_output_str/-', 'value': 'Red'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '\n'},
# {'op': 'replace', 'path': '/final_output', 'value': '\n\nRed\n'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/logs/OpenAI/streamed_output_str/-', 'value': '\n'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': 'Orange'},
# {'op': 'replace', 'path': '/final_output', 'value': '\n\nRed\nOrange'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/logs/OpenAI/streamed_output_str/-', 'value': 'Orange'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '\n'},
# {'op': 'replace', 'path': '/final_output', 'value': '\n\nRed\nOrange\n'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/logs/OpenAI/streamed_output_str/-', 'value': '\n'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': 'Yellow'},
# {'op': 'replace', 'path': '/final_output', 'value': '\n\nRed\nOrange\nYellow'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/logs/OpenAI/streamed_output_str/-', 'value': 'Yellow'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': '\n'},
# {'op': 'replace',
# 'path': '/final_output',
# 'value': '\n\nRed\nOrange\nYellow\n'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/logs/OpenAI/streamed_output_str/-', 'value': '\n'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': 'Green\n'},
# {'op': 'replace',
# 'path': '/final_output',
# 'value': '\n\nRed\nOrange\nYellow\nGreen\n'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add',
# 'path': '/logs/OpenAI/streamed_output_str/-',
# 'value': 'Green\n'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add', 'path': '/streamed_output/-', 'value': 'Blue\nIndigo\nViolet'},
# {'op': 'replace',
# 'path': '/final_output',
# 'value': '\n\nRed\nOrange\nYellow\nGreen\nBlue\nIndigo\nViolet'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add',
# 'path': '/logs/OpenAI/streamed_output_str/-',
# 'value': 'Blue\nIndigo\nViolet'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add',
# 'path': '/logs/OpenAI/final_output',
# 'value': {'generations': [[{'generation_info': {'finish_reason': 'stop',
# 'logprobs': None},
# 'text': '\n'
# '\n'
# 'Red\n'
# 'Orange\n'
# 'Yellow\n'
# 'Green\n'
# 'Blue\n'
# 'Indigo\n'
# 'Violet',
# 'type': 'Generation'}]],
# 'llm_output': None,
# 'run': None}},
# {'op': 'add',
# 'path': '/logs/OpenAI/end_time',
# 'value': '2024-01-06T12:08:36.322'})
# ------------------------------------------------------------
# RunLogPatch({'op': 'add',
# 'path': '/logs/StrOutputParser/final_output',
# 'value': {'output': '\n\nRed\nOrange\nYellow\nGreen\nBlue\nIndigo\nViolet'}},
# {'op': 'add',
# 'path': '/logs/StrOutputParser/end_time',
# 'value': '2024-01-06T12:08:36.322'})
[ Reference ]
- LangChain Interface: https://python.langchain.com/docs/expression_language/interface#async-invoke
이번 포스팅이 많은 도움이 되었기를 바랍니다.
행복한 데이터 과학자 되세요! :-)