[研討會][LangChain] LangChain 「Chains vs Agents」 Webinar Notes

LangChain "Chains vs Agents" Webinar

Weblink: https://www.crowdcast.io/c/m2ooh0uy9syg

Speak1: Swyx - smol developer

https://docs.google.com/presentation/d/1d5N3YqjSJwhioFT-edmyjxGsPBCMb1uZg0Zs5Ju673k/edit#slide=id.g254e571859c_0_133

image-20230629013808733

image-20230629013651102

Article:

Speaker2: Alex - Agent Eval

https://docs.google.com/presentation/d/1bo5uxaS4JMNt99VmsRdeTFLo9qSIByJiViIVakzF9NQ/edit#slide=id.g22b104eecb9_0_2

image-20230629004649563

  • 很難 debug agent failure:
    • failure token
    • CAPCHA

image-20230629005101725

  • 三種 Evaluation 方式

image-20230629005208061

  • 抓下一堆 dataset

image-20230629005331276

image-20230629010716866

Q&A

  1. What is the most affordable (free, local?) LLM for specific Agent Executor / Agent task like decision making, tool selection…?
    • Mpt7b
  2. In my experience, the OpenAI functions work really well in deciding what tool(s) to use even in multi-step scenarios. Do you think that a train-of-thought process is used behind the scenes, like ReACT or MLKR? And how useful are they now?
    1. 可以考慮看看 few shot

其他

Agent Hackathon

image-20230629011637608

https://lablab.ai/event/ai-agents-hackathon

AgentEval (第一名)

最後有 OpenAI CEO 演講

[學習心得][Python] 透過基於 LangChain 將許多好用工具打包起來的套件 - embedchain 來打造簡易版本客服 LINE Bot 機器人

image-20230628221201753

透過這個 EmbedChain 可以抓取許多種資料,這個圖片是測試他去抓取 「2023年LINE官方帳號方案價格調整,重點一次掌握」網頁上的資料來回覆給使用者。

  • 官方帳號在哪一天調整價錢? 官方帳號價格將在 2023 年 9 月 1 日調整。
  • 中用量方案的價格? 中用量方案的價格是每月 800 元。

前提

許多人都想要打造出客服聊天機器人 LINE Bot ,但是透過 NLU 來打造客服 LINE Bot 其實成本很高。這裡會推薦給各位透過 LangChain 加上 EmbedChain 這個套件,可以打造低成本與簡易版本的客服 LINE Bot 。 本篇文章將快速告訴各位,如何透過 EmbedChain 來打造

這裡也列出一系列,我有撰寫關於 LangChain 的學習文章:

EmbedChain 解決了那些問題

先預設本篇文章讀者,已經是懂的使用 LLM (Large Language Model) 來打造客服機器人。之前你需要先建立客服機器人的參考資料庫,(因為大部分 LLM (e.g. OpenAI) ) 不知道如何回覆你的問題。

需要的架構可以這裡參考文章 Enhancing ChatGPT With Infinite External Memory Using Vector Database and ChatGPT Retrieval Plugin

img

如上圖,快速整理架構如下:

  • 需要把客服文件透過切割成一群群的文字區塊
  • 將文字區塊透過 Embedding 技術放入 LLM 的向量空間,暫存在 Vector Database。 (會變成一個很長的數字陣列 e.g.)
  • 客戶詢問問題的時候,也去針對他的問題切割後作成 Embedding 。並且找尋最接近的文件。
  • 將文件區塊給 LLM 整理後回覆給客戶。

即便你使用了 LangChain 來包裝整個架構,你還是會遇到相關問題:

那有方式可以更快速解決這樣的架構問題嗎? 接下來就要跟大家 EmbedChain

如何透過 EmbedChain 打造客服 LINE Bot

這裡列出幾個簡單流程:

  • 準備打造客服 LINE Bot需要的素材
  • 建立 EmbedChain LINE Bot
  • 測試與調整

以下我們將透過 EmbedChain 來打造一個回覆 LINE Biz-Solution 基本資訊的客服機器人。

image-20230628210029311

(資料來源: LINE Biz-Solution)

準備打造客服 LINE Bot需要的素材

這裡列出一些經常被詢問的問題網頁:

image-20230628090828775

建立 EmbedChain LINE Bot

使用上也很簡單:

  1. 安裝 EmbedChain pip install embedchain

  2. 加上相關程式碼

    from embedchain import App
       
    naval_chat_bot = App()
       
    # Embed Online Resources 將 LINEBiz 內容放進去
    naval_chat_bot.add("web_page", "https://tw.linebiz.com/column/LINEOA-2023-Price-Plan/")
    naval_chat_bot.add("web_page", "https://tw.linebiz.com/column/stepmessage/")
    naval_chat_bot.add("web_page", "https://tw.linebiz.com/column/LAP-Maximize-OA-Strategy/")
       
    # Embed Local Resources
    naval_chat_bot.add_local("qna_pair", ("Who is Naval Ravikant?", "Naval Ravikant is an Indian-American entrepreneur and investor."))
       
    naval_chat_bot.query("What unique capacity does Naval argue humans possess when it comes to understanding explanations or concepts?")
    # answer: Naval argues that humans possess the unique capacity to understand explanations or concepts to the maximum extent possible in this physical reality.
    

測試與調整

目前測試下來發現的問題還不少:

  • 常常跑出英文
  • 容易跑出不知道答案在哪裡

結語

EmbedChain 來打造客服機器人算是可以達成 POC 概念的呈現,但是如果要正式上線的話,建議還是要透過 LangChain 來透過 vector stores 加上 Embedding 來打造(其實也是他裡面的方式)。這邊有更多的資訊,會再慢慢更新上來。

[學習心得][Python] 透過 LangChain 來處理特殊的中央氣象局資料

image-20230622194316256

前提

接下來,我們將介紹如何透過 LangChain 來打造一些實用的 LINE Bot 。第一個我們先透過旅遊小幫手的概念,來幫大家串接關於氣象的 LangChain Function Agent吧。

本篇文章將要帶給各位一些概念:

  • 如何用 LangChain 來串接 中央氣象局的 Open API Data
  • 如何在 LLM 的對話中來處理一些特別數值的輸入。
  • 如何活用 LLM 對話的聰明性,來活用 LangChain Function Agent 。

這裡也列出一系列,我有撰寫關於 LangChain 的學習文章:

直接看如何使用程式碼 https://github.com/kkdai/langchain_tools/blob/master/travel_tool/

如何用 LangChain 來串接 中央氣象局的 Open API Data

要申請中央氣象局 OpenAPI Data ,依照以下流程:

image-20230622195316423

接下來來透過 ChatGPT 來協助撰寫相關資料:

  • 透過 Execute 結果中的 CURL `
  curl -X 'GET' \
    'https://opendata.cwb.gov.tw/api/v1/rest/datastore/F-C0032-001?Authorization=你的授權碼' \
    -H 'accept: application/json'
  • 然後去ChatGPT 問說,就可以取得 get_weather_data ,這邊記住我們只有使用地點。原因如下:

    • 雖然會傳回未來三天的氣象資料,但是 LLM 可以幫我們整理,並且篩選。
    • 三天的資料也可以幫助我們來處理更多詢問,不需要再查詢的時候就修改。
    def get_weather_data(location_name=None):
      
        url = 'https://opendata.cwb.gov.tw/api/v1/rest/datastore/F-C0032-001'
      
        headers = {'accept': 'application/json'}
      
        query = {
            'Authorization': cwb_token}
      
        if location_name is not None:
            query['locationName'] = location_name
      
        response = requests.get(url, headers=headers, params=query)
      
        if response.status_code == 200:
            return response.json()
        else:
            return response.status_code
    

轉換成 LangChain Function Agent

參考之前其他的 Tool Agent 的寫法,可以很快速改成以下方式。

cwb_token = os.getenv('CWB_TOKEN', None)

# From CWB API
# https://opendata.cwb.gov.tw/dist/opendata-swagger.html#/%E9%A0%90%E5%A0%B1/get_v1_rest_datastore_F_C0032_001
class WeatherDataInput(BaseModel):
    """Get weather data input parameters."""
    location_name: str = Field(...,
                               description="The cities in Taiwan.")


class WeatherDataTool(BaseTool):
    name = "get_weather_data"
    description = "Get the weather data for Taiwan"

    def _run(self,  location_name: str):
        weather_data_results = get_weather_data(
            location_name)

        return weather_data_results

    def _arun(self, location_name: str):
        raise NotImplementedError("This tool does not support async")

    args_schema: Optional[Type[BaseModel]] = WeatherDataInput

如何在 LLM 的對話中來處理一些特別數值的輸入。

如果你依照以上的方式來寫,你會發現你執行天氣的結果都會失敗。尤其是查詢台北市的天氣。

image-20230702160209686

如果回去看原來的 Open API Spec

image-20230622200638227

誒?! 原來是固定輸入的資料,而且資料名稱用「臺北市」?!那該怎麼辦呢?

你不能要求每次叫使用者輸入「臺北市」,更不要自己去改那些輸入。(那就太不 LLM 了)。那該如何處理呢?

讓 LLM 了解你的輸入範圍,並且知道該如何調整。

既然知道,地址只能輸入一個區間的資料。並且有限定的「用字」(也就是 臺) 。其實可以透過 Function 的敘述來讓 LLM (OpenAI) 來讀懂。

location_name: str = Field(...,
                           description="The cities in Taiwan, it must be one of following 臺北市, 新北市, 臺中市, 臺南市, 雲林縣, 南投縣, 屏東縣, 嘉義市, 嘉義縣")

只要透過對於 Argument 的敘述更加的細膩,LLM(OpenAI) 就會讀懂他的含義來幫你解決。比如說這樣的敘述:

  • 台北市 –> 就會輸入 「臺北市」(同理台中)
  • 墾丁 –> 因為不在裡面,他會猜測墾丁可能在屏東縣附近。就會輸入「屏東縣」。

這樣是不是我們需要的呢?

如何活用 LLM 對話的聰明性,來活用 LangChain Function Agent 。

image-20230622194316256 image-20230622203105421

這邊用以上兩個截圖給各位一些想法,也證實了透過 LLM 是可以很強大的來讓你的聊天機器人更聰明。

  • 明天台北市跟新北市白天哪裡比較容易下雨:
    • 這會呼叫兩次,一次查「臺北市」另外一次查「新北市」的氣象資訊。然後 LLM 會幫你整理相關資訊,並且比較裡面的「降雨機率」。
    • 同理也可以知道哪裡溫度比較高。
  • 告訴我明天靠近墾丁的天氣:
    • 這會去查詢「屏東縣」的資料。
  • 明天台北需要帶傘嗎?:
    • 這就是 LLM 最聰明的事情,以前還需要透過 NLU 的處理方式。現在都不需要了,直接知道你要找氣象局。並且幫你分析究竟需不需要帶傘。

結語

還記得 2018 年,在 iThome 演講的題目裡面就有提到,Intent 跟 Entity 的重要性。也表示不論那時候多麼先進的 NLU 引擎都很難處理許多內容。但是 2022 年的年底,自從 OpenAI 的模型公開後,我們就發現了許多嶄新的應用。更加上許多殺手型的運用(Function Calling) 看來讓許多的開發者可以換了新的腦袋來思考問題。

[學習心得][Python] 透過 LangChain 的 Functions Agent 達成用中文來操控資料夾

image-20230619204550551

前提

以前 Linux 課程上,大家總是對於 ls , mvcp 的指令無法背起來。都忘記有多少次聽到朋友抱怨,難道不能用中文來下指令嗎? 比如說:

  • 幫我移動1.pdf
  • 刪除 2.cpp 這個檔案
  • 列出檔案

現在,其實你可以透過 LangChain 很快來達成。本篇文章將給你範例程式碼,跟相關的原理 LangChain Functions Agent 的用法。

這裡也列出一系列,我有撰寫關於 LangChain 的學習文章:

開源套件參考這個 https://github.com/kkdai/langchain_tools/tree/master/func_filemgr

什麼是 LangChain

透過 LLM (大型語言模型)的開發上,有許多很方便的工具可以幫助你快速地打造出 POC 。 這裡最知名的莫過於 LangChain ,除了支援眾多的大型語言模型之外,更支援許多小工具(類似: Flowise) 。

What is LangChain and how to use it

什麼是 Functions Tool

就像是這篇文章提到的一樣, Functions Tools 是根據 最新的 06/13 公佈的 OpenAI Function Calling 的功能 所打造的功能。也就是你先給予 LLM 一連串可以執行的「工具列表」後。他會根據你的語意,來回答給你說「可能」是屬於哪一個 Function Tool 可以呼叫。 並且讓你來決定,究竟是要呼叫呢? 還是要繼續處理它。

就像是幫你的 LLM 告訴他可以做哪些判斷,由他來幫你判斷使用者的語意「可能」做哪一件事情。

image-20230620112225023

(讓機器人來幫你決定,應該要準備執行哪個 Function Tools)

在 Python LangChain 裡面也相當的簡單,前一篇文章已經有大部分的內容。 這裡做相關的說明:

from stock_tool import StockPriceTool
from stock_tool import get_stock_price

model = ChatOpenAI(model="gpt-3.5-turbo-0613")

# 將工具轉換成可以被解釋的 JSON 格式給 LLM 來處理。(目前只有 OpenAI)
tools = [StockPriceTool()]
functions = [format_tool_to_openai_function(t) for t in tools]

.....

# 透過 OpenAI 的最新模型,來判斷這個使用者的文字應該去執行哪個 Function
# 回傳可能是 get_stock_price 或者甚至可能是空的。
hm = HumanMessage(content=event.message.text)
ai_message = model.predict_messages([hm], functions=functions)

# 處理 OpenAI 幫你抓出的「參數」(arguments)
_args = json.loads(
    ai_message.additional_kwargs['function_call'].get('arguments'))

# (optional) 直接去執行該 function tool
tool_result = tools[0](_args)

這邊如果直接把結果回傳,可能只會達到股價的「數字」而已。甚至那個數字的單位都不會加上去。其實這只是讓 LLM 來告訴你該使用哪個 function 的判斷跟解釋。就很像我們之前使用 NLU 的 Intent detection 一樣。

如何完成 LangChain Functions Agent

image-20230621132804983

如果是 Function Agent 的話,就像是幫你的 LLM 大腦裝上了手臂,開始讓他不只是「說」,更能夠開使「動手做」。

image-20230620110007097

這邊「更加的抽象一點」,除了讓 LLM 知道有哪些工具外。 並且透過將他們定義成 Agent 去抓取資料後再來解釋。也就是會有以下流程:

  • 輸入使用者語詞,判斷呼叫哪個 Agent。並且取出相關的 Arguments 。
  • 呼叫該 Agent ,並且取得結果。
  • 透過結果,再一次詢問 LLM 總結回覆的答案。
# 以下 impot 工具類別中的 file management 工具組
# 這些是真的可以操控檔案的相關 tools
# 分別是: 讀取檔案,複製檔案,刪除檔案,移動檔案,寫入檔案。
from langchain.tools.file_management import (
    ReadFileTool,
    CopyFileTool,
    DeleteFileTool,
    MoveFileTool,
    WriteFileTool,
    ListDirectoryTool,
)

....

# 以下方式透過 OPENAI_FUNCTIONS 的 Agent 格式將剛才所有的工具都加入進去。
# 也就是說我們的 LLM 現在多了檔案操控的能力。

    model = ChatOpenAI(model="gpt-3.5-turbo-0613")
    tools = FileManagementToolkit().get_tools()
    open_ai_agent = initialize_agent(tools,
                                     model,
                                     agent=AgentType.OPENAI_FUNCTIONS,
                                     verbose=True)



# 真的要執行 Agent 的功能只要呼叫這一行就好。
        tool_result = open_ai_agent.run(question)

Langchain Functions Agent 跟 Functions Tool 的比照表

  OpenAI Function Tools OpenAI Function Agent
定義方式 Tools 透過 LangChain Tools 包裝成 Agents (OPENAI_FUNCTIONS)
執行流程 (1)輸入使用者語詞,判斷呼叫哪個 Agent。並且取出相關的 Arguments 。 (2) 開發者自己決定要不要去執行他,或是剩下的動作。 (1)輸入使用者語詞,判斷呼叫哪個 Agent。並且取出相關的 Arguments 。 (2) 呼叫該 Agent ,並且取得結果。 (3) 透過結果,再一次詢問 LLM 總結回覆的答案。
不要回覆定意外問題? 可以,自己決定哪些要回覆 不行!不論什麼都會回覆。

成果

以下的影片可以看到,這樣才幾行的程式碼,卻可以開始操控檔案。

並且,你還不需要完整把指令打對,甚至可以使用中文的指令才「列表」「讀取」「寫入」「刪除」,

最令人不可相信的是,你甚至可以「寫一首詩,然後把內容寫進 1.txt」這種比較複雜的指令都可以完整地被執行。

asciicast

結語

近期完了不少的 LangChain 的相關範例,並且感受了透過 Flowise 來打造相關應用的方式。 覺得 LINE Bot 的開發將會幫助各位更容易貼近使用者。打造出一個「專一」「好用」的聊天機器人,並且讓 LINE 官方帳號來幫助你的生意邁向生成式 AI 的時代吧!!

[學習心得][Python] 透過 LangChain 打造一個股價查詢 LINEBot - 股價小幫手

img

前提

透過 LLM (大型語言模型)的開發上,有許多很方便的工具可以幫助你快速地打造出 POC 。 這裡最知名的莫過於 LangChain ,除了支援眾多的大型語言模型之外,更支援許多小工具(類似: Flowise) 。

本篇文章將介紹如何透過 LangChain 打造一個查詢股價 (stock price) 的小工具,並且提供一個可以快速打造的開源套件讓各位一起學習。 對了,本篇文章使用的範例也是最新的 06/13 公佈的 OpenAI Function Calling 的功能。除了可以快速判斷使用者 Intent 之外,更可以呼叫外部的 API 來查詢本來 OpenAI 無法了解的資訊(比如說現在的股價)。

What is LangChain and how to use it

透過使用 LLM 的 LINE Bot: 你可以使用任何敘述公司的文字,來找尋公司股價。 比如說:

  • 蘋果公司,甲骨文… 等中文公司名稱。
  • 甚至從英文完全找不出股票代碼的公司,比如說: CloudFlare –> NET

開源套件參考這個 https://github.com/kkdai/linebot-langchain

這裡也列出一系列,我有撰寫關於 LangChain 的學習文章:

為何要挑選 LangChain 作為開發 LINE Bot 的架構

這題目很大,很難一句話回答。

  • LangChain 是一個很方便打造 POC 概念的東西。搭配 Flowise 甚至可以讓 prompt 人員跟開發人員完全分開。
  • 但是他畢竟還是類似黑箱子,有太多需要注意的地方。真的要上線,建議還是要透過 OpenAI 自己來開發。
  • 不過 LangChain 開發出來的架構,可以無痛轉換到其他 LLM 就是了。

  • 也有視覺化的工具類似: Flowise 可以讓拉框架的人,跟 Prompt 的人分開。修改 Prompt 甚至不需要重新 deploy

img

Flowise 提供一個 LangChain 視覺畫前端,可以透過拉框架快速測試架構跟 Prompt ,開發 LINE Bot 可以直接串 API 。 甚至修改 Prompt 可以做到不需要改 API Call ,也不需要重新 Deploy 。

先來準備一個快速導入 Heroku 的 Python LINE Bot 套件

這邊有一些選擇方式:

如果是從頭開啟的專案,幾件事情需要注意:

  • app.json

    • 主要敘述設定的 build packs ,這裡主要注意兩個項目:
    • “repository”: 記得填寫正確,如果你有 Clone 過去,記得改成你的。
    • 裡面有三個參數,請參考 README 即可,有一個比較雷的地方是。
      • LangChain 只支援系統參數 OPENAI_API_KEY 你設定成其他文字都會讀不到爆掉!
      • LangChain 只支援系統參數 OPENAI_API_KEY 你設定成其他文字都會讀不到爆掉!
      • LangChain 只支援系統參數 OPENAI_API_KEY 你設定成其他文字都會讀不到爆掉!
  • Profile:
    • 這個不用改,記得使用 web: uvicorn main:app --host=0.0.0.0 --port=${PORT:-5000}
    • 如果你主程式 main.py 有改名字的話,記得跟著改。
  • requirements.txt
    • 這個不用改,照抄過去就好。
  • runtime.txt
    • 設定 Heroku 運行 Python 的版本,這邊建議使用 3.10.11 比較穩定。 不建議使用最新版本 3.11 (聽社群說很雷)

以上,雖然 Heroku 是一個需要付費的公司。但是要改到 Render 應該也是沒問題。 不過能快速協助 deploy,又有穩定的伺服器很重要。

如果只是要接 OpenAI 在 LINE Bot 上的話

其實相對程式碼是比較簡單的,不過只有最簡單的串接功能。這邊稍微列出一下:

import os
import openai

from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())  # read local .env file
openai.api_key = os.environ['OPENAI_API_KEY']


# A demo code how to call OpenAI completion
def get_completion(prompt, model="gpt-3.5-turbo"):
    messages = [{"role": "user", "content": prompt}]
    response = openai.ChatCompletion.create(
        model=model,
        messages=messages,
        temperature=0,
    )
    return response.choices[0].message["content"]

之後再來把 get_completion(event.message.text) 就可以。

來打造第一個 LangChain + LINE Bot 的範例: 記憶力

常聽到有人詢問, LangChain 到底有什麼方便的地方。我們先透過以下的範例來說明吧,以下透過相關程式碼。可以快速打造一個具有「記憶力」的聊天機器人。並且可以把你之前問題記住。

在 OpenAI API 該怎麼打造?

最常需要開發的,就是類似功能。但是原本 OpenAI 狀況下,這樣開發有點複雜。

  • User: Hi, I am John.
    • AI: Hello, John.
  • User: what is 1+1?
    • AI: 2.
  • User: What is my name?
    • AI: I am sorry, you need to provide more detail.

由於 OpenAI 每次呼叫 API 給他,其實都是嶄新的聊天視窗。 想要做成像是 ChatGPT 這種方式可能就需要有「記憶力」,在 OpenAI 的 API 中其實需要使用 Chat Completion,而且需要,每一筆慢慢填進去:

{
  "model": "gpt-3.5-turbo",
  "messages": [
  {"role": "system", "content": "You are a helpful assistant."},
  {"role": "user", "content": "Hello!"}]
}

是不是很麻煩?

使用 LangChain 的 ConversationBufferWindowMemory

這裡有完整程式碼,我只列出重要的部分:

# Langchain 串接 OpenAI ,這裡 model 可以先選 gpt-3.5-turbo
llm = ChatOpenAI(temperature=0.9, model='gpt-3.5-turbo')

# 透過 ConversationBufferWindowMemory 快速打造一個具有「記憶力」的聊天機器人,可以記住至少五回。
# 通常來說 5 回還蠻夠的
memory = ConversationBufferWindowMemory(k=5)
conversation = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=False
)

@app.post("/callback")
async def handle_callback(request: Request):
    signature = request.headers['X-Line-Signature']

   ......
   
    for event in events:
        if not isinstance(event, MessageEvent):
            continue
        if not isinstance(event.message, TextMessage):
            continue

        # 將使用者傳來的訊息 event.message.text 當成輸入,等 LangChain 傳回結果。
        ret = conversation.predict(input=event.message.text)

LangChain + OpenAI Functions 的範例: 股價查詢

快速介紹什麼 OpenAI Functions Calling

可以參考“Function calling OpenAI 說明文件“ ,也可以參考我畫出的流程圖。

這裡給一張流程圖: PlantUML

image-20230615152527422

更多細節可以參考我的另外一篇文章「關於 OpenAI 新功能: Function Calling

先來打造 Functions Tools

LangChain 裡面把 OpenAI Function calling OpenAI“ 當成是一個 Tools (Agent) 來呼叫,可以參考 LangChain 官方的範例程式 。 快速來看一下:

# 很重要!!! 一定要使用這個 model ,不然會雷的超怪的!
# 很重要!!! 一定要使用這個 model ,不然會雷的超怪的!
# 很重要!!! 一定要使用這個 model ,不然會雷的超怪的!
model = ChatOpenAI(model="gpt-3.5-turbo-0613")

# MoveFileTool 是一個基本的 tool Agent,負責移動檔案的。
from langchain.tools import MoveFileTool, format_tool_to_openai_function

tools = [MoveFileTool()]

# 取得 MoveFileTool 所有的 functions 接口
functions = [format_tool_to_openai_function(t) for t in tools]

# 透過 OpenAI 提供的 Predict Message 來呼叫 functions
message = model.predict_messages(
    [HumanMessage(content="move file foo to bar")], functions=functions
)

那我們來打造抓取股票資訊的工具 stock_tools.py

import yfinance as yf

def get_stock_price(symbol):
    ticker = yf.Ticker(symbol)
    todays_data = ticker.history(period='1d')
    return round(todays_data['Close'][0], 2)

以上是一個簡單的抓取股價的 functions ,接下來是定義這個 BaseTools

class StockPriceCheckInput(BaseModel):
    """Input for Stock price check."""

    stockticker: str = Field(...,
                             description="Ticker symbol for stock or index")


class StockPriceTool(BaseTool):
    name = "get_stock_ticker_price"
    description = "Useful for when you need to find out the price of stock. You should input the stock ticker used on the yfinance API"

    def _run(self, stockticker: str):
        # print("i'm running")
        price_response = get_stock_price(stockticker)

        return price_response

    def _arun(self, stockticker: str):
        raise NotImplementedError("This tool does not support async")

    args_schema: Optional[Type[BaseModel]] = StockPriceCheckInput

其中兩個重要的就是:

  • name = “get_stock_ticker_price”:
    • 定義相關 func call 名稱。
  • description = “Useful for when you need to find out the price of stock. You should input the stock ticker used on the yfinance API”
    • 這個敘述其實很重要,因為 OpenAI 會真的去讀取你裡面的敘述。來學習該如何抓取使用者輸入的文字。所以這邊需要講的清楚一點,不能打錯也不能隨便打。

跟 LINE Bot 主要程式碼串接起來

可以參考 main.py ,這裡節錄重要的部分:

from stock_tool import StockPriceTool
from stock_tool import get_stock_price

# Langchain (you must use 0613 model to use OpenAI functions.)
# Langchain (you must use 0613 model to use OpenAI functions.)
# Langchain (you must use 0613 model to use OpenAI functions.)
model = ChatOpenAI(model="gpt-3.5-turbo-0613")

# Prepare openai.functions format.
tools = [StockPriceTool()]
functions = [format_tool_to_openai_function(t) for t in tools]

.....

    for event in events:
        if not isinstance(event, MessageEvent):
            continue
        if not isinstance(event.message, TextMessage):
            continue

        # Use OpenAI functions to parse user intent of his message text.
        hm = HumanMessage(content=event.message.text)
        ai_message = model.predict_messages([hm], functions=functions)

        # parse args parsing result from OpenAI.
        _args = json.loads(
            ai_message.additional_kwargs['function_call'].get('arguments'))

        # Call the 3rd party API get_stock_price to get stock price.
        tool_result = tools[0](_args)

首先先讓 LangChain 知道怎麼跟你的 tool 串接

tools = [StockPriceTool()]
functions = [format_tool_to_openai_function(t) for t in tools]

這裡就是讓 OpenAI 幫你把問題變成 API 的資訊 (假設問 Google 股價)

AIMessage(content='', additional_kwargs={'function_call': {'name': 'get_stock_ticker_price', 'arguments': '{\n "stockticker": "GOOGL"\n}'}}, example=False)

就會直接轉換成 GOOGL 這個股票代號。也因為知道是 get_stock_ticker_price 會對應到 tools[0]這邊其實可以支援多個 Functions,但是支援多個代表你要判斷要呼叫哪一個。

tool_result = tools[0](_args) # 就跟 get_stock_price(`GOOGL`)

這樣就可以完成了,如果多個 Tools 判斷會比較困難。 但是往往這才是 LangChain 可以帶給你方便的地方。

結語

近期完了不少的 LangChain 的相關範例,並且感受了透過 Flowise 來打造相關應用的方式。 覺得 LINE Bot 的開發將會幫助各位更容易貼近使用者。打造出一個「專一」「好用」的聊天機器人,並且讓 LINE 官方帳號來幫助你的生意邁向生成式 AI 的時代吧!!

[學習心得][Golang] 透過 Flex Simulator 有效率開發與除錯 FLEX Message 以 Go SDK 為範例

image-20230616182027588

前提

LINE Bot 的開發上, Flex Message 是一個強大又美觀的訊息顯示方式。並且可以發出多種類型訊息格式。本篇文章分享了,如何透過快速版本設計來寫出你想要的形式。 本篇文章將透過一個流程,循序漸進告訴你如何完成上面的範例訊息,並且如果開發 FLEX Message 上的問題時,也可以透過 FLEX Simulator 來幫你除錯。

開始了,設計苦手

任何的前端苦手(像是我),都對於如何找到一個好 Flex 的格式內容感覺很辛苦。這時候可以考慮使用 FLEX Simulator 先做你的起手式。

image-20230616173437478

(FLEX Message Simulator 提供給你所見即所得的編輯方式)

這裡也推驗”藉由 Flex Message Simulator 實現並發送測試用 Flex Message” 讓你對於 FLEX Message Simulator 有更深刻的了解。

透過 Showcase 挑選喜歡的樣板

image-20230616173711658

這裡可以挑選喜歡的格式,我們先挑選出我們喜歡的 “Local Search” 版面。

透過 FLEX Simulator 修改

image-20230616174006884

依照本次範例,我們不需要評比的星星。可以透過 FLEX Message Simulator 來直接移除(用剪刀) 。

image-20230616174145606

修改好之後,按下右上角的 </> View as JSON 來查看相關資訊。這些可以讓你知道如何開始編譯你的程式碼。

開始弄到 Golang 程式碼

如果沒有要把 FLEX 套著資料,整包 JSON 直接丟下去用

如果要開始把 FLEX Message 弄到你開發的聊天機器人的話,可以先建議以下方式: 其中 jsonString

contents, err := linebot.UnmarshalFlexMessageJSON([]byte(jsonString))
		if err != nil {
			return err
		}
		if _, err := app.bot.ReplyMessage(
			replyToken,
			linebot.NewFlexMessage("Flex message alt text", contents),
		).Do(); err != nil {
			return err
		}

其中 UnmarshalFlexMessageJSON 可以直接把 JSON 直接轉換成 Golang code 裡面的元件,你可以再去修改,或是直接丟到訊息就好。

直接一個個的刻出來

這裡貼上一段 code 可以直接看到,這是一個慢慢用內部定義的格式來打造 FLEX Message 。

  • 優點:
    • 很有彈性,甚至可以套用外部資料打造數個 FLEX Bubble Carousel 。
  • 缺點:
    • 就是需要一個個把格式填寫上去,不過使用 VS Code 的體驗,應該都可以快速選到才是。

發送 FLEX Message 失敗怎麼解決?

大概也是許多開發者的痛,就是當 FLEX Message 發送失敗的時候。到底要去哪裡查錯誤訊息? 經常會發現 Log 也沒那麼清楚怎麼辦?

flexMsg := linebot.NewFlexMessage(ALT_TRAVEL_FLEX, flexContainerObj)
if _, err := bot.ReplyMessage(event.ReplyToken, flexMsg, linebot.NewTextMessage(sumMsg)).Do(); err != nil {
				log.Print(err)

				if out, err := json.Marshal(flexContainerObj); err != nil {
					log.Println("Marshal error:", err)
				} else {
					log.Println("---\nflex\n---\n", string(out))
				}
			}

這段程式碼給一個範例,當你發送訊息錯誤的時候。這時候,就把你的錯誤的 FLEX Message JSOM 印出來。然後一樣複製下來後,到 FLEX Simulator 一樣打開 “View as JSON” 然後放上 JSON 並且套用。

image-20230616182235119

image-20230616182247356

這時候可以知道你的 JSON 哪裡有問題,也可以查到。 這時候可以透過發生錯誤的元件,來回頭查看你的程式碼。

結語

FLEX Message 真的是很強大,不論在桌面上,還是在手機端都可以顯示出漂亮的資料呈現。 但是透過程式來打造的話,又會因為格式過於自由變得有些迷惘。 希望這一篇文章可以讓每一個跟我一樣的前端(視覺)苦手,知道如何開發外,遇到問題也能夠快速解決。