SRE로써 무수한 온콜 알림들과 봐야할 곳이 넓다 보니, 온콜 당번으로써 피로도가 상당하다. 이 문제를 해결하기 위해 GPT의 도움을 받아 현재 상황을 요약해서 볼 수 있는 어시스턴트를 만들어보고자 했다.

  • 다양한 상황들과 정보들을 가지고 와서,
  • GPT를 이용해서 내용을 요약하고,
  • 서비스를 파악하기 위한 질문들에 대한 답변을 제공받아,

GPT를 활용해서 인간이 빠르게 문제를 인식하고 대응할 수 있게 해 주는 서비스를 만들어 보면서, 어떻게 하면 GPT를 가지고 더 확장성 있는 프롬프트를 만들 수 있을지를 고민해 본 내용을 정리함.

이번 문서에서는 GPT에 대한 개념이나 ChatGPT 자체를 소개하지는 않습니다.

저는 GPT에 대한 자세한 지식은 없습니다만.. 문서를 찾고, 이리저리 조언을 구하다 보니… 이런 소프트웨어 형태를 “RAG”라고 하더라구요.

잘못된 지식이나 개념에 대한 수정이나, 더 발전적인 댓글 너무 감사합니다.

기초적인 OpenAI GPT 사용법

OpenAI에서는 GPT를 사용할 수 있는 기능을 라이브러리로 제공하고 있음.

# 이번에 테스트하면서는 openai 버전이 1.3.6으로 설치됨.
$ pip install openai

간단한 라이브러리 사용법.

from openai import OpenAI

# 이 부분은 과거 인터넷에 널리 알려진 문서들이랑 다름.
# 버전업 되면서 Client 초기화 과정이 많이 바뀜.
# 인터넷에 널려있는 문서들이 아웃데이트 되었으므로, 살펴볼 때 유의할 것.

OPENAI_API_KEY = 'OPENAI API KEY'

# API Client 초기화
openai_client = OpenAI(api_key=OPENAI_API_KEY)

클라이언트 사용법은 꽤 심플함.

openai_client.chat.completions.create(
    model='gpt-4',

    # 스트림 모드: 실시간으로 응답을 완성해 나가는 형식 (stream=True)
    stream=True,

    # GPT가 답변을 생성할 때, 얼마나 자유도를 줄 것인지.
    # 0 ~ Inf 라고 하는데 0.5가 가장 무난한 값.
    # 적절한 값은 상황에 따라 항상 다르며, API 사용자가 튜닝해야 한다.
    temperature=0.5,

    messages=[
        # role: system - GPT가 어떤 역할을 해야하는지를 정의함.
        {
            'role': 'system',
            'content': '사용자에게 친절하게 대해. 사용자는 SRE 온콜 당번이니까 어쩌고 저쩌고...'
        },

        # role: user - 사용자의 입력
        {
            'role': 'user',
            'content': '오늘 서비스 상황은 어때?'
        }
    ]
)

for chunk in stream:
    if chunk.choices[0].delta.content is not None:
        # (end='') 출력이후 마지막을 빈값으로 지정. 기본값은 "\n" 이라서 개행이 됨.
        # GPT가 화면에 실시간으로 답변하는 듯한 UX를 제공.
        print(chunk.choices[0].delta.content, end='')

GPT가 SRE 운영상황(비즈니스 컨텍스트)을 알게 만들기

구석기 시대: 직접 데이터 얻어와서 GPT에 넣고 물어보기

기본적으로 OpenAI가 제공하는 GPT모델에서는 인터넷에 공개된 범용적인 내용들을 학습하고 있다. 만들고자 하는 “SRE 어시스턴트”로서 GPT는 “현재 서비스 상황(비즈니스 컨텍스트)”을 잘 인지하고 있을 필요가 있다. 이 부분에 대해 GPT와 통신하기 위한 방법으로 사용자가 직접 비즈니스 컨텍스트를 제공하는 방법도 있지만.. 직접 정보들을 모으기 위한 노력이 상당하고, 대화 자체가 너무 길어지므로 이 또한 피로도가 있다.

사용자:
  현재 서비스 운영 상황을 알려줄테니까, 이 내용들을 잘 요약해 봐.
  주절주절 ...
  (어디선가 이리저리 API를 통해 가지고 온.
   장황한 서비스 컨텍스트 내용들, 로그, 메트릭 기타등등, '아 힘들다...')

GPT:
  네 현재 상황은 ...

사용자:
  그래 또 있는데 이거랑 저거랑 요런게 있는데 이렇게 되었을 때는 어떻게 하면 좋을까?...

GPT:
  네 ...
<이러다 다 죽어~>

신석기 시대: System Role로서 비즈니스 컨텍스트를 제공하기

어시스턴트와 대화하면서는 데이터를 미리 제공받을 것이 아니라 System 프롬프트로 비즈니스 컨텍스트를 제공하고, 사용자와는 필요한 대화만 하도록 만들면 피로도가 덜할 것이라 생각했다.

system 프롬프트로 GPT가 어떤 역할을 가져야 할 지, 어떤 정보들을 미리 알고있어야 할 지에 대한 로직을 작성하고, 해당 컨텍스트를 가지고 사용자와 대화를 통해 문제를 해결할 수 있을 것.

log_data = fetch_logs(...)  # log를 가지고 오는 기능

SYSTEM_PROMPT = '''
사용자는 다양한 서비스 지표들을 가지고 모니터링을 진행하고 있는 주간 온콜이야.

아래 서비스 얼럿들에 대한 컨텍스트를 가지고,
사용자가 현재 무슨 일이 어떻게 일어나고 있는지 자세하게 답변해.

얼럿이 발생했다가 해결된 경우는 짧게 답변해 줘.

로그 포맷은 "[DATE] MESSAGE" 형식이야.

{log_data}
'''

openai_client.chat.completions.create(
    model='gpt-4', stream=True, temperature=0.5,
    messages=[
        {'role': 'system', 'content': SYSTEM_PROMPT},
        # role: user - 사용자의 입력
        {
            'role': 'user',
            'content': '오늘 서비스 상황은 어때?'
        }
    ]
)

for chunk in stream:
    if chunk.choices[0].delta.content is not None:
        print(chunk.choices[0].delta.content, end='')

# GPT:
# 요약하자면, 다음과 같은 얼럿들이 발생했습니다:
# 1. "A" 클러스터의 "blabla" 네임스페이스에서 Error Log가 두 번 발생했습니다.
#    하지만 두 경우 모두 짧은 시간 내에 해결되었습니다.
# 2. "A" 클러스터의 "foobar" 네임스페이스에서 Cronjob Failed와
#    Container Restart 얼럿이 발생했습니다. 이 두 얼럿도 짧은 시간 내에 해결되었습니다.
# 3. "foobar", "johndoe", "pingpong", ...

청동기 시대 그쯤?: 미리 준비한 질문들에 대한 답변을 받도록 만들기 (질문 체크포인트 만들기)

직접 대화를 하면서 문제를 파악할 수도 있으면 좋겠지만, 서비스를 파악하고 개선해 나갈 수 있는 질문들을 미리 준비해 두면, 더 빠르게 문제를 인식하고 해결해 나갈 수 있을 것이라고 생각했고, 직접 리포트를 생성해 봄.

체크리스트라고 할 수도 있지만, 문제를 찾고 해결해 나가는 과정에서 발생하는 질문들을 미리 준비한다는 점에서 체크포인트가 더 어울리는 단어라고 생각함.

# GPT가 대답해야할 질문 목록들.
USER_PROMPT = '''
어떤 서비스에 어떤 얼럿들이 진행되었는지 요약해 봐.
그리고 당시에 문제가 되었던 클러스터와 서비스 이름들, 주요 문제들을 정리해 줘.

만약 현재 진행중인 얼럿이 있다면, 그 얼럿이 발생한 서비스와 문제를 알려주고,
해결하기 위해서 어떤 부분을 더 살펴보고 실행하면 좋을지 제안해 봐.

로그에서 False 얼럿일 수 있거나 플랩이 심한 얼럿들을 찾고,
이 부분들을 효과적으로 관리하기 위한 방법들도 제안해 줘.
'''

# GPT:
# 요약하자면, 다음과 같은 얼럿들이 발생했습니다:
# 1. "A" 클러스터의 "blabla" 네임스페이스에서 Error Log가 두 번 발생했습니다.
#    하지만 두 경우 모두 짧은 시간 내에 해결되었습니다.
# 2. "A" 클러스터의 "foobar" 네임스페이스에서 Cronjob Failed와
#    Container Restart 얼럿이 발생했습니다. 이 두 얼럿도 짧은 시간 내에 해결되었습니다.
# 3. "blabla", "foobar", "johndoe", "pingpong", 네임스페이스에서 각각
#    다양한 횟수의 warn 얼럿이 발생했습니다.
#    이 중 "johndoe"와 "pingpong"에서 가장 많은 횟수의 warn 얼럿이 발생했습니다.
# 4. "B" 클러스터의 "blabla" 네임스페이스에서 warn 얼럿이 발생했지만,
#    짧은 시간 내에 해결되었습니다.
# 5. CPU Utilisation, CPU Saturation (Load1 per CPU), istio grpc success rate 등의
#    얼럿이 발생했지만, 모두 짧은 시간 내에 해결되었습니다.
#
# 현재 진행 중인 얼럿은 없습니다. 하지만, "service_a"와 "service_b" 네임스페이스에서
# 발생한 warn 얼럿의 횟수가 많으므로, 이 부분을 주의 깊게 살펴보는 것이 좋을 것 같습니다.
# 특히, 로그, 코드, 인프라 등에서 이러한 warn 얼럿이 발생하는 원인을 찾아서 해결하는 것이 필요합니다.
#
# False 얼럿이나 플랩이 심한 얼럿을 찾기 위해서는, 얼럿이 발생한 후 짧은 시간 내에 자동으로
# 해결된 경우를 살펴보면 됩니다. 이 경우, 얼럿의 임계값을 조정하거나, 얼럿이 발생하기 전에
# 예방할 수 있는 방법을 찾는 것이 좋습니다. 예를 들어, Error Log 얼럿이 두 번 발생했지만,
# 두 경우 모두 짧은 시간 내에 해결되었습니다. 이는 임계값을 조정하거나, 로그의 에러를 줄이는 방법을 찾아서
# 얼럿을 예방하는 것이 좋을 것 같습니다.

테스트를 해 보면서 꽤 인사이트 있는 대답들을 받아보고 있는 중이고, 현재 이정도로 만족하고 있음.

요약.

GPT를 통해 문제를 빠르게 정리하기 위해서 할 일은 다음과 같았다.

  • GPT에 넣을 데이터를 가져오기 → 데이터 가지고 올 API 구현작업.
  • 가지고 온 데이터는 시스템 프롬프트로 제공하기
  • 미리 준비한 질문들로 빠르게 현재 상황을 해결할 수 있게 만들기 → 질문 체크포인트 만들기

gpt-building-block

< figure 1. GPT 빌딩블록 >

조금 더 똑똑하게 만들어 볼까?…

GPT가 한개 프롬프트 쿼리에 수용할 수 있는 토큰의 수는 제한적이다. 그래서 다양한 정보들을 종합적으로 판단하고 좀 더 넓은 범위의 상황들을 종합적이고 자세하게 판단하기 위해서는 어떻게 하면 좋을까?

  • 프롬프트가 수용할 수 있는 용량은 한계가 있고,
  • GPT는 다양한 상황을 요약하는 기능을 가지고 있으니까, (큰 의미에서 차원 축소)

이 프롬프트 구성을 다양한 컨텍스트를 가지고 오케스트레이션하면 어떨까? 하는 생각에 좀 더 개선을 진행해 보았다.

주제별로 프롬프트 쪼개기

위에서 정리한 프롬프트 처리를 작은 빌딩블록으로 나누고 합치는 과정을 통해 다양한 정보를 종합적으로 받아들일 수 있게 만들어 보고자 했다.

주제별로 작게 컨텍스트를 가진 GPT 빌딩블록을 가지고, 두 정보를 섞어서 더 좋은 인사이트를 얻을 수 있을 것 같다고 생각했고, 이 부분은 지금 고민해 보는 중..

중요한 것은 GPT가 대단하다기 보다…

  • 어떤 정보를 GPT를 통해서 요약할 것이며,
  • 요약한 정보들을 다시 시스템 프롬프트로 제공할 것인가

이런 역할들이 인간으로써 고민해야할 부분이 아닐까 싶긴 했다. (+데이터 가공까지)

orchestrated-gpts

< figure 2. GPT 오케스트레이션 >

더 더 더… 다양한 컨텍스트들이 모인다면… 이런 거대한 구조도 만들어 볼 수 있지 않을까? (상상)

orchestrated-gpts-2

< figure 3. GPT 오케스트레이션 2 >

실험. GPT 멀티플렉서

너무 많은 1차 프롬프트들로 인해서 사용자는 어떤 프롬프트를 선택해야 할 지에 대한 혼란을 느낄 수 있다.

사용자가 HTTP 서버를 통해 다양한 자원에 접근할 때 서버에서는 Path 기반으로 자원을 멀티플렉싱 하는 것 처럼, 앞단에 사용자 입력에 대한 프롬프트 라우터를 만들어 보면 좋을 것 같았다.

멀티플렉싱을 위한 GPT에게 System 프롬프트에서 JSON형태로 프로그램이 이해하기 쉬운 언어로만 답변하게 한 다음, 소프트웨어 적으로 다음 GPT를 선택할 수 있도록 만들면 사용자 초기 입력에 대해 빠르고 정확하게 답변할 수 있도록 만들 수 있을 것 같다는 가설에서 출발.

모델을 Fine-tuning하면서 발생할 수 있는 모델 드리프트를 막을 수 있을 것이다.

gpt-multiplexer

< figure 4. GPT 멀티플렉서 >

테스트 해 본 결과 꽤 잘 동작하는걸로 확인되었음. 아래와 같이 프롬프트를 정의하고…

system_prompt = '''
사용자 입력에 대해서 action_type, from_datetime, to_datetime 값을 가진 JSON으로만 응답한다.
사용자의 입력에 특정 날짜가 있으면, from_datetime은 그 시간으로부터 1시간 이전으로 지정한다.

사용할 수 있는 action_type은 다음과 같다.

- `summary`: 전체 리포트를 응답한다.
- `istio_p99_latency`: istio p99 지연시간 대한 리포트를 응답한다.
- `istio_http_errors`: istio HTTP 에러 구간들에 대한 리포트를 응답한다.
- `alerts`: 얼럿에 대한 요약 리포트를 응답한다.

사용자 입력에 대해서 action_type을 확실하게 파악할 수 없는 경우, action_type을 unknown으로 정한다.

현재 시각은 2023-12-02T19:37:00+0900 이다.
JSON 응답 시작.
'''

이런 질문들을 만들어서 테스트를 해 보았다.


user_prompts = [
    '현재 진행중인 얼럿은 어떤게 있는지 알려줘',
    '별일없니?',
    'istio 서비스메시 구간 상태가 어떻지?',
    'istio 서비스메시 특별히 지연되는 구간에 대해 알려줘',
    'istio 에러가 발생하는 구간들에 대해 알려줘',
    '서비스메시 상태 요약해 줘',
    '어제 현재시각에 있었던 얼럿들을 정리해 봐',
    '11월 3일 오전 8시에 있었던 얼럿들을 정리해 봐',
]

결과.

---
USER: 현재 진행중인 얼럿은 어떤게 있는지 알려줘
SYSTEM:
{
  "action_type": "alerts",
  "from_datetime": "2023-12-02T18:37:00+0900",
  "to_datetime": "2023-12-02T19:37:00+0900"
}
---
USER: 별일없니?
SYSTEM:
{
  "action_type": "unknown",
  "from_datetime": "2023-12-02T18:37:00+0900",
  "to_datetime": "2023-12-02T19:37:00+0900"
}
---
USER: istio 서비스메시 구간 상태가 어떻지?
SYSTEM:
{
  "action_type": "summary",
  "from_datetime": "2023-12-02T18:37:00+0900",
  "to_datetime": "2023-12-02T19:37:00+0900"
}
---
USER: istio 서비스메시 특별히 지연되는 구간에 대해 알려줘
SYSTEM:
{
  "action_type": "istio_p99_latency",
  "from_datetime": "2023-12-02T18:37:00+0900",
  "to_datetime": "2023-12-02T19:37:00+0900"
}
---
USER: istio 에러가 발생하는 구간들에 대해 알려줘
SYSTEM:
{
  "action_type": "istio_http_errors",
  "from_datetime": "2023-12-02T18:37:00+0900",
  "to_datetime": "2023-12-02T19:37:00+0900"
}
---
USER: 서비스메시 상태 요약해 줘
SYSTEM:
{
  "action_type": "summary",
  "from_datetime": "2023-12-02T18:37:00+0900",
  "to_datetime": "2023-12-02T19:37:00+0900"
}
---
USER: 어제 현재시각에 있었던 얼럿들을 정리해 봐
SYSTEM:
{
  "action_type": "alerts",
  "from_datetime": "2023-12-01T18:37:00+0900",
  "to_datetime": "2023-12-01T19:37:00+0900"
}
---
USER: 11월 3일 오전 8시에 있었던 얼럿들을 정리해 봐
SYSTEM:
{
  "action_type": "alerts",
  "from_datetime": "2023-11-03T07:00:00+0900",
  "to_datetime": "2023-11-03T08:00:00+0900"
}

최초 사람의 문장을 잘 이해하고 어떤 기능을 수행할 지 JSON으로 깔끔하게 정리해 준다. 이후 JSON 응답을 가지고 코드를 통한 기능 수행이나, 다음 프롬프트로 전달한다거나 하는 일들을 하면 된다.

소감

아직은 사람이 더 똑똑할 수 있을 것 같다.

GPT가 잘 대답하기 위해서 사람이 해야할 일이 아직 많다는 것을 느꼈다.

  • 7살짜리 애기들을 데리고 어떻게 비즈니스를 풀어갈 것인지..
  • 이 친구들에게 잘게 역할들을 나누어 주기
    • 어떤 정보를 어떻게 나누고, 어떤 역할을 부여할 지.
  • 하지만 인사이트를 합쳐가는 과정은 7살짜리를 넘어서야 할 지도 모른다.
    • 결과를 잘 낼 수 있도록 질문들을 잘 준비하기.
  • GPT가 중요한게 아니다. 인사이트를 얻기 위한 "좋은 질문"이 매우매우 중요하다.
    • 그러기 위해서는 비즈니스 디테일을 잘 알고 있어야 할 것 같다.
    • GPT는 거들 뿐

토이 프로젝트를 진행해 보면서 WWW 초창기 HTTP 서버를 작성하고 사람들끼리 공유하던 시절과, 지금 사람들이 GPT를 활용하면서 확장해 나가는 행태가 비슷하다는 생각이 들었다.

앞으로는 HTTP 서버, HTTP 개발 프레임워크의 등장같이, GPT를 기능별로 쪼개고 잘 개발할 수 있게 만드는 프레임워크들이 많이 등장하지 않을까?

아무튼 재미있었다.

함께 보면 좋은 자료