맞춤형 지식창고로 LLM 챗봇 구축하기
Published: 2024-02-01 21:14:36

이러한 LLM과 ChatGPT가 많은 관심을 받으면서 "가비지 인, 가비지 아웃"이라는 새로운 원칙이 등장했습니다. GPT-4 또는 GPT-3.5 또는 기타 대형 언어 모델을 사용할 때 이 개념은 다음 두 곳에 적용됩니다. [프롬프트 엔지니어링](https://en.wikipedia.org/wiki/Prompt_engineering#:~:text=Prompt%20engineering%20(also%20known%20as,of%20it%20being%20explicitly%20given.) 과 [미세 조정](https://en.wikipedia.org/wiki/Fine-tuning_(deep_learning)). 또한 이러한 모델이 제공하는 데이터가 얼마나 오래된 것인지 또는 새로운 것인지 확인하기 위해 언제 학습되었는지도 고려해야 합니다.

오늘날 대부분의 비즈니스는 방화벽 내부 또는 퍼블릭 도메인 인터넷이 아닌 외부의 기업 데이터 소스 내에 있습니다. 이러한 데이터에 LLM을 활용할 수 있다면 새로운 가능성이 열립니다.

이 글에서는 30분 만에 맞춤형 지식창고로 챗봇을 구축하여 인공지능이 데이터에 대한 질문에 답변하도록 하는 방법에 대해 설명합니다.

![](/cdn/3prze68gbwl1/3qYPBDJSpSd5oecj2fUDae/f2a980695856b249c645e7ea774b87fe/Screenshot_2023-07-20_at_10.17.38_PM.png)

지식 봇을 만들기 위한 전제 조건
------------------

사용자 지정 지식창고를 만들려면 얼마나 많은 데이터가 필요한지 고려해야 합니다. 이 블로그에서는 PubNub 문서를 사용하여 어시스턴트를 만들겠습니다. 문서가 많으므로 다음과 같은 프로덕션 서비스 사용을 고려해야 합니다. [Vectara](https://vectara.com/), [Pinecone](https://www.pinecone.io/)또는 [Weaviate](https://weaviate.io/) 를 사용하여 벡터 임베딩을 관리할 수 있습니다. 소량의 데이터를 위해 로컬 벡터 데이터베이스를 생성하는 데 LangChain을 사용할 수 있습니다. 또한 LangChain은 시맨틱 또는 유사성 검색을 통해 사용자 정의 임베딩을 LLM 모델에 매핑하는 기능도 지원합니다.

이 블로그에서는 모든 회사 데이터에 대한 간단한 드래그 앤 드롭 솔루션을 제공하는 벡타라에서 벡터 데이터베이스를 설정하는 방법을 살펴보겠습니다. 벡타라와 상호 작용하는 가장 좋은 방법은 다음을 활용하는 것입니다. [PubNub 함수](https://www.pubnub.com/docs/general/serverless/functions/overview#:~:text=PubNub%20provides%20Functions%20to%20capture,filter%2C%20and%20even%20aggregate%20data.)를 활용하는 것인데, 이는 사전 정의된 이벤트가 발생할 때마다 실행되는 서버리스 JavaScript 컨테이너를 제공합니다. 함수가 실행되고 실행되는 시점을 사용자 지정할 수 있어 AI 지식 봇의 작동 방식을 조정할 수 있습니다.

벡타라는 데이터 세트를 사용하여 데이터를 여러 임베딩으로 색인화합니다. 텍스트 입력 또는 사용자 입력을 전달하면 벡타라는 데이터에 대해 시맨틱 검색을 실행하고 찾은 결과를 요약하여 사용자 지정 데이터를 사용하여 질문에 대한 답변을 제공합니다. 이를 통해 필요한 관련 정보를 얻을 수 있습니다. 벡타라는 TXT, HTML, PDF, Word 파일 등 다양한 파일 유형을 지원합니다. 업로드하려는 모든 문서를 모아 개별 폴더에 추가하세요.

### 벡타라 설정 방법

벡타라 설정 방법은 다음과 같습니다:

1.  [가입](https://console.vectara.com/login) 또는 Vectara에 로그인합니다.
    
2.  대시보드에서 `코퍼스 만들기를` 클릭합니다.
    
3.  `데이터 수집` 헤더 아래에 코퍼스의 이름과 설명을 입력한 후, `파일 업로드` 섹션에 LLM이 알 수 있도록 하려는 파일을 끌어다 놓습니다. 파일이 업로드되면 웹페이지 상단에서 코퍼스 ID를 확인할 수 있는데, 이는 쓰기 요청에 필요하기 때문입니다.
    
4.  오른쪽 상단에 있는 이메일을 클릭하고 나중에 사용할 수 있도록 `고객 ID를` 저장합니다.
    
5.  `API 키를` 선택하고 드롭다운 메뉴에서 말뭉치를 선택하여 말뭉치에 대한 API 키를 생성합니다. 나중에 사용할 수 있도록 API 키를 저장합니다.
    

### 높은 수준의 아키텍처

아키텍처는 다음과 같이 구조화됩니다:

1.  채팅 애플리케이션은 PubNub을 사용하여 메시지를 보내고 받습니다.
    
2.  PubNub 함수는 특정 채널에서 이러한 메시지를 수신합니다.
    
3.  인공지능이 생각하고 있는 시점과 완료된 시점을 사용자에게 알리기 위해 PubNub 신호가 발생합니다.
    
4.  그런 다음 메시지는 Vectara Rest API를 사용하여 Vectara로 전달됩니다.
    
5.  그러면 PubNub 함수가 Vectara의 응답에서 여러 결과 중 하나를 파싱합니다.
    
6.  그러면 응답이 챗봇과 연결된 채널에 게시됩니다.
    

PubNub 함수 구성하기
--------------

1.  관리 대시보드로 이동합니다. [관리자 대시보드](https://admin.pubnub.com/)
    
2.  왼쪽 메뉴에서 `기능을` 선택하고 사용하려는 적절한 키 세트를 클릭합니다.
    
3.  `모듈 생성을` 선택하고 모듈 이름과 설명을 입력합니다.
    
4.  방금 만든 모듈을 선택하고 `+ 함수 만들기를` 클릭합니다.
    
5.  함수에 `벡타라 쿼리와` 같은 이름을 지정하고 드롭다운 메뉴에서 `게시 후 또는 실행을` 선택합니다. 이 함수는 메시지가 관련 채널(이 경우 `docs-pubnub-ai` )에 게시된 후에 실행됩니다.
    
6.  채널 이름을 `docs-pubnub-ai로` 설정합니다.
    
7.  `내 비밀번호를` 클릭하고 `VECTARA_API_KEY` 및 `CUSTOMER_ID라는` 비밀번호를 생성합니다.
    

다음은 PubNub 함수에서 벡타라 데이터베이스를 쿼리하는 코드입니다.
---------------------------------------

PubNub 함수의 코드 스니펫은 다음과 같이 정의됩니다:

```js
const Promise = require('promise');

//
// API Key For OpenAI
// **Add your Vectara API Key and Customer ID to MY SECRETS (Left Panel)**
//
let VECTARA_API_KEY = null;
let CUSTOMER_ID = null;
let channel = "docs-pubnub-ai-response";
function getVectaraKey() {
   // Use cached key
   if (VECTARA_API_KEY && CUSTOMER_ID) {
       return new Promise(resolve => resolve(VECTARA_API_KEY));
   }
   // Fetch key from vault
   return vault.get("VECTARA_API_KEY").then(apikey => {
       return vault.get("CUSTOMER_ID").then(customer_id => {
            VECTARA_API_KEY = apikey;
            CUSTOMER_ID = customer_id;
           return new Promise(resolve => resolve(VECTARA_API_KEY));
       });
   });
}

//
// Import Modules
//
const xhr = require('xhr');
const vault = require('vault');
const pubnub = require('pubnub');

//
// Main
//
export default (request) => {
   // Input data for Vectara
   let message = request.message.text;
   let signalMessage = { message: { type: "typing_on" }, channel: channel };
   return pubnub.signal(signalMessage).then((_) => {
       return getVectaraKey().then(_ => {
           return vectara(message).then(response => {
               return pubnub.publish({
                   channel: channel,
                   message: {
                       id: "PubNubAI",
                       type: "default",
                       text: response
                   },
               }).then((publishResponse) => {
                   console.log(publishResponse);
                   message = { message: { type: "typing_off" }, channel: channel };
                   return pubnub.signal(message).then((signalOffResponse) => {
                       console.log(signalOffResponse);
                       return request.ok();
                   });
               }).catch((err) => {
                   console.error(err);
               });
           });
       });
   });
};

//
// API Call to Vectara asking the AI a question
//
async function vectara(question) {
   console.log("SENDING REQUEST TO VECTARA");
   const url = "https://api.vectara.io/v1/query";
   const body = JSON.stringify({
       "query": [
           {
           "query": question,
           "start": 0,
           "numResults": 10,
           "contextConfig": {
               "charsBefore": 0,
               "charsAfter": 0,
               "sentencesBefore": 2,
               "sentencesAfter": 2,
               "startTag": "<b>",
               "endTag": "</b>"
           },
           "corpusKey": [
               {
               "customerId": CUSTOMER_ID,
               "corpusId": 1,
               "semantics": "DEFAULT",
               "dim": [
                   {
                   "name": "string",
                   "weight": 0
                   }
               ],
               "lexicalInterpolationConfig": {
                   "lambda": 0.025
               }
               }
           ],
           "rerankingConfig": {
               "rerankerId": 272725717
           },
           "summary": [
               {
               "summarizerPromptName": "",
               "maxSummarizedResults": 5,
               "responseLang": "eng",
               "summarizerPromptId": 1,
               "debug": false,
               "responseChars": 0
               }
           ]
           }
       ]
   });

   const http_options = {
       'method': 'POST',
       'timeout': 20000,
       'headers': {
           'Content-Type': 'application/json',
           'customer-id': CUSTOMER_ID,
           'x-api-key': VECTARA_API_KEY
        },
       'body': body
   };

   xhr.timeout = 100000;

   // Send API Request to OpenAI GPT Model
   const response = await xhr.fetch(url, http_options).then(res => res.json());

   // Parse the response and get the summary
   const summary = response.responseSet[0].summary[0].text;

   return summary;
}
```

PubNub 함수를 UI에 연결하기
-------------------

여러 가지 중 하나를 사용하여 위에 정의된 코드에 따라 PubNub 함수를 UI에 연결하려면 다음을 수행합니다. [SDK](https://www.pubnub.com/docs/sdks) 중 하나를 사용하여 위에 정의된 코드에 따라 연결합니다. [게시/구독](https://www.pubnub.com/docs/sdks/javascript/api-reference/publish-and-subscribe) 를 `pubnub-docs-ai` 채널에 게시하고 위의 PubNub 함수를 사용한 후 Vectara 쿼리 실행이 완료될 때까지 기다립니다. 연결하기 [타이핑 표시기](https://www.pubnub.com/docs/chat/sdks/messages/typing) 를 연결하여 `pubnub-docs-ai` 채널에서 PubNub 신호를 수신하면 사용자는 PubNub 지식 봇이 언제 생각하고 있는지 확인할 수 있어 보다 원활한 최종 사용자 경험을 제공할 수 있습니다.

React에서 PubNub 함수를 연결하기 위한 코드:

```js
const pubnub = new PubNub({
   publishKey: process.env.NEXT_PUBLIC_PUBLISH_KEY!,
   subscribeKey: process.env.NEXT_PUBLIC_SUBSCRIBE_KEY!,
   userId: "You",
 });

 const publishChannel = "docs-pubnub-ai";

 const sendMessage = (message: string) => {
   if (message) {
     pubnub.publish({
         channel: publishChannel, message: {
           text: message
       }});
   }
 };
```

요약
--

PubNub 함수를 벡터 데이터베이스 또는 벡터 스토어와 함께 사용하면 매우 빠르고 프로덕션에 바로 사용할 수 있는 방법으로 나만의 AI 지식 봇을 만들 수 있습니다. 이 방법으로 Vectara뿐만 아니라 Pinecone, Weaviate 또는 다른 프로덕션 벡터 데이터베이스도 활용할 수 있습니다. PubNub 함수를 사용하면 메시지가 전송되는 방식과 전송 시기를 쉽게 호스팅하고 제어하여 벡터 데이터베이스 기능을 향상시킬 수 있습니다.

가입하기 [관리자 대시보드](https://admin.pubnub.com/#/register) 에 가입하여 PubNub 키세트 구성을 시작하세요. 또한 [튜토리얼](https://www.pubnub.com/tutorials/) 및 [블로그](https://www.pubnub.com/blog/) 특정 사용 사례에 대한 [사용 사례](https://www.pubnub.com/use-case/).

펍넙이 어떤 도움을 줄 수 있을까요?
====================

이 문서는 원래 [PubNub.com에](https://www.pubnub.com/blog/build-chatbot-with-custom-knowledge-base/) 게시되었습니다.

저희 플랫폼은 개발자가 웹 앱, 모바일 앱, IoT 디바이스를 위한 실시간 인터랙티브를 구축, 제공, 관리할 수 있도록 지원합니다.

저희 플랫폼의 기반은 업계에서 가장 크고 확장성이 뛰어난 실시간 에지 메시징 네트워크입니다. 전 세계 15개 이상의 PoP가 8억 명의 월간 활성 사용자를 지원하고 99.999%의 안정성을 제공하므로 중단, 동시 접속자 수 제한, 트래픽 급증으로 인한 지연 시간 문제를 걱정할 필요가 없습니다.

PubNub 체험하기
-----------

[라이브 투어를](https://www.pubnub.com/tour/introduction/) 통해 5분 이내에 모든 PubNub 기반 앱의 필수 개념을 이해하세요.

설정하기
----

PubNub [계정에](https://admin.pubnub.com/signup/) 가입하여 PubNub 키에 무료로 즉시 액세스하세요.

시작하기
----

사용 사례나 [SDK에](https://www.pubnub.com/docs) 관계없이 [PubNub 문서를](https://www.pubnub.com/docs) 통해 바로 시작하고 실행할 수 있습니다.