iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0

每天的專案會同步到 GitLab 上,可以前往 GitLab 查看,有興趣的朋友歡迎留言 or 來信討論,我的信箱是 nickchen1998@gmail.com

由於時間關係,本次專案不考慮系統架構,僅止於快速實作出站台功能。

今天我們要介紹的是問題及解答重構,並且把它串接近爬文流程當中。

為什麼需要重構?

在前面的章節有提到,過於冗長的文本在計算 embedding 時會比較不精準,且不利於查詢,尤其是患者在描述自己症狀的時候,常常會過於冗長,這時候就需要將問題及解答進行重構,讓它更加精簡,這樣在進行 embedding 時,就能夠更加精準地找到相似的問題及解答。

在本次的系統設計當中,我們主要會用使用者輸入的問題,去查出相近的問題,並且取得這個問題對應的醫生建議,然後將原始問題一併送交給 LLM 進行回答。

系統架構

這邊先快速介紹一下專案架構:

專案架構

  • crawler.py:爬蟲程式,用來爬取問題及解答。
  • llms.py:問題及解答重構程式,用來將問題及解答進行重構,後續的問答及計算向量也會放在這邊。

回答的重構

前面提到,我們會針對使用者的問題進行搜尋而不是回答,因此回答的重構目標主要是將內容進行精簡,盡可能減少冗言贅字,避免將參考資料送給 LLM 的時候會產生過多的雜訊。

根據上面的目標,讓我們看一下下面這個 function:

from langchain_core.prompts import ChatPromptTemplate


def get_refactor_answer(paragraph: str):
    prompt = ChatPromptTemplate.from_template(
        """
你是一個專業的醫生,下面是一篇醫生針對某個患者描述的情況的回應,請幫我使用繁體中文做重點整理,讓患者可以更清楚狀況。
請針對我給予的文章做回覆整理,不要使用文章以外的內容做回覆。
----
文章: {paragraph}
"""
    )
    chain = prompt | get_llm()
    return chain.invoke({"paragraph": paragraph}).content

可以看到我在 prompt 當中沒有做過多的限制,只有限制使用的語言以及不要使用文章以外的內容做回覆。

在程式碼當中可以看到一個 get_llm 的函式,這個主要是用來建立一個 LangChain 的物件,讓我們可以輕易的調用 OpenAI 來進行問答,可以參考下面這段程式碼:

from langchain_openai import ChatOpenAI
from env_settings import EnvSettings


def get_llm():
    env_settings = EnvSettings()
    return ChatOpenAI(
        api_key=env_settings.OPENAI_API_KEY,
        model_name="gpt-4o"
    )

讓我們看一下重構前後的內容對比:

  • before

    before_answer

  • after

    after_answer

可以看得出來在重構後的內容中,已經將冗言贅字去除,讓醫生的建議更佳精簡。

問題的重構

由於我們是要使用者輸入的問題去查找相似的問題,因此問題的重構也是非常重要的一環,讓我們看一下下面這個 function:

from langchain_core.prompts import ChatPromptTemplate


def get_refactor_question(paragraph: str):
    prompt = ChatPromptTemplate.from_template(
        """
你是一個要去診所進行看診的換診,下面是你的問題,請幫我是用繁體中文做重點整理,讓醫生可以更清楚你的症狀。
過程中請不要針對我的病況給予我任何建議,請幫我整理問題就好,並且不要使用文章以外的內容。
我希望可以把內容縮減在 100 字以內,並且使用簡答的方式整理成一句話,並且不要列點。
請直接給我回覆,不需要給予開頭或結尾。
----
文章: {paragraph}
"""
    )
    chain = prompt | get_llm()
    return chain.invoke({"paragraph": paragraph}).content

可以看到相比於回答的重構,問題的重構多了一些限制,例如不要使用文章以外的內容,並且要縮減在 100 字以內,並且使用簡答的方式整理成一句話,且不要列點。

我們馬上來看一下對比:

  • before

    before_question

  • after

    after_question

可以看到我們成功地將問題進行了重構,讓問題更加精簡,這樣在進行 embedding 的時候,就能夠更加精準地找到相似的問題。

串接爬文流程

前面有提到,由於時間的關係,不考慮執行時間、效率等其他因素,因此我們這邊直接將剛剛兩個 function 串接進爬文流程當中,讓我們看一下下面這段程式碼:

from llms import get_refactor_answer, get_refactor_question

...
data = dict(
        category=category,
        subject=subject,
        question=question,
        gender=gender,
        question_time=question_time,
        answer=answer,
        doctor_name=doctor_name,
        doctor_department=doctor_department,
        answer_time=answer_time,
        view_amount=view_amount,
        refactor_question=get_refactor_question(question),
        refactor_answer=get_refactor_answer(answer)
    )
...

我們直接在昨天的 data 這個區塊裡面加入兩個 key,而 value 的部分則是使用剛剛的兩個 function 進行轉換,這樣就完成了問題及解答的重構。

內容預告

今天我們完成了將問題及回覆的重構,明天我們要來把問題計算成向量,並且將所有的資料插入到 MongoDB 當中。


上一篇
Day 23 - 使用 Selenium 進行動態網頁資料擷取
下一篇
Day 25 - 計算向量 & 建立資料及索引
系列文
初探 Langchain 與 LLM:打造簡易問診機器人30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言