본 포스팅은 "Do it! LLM을 활용한 AI 에이전트 개발 입문"을 독학하며 쓴 글입니다.
내돈내산 포스팅임을 참고해주시면 감사하겠습니다.
2026년 2월 16일 기준으로 작성되었습니다.
본 포스팅에서는 랭체인에서 스트림 출력 방식을 구현해보겠습니다!!
이제 랭체인의 스트림 방식으로 결과를 출력해보자!!
LLM 개발 입문 (7) - 1에서 스트림 방식으로 출력하는 방식에 대해 배웠는데 랭체인의 도구를 이용할 때에는 GPT의 응답이 단순 텍스트 형태가 아니라 어떤 함수에 어떤 인자를 넣어 실행할지를 판단해서 딕셔너리의 형태로 넘어온다!
따라서 스트림 출력을 하려면 랭체인에서도 별도 처리를 해야한다
지금까지 작성한 주피터 노트북 파일을 복습하면서 랭체인에서 스트림 방식으로 출력하는 방법을 익혀보자
앞에서 만들었던 파일으 언어 모델만 있을 때와 도구를 추가했을 때로 나누어 살펴보면서 랭체인 스트림 출력 방식을 익혀보자
langchain_tool.ipynb 파일에 이어서 실습하려 한다
- 1 - (1) 언어 모델만 있을 때 스트림 방식으로 출력하기
도구를 사용하지 않고 언어 모델의 답변을 스트림 방식으로 출력하는 방법은 간단하다
(7) - 1 에서 했듯 .invoke() 대신 .stream()을 사용하면 된다
이렇게 하면 답변이 생성되는 즉시 스트림 방식으로 촐력된다
코드를 model.invoke()에서 model.stream()으로 수정한다
이때 스트림 방식으로 출력되는지 확인하기 위해 길게 답변해야 하는 질문을 추가하고
또한 출력할 때 end = "|"을 사용해서 각 단위가 어떻게 출력되는지 확인할 수 있도록 한다
for c in llm.stream([HumanMessage("한국 사회의 문제점에 대해서 이야기해줘")]):
print(c.content, end="|")

코드를 실행하면 위와 같이 출력되는 것을 알 수 있다
자연스럽게 하려면 end를 설정하지 않거나 end=''로 하면 된다!
- 1 - (2) 도구를 추가했을 때 스트림 방식으로 출력하기
이제 스트림 방식으로 도구 호출 결과를 순차적으로 받아와 최종 결과를 생성해보도록 하자
대화 기록을 리스트에 담는 messages는 새로 선언한다
해당 코드는 랭체인 공식 문저 'How to stream tool calls'를 참고했습니다
messages = [
SystemMessage("너는 사용자의 질문에 답변을 하기 위해 tools를 사용할 수 있다"),
HumanMessage("부산은 지금 몇시야?")
]
response = llm_with_tools.stream(messages)
is_first = True
for chunk in response:
print("chunk type : ", type(chunk))
if is_first:
is_first = False
gathered = chunk
else:
gathered += chunk
print("content : ", gathered.content, "tool_call_chunk", gathered.tool_calls )
messages.append(gathered)
- response = llm_with_tools.stream(messages)
.invoke() 대신에 .stream()을 이용해서 질문한다
단순한 텍스트 답변을 받을 때에는 .stream()을 이용하면 문제없이 텍스트를 이어 붙여 최종 답변을 만든다
하지만 어떤 함수가 어떤 값으로 실행할지에 관한 정보도 스트림 방식으로 반환된다
따라서 response를 for문으로 처리해서 순차적으로 넘어오는 결과를 출력한다
- for chunk in response:
stream 방식으로 받은 결과를 하나씩 이어 붙여서 최종 결과를 만들어야 한다
터미널 창에서 스트림 방식으로 출력하기 위해서는 yield 키워드를 사용하고 tool_list_to_tool_obj 함수를 만들어서 사용했지만 랭체인에서는 간단히 + 연산자를 이용해서 해결할 수 있다

이제 새로운 셀에서 다음과 같이 + 연산자로 계속 더해진 gathered를 출력해보면 여전히 AIMessageChunk 타입임을 볼 수 있다
즉, AIMessageChunk는 계속해서 이어 붙일 수 있는 형태로 유지된다

AIMessageChunk는 과거 대화 내용이 담긴 messages에 추가해서 랭체인에서 바로 활용할 수 있다
함수 실행 과정은 스트림 방식으로 출력할 필요가 없으니까 selected_tool.invoke()로 바로 실행한다
이 단계에서는 날씨 API 실행 결과가 tool_msg에 반환되어 그 결과를 다시 message에 추가하고 출력했다
for tool_call in gathered.tool_calls:
selected_tool = tool_dict[tool_call["name"]] # tool_dict를 사용하여 도구이름으로 도구 함수 선택
print(tool_call["args"])
tool_msg = selected_tool.invoke(tool_call)
messages.append(tool_msg)
messages

실행 결과를 보면 이전에 만들어두었던 get_current_time 함수의 실행 결과가 마지막에 ToolMessage로 추가된 것을 볼 수 있다!
이 상태에서 llm_with_tools.stream()을 이용해서 마지막 답변을 생성하고 스트림 방식으로 출력하자
이전과 똑같이 end = "|"으로 설정해서 출력이 어디서 끊어지고 넘어오는지 확인할 수 있다
for c in llm_with_tools.stream(messages):
print(c.content, end= "|")

이전 챕터에서 스트림 방식으로 출력할 때에는 yield도 사용하고 새로 함수도 만들어서 사용하고
꽤나 많이 복잡했던것 같은데 랭체인을 사용하니까 훨씬 편한 방식으로 사용할 수 있는것 같다!!
확실히 랭체인이 여러모로 편의성 측면에서 좋은것같다는 생각을 계속하게 되는 요즘이다....
이번 포스팅에서 배운 것을 응용해서 이제 스트림릿에서 스트림 방식 출력을 구현해보려한다!!
다음에도 랭체인의 힘으로 쉽게 할 수 있지 않을까?!?!