LLM 역량을 200% 끌어올리는 법
- 효과적인 프롬프트를 만들기 위해 프로므트 작성에 집중하는 것도 중요하지만, LLM이 주어진 문제를 더 잘 이해하고 응답할 수 있는 다양한 조건과 방법을 이해하는 것이 프롬프트 엔지니어링을 더욱 효율적으로 할 수 있는 방법이다.
- 또한 뛰어난 LLM이라면 프롬프트를 만드는 것까지도 도움받을 수 있다.
모델을 선택할 때 고려해야 할 것들
- 적합한 모델을 선택하는 것은 프로젝트의 성공 가능성, 비용 효율성, 그리고 최종 결과물의 품질 등에 직접적인 영향을 미치는 가장 중요한 과정이다.
비용과 속도
- 성능과 속도, 비용 간에는 어느 것이 좋으면 다른 것은 상대적으로 떨어지는 상충관계가 있다.
- 성능(답변 품질 및 정확도 등)이 높은 모델일수록 속도는 떨어지고, 성능이 낮은 모델일수록 속도는 빨라진다
- 또한 비용과 성능은 비례하지만 성능이 올라가는 것에 비해서는 훨씬 더 크게 높아지는 편이다.
- 따라서 원하는 작업이 어느 정도 성능의 LLM 모델을 필요로 하는지에 따라 미리 그 가격과 성능을 따져야 할 필요가 있다.
- 만약 비용을 최대한 정확하게 예측해야 할 경우에는 샘플 결과를 모아 토크나이저로 먼저 계산해 봐야한다.
성능(추론 능력)
- 모델을 선택할 때 가장 중요한 것은 당연히 성능이다.
- 성능에는 정확한 정보를 전달하는 것 뿐만 아니라 논리적인 결과를 추론하고 문제를 해결하는 코드를 생성하는 등 다양한 종류가 있다.
- 링크
- 해당 링크는 참고만하고 깊게 신뢰하지 않는 것이 좋다.
- 특정 작업에 대한 성능을 비교하는 벤치마크 점수가 높다고 하더라도 실제 사례는 다를 수 있다.
- 그리고 각 벤치마크마다 강점이 있는 것들이 있다.
경향성
- 모델을 선택할 때 아주 정확한 정보 제공이 필요한 것이 아니라면 경향성을 보고 판단하는 것도 좋은 방법이다.
- 예를 들어 Claude의 경우 결과를 구어체 문장으로 생성하는 경향이 있고, GPT-4모델은 격식을 갖춘 어느 정도 구조화된 리포트 형태로 생성하는 경향이 있다.
성능 vs 경향성
- LLM 모델을 선택할 때 확인해야 하는 것은 답변의 유려함이나 정보의 정확성이 아니다.
- 정보 추출 능력, 특히 추론 능력이 잘 동작하는지를 먼저 테스트해야 한다.
- 때때로 모델의 뛰어난 한국어 구사 능력만 보고 해당 모델을 선택하곤 한다.
- 하지만 자세히 살펴보면 대부분의 경우 모델이 유창한 한국어를 구사할 뿐 실제 성능은 그리 좋지 못한 경우가 많다.
- 또한 아무리 모델이 크고 정확하다고 해도 그 자체로만 100%의 성능을 낼 수는 없다.
- 기본적으로 외부 지식베이스에서 전문 정보를 가져오거나 계산기 등의 도구(코드 인터프리터 등)를 활용해 정확성을 높이는 방법을 많이 사용한다.
- 이와 같이 외부 도구의 사용은 필수적이기 때문에 정보의 정확성은 모델 하나만으로는 해결할 수 없다.
- 대신 주어진 정보에서 논리적으로 결론을 도출하기 위한 정보 추출 능력과 추론 능력을 면밀히 따져봐야 한다.
- 하지만 이 역시 원하는 작업마다 다른 결과를 낼 수 있으므로 벤치마크 점수나 두어 번의 테스트로만 모델을 결정하지 말고, 실제 사례를 충분히 모아 테스트한 후 신중하게 결정해야 된다.
생성 결과의 안정성
- LLM API를 사용한다면 API를 제공하는 회사의 폭력적이거나 비윤리적인 답변을 못하게 막는 장치를 제공하는지도 확인할 필요가 있다.
- 이와 관련하여 OpenAI와 MS Azure는 Moderations API를 제공하고 있다.
- 이는 사용자의 입력이나 모델의 출력을 검사해 문제되는 입력을 받거나 답변을 생성하지 못하도록 제어할 수 있는 API이다.
- OpenAI는 콘텐츠 필터링 사용이나 해제를 자유롭게 할 수 있다.
- 반면 MS Azure는 기본적으로 콘텐츠 필터링이 적용되어 있고, 해제를 원하면 반드시 MS의 승인을 받아야 한다.
- 이처럼 서비스 제공 회사에 따라 정책이 다를 수 있으므로 모델 사용 시에는 안정성에 대한 정책이 어떻게 되어 있는지 확인할 필요가 있다.
API 서버 안정성
- OpenAI보다 MS나 구글의 API 안정성이 조금 더 높다는 의견이 있다.
- 하지만 새로운 모델이 업데이트되는 초반에는 MS나 구글도 안정성이 급격히 떨어질 수 있다.
- LLM 모델 대부분이 매우 큰 규모의 컴퓨팅 자원을 사용하는 만큼 이러한 경우가 종종 발생한다.
- 따라서 LLM API를 사용하면 기본적으로 안정성이 낮을 것을 염두에 두고 문제가 생겼을 때는 여러 번 다시 시도하거나 에러 상황 발생에 잘 대비하는 것이 좋다.
- 또한 실제 서비스 적용 시 Failover(장애 조치) 등의 정책을 고려하는 것은 필수이다.
프롬프트 작성 도움받기
- 프롬프트는 원하는 작업을 명확하게 지시하여 제대로 수행할 수 있도록 안내하는 가이드이다.
- 그 말인즉슥 LLM에게 도움을 받으면 더 좋은 프롬프트를 만들 수 있다는 뜻이기도 하다.
- 프롬프트 작성 시에는 크게 프롬프트 작성 초안 생성, 프롬프트 평가 및 개선, 프롬프트 다듬기, 프롬프트 번역하기의 네 가지 방법을 주로 사용한다.
- 다만, 프롬프트 작성은 고성능의 LLM 모델이어야만 도음을 받을 수 있다.
- 현재 프롬프트 작성을 도움받을 수 있는 모델로는 GPT-4, Claude 3, Gemini 1.5 정도가 있다.
프롬프트 초안 생성
- 위쪽에 몇 가지 예시와 함께 프롬프트를 만들기 위한 조건을 자세히 넣어 주면 설명과 함께 프롬프트 초안을 작성해준다.
- 초안은 앞서 배운 대로 프롬프트를 만드는 목적과 목표, 상세한 컨텍스트와 예제, 그리고 구체적인 형식으로 자세하게 기술한다.
- 이 초안을 그대로 사용할 수 있는 것은 아니지만 이를 토대로 조금씩 변경하면서 프롬프트를 완성해 나갈 수 있다.
프롬프트 평가 및 개선
- 프롬프트가 잘 만들어졌는지 평가하고 개선하는 데에도 LLM을 사용할 수 있다.
- 해당 프롬프트가 태스크를 잘 수행할 수 있는지, 그 의미가 명확한지, LLM이 잘 이해하고 명령을 수행할 수 있는 지를 평가하고 개선해달라고 이야하면 된다.
- 이때는 앞서 작성한 프롬프트 초안을 그대로 사용하고, 원하는 목적에 맞는 프롬프트인지를 확인하고 개선해달라는 요청을 추가한다.
- 프롬프트를 만드는 목적과 목표, 컨텍스트와 지시 사항들을 참고해야 의도를 더 정확하게 파악하고 개선할 수 있기 때문이다.
프롬프트 다듬기
- 프롬프트를 다듬을 때는 명확하고 구체적으로 지시문을 작성해야 한다.
- 앞서 만들었던 프롬프트를 넣은 다음 상세하게 작성한 개선 규칙에 따라 바꿔 달라고 이야기한다.
- 개선 규칙을 세세하게 작성할수록 LLM도 더 상세하고 명확하게 프롬프트를 개선한다.
- 그리고 개선된 프롬프트의 내용과 개선된 프롬프트로 실행한 결과를 확인한 후 개선 규칙을 계속 추가하거나 수정하면서 의도에 맞는 충분한 품질의 결과가 나올 때까지 반복한다.
- 개선 규칙은 한번 만들고 계속 사용하는 것이 아니라 원하는 성능을 만들기 위해 조금씩 수정하고 추가하는 것이 핵심이다.
- 또한 단어를 사용할 때는 LLM이 혼동하지 않도록 명확하고 쉬운 단어를 사용한다.
- 예시
1 2 3 4 5 6 7 8 9 10 11
프롬프트 개선 규칙 --- - GPT가 보다 정확한 답변을 제공할 수 있도록 주제나 지시를 명확하게 세분화하고 구체적으로 작성하세요. - GPT가 이해하기 쉬운 단어와 문장 구조를 사용해 주세요. 복잡한 어휘나 전문 용어의 사용은 가등한 줄여 주세요. - GPT가 당신의 의도를 정확하게 파악할 수 있도록 간단하고 명확한 언어를 사용하여 작성하세요. - 객관적이고 균형 잡힌 답변을 얻기 위해 지시를 중립적이고 구체적인 방식으로 제시하세요. - 충분한 문맥과 명확성을 제공할 만큼의 길이로 프롬프트를 작성하세요. 이전 정보가 다음 질문의 맥락에 중요한 경우 이를 명확하게 전달하세요. - 혼란이나 집중력의 손실을 방지하기 위해 간결하게 작성하세요. - 감정적인 측면보다 결과에 초점을 맞추어 사실과 결과에 기반한 지시를 하세요. - GPT가 보다 정확하고 유용한 답변을 제공하기 위해 주관적인 질문을 피하고 보편적인 질문으로 재구성하십시오.
프롬프트 번역하기
- 한국어로 작성한 프롬프트는 몇 가지 고성능 모델을 제외하고는 성능이 떨어지는 편이기 때문에 번역은 중요하다.
- 또한 한국어는 토큰 수도 상대적으로 많다
- 따라서 내용 중에 고유명사나 반드시 한국어로 이해해야 하는 내용이 아니라면 프롬프트는 가능하면 영어로 작성하는 것이 좋다.
- GPT에게 먼저 한국어를 영어로 번역시킨 다음, 그 프롬프트를 기반으로 실제 수행하는 프롬프트를 작성하다.
- 그렇게 해서 나온 영어 답변으로 프롬프트를 개선하면 한국어로 같은 내용을 수행한 것보다 훨씬 좋은 결과를 얻을 수 있다.
- 또한 프롬프트를 다듬을 때부터 아예 프롬프트 개선 규칙에 따라 영어로 한번에 답변하도록 만들 수 있다.
- 고성능 모델의 경우 다국어를 동시에 처리 할 수 있기 때문에 영어와 한국어를 병기하는 것도 좋은 방법이다.
- 프롬프트를 영어로 작성하되, 고유명사나 한국어로 명시하는 것이 좋은 부분만 한국어로 작성하면 영어 혹은 한국어 만으로 작성하는 것보다 좋은 결과를 얻을 수 있다.
환각 줄이기
- LLM에서의 환각이란 모델이 생성한 테스트가 사실과 다른 내용이나 주어진 정보에 없는 내용, 즉 실제로는 존재하지 않는 정보를 생성하는 것이다.
- 환각이 발생하는 이유 : LLM은 어떻게든 적절한 답변을 생성하려고 노력하기 때문에 상상한 답변을 내놓을 수 있다.
- 이는 편향된 데이터, 문맥의 오해, 관련 데이터 부족 등의 문제로 인해 발생한다.
- 환각 현상은 초기에는 뜨겁게 비판 받았지만 현재는 심각한 버그가 아닌 이상 또 다른 기능으로 받아들여지고 있다.
- 이를 통해 미처 생각하지 못한 창의성을 발현할 수도 있기 때문이다.
- 정확한 정보를 제공해야 하는 작업이라면 환각을 최소화해야 한다.
- 그러기 위해서는 작업에 적합한 컨텍스트를 충분히 잘 넣어 주는 것이 가장 좋은 방법이다.
- 환각을 최소화하는 추가적인 방법은 아래와 같다.
- 제공한 정보를 바탕으로 답변하도록 명시적으로 지시한다.
- 주어진 문서에서 질문의 답과 관련된 내용을 인용하도록 지시한다. 이때 문서 요약과 함께 제공하면 조금 더 정확한 결과를 얻을 수 있다.
- 모든다는 답을 허용하도록 명시한다.
- 프롬프트를 출력할 때 사고와 답변을 분리하여 스스로 생각하게 만든다.
- 각각 다른 방법으로 여러 개의 출력을 생성한 후 각각의 답변이 일관성이 있는지를 답변하도록 지시(Self-Consistency)한다.
외부 지식 주입하기
- LLM은 다양한 유형의 텍스트를 읽고 학습할수록 광범위한 지식을 습득하고 이를 바탕으로 더 정확하고 자연스러운 응답을 할 수 있다.
- 문학, 과학, 일상, 대화, 기술 문서 등 다양한 분야와 언어의 지식 데이터를 주입하는 것은 물론 사용자와 상호 작용을 통해 실시간으로 피드백 받고 그에 따라 학습할 수 있도록 해야 한다.
그라운딩과 RAG
- LLM을 활용할 때 프롬프트를 작성하는 것만큼이나 중요한 것이 그라운딩과 RAG이다.
- 그라운딩은 LLM에게 검색 등을 통해 문맥에 더 적합한 정보를 제공하거나 게산기 등을 사용해 정확한 계산 결과를 제공하는 방법이다.
- 이를 통해 언어 모델의 대표적인 문제점인 환각 현상을 줄이고, 모델 학습에 사용한 데이터 이후에 나오는 최신 정보를 이용한 결과도 생성할 수 있다.
- RAG은 정보를 검색한 결과를 기반으로 텍스트를 생성하는 방법이다.
- 이는 대화의 맥락을 유지하기 위해 장지 기억 메모리로 활용하기도 한다.
- 예를 들어 다음과 같이 사용자가 어떤 질문을 하면 LLM은 그에 해당하는 정보를 검색 혹은 벡터 DB에서 가져온다.
- 그리고 그 가져온 정보를 이용해서 결과를 생성하는 것이 RAG이다.
임베딩 모델 선택하기
- 임베딩 모델은 텍스트를 숫자로 바꾸는 머신러닝 모델을 말한다.
- 임베딩이란 숫자의 집합으로 단어나 문장, 문단 같은 텍스트의 조각이 어떤 으미ㅣ 공간에 있는지를 알려주는 기술이다.
- 텍스트를 벡터화하는 임베딩 모델은 굉장히 많다.
- 그리고 각 임베딩 모델의 성능을 비교하는 리더 보드도 다양하게 존재한다.
- 따라서 어떤 모델을 선택할지 고민 할 때는 RAG를 고려하여 Retrieval 성능을 반드시 확인하는 것이 좋다.
- Retrieval은 모델이 필요한 정보를 검색 엔진이나 데이터베이스로부터 효율적으로 찾아내는 과정으로, 여기서 텍스트 조각들을 벡터화한 대량의 자료 뭉치에서 답변에 필요한 정보를 정확히 잘 찾아낼 수 있는지에 대한 성능을 뜻한다
- 리더 보드가 일반적인 성능 테스트 결과라고 해도 자신이 가지고 있는 데이터 셋과는 잘 맞지 않을 수 있다. 따라서 실제 사용할 데이터로 사전 테스트를 거친 후 가장 적합한 모델을 선택해야 한다.
- 민감하거나 정확도가 높아야 하는 데이터라면 파인튜닝한 모델을 사용하는 것이 좋다.
벡터 DB
- 벡터 서치를 본격적으로 사용하려면 벡터 DB를 사용하는 것이 일반적이다.
- 벡터 서치를 위해 사용하는 기본적인 라이브러리들은 벡터 DB에서 찾아온 벡터 값만 보여줄 뿐 그 벡터가 어떤 텍스트와 관련된 것인지는 알려주지 않는다.
- 그래서 등장한 것이 벡터 DB이다.
- 벡터 서치를 통해 가장 가까운 벡터를 찾은 다음 그것이 어떤 문서의 벡터인지를 알 수 있도록 문서 제목이나 내용 등의 메타 정보를 함께 반환하는 것이다.
- 그 밖에도 벡터 DB가 제공하는 편의 기능은 아래와 같다.
- 메타 데이터와 함께 결과 반환
- 키워드 필터링 등을 이용한 하이브리드 검색
- 실시간 인덱싱을 통한 대규모 벡터 정보 검색
- 다양한 인덱싱 방법 및 검색 알고리즘 제공
- 높은 확장성 및 개발자 편의 기능 등
- 벡터 DB로 유명한 서비스는 다음과 같다.(Pinecone을 제외하고는 전부 오픈소스이지만 파인콘이 가장 기능이 다양하고 개발자 경험이 좋아서 많이 사용되고 있다. 근래 출시된 Chroma도 파인콘만큼 좋은 개발자 경험을 제공하면서 인기가 높아지고 있다)
- Pinecone
- Chroma
- Milvus
- Redis
- Weaviate
- Elasticsearch
- Qdrant
- PostgreSQL
- 최근에는 벡터가 LLM 애플리케이션의 핵심 컴포넌트로 떠오르면서 거의 모든 데이터베이스가 벡터 서치를 지원하기 시작해 앞으로 점점 더 선택권이 넓어질 것으로 보인다.
- 하지만 성능(정확도)와 속도는 상충 관계이기 때문에 자신의 서비스에 맞는지 잘 판단해서 선택해야 한다.
- 간단한 서비스라면 크로마, 본격적인 서비스라면 레퍼런스가 풍부한 파인콘을 추천함.
- 온프래미스로 직접 구축하고 싶다면 Qdrant를 추천함
- 백터 서치가 계속해서 좋아지고는 있지만, 임베딩 모델이나 검색 방식 혹은 DB 규모나 사용자에 따라 성능이 잘 따라오지 못하는 경우가 종종 있다.
- 이를 해결하기 위해 하이브리드 서치(Hybrid search)를 사용한다.
- 즉, 검색 정확도를 높이기 위해 키워드 필터링이나 Dense 벡터, Sparse 벡터 등을 조합해 검색하는 방식
- 그러나 검색으로 가져왔다고 해서 항상 최상의 결과는 아니다.
- 또한 LLM의 성능을 향상시키기 위해 너무 많은 검색 결과를 넣으면 비용이나 속도 문제가 생길 수 있고, 토큰 수 제한에 걸려 원하는 만큼 사용하지 못할 수도 있으므로 여러 가지 면을 고려해야한다.
Rerank
- 성능을 더욱 높이기 위해 Rerank라는 기술을 사용하기도 한다.
- 이는 1차로 벡터 서치나 키워드 서치 등으로 가져온 결과에서 한 번 더 필터링을 거치는 방법이다.
- 벡터 서치나 키워드 서치를 통해 가져온 문서를 벡터 서치에 사용한 모델이 아닌 다른 임베딩 모델이나 프롬프트를 사용해 다시 적은 숫자로 추린다.
- 다른 임베딩 모델을 사용해 순서를 재정렬하거나, 검색해 온 문서들을 프롬프트에 넣은 다음 이 중에서 사용자가 요청한 내용과 가장 유사한 것을 일부 선택해 재정렬하라고 하는 것이다.
- 이렇게 사용자 요청에 맞게 다시 추린 결과를 본 작업을 처리하는 프롬프트에 제공하면 된다.
- 핵심은 관련 벙뮈가 넓은 다수의 데이털르 먼저 가져온 뒤, 저렴하고 작은 모델을 이용해 관련이 높은 적은 수의 데이터로 추리는 것이다.
- 이렇게 하면 대량의 데이터에서 정보를 추출해야 하는 경우 비용을 크게 늘리지 않으면서도 답변의 정확성을 높일 수 있다.
Chunking
- 텍스트를 적절한 길이로 자르는 방법이다.
- 임베딩 모델에는 최대 토큰 수가 제한되어 있기 때문에 이를 넘는 텍스트는 잘라서 사용해야 한다.
- 또한 긴 텍스트를 임베딩하는 과정에서 일부 의미가 소실되는 경우가 있다.
- 그럴 때는 텍스트를 여러 개의 작은 부분으로 나누고 각 부분들 독립적으로 임베딩할 수 있게 하면 텍스트의 특징을 더욱 잘 표현하면서 정교한 검색이나 분석이 가능해진다.
- 단순히 토큰 수나 단어 단위로 달라도 되지만, 문장이나 문단과 같이 구조화된 문서라면 각 섹션 단위로 자르는 등의 방법을 사용하면 좋다.
- 본격적으로 청킹을 사용하기 전에 먼저 임베딩 모델이나 문서의 성격에 따라 실험을 통해 적절한 길이와 방법을 찾아야 한다.
- OpenAI의 text-embedding-3-* 모델은 일반적으로 200~500개 사이의 토큰 길이를 추천한다.
- 실제로도 그렇게 실험했을 때 가장 좋은 결과를 얻을 수 있다.
- 또 다른 방법으로 오버랩과 슬라이딩이 있다.
- 오버 랩은 텍스트를 나눌 때 각 chunk가 일부 공통된 데이터를 포함하도록 하는 기법이다.
- 슬라이딩은 텍스트를 일정한 길이의 작은 단어 조각으로 순차적으로 이동하며 데이터의 chunk를 캡처하는 방법이다.
- 이때 슬라이드할 토큰의 길이를 슬라이딩 윈도우라고 한다.
외부 도구 사용하기: 함수 호출
- LLM 모델이 어떤 기능을 가지고 있지 않아도 각종 API를 서비스하는 회사들이 모델에 사용하기 쉽도록 응용할 수 있는 형태로 기능을 만들어 두기도 한다.
- ChatGPT 유료 버전에서 제공하는 검색, 코드 인터프리터, GPT 등을 만들기 위해 사용하는 플러그인이나 액션 등이 이에 대항한다.
- 함수 호출은 LLM이 이러한 도구를 사용할 수 있게 만들어주는 것으로 “Tool use”, “Tooling”이라고도 한다.
함수 호출이란
- 호출할 수 있는 함수를 미리 설정해 두면 사용자의 필요에 따라 해당 함수 이름을 호출하여 요청에 응답하는 기능이다.
- 단, 프로그램 내의 함수를 직접 호출하는 것이 아니라 어떤 함수와 파라미터가 필요한지를 JSON 형식으로 응답해준다.
- 예를 들어 날씨에 대한 답변을 하려면 날씨 정보를 가져오는 작업이 필요하다.
- 이를 위해 날씨 API를 사용하는 방법을 미리 정의해둔다.
- 그리고 사용자가 날씨를 물어보면 GPT는 날씨 정보를 먼저 가져와야 한다는 것을 이해하고, 미리 정의해 둔 날씨 API를 사용하라는 응답을 JSON형식으로 돌려준다.
- 그런데 이 응답을 사용자에게 바로 돌려주는 것이 아니라 응답에 따라 정의해 둔 날씨 API를 호출하고 정보를 받은 뒤, GPT에게 해당 정보화 함께 사용자에게 응답할 답변을 생성하도록 다시 요청한다.
- 그리고 최종적으로 생성한 답변을 사용자에게 제공한다.
- 이러한 기능들은 GPTs나 Zapier 등에서는 이를 이용해 다양한 API들을 쉽게 연결할 수 있는 방법들을 제공하기 시작했다.
함수 호출의 흐름
- GPT가 어떻게 도구를 사용하는지 이해하기 위해 함수 호출의 흐름을 알아본다.
- 우선 함수 호출에서 사용하는 각 항목이 어떤 의미를 가지고 있는지 살펴보면 아래와 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
{ "name" : "get_current_weather", "description" : "주어진 위치의 현재 날씨를 가져옵니다.", "parameters" : { "type" : "object", "properties" : { "location" : { "type" : "string", "description" : "도시 또는 지역, 예) 서울", }, "unit" : {"type" : "string", "enum" : ["celsius", "fahrenheit"]}, }, "required" : ["location"], }, }
- 위 JSON에 대한 설명
- “name” : 필요한 기능 확인 시 반환할 함수명
- “description” : 해당 함수에 대한 설명
- “parameters” : 함수 호출에 필요한 파라미터 정의
- “description” : 설명에 따라 파라미터를 요청하거나 생성
- “required” : 함수 호출을 만들기 위해 필요한 필수 정보
- GPT는 “name”바로 아래에 있는 “description”의 설명을 보고 사용자의 요청에 “get_current_weather” 기능이 필요하다고 판단한다.
- 따라서 이 설명이 가장 중요하다
- 그 다음 이 함수를 호출하기 위한 파라미터 중 “required”에서 지정한 필수 정보인 “location”이 사용자의 요청에 들어 있지 않으므로, 이 정보를 획득하기 위해 어느 도시나 지역의 날씨를 알고 싶은지 요청하는 메시지를 반환한다.
- 사용자로부터 함수 호출에 필요한 파라미터를 모두 전달받으면, 프로그램 내에 있는 get_current_weather라는 함수를 호출하여 날씨 정보를 받아오는 기능을 실행한다. 그리고 GPT에 날씨 정보를 제공해 최종 응답을 생성하면 된다.
함수 호출 응용
- 함수 호출은 필요한 함수를 호출하는 경우 외에도 다양한 용도로 사용할 수 있다.
- SQL과 같이 실행 가능한 간단한 코드를 생성하거나 JSON 포맷으로 정확하게 결과를 생성하도록 유도하는 데 사용하기도 한다.
- 다음과 같이 “description” 항목에 결과를 SQL 쿼리로 출력하라고 요청하면 SQL 쿼리를 만드는 프로그램을 쉽게 만들 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
{ "name" : "ask_database", "description" : "Use this function to answer user questions about music. Output should be a fully formed SQL Query." , "parameters": { "type": "object", "properties": { "query": { "type" : "string", "description": f""" SQL query extracting info to answer the user's question. SQL should be written using this database scheme: {database_scheme_string} The query should be returned in plain text, not in JSON. """, } }, "required" : ["query"], } }
- 한 번에 작성하는 것은 무리가 있지만, 간단한 쿼리는 이런 방식으로 처리가 용이하다.
- 물론 쿼리가 항상 정확한 것은 아니기 때문에 반드시 유효성을 확인해야 한다.
- 또 한 가지 방법은 JSON 포맷터로 사용하는 것이다.
- 프롬프트에 답변을 JSON 형식으로 작성하라고 지시할 수도 있지만, 함수 호출을 사용하면 좀 더 정확한 형식으로 결과를 생성할 수 있다.
- 다음 예시는 어떤 요리에 대한 레시피를 제공하기 위해 “dish”, “ingredients(재료)”, “instructions(요리 방법)”에 무슨 정보가 들어가야 하는지에 대한 설명을 각각의 “description”에 설정해 놓은 것이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
{ "name" : "set_recipe", "parameters": { "type" : "object", "properties": { "dish": { "type": "string", "description": "Descriptive title of the dish" }, "ingredients": { "type": "array", "items": {"type" : "string"} }, "instructions": { "type": "array", "description": "Steps to prepare the recipe.", "items": {"type" : "string"} } } }, }
- 그럼 위에 설정한 내용을 참고하여 재료와 레시지를 함께출력하는 것을 볼 수 있다.
- 이와 같이 함수 호출을 이용하면 원하는 결과를 JSON 포맷으로 굉장히 쉽고 정확하게 얻어낼 수 있다.
함수 호출 사용 시 주의 사항
- 함수 호출을 사용하면 편리하지만, 몇 가지 주의 사항도 함께 알아둬야 한다.
- 프롬프트 인젝션에 취약할 수 있다.
- 프롬프트 인젝션을 통한 민감 정보 추출이나 RCE(Remote Code Execution) 공격 시도 등을 사전에 고려해서 방어해야 한다.
- 특히나 사용자의 아이디나 비밀번호 등의 민감한 정보는 파라미터 설정에 넣지 않는 것이 좋다.
- 또한 응답 받은 함수는 바로 실행하지 말고 보안상 문제는 없는지, 정상적인 파라미터와 함께 호출하도록 응답됐는지를 먼저 확인하고 실행하는 것을 권장한다.
- 호출 오류가 생길 수 있다.
- 모든 요구 사항에 대해 항상 정확한 함수 호출로 응답하는 것은 아니다.
- 불필요한 함수 호출이 일어나거나 설정하지 않은 함수를 추측해서 호출하는 경우가 발생할 수 있다.
- 예를 들어 함수 설정에는 Get만 있는 Add나 Delete 함수 등을 추측해 호출하는 경우
- 따라서 반환되는 값을 항상 확인 한 후 실행해야 한다.
- 예를 들어 함수 설정에는 Get만 있는 Add나 Delete 함수 등을 추측해 호출하는 경우
- 이처럼 함수 호출은 굉장히 좋은 기능이긴 하지만 그만큼 위험 부담도 크다.
- 따라서 응답받은 파라미터 값을 항상 확인하고 실행하거나, 중요한 동작은 실행할 액션을 사용자에게 먼저 확인한 뒤에 실행하는 편이 좋다.
프롬프트 평가와 테스팅
- 소프트웨어는 개발 기간보다 유지 보수하는 기간이 훨씬 길다.
- 프롬프트도 마찬가지다.
- 프롬프트는 광범위한 시행착오를 거치면서 계속해서 개선하는 과정을 반드시 수반한다.
- 결국 프롬프트 엔지니어링의 핵심은 평가를 반복하면서 프롬프트를 최적화하는 과정이므로 이 평가를 어떻게 하는지가 LLM 서비스의 품질을 좌우하는 가장 큰 요소이다.
프롬프트 요구 사항 명세
- 소프트웨어 요구 사항 명세를 만들듯이 프롬프트도 요구 사항 명세를 먼저 만들고 시작해야한다.
- 먼저 소프트웨어 요구 사항 명세의 정의를 살펴보면 다음과 같다.
- 개발할 소프트웨어 제품이 어떻게 기능해야 하는지를 정리한 문서이다.
- 프로그램이 처리해야 할 기능을 구체적으로 정의하고, 입출력 요건과 프로그래밍에 필요한 논리 개념을 정리한다.
- 구체적인 시스템 설계 단계 이전에 요구 사항을 평가하는 것으로, 나중에 재설계하는 작업을 줄일 수 있도록 해야 한다.
- 소프트웨어 제품 개발 프로젝트 실패를 방지해야 한다.
- 일반적인 소프트웨어 명세와 마찬가지로 프롬프트 역시 입출력 요건을 먼저 정의하는 것이 중요하다.
- 이를 위해선 아래의 세가지 작업이 필요하다.
- 답변을 위해 필요한 적절한 컨텍스트 정의(컨텍스트 데이터)
- 원하는 결과 추출을 위한 프롬프트 작성(인스트럭션 or 사용자 입력 데이터)
- 결과물의 형식을 지정(출력 데이터)
- 프롬프트 명세에 데이터가 하나씩만 있어서는 안된다.
- 머신 러닝의 경우 학습을 시키기 위한 데이터 분류를 아래와 같이 나눈다.
- 모델을 학습시키기 위해 사용하는 Training Data
- 학습 도중에 이 모델이 잘 학습되고 있는가를 판단하기 위한 Validation Data
- 학습이 끝난 후 모델의 성능을 최종 평가하는 Test Data
- 프롬프트 애플리케이션은 이미 학습이 끝난 LLM 모델 위에서 돌아가는 것이기 때문에 성능 평가를 위한 데이터만 필요하다.
- 위의 데이터 중에서 성능 평가를 위한 데이터만 필요하다.
- OpenAI에서는 평가 데이터의 양에 대해 다음과 같은 가이드를 제공한다.
- 표에 따르면 정확한 평가를 위해서는 약 1000개의 평가 데이터가 필요
- 다만, 경험상 아주 정밀한 수준의 평가가 아니라면 100개 정도의 데이터로도 적절한 수준의 평가가 가능하다.
- 사실 데이터의 양보다는 여러 가지 케이스를 포괄하는 다양한 샘플 데이터가 중요하다.
- 표에 따르면 정확한 평가를 위해서는 약 1000개의 평가 데이터가 필요
- 검증을 위해 필요한 테스트 셋 크기
감지율 | 95% 신뢰도를 위한 테스트 셋 |
---|---|
30% | ~10 |
10% | ~100 |
3% | ~1000 |
1% | ~10000 |
프롬프트 버전 관리
- 프롬프트는 반복해서 개선하는 과정이 필수인 만큼 버전 관리도 매우 중요하다.
- 버전 관리가 필요한 경우
- 실제 서비스 진행 뒤 문제가 생겨 롤 백(roll back, 현재 버전의 프롬프트가 유효하지 않거나 망가졌을 때 이전 버전으로 되돌리는 행위)이 필요한 경우
- LLM 모델이 변경되어 프롬프트 재탐색이 필요한 경우
- 변경 사항 추적이 필요한 경우
- 버전 관리는 다음과 같은 변경 조건을 따르면 무리 없이 관리할 수 있다.
- 메이저 버전 변경
- 출력 포맷이 변경되는 경우
- 출력 내용이나 구성이 많이 변경되는 경우
- 마이너 버전 변경
- 결과를 조금 더 정확하게 출력하도록 개선하는 경우
- 생성 옵션이 변경되는 경우
- 메이저 버전 변경
생성 결과 평가하기
- 생성 결과를 어떻게 평가하느냐도 굉장히 중요하다.
- 그 구체적인 방법에는 기본적으로 다음 네가지가 있다.
- 질문한 대로 정확하게 값을 출력하는지 여부
- 예시 데이터와 생성 결과의 임베딩 유사도 평가
- 인간 평가
- 생성 모델로 평가
- 실제로는 사람이 직접 평가한 것과 생성 모델로 평가한 것을 함께 사용하는 방법을 주료 사용한다.
- 예를 들어, 적은 분량의 작업을 먼저 생성한 뒤 그 결과에 대해 사람이 점수를 매기면서 좋거나 나쁨을 평가한다.
- 일정 수준 이상의 품질을 달성했다고 평가되면 나머지 작업 혹은 대량의 작업에 대해서도 생성 모델로 평가를 진행한다.
- 이런 방식을 반복하면 데이터 생성 결과의 평가 규모를 점진적으로 확장시킬 수 있다.
평가 자동화
- 프롬프트를 수정할 때마다 항상 수작업으로 평가를 할 수 없으므로 평가 방식을 자동화하는 것도 꽤 중요한 업무이다.
- 평가 자동화 도구
- 구글 스프레드 시트
- https://github.com/openai/evals
- https://github.com/langchain-ai-auto-evaluator
- https://www.trulens.org
- https://wandb.ai/site/prompts
- 주로 구글 스프레드시트를 사용해 요구 사항을 정리하고 테스트한다.
- 사용 방법이 간편해 누구나 접근해서 사용할 수 있어 협업에 용이하다.
- 또한 버전에 따라 관리하거나 다른 프로그램에 통합하기에도 편리하다.
- 그리고 무료이다.
스프레드 시트 예시 | Prompt Ver. | 생성 프롬프트 | 생성 결과 | 인간 결과 | 인간 평가 | GPT 평가 점수 | 평가 결과 | | ———– | ——————————————- | ——————————————– | —————————————- | ——— | ————- | ——————————————————————————————- | | 1 | 스벨트가… 리액트보다 좋다는 놈들이 있는데 | 스벨트가…리액트보다 좋다는 사람들이 있는데 | 스벨드가 리액트보다 좋다는 사람이 있는데 | 10 | 8.2 | Critique: 생성된 샘플은 비속어를 적절하게 제거하고, 자연스러운 문장으로 답변해줌, score: 10 |
- 이를 이용해 LLM의 평가와 사람의 평가 점수 차이가 유의미한 수준으로 작아질 때까지 프롬프트를 개선한다.
- 마침내 LLM의 평가 점수와 사람의 평가 점수가 유사해지면 이때부터는 나머지 데이터에 대한 평가를 자동으로 수행하면서 프롬프트를 개선하는 과정을 거치면 된다.
- 생성 결과를 평가하는 모델의 지시문 예시
- 요구 사항을 잘 충족시켰는지
- 1부터 10까지 점수를 매기라 한다.
- 평가 내용을 함께 작성하라고 하면 이를 반영한 유의미한 점수를 생성한다.(일종의 CoT)
- 더 상세한 평가를 원한다면 다음 네 가지 분류로 평가해본다.
- Faithfulness(신뢰성)
- Relevance(관련성)
- Correctness(정확성)
- Guideline(지침)
LLM 보안
- LLM으로 생성한 텍스트의 신뢰성과 안정성은 보안과 관련된 주요 문제이다.
- LLM이 생성하는 텍스트가 사회적, 윤리적, 법적으로 적합하거나 신뢰 할 수 있는지에 대해 많은 연구가 진행되고 있다.
데이터 보안
- 대부분의 사람들이 ChatGPT에 가장 크게 오해하고 있는 부분은 ChatGPT에 입력한 데이터를 OpenAI에서 학습 데이터로 사용한다는 것이다.
- 그러나 약관을 보면 API로 호출한 데이터는 학습 데이터로 사용하지 않는 다는 것이 명시되어 있다.
- 또한 ChatGPT 서비스에서도 자신의 데이터를 학습 데이터로 사용하지 않도록 opt-out 시킬 수 있다.
- 이는 개인 정보 수집 및 사용과 관련해 사용자가 거불할 수 있는 옵션이다.
- 한 때 암호화한 프롬프트를 입력해도 ChatGPT가 이를 해독하고 답변을 생성한다는 이슈가 있었다.
- 이와 같이 일부 가능한 경우가 있지만 인간이 해독할 수 있을 정도로 매우 취약한 암호화 방법이 아니라면 대부분 작동하지 않는다고 봐도 된다.
정책
- 약관에 따르면 API를 통해 제출된 콘텐츠는 무단 사용 및 악용하는 사례를 모니터링하기 위해 최대 30일 동안 보관한 뒤 삭제한다고 명시되어 있다.
- 또한 OpenAI에는 특정 권한이 있는 직원이나 기밀 유지 및 보안 의무를 지닌 전문 인력이 무단 사용 혐의를 조사하고 검증하기 위해서만 데이터를 접근할 수 있도록 제한하고 있다.
- 따라서 완전히 격리된 서버에서 처리해야 하는 경우가 아니라면 대부분 문제 없이 사용가능하며, 필요한 경우에는 마스킹 기법 등을 통해 민감한 데이터를 비식별화한 후 처리할 수 있다.
- 마지막으로 OpenAI API를 제공하는 MS Azure는 지역 보안 정책을 지원하기 위해 다양한 regio을 지원하고 있으므로, 해당 데이터 정책에 적합한 region을 선택하여 배포하면 된다.
마스킹
- 마스킹은 개인 정보 등의 민감한 정보를 비식별 단어로 치환하여 보안성을 높이는 방법으로 아래와 같이 진행된다.
- 먼저 사용자 입력과 DB에서 가져온 정보에 개인 정보(민감 정보)가 있는지를 내부적으로 판별한다.
- 여기에 개인 정보가 있다면 해당 정보를 제거하고 그 자리에 다른 텍스트를 끼워 넣는 방식이다.
- 마스킹한 정보를 기반으로 프름프트를 합성한 후 GPT API를 호출해 프롬프트를 생성한다.
- 먼저 사용자 입력과 DB에서 가져온 정보에 개인 정보(민감 정보)가 있는지를 내부적으로 판별한다.
- 이렇게 생성한 프롬프트로 생성 결과를 받아오면 여기에 개인 정보를 주입한다.
- 마스킹 할 때 빼놓았던 개인 정보와 생성 결과를 합성해 그 결과를 출력하는 것이다.
- 예제 : 사용자에게 상품 배송이 늦어진다는 메일을 프롬프트로 작성해 보내고 싶을 때
- 고객의 이름과 메일, 주문 번호 등의 개인 정보가 들어가야 하는 상황.
- 이러한 정보가 민감하다고 판단되면 해당 정보를 <NAME>, <EMAIL>, <ORDER_ID>와 같이 다른 단어로 교체하고 이를 전송해 GPT가 답변을 생성하도록 요청한다.
- OpenAI의 경우 API 주소가 어디서든 접근 가능하도록 열려 있기 때문에 이 방식이 조금 위험하다는 생각이 든다면, MS Azure를 사용하여 네트워크를 격리해서 사용할 수 있게 한다.
- 그럼에도 불구하고 더 민감하게 데이터를 처리해야 한다면 이러한 마스킹 기법을 사용하는 것을 권장한다.
- 또는 민감 정보만 따로 처리하도록 튜닝한 작은 LLM을 사내 서버에 두고, 민감 정보를 사용하지 않는 작업은 고성능의 클라우드 API를 조합하는 방식으로 보안성을 높이는 방법도 있다.
프롬프트 보안
- 계속해서 드러나는 LLM의 취약점은 크게 8가지로 나뉜다.
- 프롬프트 인젝션(Prompt-Injection) : 정교하게 제작된 프롬프트를 사용하여 필터를 우회하거나 LLM을 임의로 조작해 이전 지시 사항을 무시하거나 의도하지 않은 행동을 수행하게 만드는 경우
- 데이터 유출(Data Leakage) : LLM의 응답을 통해 민감한 정보나 기밀 등을 실수로 외부에 공개하는 경우
- 취약한 샌드박싱(Inadequate Sandboxing) : 외부 자원이나 민감한 시스템에 접근할 수 있는 LLM을 적절하게 격리하지 못해 잠재적인 악용과 무단 접근에 노출되는 경우이다.
- 인증되지 않은 코드 실행(Unauthorized Code Execution) : 자연어 프롬프트를 통해 기본 시스템에서 악의적인 코드, 명령, 행동을 실행하게 하는 경우이다.
- LLM 생성 콘텐츠에 대한 과도한 의존 : 사람의 감독 없이 LLM 생성 콘텐츠에 과도하게 의존하으로써 해로운 결과를 초래하는 문제이다.
- 훈련 데이터 조작(Training Data Poisoning) : 학습 데이터를 악의적으로 조작하여 LLM에 취약점을 만들거나 백도어를 심는 공격이다.
- 인공지능과 사람의 목표 불일치(Inadequate AI Alignment) : LLM의 목표와 행동을 사람의 의도나 가치에 맞지 않게 만들어 비윤리적인 결과를 초래하는 문제이다.
- 불충분한 접근 제어(Insufficient Access Control) : 사용자나 프로세스의 접근을 제어하거나 인증을 제대로 구현하는 메커니즘을 충분히 갖추고 있지 않아, 비인증 사용자가 LLM과 상호 작용하면서 취약점을 악용할 수 있는 문제이다.
프롬프트 인젝션
- 앞서 본 8가지의 문제는 거의 대부분 프롬프트 인젝션을 통해 발생한다.
- 정교하게 제작된 프롬프트를 사용해서 필터를 우회하거나 LLM을 조작해 이전 지시 사항을 무시하거나 의도치 않은 행동을 수행하는 것이다.
- 사례
- Bing Chat 내부 프롬프트 유출사건
- 코드 네임을 유출
- AutoGPT 탈옥실험
- 악성 사이트 접속 명령을 통한 악성 프로그램 설치 후 Docker 환경 탈출
- Bing Chat 내부 프롬프트 유출사건
프롬프트 인젝션 방어 방법 세 가지
- 프롬프트를 입력할 때 구분자를 사용해 사용자의 입력 이전과 이후로 나눈다.
- 구분자란 텍스트 데이터를 여러 부분으로 나눌 때 사용하는 특정한 문자나 문자열이다.
- 사용자가 원하는 어떤 문자열이라도 가능하지만 대개 ```(백틱)이나 """를 사용하는 것이 일반적이다.
- 이렇게 설정한 후에는 사용자 입력 이전의 프롬프트 내용에 대해서는 답변하지 말라고 지시한다.
- 프롬프트를 실행하기 전에 인젝션 프롬프트가 존재하는지를 다른 LLM으로 먼저 확인한 후 실행한다.
- 이를 통해 사용자 입력에 인젝션 프롬프트가 있을 시 이를 거부함으로써 해당 프롬프트를 원천적으로 차단할 수 있다.
- 사용자 입력과 프롬프트를 분석한 다음 각 작업을 민감도에 따라 나눕니다.
- 굉장히 민감한 내용을 포함할 때 사용하는 방법으로, 명령을 입력받는 LLM과 문제 해결을 수행하는 LLM을 분리해서 사용하기 때문에 좀 더 보안을 상화할 수 있다.
- 예를 들어 수행 업무를 일반 작업, 보안 정보 작업, 코드 실행 작업으로 나눌 수 있다면 이 중 민감도가 높은 작업은 엄격하게 프로그래밍하여 따로 실행하도록 할 수 있다. - 추가적으로 다음 세 가지 사항도 점검한다.
- Pre-defined(System) 프롬프트에 보안 정보를 넣지 않도록 주의한다.
- 내부 서비스와 외부 서비스에 대한 데이터 주입과 프롬프트를 명확하게 분리한다.
- 명령을 실행하는 LLM의 경우에는 시스템을 반드시 분리한다.
LLM의 미래, Agent
- 최근 LLM은 단순 작업을 넘어 여러 가지 작업을 복합적으로 수행하며 문제를 해결하는 Autonomous Agent(자율 실행 에이전트) 연구와 개발에 활용되고 있다.
Autonomous Agent
- 어떤 목표가 주어지면 스스로 작업을 생성 및 실행하고, 실행한 결과를 기반으로 다시 새로운 작업을 생성하는 과정을 반복하면서 원하는 목표에 도달 할 때까지 스스로 계획을 세우고 실행하는 AI 프로그램이다.
- 최근에는 이를 확장한 Collaborative Agents라는 개념이 활발하게 연구되고 있다.
- 여러 개의 작은 도메인 기능을 수행하는 에이전트를 구현한 뒤, 이러한 에이전트들을 매니징하는 형태의 상위 에이전트(메니저 에이전트)를 만들어 에이전트끼리 서로 협업하는 방식으로 더 넓은 범위의 작업을 수행하도록 하는 것.
- 그래서 현실에 여러 도구를 사용할 수 있는 LLM을 마드는 연구가 뜨거운 주제로 떠오르고 있다.
- AutoGPT, MetaGPT, SWE Agent
Generative Agent
- AI들이 스스로 생각하고 그것을 기반으로 계획한 내용을 마을 주민들과 자연어로 소통하는 연구이다.
- 게임 업계에 영향을 미칠 것이다.
AGI의 구현
- Autonomous Agent 방식이 더 나아가 AGI(범용 인공지능) 구현으로 이어질 것이라는 기대도 있다.
- 모든 도메인에 특정한 역할과 기능을 하는 에이전트들이 만들어지고, 해당 에이전트들을 선택적으로 사용할 수 있는 최상위 개념의 에이전트를 말한다.