1. CoT와 FewShotPrompt 조합하기

dasd412·2023년 10월 20일
0

SW 마에스트로

목록 보기
9/10

참고 사항

이 글은 디스콰이엇에도 게시되는 글이며, 모든 예제는 GPT-3.5 기준으로 작성되었습니다.


문제 상황

프로젝트 특성

제가 만들고 있는 프로젝트는, "취준생을 위한 면접 연습 서비스"입니다. 🤩

핵심 기능은 다음과 같습니다.
1. 모집공고와 자소서 분석으로 개인 맞춤형 질문을 제공한다.
2. 상황에 맞게 꼬리질문을 제공한다.

제 생각에 LLM 서비스는 두 가지로 나뉩니다.
첫 번째는 환각을 어느 정도 허용해도 되는 서비스, 두 번째는 환각을 허용하면 안되는 서비스입니다.

예를 들어, LLM을 활용한 채팅 앱은 전자에 해당합니다. 이 경우 환각이 발생해도 사용자는 허허 웃고 말겠죠. 하지만, B2B라던가 제가 만든 면접 연습 서비스는 후자에 해당합니다. 환각이 발생하면 그 서비스의 품질이 심각하게 떨어지는 것처럼 보일 수 있기 때문입니다.

그래서 프롬프트 결과가 이상한 결과가 나오지 않게 하는 노력이 시작됬습니다. (지옥문을 연거죠) 🤪

발생했던 문제들

입력의 특성

먼저, 모집 공고와 자소서의 입력 크기는 어느 정도 될까요?

다음은 예시로, 라인 공고 중 하나를 복사해 놓은 것입니다. 딱 봐도 문자 수가 많습니다.

LINE ADs Data Engineer는 LINE 광고에서 발생하는 방대한 광고 데이터를 가공하여 활용가능하도록 하는 플랫폼 제작을 담당합니다.
Global Big Tech 회사가 비즈니스를 위해 대용량의 데이터를 어떻게 다루는지 경험할 수 있습니다.

[담당 업무]
- 광고 비즈니스를 위한 데이터웨어하우징/ 배치 / 스트리밍 파이프라인 개발 및 운영
- Container 기반의 데이터 처리 플랫폼 개발
- 각종 데이터 플랫폼 운영 및 개선

[자격 요건]
- 컴퓨터 과학의 기초 지식 (자료구조,알고리즘,네트워크 등)을 이해하고 활용할 수 있으신 분
- Java, Python 등의 프로그래밍 언어에 대한 활용 능력이 있으신 분
- 데이터를 다루기 위한 Python, Scalar, Spark, SQL 등에 대한 이해도가 있으신 분
- 궁금한 점은 스스로 찾아 공부하고 끝까지 파고드는 열정이 있으신 분

[우대 사항]
- Hadoop ecosystem, Kubernetes 등에 대한 이해가 있으신 분
- 데이터 처리를 위한 데이터 파이프라인에 대한 이해가 있으신 분

그리고 자소서 문항은 대부분 3~4개입니다.
또한 자소서 한 문항에 대한 응답은 평균적으로 1000~1500자입니다.
이를 한 번에 프롬프트 입력을 넣으면 어떻게 될까요?

예상하시다시피 GPT 3.5기준으로 토큰 제한에 걸립니다.

GPT 3.5의 한계

저는 프로젝트에 GPT 3.5를 사용하기로 선택했습니다.
이유는 일단 싸고 빠르기 때문입니다.

아무리 GPT4가 성능이 더 좋더라도 느리면 사용자가 도망갈 것 같았습니다. (결과적으로는 옳은 선택이였던게, 현재 기준으로 프로젝트 프롬프트 결과는 3.5임에도 꽤 합리적인 편이며, AWS, 네트워크 I/O 등을 감안하면 3.5 기준으로도 어느 정도 기다려야 하기 때문입니다.)

어쨋든, 그 때 당시엔 지금처럼 결과가 안정적이진 못했습니다.
입력 토큰 제한에 걸리거나, 걸리지 않더라도 소위 말하는 환각 현상이 발생했습니다.

원하는 출력 값은 면접 질문들인데, 엉뚱한 값이 꽤 빈번하게 나왔었습니다.


해결 과정

입력 나누기

먼저 입력 토큰 제한 문제를 해결해야 했습니다.
가장 간단한 방법을 활용했죠.
모집공고 A와 자소서 a,b,c,d가 있다면, 한 입력에 A,a,b,c,d를 넣는게 아니라 (A,a), (A,b), (A,c), (A,d) 처럼 쌍을 묶어서 입력을 넣었습니다.
그럼에도 간혹 토큰이 터졌었는데, 그런 문제는 GPT 3.5 turbo 16k로 바꾸니 발생하지 않게되었습니다.

다른 방법도 시도해보았습니다. 결론부터 말하면 효과적이지 않았습니다.
1. Langchain의 SummaryMemory 활용하기
2. Langchain 요약 체인 -> Langchain 출제 체인 (SequentialChain 활용한 것입니다.)

이유는, "요약"때문입니다. 요약이라는 것은 토큰 수를 줄이는데에는 도움이 될 수 있습니다. 하지만 요약한 결과는 요약하기 전 텍스트와 꽤 많이 달라지는 현상이 발생했습니다.

모집 공고와 자소서에서 면접 질문을 내야하는데, 그 원본이 요약때문에 달라지면 무슨 소용이겠습니까? 😠

논문 참고하기

입력 토큰 수를 해결했어도 역시나 환각 현상은 꽤 많이 발생했습니다. 그래서 삽질 도중에 OpenAI가 제공해주는 논문들을 발견했습니다. 그 때 도움이 많이 되었던 것들을 소개합니다.

아래 내용들은 이미 아실 분들은 다 아실수도 있겠습니다 ㅎㅎ

1. Let's think step by step (CoT)

이 구문을 서두에 기입하세요. 그러면 논문에 소개된 것처럼 GPT의 환각이 많이 줄어듭니다. 제 프로젝트에서도 많은 효과를 봤었습니다. 입력의 길이가 꽤 길어도, 구분자만 잘 해주면 면접 질문들을 잘 뽑아낼 수 있었습니다.

ChatGPT 개발자 핸드북이란 서적에 의하면, 이 구문은 CoT(생각의 사슬) 이라고 불리는 기법을 활성시킨다고 하네요.

2. 상황 및 역할 주입하기

상황이나 역할을 주입하면, GPT가 더 적합한 결과를 찾아와줍니다.

3. 구분자 사용하기

구분자를 잘 활용하는 것 역시 결과 찾기에 도움이 됩니다.

4. 예시 주입하기

GPT는 상식이 없습니다. 그저 흉내낼 뿐이죠. 그래서 알맞은 결과를 찾기 쉽도록 예시를 잘 주입해주어야 합니다.

예를 들어, "IT 면접 질문 중 쿠키와 관련된 질문을 해봐"라고 한다면, 가끔씩 쿠키 조리법을 묻기도 합니다 🤮

프롬프트 예시

다음은 2달 전 버전의 프롬프트 중에서 필터에 해당하는 프롬프트입니다.
괜찮은 예시인 것 같아 공유합니다.
지금은 사용되지 않긴 합니다 ㅎㅎ

                        f"""
                         Let's think step by step.

                        [Situation]
                        You are interviewers working at company in job position {job_group}.
                        You are evaluating the interview candidate's response to the previous interview question.

                        [Evaluation]
                        After analyzing the interviewee's response, please select the option with the highest relevance among the following items.

                        1. Direct request or Repeated requests to repeat the question
                        2. Uncertain responses
                        3. Silence or minimal response
                        4. Off-topic responses
                        5. A standard/interview-appropriate response.
                        
                        (HINT!)The criteria of evaluation:
                        - Direct request: The most definitive criterion is when the candidate explicitly requests further explanation or clarification, such as "I did not understand the question" or "Could you please explain that again?".

                        - Uncertain responses: If a candidate responds to a question hesitantly or ambiguously, or uses uncertain language like 'maybe', 'possibly', 'it could be', the interviewer may infer that they did not fully understand the question.

                        - Repeated requests to repeat the question: If a candidate repeatedly asks for the question to be repeated, they likely did not understand the question.

                        - Off-topic responses: If a candidate's answer is not related to the question or strays from the topic, the interviewer may suspect that the candidate did not properly understand the question.

                        - Silence or minimal response: If the candidate provides no or minimal response to a question, the interviewer may infer that they did not understand the question or are unsure about how to respond.

                        [Conclusion]
                        (This part must not be omitted from the output.)
                        (The beginning of output format must be as follows)
                        "I think it is (only number)"


                        """

위 프롬프트는 면접 지원자의 답변이 "적절한가"를 판단하는 프롬프트입니다. 클래스 이름도 AnswerFilter구요.
보시다시피 4가지를 조합했습니다.
처음에 "Let's think step by step"을 주입했고, 인터뷰어라는 상황과 어떠한 문제를 해결해야 하는지 [situation]에 작성했습니다.

그리고 각 단계는 []이라는 문자로 구분되고 있습니다.

또한 상식이 없는 GPT를 위해서 어떤 것이 적절하지 않은 면접 답변인지 예시를 5개 주고 있습니다.

입출력 예시

정상 답변부터 보죠.

{'question': 'JPA N+1 문제는 언제 발생하나요?', 'answer': '두 개의 엔티티가 1:N 관계이며 JPQL로 객체를 조회할 때 발생합니다. 두 가지 경우로 나뉠 수 있는데요.\n    첫 번째는 ‘EAGER’ 전략으로 데이터를 가져올 경우입니다. 만약 1에 해당하는 엔티티를 조회할 때 ‘즉시 로딩’이라면, N에 해당하는 엔티티들 전부를 일일이 검색하게 됩니다.\n    두 번째는 ‘LAZY’ 전략으로 데이터를 가져온 이후에 해당 데이터와 연관된 엔티티를 다시 조회할 경우에 발생합니다. ‘지연 로딩’일 경우엔 1에 해당하는 엔티티를 조회시 연관된 엔티티들을 프록시로 임시 저장해놓습니다. 하지만, 프록시이기 때문에 N에 해당하는 연관 엔티티들을 실제로 조회할 땐 결국에 N개의 엔티티에 대한 검색이 필요합니다.'}

I think it is 5. A standard/interview-appropriate response.

다음부터는 비정상 답변입니다.

{'question': 'JPA N+1 문제는 언제 발생하나요?', 'answer': '잘 모르겠습니다.'}

I think it is option 2. Uncertain response.
{'question': 'JPA N+1 문제는 언제 발생하나요?', 'answer': '...네?'}
I think it is 1. Direct request or Repeated requests to repeat the question
{'question': '당신이 경험한 가장 큰 프로젝트 실패는 무엇이었고, 그로 인해 어떤 배움을 얻었나요?', 'answer': "제가 이해를 잘 못했는데, '프로젝트 실패'라는 것이 구체적으로 어떤 상황을 말씀하시는 건가요?"}

I think it is 1. Direct request or Repeated requests to repeat the question.
{'question': '문제 해결에 어떤 접근 방식을 취하는지 설명해 주십시오.', 'answer': '하늘 끝에서 흘린 눈물이 비 되어 내리면'}


I think it is 4. Off-topic response.

맺으며

다음 시리즈인 프롬프트로 switch ~ case 구현하기에서 뵙겠습니다. 감사합니다.


참고 링크

https://github.com/openai/openai-cookbook/blob/main/articles/techniques_to_improve_reliability.md

profile
시스템 아키텍쳐 설계에 관심이 많은 백엔드 개발자입니다. (Go/Python/MSA/graphql/Spring)

0개의 댓글