1 of 82

深入 LINE Bot 與 ChatGPT Plugin

從實作到理論的探討

卡米哥

2 of 82

3 of 82

4 of 82

5 of 82

6 of 82

今天的內容

  • 認識 ChatGPT Plugin
  • 認識 LangChain
  • 用 LangChain 實作 LINE Bot 的範例展示

7 of 82

認識 ChatGPT Plugin

8 of 82

ChatGPT Plugin

  • 讓 ChatGPT 可以串接其他服務
  • 可能是新一代的 app store
  • 一個簡單的說明檔 ,再加上一組 API 和 OpenAPI 格式的 API 說明文件

9 of 82

試用 ChatGPT Plugin

  • 目前要付錢才能用

10 of 82

ChatGPT 設定頁面

11 of 82

ChatGPT 啟用 Plugin 後

12 of 82

可以選擇要啟用的工具

13 of 82

也有 Plugin store

14 of 82

試用 Wolfram

15 of 82

ChatGPT 發給 Wolfram 的 request 以及 Wolfram 的 response

16 of 82

ChatGPT 跟 Plugin 是怎麼溝通的?

17 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

發問

18 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

思考

19 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

發問

20 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

回覆

21 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

思考

22 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

回覆

23 of 82

ChatGPT Plugin 做了什麼?

  1. ChatGPT 收到來自用戶的發問
  2. ChatGPT 思考
  3. ChatGPT 對 Wolfram 發問
  4. ChatGPT 收到 Wolfram 的回覆
  5. ChatGPT 思考
  6. ChatGPT 回覆用戶的發問

24 of 82

ChatGPT 怎麼思考?

  • 使用正確的 Prompt 引導 ChatGPT 進行思考
    • 告訴他不要自己做事
    • 告訴他可以用哪些工具
    • 告訴他工具的使用方法

25 of 82

26 of 82

27 of 82

28 of 82

29 of 82

ChatGPT 怎麼思考?

  • 實際使用 Plugin

30 of 82

31 of 82

32 of 82

33 of 82

34 of 82

ChatGPT 怎麼思考?

  • 使用正確的 Prompt 引導 ChatGPT 進行思考
    • 告訴他不要自己做事
    • 告訴他可以用哪些工具
    • 告訴他工具的使用方法
  • 語言模型使用文字來表示呼叫外部工具的指令
    • 當語言模型輸出指令時,程式執行指令,並將結果做成一個新的 Prompt 再丟給語言模型

35 of 82

ChatGPT 怎麼思考?

  • 使用正確的 Prompt 引導 ChatGPT 進行思考
    • 告訴他不要自己做事
    • 告訴他可以用哪些工具
    • 告訴他工具的使用方法
  • 語言模型使用文字來表示呼叫外部工具的指令
    • 當語言模型輸出指令時,程式執行指令,並將結果做成一個新的 Prompt 再丟給語言模型
  • Prompt 的撰寫技巧:ReAct

36 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

發問

大型語言模型

37 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

將 Prompt 結合工具資訊後傳入

大型語言模型

38 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

請求使用工具

大型語言模型

39 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

呼叫 API

大型語言模型

40 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

回覆

大型語言模型

41 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

大型語言模型

將先前的對話、工具資訊、呼叫工具的結果整合成 Prompt 後傳入

42 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

回覆結果

大型語言模型

43 of 82

ChatGPT Plugin 做了什麼?

用戶

ChatGPT

Wolfram

回覆

大型語言模型

44 of 82

ChatGPT 就是代理人

用戶

ChatGPT

Wolfram

大型語言模型

Agent

45 of 82

做一個

ChatGPT Plugin

46 of 82

做一個 ChatGPT Plugin

  • 需要架一個 API server
    • OPTIONS /.well-known/ai-plugin.json
    • GET /.well-known/ai-plugin.json
    • GET /openapi.yaml
  • 再加上 ai-plugin.json 和 openapi.yaml 當中提到的檔案和 API 實作即可

47 of 82

做一個 ChatGPT Plugin

48 of 82

做一個 ChatGPT Plugin

49 of 82

{

"schema_version": "v1",

"name_for_human": "My Bash Plugin",

"name_for_model": "bash",

"description_for_human": "Plugin for executing bash commands on my MacOS.",

"description_for_model": "Plugin for executing bash commands on MacOS.",

"auth": {

"type": "none"

},

"api": {

"type": "openapi",

"url": "https://ngrok.etrex.tw/openapi.yaml",

"is_user_authenticated": false

},

"logo_url": "https://ngrok.etrex.tw/logo.png",

"contact_email": "your-email@example.com",

"legal_info_url": "https://ngrok.etrex.tw/openapi.yaml"

}

/.well-known/ai-plugin.json

50 of 82

51 of 82

ChatGPT 發出的 request 和對應的 response

52 of 82

本機的 API Server Log

53 of 82

認識 LangChain

54 of 82

LangChain

  • 是目前最完整的語言模型開發框架
  • 能夠快速地打造有記憶能力且能串接其他服務的聊天機器人
  • 擁有大量的開發者進行開發和維護,能協助開發者解決實現過程中的問題

55 of 82

LangChain Agent

  • Agent 負責組合 Prompt 和決定要發送 Request 給誰

用戶

LangChain

Wolfram

ChatGPT API

Agent

56 of 82

LangChain Agent

  • 不同的 Agent 使用不同的 Prompt,即產生不同的效果
  • 其中一個比較好懂的 Agent

57 of 82

PREFIX = """回應人類,盡可能有用和精確。你可以使用以下工具:"""

FORMAT_INSTRUCTIONS = """使用一個json塊來通過提供一個動作鍵(工具名稱)和一個動作輸入鍵(工具輸入)來指定工具。

有效的"動作"值:"最終答案"或 {tool_names}

每個$JSON_BLOB只提供一個動作,如下所示:

===

{

"action": $TOOL_NAME,

"action_input": $INPUT

}

===

遵循此格式:

問題:輸入要回答的問題

思考:考慮先前和後續步驟

動作:

===

$JSON_BLOB

===

觀察:動作結果

... (重複 思考/動作/觀察 N 次)

思考:我知道該如何回應

動作:

===

{

"action": "Final Answer",

"action_input": "Final response to human"

}

===

"""

58 of 82

LangChain Agent

  • 不同的 Agent 使用不同的 Prompt,即產生不同的效果
  • 其中一個比較好懂的 Agent

SUFFIX = """開始!始終用單一動作的有效json塊回應。如有必要,使用工具。如有必要,直接回應。格式是Action:===\$JSON_BLOB===然後Observation:。

思考:"""

59 of 82

用 LangChain 實作 LINE Bot 的範例展示

60 of 82

LINE Bot 結合 LangChain

App Server

Wolfram

用戶

LINE

傳送訊息

Webhook

LangChain

ChatGPT API

61 of 82

LINE Bot 結合 LangChain

App Server

Wolfram

用戶

LINE

function

call

LangChain

ChatGPT API

62 of 82

LINE Bot 結合 LangChain

App Server

Wolfram

用戶

LINE

LangChain

api call

終究是 Server

ChatGPT API

63 of 82

LINE Bot 結合 LangChain

Wolfram

ChatGPT API

用戶

LINE

App Server &

LangChain

Webhook

Server &

Agent

64 of 82

LINE Bot 結合 LangChain

Wolfram

ChatGPT API

用戶

LINE

App Server &

LangChain

生成 Prompt

65 of 82

LINE Bot 結合 LangChain

Wolfram

ChatGPT API

用戶

LINE

App Server &

LangChain

回覆

66 of 82

LINE Bot 結合 LangChain

Wolfram

ChatGPT API

用戶

LINE

App Server &

LangChain

有需要使用工具時

67 of 82

LINE Bot 結合 LangChain

Wolfram

ChatGPT API

用戶

LINE

App Server &

LangChain

call api

回覆訊息

回覆訊息

68 of 82

Evan Lin 的股價小幫手

  • https://engineering.linecorp.com/zh-hant/blog/langchain-llm-linebot
  • 使用 Fast API 網頁框架
  • 使用 LangChain 語言模型框架
  • 使用最新的 OpenAI Function Calling 實作
    • 不需要自己再設計工具相關的 Prompt

69 of 82

Evan Lin 的股價小幫手

  • https://engineering.linecorp.com/zh-hant/blog/langchain-llm-linebot
  • 使用 Fast API 網頁框架
  • 使用 LangChain 語言模型框架
  • 使用最新的 OpenAI Function Calling 實作
    • 不需要自己再設計工具相關的 Prompt

70 of 82

程式碼 - main.py

# 3-13 行 License

# 15-43 行 載入模組

# 45-53 行 載入環境變數

# 55-59 行 App Server Setup

# 61-68 行 LangChain Setup

# 71-97 行 Webhook

71 of 82

程式碼

# 45-53 行 載入環境變數

# get channel_secret and channel_access_token from your environment variable

channel_secret = os.getenv('ChannelSecret', None)

channel_access_token = os.getenv('ChannelAccessToken', None)

if channel_secret is None:

print('Specify LINE_CHANNEL_SECRET as environment variable.')

sys.exit(1)

if channel_access_token is None:

print('Specify LINE_CHANNEL_ACCESS_TOKEN as environment variable.')

sys.exit(1)

72 of 82

程式碼

# 55-59 行 App Server Setup

app = FastAPI() # App Server

session = aiohttp.ClientSession()

async_http_client = AiohttpAsyncHttpClient(session)

line_bot_api = AsyncLineBotApi(channel_access_token, async_http_client) # LINE SDK

parser = WebhookParser(channel_secret) # LINE SDK

73 of 82

程式碼

# 61-68 行 LangChain Setup

model = ChatOpenAI(model="gpt-3.5-turbo-0613") # 選擇語言模型

tools = [StockPriceTool(), StockPercentageChangeTool(), # 可以使用的工具

StockGetBestPerformingTool()]

open_ai_agent = initialize_agent(tools,

model,

agent=AgentType.OPENAI_FUNCTIONS, # 選擇 Agent Type

verbose=False)

74 of 82

程式碼

# 71-97 行 Webhook

@app.post("/callback")

async def handle_callback(request: Request):

# 取得 events

...

# 對每個 event 篩選出文字訊息

...

# 交給 LangChain Agent 生成回覆訊息

...

# 回覆訊息給 LINE 用戶

...

75 of 82

程式碼

# 71-97 行 Webhook

@app.post("/callback")

async def handle_callback(request: Request):

# 取得 events

body = await request.body()

body = body.decode()

try:

events = parser.parse(body, signature)

except InvalidSignatureError:

raise HTTPException(status_code=400, detail="Invalid signature")

76 of 82

程式碼

# 71-97 行 Webhook

@app.post("/callback")

async def handle_callback(request: Request):

# 取得 events

...

# 對每個 event 篩選出文字訊息

for event in events:

if not isinstance(event, MessageEvent):

continue

if not isinstance(event.message, TextMessage):

continue

77 of 82

程式碼

# 71-97 行 Webhook

@app.post("/callback")

async def handle_callback(request: Request):

# 取得 events

...

# 對每個 event 篩選出文字訊息

for event in events: ...

# 交給 LangChain Agent 生成回覆訊息

tool_result = open_ai_agent.run(event.message.text)

78 of 82

程式碼

# 71-97 行 Webhook

@app.post("/callback")

async def handle_callback(request: Request):

# 取得 events

...

# 對每個 event 篩選出文字訊息

for event in events: ...

# 交給 LangChain Agent 生成回覆訊息

...

# 回覆訊息給 LINE 用戶

await line_bot_api.reply_message(event.reply_token,

TextSendMessage(text=tool_result))

return 'OK'

79 of 82

我的 Fork

  • 改為使用 STRUCTURED_CHAT Agent
  • 新增執行 Bash 的工具

80 of 82

我的 Fork

  • 改為使用 STRUCTURED_CHAT Agent
  • 新增執行 Bash 的工具

open_ai_agent = initialize_agent(

tools,

model,

agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,

#agent=AgentType.OPENAI_FUNCTIONS,

verbose=False

)

81 of 82

我的 Fork

  • 改為使用 STRUCTURED_CHAT Agent
  • 新增執行 Bash 的工具

82 of 82

感謝聆聽