고객 상담을 효율적으로 요약하기

채팅 시나리오에 맞춘 효율적인 요약 방법

Dobby • ML engineer

  • 테크 인사이트

안녕하세요, AI팀 ML 엔지니어 도비입니다 🤗

이번 포스팅에서는 일반적인 요약 시스템 시나리오가 아닌, 채팅 시나리오에서 효율적으로 요약할 수 있는 방법에 대한 고민들을 담아 보았습니다.

채팅 시나리오에서 요약

최근 Large-scale Language Model (LLM)을 활용한 다양한 서비스들이 출시되고 있는데요. 요약 시스템을 구축하는데도 LLM의 능력을 사용하면 더 좋은 품질의 요약 결과를 얻을 수 있습니다. 하지만 LLM의 크기, 즉 모델의 파라미터 수가 많을 수록 요약 결과의 품질은 더 좋아지겠지만 그만큼 latency가 같이 높아지는 문제가 있는데요 😢

특히 OpenAI같이 RESTful API로 제공하는 SaaS 형태의 모델들을 사용하는 경우에,

  1. 모든 채팅 내용을 한번에 요약하는 경우 요청의 body가 너무 클 수 있고

  2. 채팅이 모두 완료될 때까지 기다린 뒤에 요약을 해야한다

는 주의점들이 있는데요. 이번 포스팅에서는 채팅의 특성을 살려서 이 부분들을 개선할 수 있는 방법을 살펴 볼 예정입니다.

채팅 시나리오에 대응하기 전에 LLM을 사용하는 다양한 요약 방법들을 먼저 알아보겠습니다. 크게 아래의 세 가지 방법이 있는데요,

  • Stuffing method

  • MapReduce method

  • Refine method

각 방법들에 대한 자세한 소개는 해당 블로그를 참고하시길 바랍니다. 여기서는 각 방법에 대해 간단하게만 설명드리겠습니다.

1. Stuffing Method

먼저 입력을 한번에 처리하는 요약 방식인 Stuffing Method는 입력 토큰 수가 언어 모델의 context size 보다 작은 경우 일반적으로 사용하는 방식입니다. 이렇게 하나의 단계로 바로 요약을 끝내버리는 방식을 Coarse-grained Summarization이라고도 합니다.

2. MapReduce Method

이와 반대로 문서를 청크로 나누어서 여러 단계에 걸쳐 처리하는 방식을 Fine-grained Summarization 방식이라고 합니다. 그 중 MapReduce Method는 특정 조건으로 텍스트를 여러개의 청크로 나눈 뒤 각 청크들을 각각 요약하고, 그 결과들을 다시 합쳐 최종 요약을 생성하는 방식입니다.

3. Refine method

또 다른 방법인 Refine method는 MapReduce처럼 청크를 나눠서 하지만 순서대로 청크별로 요약을 하되 이전 청크 요약을 추가적인 context로 주어 다음 청크에 대한 요약을 생성하여 단계별로 전체적인 내용들이 연결된 요약을 얻을 수 있습니다.

이번 블로그에서는 Refine method를 통해서 요약을 효율적으로 수행하는 방법에 대해서 좀 더 살펴보겠습니다.


Refine Method

Summarizer(LLM)의 positional embedding의 길이 한계로 document를 한번에 요약할 수 없는 상황을 가정해 보겠습니다.

먼저 일정한 토큰 개수를 설정해 fixed size chunking이 가능한데요.

3개의 chunk가 나오는 경우,

  1. chunk 1을 요약해 summary 1를 생성합니다.

  2. 그 후 summary 1를 chunk 2와 결합하여 이전 정보를 반영한 summary 2를 생성합니다.

  3. 마지막으로 summary 2와 chunk 3을 결합하여 최종 요약인 final summary를 생성합니다.

만약 n개의 chunk가 나오는 경우 n번의 반복적인 요약을 통해 최종적인 요약문을 생성할 수 있습니다.

그러나 refine method를 사용하더라도 아직 구조적으로 위 문제들이 모두 해결될것만 같진 않습니다.

또한 청크의 요약을 기다려야하기 때문에 MapReduce 대비 오히려 latency는 오히려 늘어날 수도 있을 것 같네요.

그러나 채팅 중간에 요약을 만들고 이전요약으로 미리 저장이 가능하다면,

이 요약 방법의 장점을 살리면서 언급된 문제들을 해결 할 수 있지 않을까요?

이러한 구조를 설계해서 몇가지 실험 내용들을 같이 살펴보겠습니다! 🧐

Redis를 활용한 이전 요약 관리

Summary 1을 생성하는 동안 다음 채팅이 진행되고 있는 상황을 가정해 보겠습니다.

위 파이프라인을 조금 변형하여서 chunking 단계에서 문서를 한번에 입력받는 것이 아닌

  • 설정된 토큰 개수 k개가 넘는 경우 chunk를 전달하도록 변경

  • 이때 현재 채팅 ID, 이전 요약을 저장

으로 모델 입력 방식을 바꿔준다면 채팅이 진행되는 동안 요약이 가능하게 됩니다.

그럼 위 변수 관리를 위해 Redis를 사용하여 위 파이프라인이 적용된 간략한 플로우 차트를 그려보았습니다.

플로우 차트의 흐름은 다음과 같습니다.

  1. Redis에서 get_data()를 호출해 통해 데이터를 받아올 때까지 대기합니다.

  2. 데이터를 받아온 경우, 현재 채팅 id 세션이 요약 중인 경우 대기합니다.

  3. 만약 요약이 끝난 경우, 이전 요약을 받아와 기존 쿼리와 합쳐서 요약합니다.

  4. 만약 상담이 종료되는 트리거가 발동된 경우 output_id에 요약을 저장하고, 그렇지 않은 경우 이전 요약으로 저장합니다.

위 구조의 파이프라인과 refine method를 사용한다면 다음 두 장점들을 살릴 수 있을 것 같습니다 😀

  • 채팅 중간에 요약을 미리 할 수 있음

  • Consistency를 어느정도 유지하며 요약할 수 있음

그리고 이에 따른 클라이언트의 코드 개요를 작성해 보겠습니다.

먼저 입력 토큰이 k개 이상인 경우 Redis에 입력 텍스트를 푸쉬합니다.

Plaintext
# 타이핑 된 텍스트들이 담겨있는 query의 토큰 수 가 k개 이상이면
if len(query.split(' ')) > k:  
    data = {
        'query': query,
        'id': id,
        'output_id': output_id
    }

    # redis 서버에 데이터를 push
    redis_client.lpush(queue_name, json.dumps(data))

그 후 특정 상황에 대한 트리거가 발생되면 output_id로 부터 최종 요약문을 받아옵니다.

Plaintext
while trigger:  
    output = redis_client.get(output_id)

최종적으로 설계된 서버의 테스트 코드를 작성하고 두 방식을 비교해 보겠습니다.

요약 방식 별 레이턴시 비교

위에서 설명드린 방식들을 요약 시간이 고정된 토큰 수가 누적되는 시간보다 짧다고 가정된 시나리오로 아래 케이스들의 레이턴시를 비교해보겠습니다.

먼저 실험에는 gpt-4 turbo를 사용했으며, refine method의 fixed size는 5,000으로 설정하였습니다.

실험 내용은 다음과 같습니다.

  • 입력 청크를 한번에 요약하는 경우 한번에 요약 (Stuffing Method)

  • 캐시를 사용하지 않는 Refine Method (Refine Method w/o Cache)

  • 채팅을 fixed size로 chunking 후 이전 요약을 캐싱하는 Refine Method (Refine Method w/ Cache)

Stuffing Method처럼 한번에 컨텍스트를 보듯 Refine Method 역시 연속적인 메시지들의 구성으로 이루어진 채팅 시나리오에서 요약 내용의 지속성을 유지할 수 있습니다. 그러나 위 그래프에서 보실 수 있듯이 Refine Method의 레이턴시는 선형적으로 증가하게 됩니다. 여러번 요약하는 과정을 병렬적으로 처리하기 어려워 이전 요약이 완료될 때까지 기다려야 하기 때문입니다.

그러나 캐시를 사용하면 Refine Method의 장점을 살리면서 채팅하는 동안 중간에 요약을 미리 해놓을 수 있습니다. 중간 요약 캐시를 활용하면 Stuffing Method보다 최종 요약 시 토큰 수가 절감되기에 latency가 빨라지고, 서버의 부하를 줄일 수 있습니다.

따라서 서비스 시나리오에 따라 적절한 요약 방식과 설계를 선택함으로써 LLM을 활용한 애플리케이션의 효율성을 높일 수 있습니다.

마지막으로

머신 러닝 모델을 실질적인 서비스 환경에 통합하고, 운영하는 과정은 품질과 latency의 균형을 맞추는 것이 굉장히 어려운 과제인 것 같아요.

그러나 실제 사용자 경험(UX)을 깊이 이해하고, 이를 기반으로 머신 러닝 서빙 아키텍처를 잘 설계하면,

효율적으로 시스템을 제공하여 사용자 경험을 개선할 수 있을 것 같습니다.

비슷한 시나리오의 머신러닝 시스템을 구축하시는 분들께 좋은 인사이트를 드릴 수 있으면 좋겠습니다.

긴 글 읽어주셔서 감사합니다.

We Make a Future Classic Product

채널팀과 함께 성장하고 싶은 분을 기다립니다

사이트에 무료로 채널톡을 붙이세요.

써보면서 이해하는게 가장 빠릅니다

회사 이메일을 입력해주세요