카테고리 보관물: AI

RESTful API 설명

API (Application Programming Interface)

API는 어떤 프로그램의 함수를 호출하고 결과를 받는 대화 형식을 정해놓은 것입니다. API에는 SOAP API, GraphQL API, gRPC API 등 여러 종류들이 있는데 인터넷에서 가장 많이 사용하고 있는 API 중 하나가 REST API 입니다. REST API 규약을 잘 따르면 RESTful 하다고 합니다.

Representation State Transfer (REST) API

REST API는 웹 상의 자원(Resource)을 고유한 URL을 통해 나타내고, HTTP 메소드를 사용하여 해당 자원과 관련된 작업을 수행하는 API입니다. 사용할 수 있는 메소드(행위)는 다음과 같습니다.

  • GET: 데이터를 조회하거나 검색 (Read)
  • POST: 새로운 데이터를 생성 (Create)
  • PUT: 기존 데이터를 업데이트하거나 대체 (Update)
  • PATCH: 기존 데이터의 일부를 업데이트 (Update)
    • DELETE: 데이터를 삭제 (Delete)

이러한 Create-Read-Update-Delete 작업을 CRUD 작업이라고도 합니다.

REST API는 자원 식별자, 메소드, 내용(입력값, Pay Load)으로 이루어집니다. 메소드는 위에 주어져 있고, 내용은 데이터에 관한 정보가 되겠습니다. 입출력 내용에 고정된 형식이 있는 것은 아니지만 JSON (JavaScript Object Nation)과 XML (eXtensible Markup Language) 형식을 많이 사용합니다. 자원 식별자는 뭘까요?

자원 식별자

고유한 URL을 이용해 웹 상에서 내가 원하는 자원에 접근할 수 있는데, 자원 식별을 위해 사용하는 고유한 식별자를 자원 식별자 URI (Uniform Resource Identifier)라고 합니다. URL과 URN은 모두 URI의 일종입니다.

  • URL (Uniform Resource Locator): 인터넷 상에서 자원의 위치를 나타내는 주소
  • URN (Uniform Resource Name): 자원에 대한 유일한 이름으로, 위치와 상관없이 식별 가능

상태 코드

자원 식별자, 메소드, 내용이 있으면 REST API를 호출해서 결과를 받아볼 수 있습니다. 구체적인 호출 방법은 사용하는 언어나 프로그램에 따라 달라집니다. GET 메소드의 경우 요청한 정보를 결과물로 받게 되지만, 다른 메소드(생성, 업데이트, 삭제)의 경우 서버 내에서 처리하면 되기 때문에 반환하는 데이터가 없을 수 있습니다. 그럼 요청이 정상적으로 처리되었는지 알 수가 없겠죠? 그래서 REST API에서는 항상 숫자로 된 상태 코드를 반환합니다. 숫자 범위에 따른 상태 코드입니다.

  • 2xx: 성공적인 응답 – 200은 성공적인 응답, 201은 자원이 성공적으로 생성되었음
  • 3xx: 리다이렉션 – 301은 자원 위치가 영구적으로 변경되었음, 302는 자원 위치 임시 변경
  • 4xx: 클라이언트 오류 – 400은 잘못된 요청, 404는 찾을 수 없는 자원
  • 5xx: 서버 오류 – 500은 서버 내부 오류(서버에서 요청을 처리할 수 없는 상태)

URL 주소로 웹 페이지를 열면 GET 메서드를 호출하는 셈입니다. 찾는 페이지가 없을 때 404 Error – Page not found 오류를 보신 적이 있을겁니다.

인공지능 비서와 외부 API

인공지능 비서를 만들 때 LLM은 두뇌라 할 수 있습니다. 두뇌만 있는 것보다는 손발이 있어야 더 많은 일들을 할 수 있겠죠? LLM에게 각종 함수나 API들을 손발로 쓸 수 있도록 만들어줄 수 있습니다. 파이썬에서 LLM의 API를 이용해 인공지능 비서를 만든다고 해봅시다. 다음은 LLM에게 API 사용 기술을 전수하는 과정입니다.

  • LLM에게 명령과 함께 REST API와 같은 외부 API 사용법을 알려주고 명령 수행을 위해 필요하면 API 호출을 요청하라고 알려줍니다.
  • LLM이 필요할 경우 REST API를 특정 메소드와 내용으로 호출하라고 프로그램에 요청합니다.
  • 파이썬에서는 LLM의 요청대로 REST API를 호출한 후 얻은 결과를 LLM에 알려줍니다.
  • LLM은 API 호출 결과를 가지고 계속해서 명령을 수행합니다. 필요하면 여러 개의 API를 호출할 수도 있습니다.
  • 이 과정을 주어진 명령을 완수할 때까지 반복합니다.

부동 소수와 딥러닝에서의 양자화

부동 소수 Floating point numbers

부동 소수는 실수를 표현하는 방법 중 하나입니다. 고정 소수와 달리 소숫점 자리가 움직인다고 부동 소수라고 부릅니다.

  • 고정 소수: 123.45
  • 부동 소수: 0.12345\times10^3, 1.2345\times 10^2, 등

부동 소수는 \pm m\times n^e 라고 쓸 수 있는데 각 부분의 명칭은 다음과 같습니다.

  • \pm: 부호 sign
  • m: 가수 significand
  • n: 기수 base=2 (항상 2)
  • e: 지수 exponent

정밀도 Precision

부동 소수는 숫자를 표현(저장)하기 위해 사용하는 비트 수에 따라 반정도, 단정도, 배정도 자료형 등으로 나눌 수 있습니다(IEEE754 표준). 비트 수를 많이 사용할수록 정밀도가 높죠.

  • 반정도 FP16, half-precision: 16 비트 = 2 바이트
  • 단정도 FP32, single-precision: 32 비트 = 4 바이트
  • 배정도 FP64, double-precision: 64 비트 = 8 바이트

표준에는 더 많은 비트를 사용한 부동 소수도 있는데 보통 위의 세 가지 자료형을 많이 사용합니다.

정밀도부호 비트지수 비트가수 비트최소 양수 (근사치)최대 양수 (근사치)
반정도15105.96\times10^{-8}6.55\times10^4
단정도18231.40\times10^{-45}3.40\times 10^{38}
배정도111524.941\times10^{-324}1.798\times10^{308}
부동 소수 비트

위 표를 보면 기수(base) 저장에는 비트를 사용하지 않는 것을 알 수 있습니다. 항상 2이기 때문에 저장할 필요가 없죠. 지수 비트를 더 많이 사용할수록 더 넓은 범위를 표현할 수 있고, 가수 비트를 더 많이 사용할수록 소숫점 아래 더 많은 자리까지 정밀한 값을 표현할 수 있습니다. 많은 비트를 사용할수록 더 정확하지만 메모리를 많이 차지하고 계산 속도가 느려지게 됩니다.

자료형 변환

자료형 사이에는 변환이 가능합니다. 낮은 비트의 자료형에서 높은 비트의 자료형으로 변환할 때는 저장된 숫자의 정밀도에 변함이 없지만, 높은 비트의 자료형에서 낮은 비트의 자료형으로 변환하면 저장된 숫자의 정밀도를 일부 희생하게 됩니다.

양자화 Quantization

딥러닝에서는 신경망 매개변수(가중치) 저장에 기본적으로 단정도 부동 소수를 사용합니다. 거대 언어 모델과 같이 큰 모델의 경우 수많은 매개변수(보통 수십억 개가 넘어갑니다)가 존재하기 때문에 메모리와 계산량 부담을 줄이기 위해 반정도나 더 낮은 정밀도(8비트 정수)의 자료형으로 변환을 하는 경우가 많습니다. 이를 양자화(Quantization)라고 합니다.

양자화에는 신경망 훈련 중 양자화, 훈련을 마친 후 양자화, 동적 양자화, 정적 양자화 등 다양한 기법이 존재합니다.

Retrieval Augmented Generation & Fine Tuning

기초 모델(Foundation Model)의 한계

ChatGPT나 Bard와 같은 거대 언어 모델(LLM)을 다양한 분야의 일반적인 지식에 대해 훈련된 기초 모델(Foundation Model)이라고 합니다. 기초 모델은 일반적인 작업을 대체로 잘 수행합니다. LLM은 질문에 따라 응답이 달라지기 때문에 응답의 질을 향상시키기 위해 어떻게 메시지를 보내야 하는지 연구하는 것을 프롬프트 엔지니어링이라고 합니다. 프롬프트 엔지니어링을 통해 훌륭한 프롬프트를 찾아냈다고 하더라도 LLM에는 한계가 존재합니다.

  • 특정 시기까지의 데이터만 가지고 훈련되었기 때문에 최신 정보를 반영하지 못합니다. 최신 정보를 물어보면 엉터리 대답(hallucination)을 하기도 하죠.
  • 다양한 분야의 일반적인 자료를 이용해 훈련시켰기 때문에 특정 세부 분야의 지식이 부족합니다.

이러한 한계를 극복하기 위해 Retrieval Augmented GenerationFine Tuning을 많이 사용합니다.

Retrieval Augmented Generation (RAG)

벡터 데이터베이스를 이용하면 문서에서 질문과 관련된 부분을 추출하여 LLM 프롬프트에 Context로 전달할 수 있습니다. LLM은 Context의 내용을 바탕으로 질문에 맞는 답을 내놓을 수 있죠. 특정 분야의 최신 정보를 반영한 문서를 사용하면 위에서 말한 LLM의 한계를 극복할 수 있습니다.

Fine Tuning

Fine Tuning은 이미 훈련되어 있는 기초 모델에 목적에 맞는 자료를 이용해 추가 훈련을 시키는 전이학습 과정입니다. 이를 통해 LLM이 특정 분야의 최신 정보를 반영하도록 만들 수 있죠. 이렇게 훈련된 LLM에 질문을 던지면 추가 훈련 정보를 반영한 응답을 얻을 수 있습니다.

RAG or Fine Tuning?

두 가지 기법은 모두 LLM의 한계를 극복하여 성능을 향상시키기 위한 기법입니다. 하지만 서로 다른 기법으로, 장단점 차이가 있기 때문에 목적에 맞는 기법을 이용하는게 좋습니다.

RAG 장점, Fine Tuning 단점

  • 새로운 정보 업데이트: RAG에서 최신 정보나 새로운 분야의 정보를 반영하려면 새 문서를 이용해 벡터 데이터베이스를 업데이트하면 됩니다. LLM은 건드릴 필요가 없습니다. 하지만 Fine Tuning에서는 새로운 정보를 추가할 때마다 전이학습이 필요하고, 거대한 LLM일수록 추가 학습 비용이 높아집니다.
  • 추가 정보 준비: RAG에서는 추가 정보를 입력하는데 특별한 형식이 필요하지 않습니다. 주어진 문서를 일정 길이로 나누어 임베딩 모델을 통해 벡터로 만들고 벡터 데이터베이스에 입력하면 됩니다. 하지만 Fine Tuning을 위해서는 바람직한 질문-응답(Label) 쌍을 충분히 준비해야 합니다.
  • 해석 가능성: RAG에서는 LLM이 벡터 검색 결과를 바탕으로 응답하기 때문에 벡터 검색 결과를 확인하면 LLM이 왜 그렇게 대답했는지 알 수 있습니다. Fine Tuning의 경우 기초 모델과 같이 왜 그런 대답을 했는지 명확히 알기 어렵습니다.

Fine Tuning 장점, RAG 단점

  • 응답 속도: Fine Tuning은 훈련을 통해 가중치가 업데이트된 LLM을 이용하기 때문에 실제 사용시 기초 모델과 응답 속도 차이가 거의 없습니다. 하지만 RAG는 기초 모델에 벡터 검색 과정이 추가되므로 응답 속도가 느려지게 됩니다.
  • 실제 사용시 계산 비용: Fine Tuning은 추가 훈련 비용이 들지만 훈련 후 실제 사용시 계산 비용은 기초 모델과 동일합니다. RAG는 추가 훈련 비용은 안 들지만 벡터 검색 비용이 추가됩니다. 단, 전체 계산 비용은 추가 훈련을 얼마나 많이 하느냐에 따라 달라질 수 있습니다.
  • 특정 스타일 반영: Fine Tuning은 훈련 자료를 이용해 LLM이 특정 스타일(문어체, 구어체 등)로 응답하도록 훈련시킬 수 있습니다. RAG에서도 Few-shot learning을 이용해 스타일을 학습시킬 수 있지만, 그렇게 되면 토큰 수가 증가하고, 이는 비용 증가로 이어집니다.

물론, Fine Tuning한 모델에 RAG를 추가하는 것도 가능합니다. 대신 비용이 더 증가하죠.

벡터 데이터베이스

벡터 임베딩과 벡터 검색

텍스트는 토크나이저와 임베딩을 거쳐 벡터가 됩니다. 토큰화와 임베딩을 합해서 그냥 임베딩이라고 이야기하기도 합니다. 벡터를 이용한 검색 과정에 대해 생각해봅시다. 문서를 문단, 문장 등 작은 단위(chunk)로 분리하고 각각을 벡터로 만들어 저장해 놓습니다. 질문이 들어왔을 때 질문도 임베딩 벡터로 만들면 저장된 벡터와 질문의 임베딩 벡터 사이의 거리를 계산할 수 있습니다. 거리가 가까운 벡터는 질문과 관련된 내용을 포함할 가능성이 높습니다. 이렇게 질문과 관련된 벡터를 찾는 과정이 벡터 검색입니다.

검색 후에는 거리가 가장 가까운 벡터 K개를 추출하여 거대 언어 모델의 프롬프트에 포함시킵니다. 이 방법을 Retrieval-Augmented Generation (RAG)라고 합니다.

벡터 거리 측정

검색을 위해 벡터 사이의 거리를 측정하는 방법에는 여러 가지가 있습니다.

  • 코사인 유사도
  • 해밍
  • 유클리드 거리 (L2)
  • 맨하탄 거리 (L1)
  • 내적

이 외에도 여러 가지가 있는데, LLM과 관련해서 코사인 유사도를 많이 사용합니다. 보통 질문의 임베딩 벡터와 가장 가까운 벡터를 하나만 찾는게 아니라 K개를 찾습니다. K-Nearest Neighbor (KNN)라고 하죠.

이 때 문서가 짧으면 벡터도 많지 않고 거리를 구하는 계산이 금방 끝나지만 문서가 길어지게 되면 벡터 검색 시간이 크게 증가하게 됩니다. 그래서 보통 Approximate Nearest Neighbor (ANN) 기법을 사용해 근사적으로 가장 가까운 벡터들을 찾습니다. 정확도를 약간 희생하고 검색 속도를 높이는 방법입니다. ANN 관련 기술도 여러 가지가 있습니다.

  • Locality Sensitive Hashing (LSH)
  • Random Projection
  • Hierarchical Navigable Small World (HNSW) Graphs
  • Product Quantization

벡터 라이브러리

ANN 기법은 검색 범위를 좁히거나 벡터의 길이를 짧게 만들어 벡터 검색 계산량을 줄이는데, 그렇게 하기 위해서는 미리 벡터를 인덱싱하는 과정이 필요합니다. 이렇게 인덱스를 만들고 벡터간의 거리를 계산해서 검색하는 프로그램을 벡터 라이브러리라고 합니다. 다음은 많이 사용하는 벡터 라이브러리들입니다.

  • 메타에서 개발한 FAISS (Facebook AI Similarity Search)
  • 스포티파이에서 개발한 Annoy (Approximate Nearest Neighbors Oh Yeah)
  • 구글에서 개발한 ScaNN (Scalable Nearest Neighbors)
  • NMSLIB
  • HNSWLIB

벡터 데이터베이스

실제 LLM에서 벡터 임베딩을 이용한 검색을 위해서는 벡터 라이브러리의 기능 외에도 추가 기능들이 필요합니다. 벡터 외에 벡터의 원본 텍스트와 같은 메타 정보를 포함하는 기능, 메타 정보를 이용한 필터링, 벡터의 손쉬운 추가/제거/업데이트, 병렬 연산 지원, 백업이나 보안 지원 등과 같은 기능을 추가한 벡터 라이브러리가 벡터 데이터베이스입니다. 최근에는 기존 데이터베이스에서 벡터 검색을 지원하기도 하는데, 많이 사용하는 벡터 전용 데이터베이스는 다음과 같습니다.

  • Pinecone
  • Milvus
  • Chroma
  • Weaviate
  • Deep Lake
  • Qdrant
  • Vespa

LLM을 이용해 RAG를 구현할 때 위 내용들을 몰라도, 벡터 데이터베이스 사용법만 알면 구현이 가능합니다^^ 하지만, 어느 정도의 배경 지식은 알고 만들면 더 좋겠죠?

토큰과 임베딩 벡터

거대 언어 모델(LLM)에 우리는 텍스트 문자열을 입력해 답을 얻습니다. 그러나 컴퓨터에서 실제 계산은 숫자로 이뤄지죠. 우리가 입력한 글자들은 토크나이저(Tokenizer)를 거쳐 토큰으로 분리되고, 각각의 토큰은 임베딩(Embedding) 모델을 거쳐 숫자들로 이루어진 벡터가 됩니다. 거대 언어 모델에는 이 벡터들이 순차적으로 전달되고, 연산을 통해 응답이 나오게 됩니다.

토크나이저와 토큰

토크나이저는 텍스트를 단어나 더 작은 단위(subwords)로 나누는 프로그램입니다. 나눠진 결과를 토큰이라고 하고, 이 과정을 토큰화(tokenize)라고 합니다. 토큰은 아직 문자죠. 토크나이저에는 단어 기반, 서브워드 기반, 문자 기반 토크나이저가 있는데, 거대 언어 모델들은 주로 서브워드 기반 토크나이저를 사용합니다.

  • 단어 기반: [인공지능을]
  • 서브워드 기반: [인공, ##지능, ##을]
  • 문자 기반: [인, 공, 지, 능, 을]

임베딩

토큰이 임베딩 층을 거치면 벡터가 되고, 이 벡터를 임베딩 벡터라 합니다. 거대 언어 모델에서 임베딩 벡터는 보통 수백~수천 차원의 밀집 벡터(0이 별로 없는)를 이용합니다. 이렇게 토큰별로 만들어진 벡터들은 차례대로 거대 언어 모델에 입력으로 전달됩니다.

예시

이해를 돕기 위해 간략한 예시를 봅시다(실제 결과와는 차이가 있습니다). “인공지능을 활용합시다”라는 텍스트를 입력으로 사용했다고 해봅시다. 그럼 텍스트는 토크나이저를 거쳐 토큰으로 분리가 됩니다.

  • 입력: 인공지능을 활용합시다
  • 토큰화: [인공, ##지능, ##을, 활용, ##합, ##시다]

결과 토큰은 사용하는 토크나이저에 따라 달라지게 됩니다. 각 토큰은 임베딩을 거쳐 벡터가 됩니다. 실제는 고차원 벡터이지만 아래에는 간략하게 3차원으로 표시했습니다.

  • 인공: [0.32, -0.21, 0.59]
  • ##지능: [0.12, 0.45, -0.22]
  • ##시다: [0.15, -0.33, 0.72]

거대 언어 모델은 실제로 이런 숫자를 받아들여 자연어 처리 작업을 수행합니다. 요즘 많이 사용하는 트랜스포머 신경망에서 각각의 벡터는 순차적으로 입력으로 사용되는데, 이 벡터들에 위치 정보가 추가되고 신경망의 여러 층을 거치면서 토큰들 사이의 관계와 문맥이 반영된 출력이 계산됩니다.

문장, 문서 수준의 임베딩

앞에서 다룬 임베딩은 거대 언어 모델의 입력으로 사용하기 위한 임베딩이고, 주어진 텍스트의 전체적인 의미와 문맥을 벡터로 표현하기 위한 임베딩 모델들도 있습니다. 벡터 데이터베이스 검색에 사용하는 임베딩이죠. 이러한 모델을 사용하면 임베딩 벡터를 이용해 문장의 유사도를 계산하거나 정보 검색, 클러스터링, 분류 등을 수행할 수 있습니다.

이러한 모델에서는 주어진 입력을 먼저 토크나이저를 이용해 토큰으로 분리하고, 각 토큰들의 벡터 임베딩을 생성한 후, 이 벡터들을 조합하여 전체 문서를 대표하는 하나의 벡터를 만드는 과정을 거칩니다. 대표 벡터를 만드는 방법에는 벡터의 평균을 이용하는 평균 임베딩 방법, 단어의 등장 빈도를 이용하는 TF-IDF 가중치 방법, 딥 러닝 모델을 사용하는 방법 등이 있습니다.

거대 언어 모델(Large Language Model, LLM)과 프롬프트 엔지니어링

프롬프트와 프롬프트 엔지니어링

ChatGPT와 같은 거대 언어 모델(Large Language Model, LLM)을 사용할 때 모델에 전달하는 메시지를 프롬프트(Prompt)라고 하죠. 프롬프트를 잘 만들어서 원하는 결과물을 얻기 위해 연구하는 것을 프롬프트 엔지니어링이라고 합니다.

프롬프트는 한 문장이 될 수도 있고 여러 문단이 될 수도 있죠. 프롬프트를 몇 가지 주요 구성 요소들로 나눠보면 아래와 같이 정리할 수 있습니다.

  • Goal: 달성해야 하는 목표
  • Instruction: 구체적인 지시, 요구 사항 또는 질문
  • Role: 모델에게 조언자나 편집자, 작가 등의 역할을 지정해주는 부분
  • Context: 작업의 배경 지식이나 상황 제공
  • Output Format: 원하는 응답 형식을 지정해주는 부분
  • Systematic Approach: 특정 시스템이나 알고리즘을 따르도록 지시
  • Step-by-step: 복잡한 작업을 단계별로 처리하라고 지시
  • Clarifying Questions: 불확실한 부분은 모델이 사용자에게 질문하도록 권장
  • Examples: 질문과 응답 예제

이러한 분류는 정해져 있는 것은 아니고, 사람에 따라 다르게 분류할 수 있습니다. 또 매번 위의 모든 요소가 다 들어갈 필요도 없죠. 사용 목적에 따라 들어가는 요소들이 달라지게 됩니다. LLM은 예제로부터 학습할 수 있는데, 예제가 없으면 Zero-shot, 하나 있으면 One-shot, 두 개 이상 있으면 Few-shot learning이라고 합니다.

아래 나오는 내용은 주로 대화형 환경 보다는 LLM의 API (Application Programming Interface)를 이용해 사용자에게 드러나지 않게 구현하게 됩니다.

환각 현상의 완화

거대 언어 모델에서 나타나는 환각(hallucination, 거짓 응답) 현상을 줄이는 방법 중 하나가 Context를 제공하고 주어진 정보를 이용해 답하라고 지시하는 방법입니다. 물론 Context에는 사실을 담아야겠죠. 그러려면 Context 정보를 어디선가 가지고 와야 합니다.

Bing Chat, Bard

질문을 가지고 인터넷을 검색해서 Context에 들어갈 내용을 가져오면 Microsoft의 Bing Chat이나 Google의 Bard와 같이 최신 정보를 반영한 모델이 됩니다. 검색한 웹문서를 직접 열어서 필요한 부분을 찾을 필요 없이 질문에 대한 답을 알아서 정리해주죠.

문서에 대한 질의 응답: ChatPDF

Context를 PDF 파일과 같은 문서에서 가져오면 문서의 내용에 대해 질문할 수 있는 챗봇, ChatPDF가 됩니다. 인터넷 검색의 경우 이미 있는 Google이나 Bing과 같은 검색 엔진의 검색 결과에서 가장 먼저 나오는 몇 개의 인터넷 문서에서 정보를 가져오면 됩니다. PDF 파일은 어떻게 할까요?

PDF나 워드 문서의 경우 문서에서 텍스트 정보를 추출하여 텍스트를 컴퓨터에서 처리할 수 있는 숫자들의 벡터로 변환합니다. 이 과정을 벡터 임베딩(Vector Embedding)이라고 하죠. 문서 전체의 텍스트를 일정 길이(Chunk)로 나눠서 벡터로 변환한 후 벡터들을 벡터 데이터베이스(VectorDB)에 저장해 놓습니다. 질문이 들어오면 질문도 벡터로 변환합니다. 벡터들끼리는 거리를 측정할 수 있죠? 질문 벡터와 문서의 벡터들 사이의 거리를 측정하여 거리가 가까운 벡터들을 몇 개 추출하면 그 벡터에 해당하는 원본 텍스트가 Context에 들어가게 됩니다. 그럼 LLM은 질문에 대한 답을 포함할 가능성이 높은 Context의 정보를 이용해서 대답을 해주죠. 정리해보면, 다음과 같습니다.

  1. 답을 찾고자 하는 문서(문서들)에서 텍스트 추출
  2. 텍스트를 일정 길이로 나누기
  3. 나눈 내용을 벡터 임베딩을 이용해 벡터로 변환
  4. 변환한 벡터들을 벡터 데이터베이스에 저장
  5. 사용자 질문 (사용자 질문이 제일 처음에 문서와 함께 주어질 수도 있습니다)
  6. 사용자 질문을 벡터 임베딩을 이용해 벡터로 변환
  7. 질문 벡터와 벡터 데이터베이스에 저장된 벡터들 사이의 거리 계산
  8. 거리가 가장 가까운 벡터들 추출
  9. 추출한 벡터들의 원본 텍스트를 LLM에 질문에 대한 Context로 제공
  10. LLM은 질문에 대한 답을 Context에서 찾아서 사용자에게 응답

일반 검색에서는 검색하는 단어나 문장과 글자가 일치하는 것을 찾지만 벡터 검색은 의미가 유사한 내용을 찾는 의미 검색(semantic search)입니다. 벡터 데이터베이스에 회사의 제품에 관한 여러 가지 문서들을 넣으면 회사의 제품 상담 챗봇이 됩니다.

문서에는 PDF 뿐 아니라 Word, Excel, Power Point, Gmail, Notion 등 다양한 문서들이 있습니다. 이러한 문서들에서 텍스트를 편리하게 추출해주는 라이브러리로 Llama-Index가 있습니다.

인공지능 비서: AutoGPT, BabyAGI

LLM의 API를 호출하는 프로그램에서 Instruction에 특정 함수의 사용법을 알려줄 수 있습니다. 예를 들면 위키피디아 검색을 하고 싶으면 wikipedia(query)라고 출력하라고 알려줄 수 있습니다. 수학 계산을 하고 싶으면 calculate(equation)이라고 출력하라고 알려줄 수도 있죠. 질문과 함께 함수 사용법을 알려주고 함수를 사용할 수 있다고 LLM에 알려주면 LLM은 최종 대답을 하기 전에 필요한 정보를 얻기 위해 함수를 사용하게 됩니다. 직접 함수를 호출하는 것은 아니고 함수 호출에 필요한 명령을 출력하게 되는거죠. 그럼 프로그램에서 해당 함수를 호출하여 결과를 LLM에 전달해줍니다.

  1. 질문과 함께 사용할 수 있는 함수들을 LLM에 제시
  2. LLM에서 필요한 함수를 호출하는 명령 출력
  3. LLM을 호출하는 프로그램에서 함수 실행
  4. 함수 실행 결과를 LLM에 알려주기
  5. LLM에서 최종 응답

예를 들어, 광안대교를 언제 개통했는지 질문하고 위의 함수를 사용할 수 있다고 알려주면, wikipedia(광안대교 개통일)과 같은 출력을 내놓게 됩니다. 그럼 이 함수 호출 내용을 프로그램에서 분석해서 위키피디아 검색을 수행하고 결과 페이지(위키피디아 광안대교 페이지)의 내용을 LLM에 질문과 함께 Context로 전달하게 됩니다. 그럼 LLM은 Context에서 답을 찾아 대답하게 되죠.

LLM에서 Python 코드를 출력하면 코드를 실행해서 결과를 알려주겠다고 지시할 수도 있습니다. LLM에 지시를 내리면 LLM에서 지시를 수행하기 위한 코드를 작성해서 출력하고, 프로그램에서 코드를 실행한 후 실행 결과를 다시 LLM에 전달합니다. 그럼 LLM은 결과를 이용해 이후의 응답을 생성할 수 있죠. ChatGPT Plus의 Advanced Data Analysis (Code Interpreter의 새 이름)의 기본 원리입니다.

이렇게 LLM에 알려주는 함수는 LLM의 Tool 또는 Skill이라고 부릅니다. 많은 함수를 알려줄수록 LLM이 할 수 있는 일도 많아지죠. 복잡한 문제의 경우 문제 풀이 단계를 논리적으로 분석해서 제시하고 하나씩 차례대로 수행하라고 지시할 수도 있습니다. 각 단계를 수행할 때 사용할 수 있는 함수들도 같이 알려주죠. AutoGPTBabyAGI의 기본 원리입니다. 이런 LLM 프로그래밍을 편리하게 만들어주는 라이브러리로 LangChain이 있습니다.

J.A.R.V.I.S.

말로 지시를 내리고 소리로 응답을 듣고 싶다면? 음성 인식(Speech Recognition) 기술을 이용해 말을 글로 바꿔서 지시를 내릴 수 있습니다. LLM의 출력은 글을 읽어주는 음성 합성(Text-to-Speech) 기술을 이용하면 됩니다.

  1. 사용자가 음성으로 명령
  2. 음성 인식: 음성을 글자로 변환
  3. 글자를 LLM (AutoGPT)에 전달
  4. LLM (AutoGPT)에서 응답
  5. 음성 합성: 응답 결과를 읽어주기

간단한 자비스(JARVIS)가 됩니다. 토니 스타크의 자비스에 비하면 아직 한참 멀었지만, 점점 향상되고 있습니다.