PubNub 및 ChatGPT/OpenAI로 챗봇 구축하기
Published: 2024-03-11 14:48:19

최근까지만 해도 챗봇을 구축하려면 '자연어 처리(NLP)'를 사용하여 사용자가 무엇을 묻는지 이해하고 해석한 다음, 백엔드 로직을 사용하여 해당 요청을 처리하거나 독점 서비스와 통합하려고 시도했습니다. Dialogflow 또는 Microsoft Bot 프레임워크와 같은 솔루션은 머신 러닝을 기반으로 대화형 AI를 제공하며, 전통적으로 챗봇을 만드는 개발자들에게 인기가 있었습니다.

OpenAI와 OpenAI의 ChatGPT를 사용하면 인공지능 기반의 AI 챗봇을 그 어느 때보다 쉽게 만들 수 있습니다. OpenAI를 구동하는 대규모 언어 모델(LLM)은 공개 데이터세트를 기반으로 하기 때문에 공개 지식 기반에 존재할 것으로 예상되는 모든 정보를 제공하여 앱의 사용자 경험을 쉽게 향상시킬 수 있습니다.

PubNub는 다음과 같은 다양한 산업 및 사용 사례를 위한 실시간 경험을 제공합니다. [고객 지원](https://www.pubnub.com/solutions/communications/) 및 [인앱 채팅](https://www.pubnub.com/solutions/chat/)이러한 모든 실시간 경험은 사용자가 읽을 수 있는 메시지나 솔루션에 대한 메타데이터와 같은 데이터를 기반으로 제공되므로 **기존 데이터를 활용하여 챗봇을 구동하는 것이 좋지 않을까요?**

_몇 가지 실제 사용 사례를 살펴보세요:_

-   자주 묻는 **고객 지원** 질문에 대한 답변 제공
    
-   제공된 위치 근처의 맛집 추천 등 추가 콘텐츠로 기존 데이터를**보강하기**
    
-   메시지 기록을 기반으로 **대화 요약** 제공.
    

저희는 [기사](https://www.pubnub.com/blog/building-a-chatbot-with-openai-gpt3-and-pubnub/) 를 게시한 적이 있는데, 그 이전 글도 여전히 유효하지만 업계는 매우 빠르게 변화하고 있으며 몇 달이라는 시간은 긴 시간입니다.

이 글에서는 현재 운영 중인 것과 유사한 OpenAI 기반의 챗봇을 구축하는 방법에 대해 설명합니다. [PubNub 쇼케이스](http://pubnub-showcase.netlify.app/) 애플리케이션에서 볼 수 있는 것과 유사한 챗봇을 구축하는 방법에 대해 설명합니다.

![The showcase's AI model has been primed to mention PubNub, where appropriate](https://www.pubnub.com/cdn/3prze68gbwl1/6G6aZfuXXtSqh9aBDyA7fw/5c416e9b87a4c0de5070271669bd13dd/showcase_app.png)

**높은 수준의 아키텍처**
---------------

ChatGPT와 같은 챗봇을 만들려면 [OpenAI Chat API를](https://platform.openai.com/docs/api-reference/chat) 사용하고 계정을 등록하여 [API 키를](https://platform.openai.com/account/api-keys) 생성해야 합니다. OpenAI API는 REST 엔드포인트로 액세스할 수 있으므로 거의 모든 프로그래밍 언어에서 호출할 수 있지만 제공되는 예제는 대부분 Python으로 작성되어 있습니다.

PubNub에서 데이터를 추출하고 챗봇과의 대화를 시작하거나 계속하기 위해 가장 좋은 방법은 [함수를](https://www.pubnub.com/products/functions/) 사용하는 것입니다. 함수는 Node.JS에서 실행되는 서버리스 [JavaScript](https://www.pubnub.com/guides/javascript/) 컨테이너를 제공하며, 채팅 메시지 수신과 같은 이벤트가 발생할 때마다 비즈니스 로직을 실행할 수 있습니다. PubNub 함수는 실시간 즉석 언어 번역, 욕설 필터링 또는 OpenAI 같은 타사 서비스를 호출하는 데 자주 사용됩니다.

이 예제는 다음과 같이 작동합니다:

-   기존 채팅 애플리케이션이 실시간 메시지 송수신을 위해 PubNub를 사용하고 있습니다.
    
-   PubNub 함수는 특정 채널로 전송되는 메시지를 수신 대기합니다.
    
-   단일 메시지는 그 자체로는 ChatGPT에 컨텍스트를 제공하지 않으므로 대화 기록의 일부도 캐시되어 대화가 계속 진행될 수 있습니다.
    
-   PubNub 함수는 OpenAI API를 호출하여 응답을 검색합니다.
    
-   응답은 자체 챗봇과 연결된 PubNub 채널에 게시됩니다.
    

아래 시퀀스 다이어그램에서 이를 확인할 수 있습니다:

![Example sequence diagram for implementing a ChatGPT-like chatbot with PubNub and OpenAI](https://www.pubnub.com/cdn/3prze68gbwl1/64ZjHOSpoWo5vfykIpNPVU/44eb69443493a131043d8142133b234c/architecture.png)

1.  사용자가 채팅 앱에 메시지를 입력합니다. PubNub는 50개 이상의 SDK를 통해 대부분의 애플리케이션을 지원할 수 있으며, 메시지는 PubNub 네트워크의 챗봇을 나타내는 채널에 [게시됩니다](https://www.pubnub.com/docs/general/messages/publish).
    
2.  PubNub 함수는 채널에서 [게시 이벤트가](https://www.pubnub.com/docs/general/serverless/functions/overview#after-publish-or-fire-functions) 발생한 [후](https://www.pubnub.com/docs/general/serverless/functions/overview#after-publish-or-fire-functions) 호출되도록 구성됩니다. 메시지가 수신되면 채널 기록을 검색하여 대화에 대한 컨텍스트를 제공하고, 이 기록은 사용자 입력 및 일부 추가 컨텍스트와 함께 [채팅 완료 API를](https://platform.openai.com/docs/api-reference/chat/create) 통해 ChatGPT에 제공됩니다.
    
3.  ChatGPT API는 대화 흐름에 적합한 응답을 생성합니다.
    
4.  PubNub 함수 내에서 ChatGPT로부터 응답이 수신되고, 이 응답은 파싱되어 PubNub 네트워크에 다시 [게시됩니다](https://www.pubnub.com/docs/general/messages/publish).
    
5.  이전에 PubNub에서 메시지를 수신하도록 [가입한](https://www.pubnub.com/docs/general/channels/subscribe) 애플리케이션은 챗봇의 응답을 표시합니다.
    

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

### 다음과 같이 PubNub 함수를 만듭니다:

전제 조건: PubNub을 처음 사용하는 경우 [문서를](https://www.pubnub.com/docs/general/basics/set-up-your-account) 따라 계정을 설정하거나 [둘러보기를](https://www.pubnub.com/tour/introduction/) 방문하여 PubNub이 무엇인지 이해하세요.

1.  [관리자 대시보드로](http://admin.pubnub.com/) 이동합니다.
    
2.  왼쪽 메뉴에서 `함수를` 선택하고 함수를 만들려는 위치에서 적절한 키 세트를 선택합니다.
    
3.  `새 모듈 만들기를` 선택합니다.
    
4.  모듈 이름과 모듈 설명을 입력하고 키셋을 선택한 다음 `만들기를` 누릅니다.
    
5.  방금 만든 모듈을 선택합니다.
    
6.  `새 함수 만들기 +` 선택
    
7.  함수에 이름을 지정하고 이벤트 유형을 `게시 후 또는 실행 후를` 선택합니다. 이 함수는 메시지가 PubNub에 제출된 후에 호출됩니다. 함수는 동기식 또는 비동기식일 수 있으며, 이 경우 메시지의 사본을 캡처하여 OpenAI로 전송합니다. [다양한 유형의 함](https://www.pubnub.com/docs/general/serverless/functions/overview#before-publish-or-fire-functions) 수에 대한 자세한 내용은 다음 문서에서 확인할 수 있습니다.
    
8.  함수 채널은 OpenAI에 보내려는 메시지를 [게시하는](https://www.pubnub.com/docs/general/messages/publish) 채널과 일치해야 합니다. 여기에 와일드카드를 사용할 수 있으므로 예를 들어 chatgpt `.*는` 채팅을 시작하는 모든 채널과 일치합니다. 이 함수는 여러 사람과 동시에 대화하기를 원하므로 와일드카드를 사용하면 활성 대화에 참여하는 사용자를 구분하여 적절한 채널에서 응답할 수 있도록 할 수 있습니다.여러 사람이 동시에 OpenAI와 대화하는 경우 PubNub는 함수의 여러 인스턴스를 생성하는 작업을 처리합니다. 예를 들어 `chatgpt.dave와` `chatgpt.simon은` 서로 다른 두 채널이지만 둘 다 `chatgpt.*에서` 수신 대기 중인 PubNub 함수를 호출할 것입니다. [PubNub에서 채널 와일드카드를 처리하는 방법은](https://support.pubnub.com/hc/en-us/articles/360051495072-How-do-I-subscribe-to-a-wildcard-channel-) 문서에 자세히 설명되어 있습니다.
    
9.  `내 비밀번호를` 선택하고 OpenAI [API 키에](https://platform.openai.com/account/api-keys) 대한 새 비밀번호를 만듭니다. 아래 코드에서는 이 비밀번호를 `OPENAI_API_KEY라고` 가정합니다.
    

### **다음은 OpenAI / ChatGPT를 호출하는 PubNub 함수 예시입니다.**

```js
const pubnub = require('pubnub');
const xhr = require('xhr');
const vault = require('vault');

// Process all messages posted to the private ChatGPT channel
// This will be unique for each user, so chat is 1:1 with ChatGPT
export default request => {
  const inboundChannel = request.channels[0];
  if (request.message.content.type == "text" && request.message.sender != "OpenAI")
  {
    //  user’s query
    let naturalCommand = request.message.content.text;
   // Always provide OpenAI with some context of how you want questions answered
    let historicalMsgs = 
      [{"role": "system", "content": "You are a helpful assistant, expert in PubNub"}];
    return getOpenaiApiKey().then(apikey => {
      // Read the last messages from the conversation to provide conversation context
      return pubnub.history({
        channel: inboundChannel,
        count: 10
        }).then((response) => {
          response['messages'].forEach((value, index) => {
            // The message role will vary depending on whether it was sent or received 
            if (value.entry.sender && value.entry.sender == "OpenAI")
              historicalMsgs.push({"role": "assistant", 
                "content": value.entry.content.text})
            else
              historicalMsgs.push({"role": "user", 
                "content": value.entry.content.text})
          });

          // Depending on timing, last published message may or may not yet be stored
          if (historicalMsgs[historicalMsgs.length - 1].content != naturalCommand)
          {
            historicalMsgs.push({"role": "user", 
              "content": naturalCommand});
          }
          return openAI(naturalCommand, historicalMsgs).then(aiResponse => {
            // Respond back by publishing the message to PubNub
            pubnub.publish({
              channel: inboundChannel,	//  In the showcase, this is unique per user
              message: {
                content: {
                  type: "text",
                  text: aiResponse
                },
                sender: "OpenAI",
              },
            });
            return request.ok();
          });
        })
      });
    }
    return request.ok();
  };


  // Get API Key for OpenAI
  // Key is populated via Vault Secret Manager  
  let OPENAI_API_KEY = null;
  function getOpenaiApiKey() {
    // Use cached key
    if (OPENAI_API_KEY) {
      return new Promise(resolve => resolve(OPENAI_API_KEY));
    }
    // Fetch key from vault
    return vault.get("OPENAI_API_KEY").then(apikey => {
      OPENAI_API_KEY = apikey;
      return new Promise(resolve => resolve(OPENAI_API_KEY));
    });  
  }

  // API Call to OpenAI asking the AI to run functions if it thinks it needs to
  function openAI(naturalCommand, msgs) {
    // Generate Function Instructions for the AI
    const url = 'https://api.openai.com/v1/chat/completions';
    const http_options = {
      'method': 'POST',
      'headers': {
        "Content-Type": "application/json",
        "Authorization": `Bearer ${OPENAI_API_KEY}`,
      },
    'body': JSON.stringify({
      "model": "gpt-3.5-turbo",
      "messages": msgs,
      "max_tokens": 300
    }),
    timeout: 9500, // PubNub functions timeout limit can be raised if needed
    retries: 0
  };

  return xhr.fetch(url, http_options).then((resp) => {
    const body = JSON.parse(resp.body);
    return body.choices[0].message.content;
  })
  .catch((err) => {
    console.log(err);
    return "Timed out. Please try again or ask a simpler question";
  });
}
```

**OpenAI API 호출 시 실용적인 고려 사항**
------------------------------

### **채팅 완료 API 속성**

이 문서에 소개된 코드는 [OpenAI 채팅 완료 API를](https://platform.openai.com/docs/api-reference/chat/create) 사용하지만 위에 표시된 것보다 더 많은 구성이 가능합니다.

`stream을` true로 지정하면 [서버에서 전송된 이벤트에](https://www.pubnub.com/guides/server-sent-events/) 대한 OpenAI 응답이 데이터 스트림으로 반환됩니다. 실제로는 ChatGPT 웹 인터페이스의 작동 방식과 유사하게 사용자에게 보다 즉각적인 응답이 표시되므로 체감 대기 시간을 줄일 수 있습니다.

`model을` 사용하면 응답을 생성하는 데 사용되는 언어 모델을 지정할 수 있습니다. 이 API는 다양한 기능과 가격대를 가진 모델 제품군으로 구동되며, 모델이 업그레이드되고 새로운 모델이 자주 추가됩니다.

`max_tokens는` API가 출력을 생성하는 데 사용할 [토큰](https://platform.openai.com/tokenizer) 수를 제한합니다. 일반적으로 토큰 수가 적을수록 출력이 덜 복잡해지고 컨텍스트가 덜 추적되지만 응답이 더 빨리 제공됩니다.

메시지 `역할을` 사용하면 메시지의 작성자를 지정할 수 있습니다. 이 문서의 예에서는 `시스템을` 사용하여 OpenAPI에 몇 가지 지침을 제공하고, 최종 사용자가 보낸 메시지는 `사용자`, 이전에 OpenAI가 제공한 응답은 `어시스턴트를` 사용합니다.

`온도/최고_p`, `빈도_페널티`, `존재_페널티를` 지정하여 모델을 추가로 조정할 수 있습니다. 이에 대한 자세한 내용은 [OpenAPI 설명서를](https://platform.openai.com/docs/api-reference/chat/create) 참조하세요.

또한 이 API를 사용하면 모델의 기능을 강화하는 사용자 지정 함수를 정의하고 지정할 수 있지만 이 블로그의 범위를 벗어납니다. 더 자세히 알아보려면 [별도의 게시](https://gist.github.com/stephenlb/de558e9802a6f950951eb0939ab71bcd) 물을 통해 ChatGPT가 사용자를 대신하여 PubNub에 게시하도록 허용하여 "5분 후에 준비될 것이라는 메시지를 메인 채널에 보냅니다."와 같은 메시지를 보내는 방법을 설명해 드립니다."또한 ChatGPT가 자체 비즈니스 API를 호출하도록 허용하여 고객에게 직접 제품 정보나 주문 상태 정보 등을 제공할 수도 있습니다.

### **채팅에 컨텍스트 제공**

[HTTP](https://www.pubnub.com/guides/http/) 요청은 상태가 없으므로 OpenAI와 장기적인 대화를 진행하려면 API에 컨텍스트를 제공하고, 지금까지의 대화를 설명하고, 해당 대화에 대한 메타데이터를 제공할 수 있는 방법이 필요합니다.

[채팅 완료 API는](https://platform.openai.com/docs/api-reference/chat/create) 다양한 `메시지를` 받아들여 AI 모델이 모호할 수 있는 질문에서 의미를 도출할 수 있게 해줍니다. 다음 예시를 살펴보세요:

\> \[사용자\] 지구는 얼마나 큰가요?

\> \[OpenAI\] 지구의 지름은 약 12,742킬로미터입니다.

\> \[사용자\] **얼마나 무겁냐고요?**

\> \[OpenAI\] 지구의 질량은 약 5.97x10^24 kg입니다.

"얼마나 무겁나요?"라는 질문에 답하기 위해 AI는 '그것'이 무엇인지 이해해야 했습니다.

PubNub 기반 챗봇을 구축할 때 얼마나 많은 대화 컨텍스트를 제공할지 결정해야 합니다. PubNub 기능을 사용하는 경우 채널의 전체 메시지 기록에 액세스할 수 있으며 예제에서는 대화의 이전 10개 메시지를 제공합니다. 물론 필요에 따라 훨씬 더 많은 정보를 제공할 수도 있습니다:

```js
// Read in the last messages from the conversation to provide some context to Chat GPT
pubnub.history({
  channel: inboundChannel,
  count: 10
}).then((response) => {
  response['messages'].forEach((value, index) => {
    if (value.entry.sender && value.entry.sender == "ChatGPT")
      historicalMsgs.push({"role": "assistant", "content": value.entry.content.text})
    else
      historicalMsgs.push({"role": "user", "content": value.entry.content.text})
});
```

**대화 컨텍스트가 이미 PubNub 내에 있으면 해당 컨텍스트를 OpenAI에 제공하는 것은 간단합니다**. 메시지가 OpenAI로 전송되었는지 또는 OpenAI로부터 수신되었는지에 따라 `역할이` 달라진다는 점에 유의하세요.

### **장기 실행 쿼리**

ChatGPT와 유사한 챗봇을 개발하고 AI 모델에서 사용하는 매개변수를 구성할 때 쿼리에 대한 예상 응답 시간을 고려하세요. 기본적으로 PubNub 함수는 호출당 최대 10초의 런타임을 제공하며, 지원팀에 문의하여 늘릴 수 있습니다. 일반적으로 사용자의 질문에 응답하는 데 너무 오래 걸리는 챗봇은 사용자에게 부정적으로 인식되므로 앞서 언급한 것처럼 응답성과 기능 간의 균형을 이루도록 모델의 매개변수를 조정하는 것이 바람직합니다.

OpenAI의 일부 사용 사례에서는 몇 초가 아닌 몇 분 단위로 측정된 응답을 기대할 수 있습니다. OpenAI를 PubNub 솔루션에 통합하는 경우 응답 시간이 기본 함수 런타임을 초과할 것으로 예상되는 경우 당사에 [문의해](https://www.pubnub.com/company/contact-us/) 주시면 권장 사항과 조언을 제공해 드릴 수 있습니다.

**요약**
------

PubNub와 OpenAI / ChatGPT를 함께 사용하면 모든 온라인 경험에 AI와 채팅을 추가할 수 있는 매우 강력한 실시간 솔루션을 빠르게 만들 수 있습니다.

시작할 준비가 되었다면 [관리자 대시보드를](http://admin.pubnub.com/) 방문하여 무료 PubNub 키 세트에 가입하세요. 모든 업계를 아우르는 다양한 [튜토리얼과](https://www.pubnub.com/tutorials/) [데모를](https://www.pubnub.com/demos/) 확인하거나 [PubNub 쇼케이스](http://pubnub-showcase.netlify.app/) ( [Github에서도](https://github.com/PubNubDevelopers/PubNub-Showcase) 제공)를 통해 OpenAI로 구동되는 챗봇의 예시를 살펴볼 수 있습니다.

#### 콘텐츠

[상위 수준](#h-0)[아키텍처PubNub 함수](#h-1) 구성하기다음과[같이 PubNub 함수](#h-2)[만들기](#h-1)[:](#h-2)[다음은 OpenAI / Chat을 호출하는 PubNub 함수 예제입니다](#h-3).[OpenAI API를 호출할 때](#h-4)[실제적인](#h-3)[고려 사항대화](#h-4)[완료 API](#h-5)[속성챗에 컨텍스트 제공하기장기 실행](#h-6)[쿼리](#h-7)[요약](#h-8)

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

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

저희 플랫폼은 개발자가 웹 앱, 모바일 앱 및 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) 통해 바로 시작하고 실행할 수 있습니다.