跳到主要內容

探索 進階 ChatBot 結合 DeepSeek

 前言

透過這篇文章,在先前 簡單聊天機器人 文章中開發的聊天機器人。雖然後續可以新增或調整對話內容,但還是固定對話規則型回覆。對應無法匹配的意圖。讓我們結合 LLM ,使聊天更靈活自然,語氣更像真人 。另外,考量效能成本(LLM 只在必要時呼叫),不是所有對話都丟給 LLM。


DeepSeek方案 (需要申請 API Key)

相關成本費用參看: https://api-docs.deepseek.com/zh-cn/quick_start/pricing/


安裝相關模型

pip install python-dotenv

python-dotenv 是一個專門用於從 .env 檔案載入環境變數到 Python 程式中的函式庫


實作代碼


環境變數(.env

DEEPSEEK_API_KEY=你的api_key


deepseek_client.py

import os

import requests

from dotenv import load_dotenv


load_dotenv()


DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")



def call_deepseek(user_input: str) -> str:


    if not DEEPSEEK_API_KEY:

        return "API key 未設定"


    url = "https://api.deepseek.com/chat/completions"

    headers = {

    "Authorization": f"Bearer {DEEPSEEK_API_KEY}",

    "Content-Type": "application/json"

    }


    data = {

        "model": "deepseek-chat",

        "messages": [{"role": "user", "content": user_input}],

        "max_tokens": 200, # 日常聊天:200-300 tokens

        "temperature": 0.7, # 控制AI輸出的隨機性和創造性,中溫(0.5-0.7)

        "stream": False # 一次性返回完整回复

    }


    try:

        response = requests.post(url, headers=headers, json=data, timeout=30)


        if response.status_code == 200:

            result = response.json()

            reply = result["choices"][0]["message"]["content"]

            return reply

        elif response.status_code == 402:

            return "AI 服務額度不足" # 可能要去充值

        elif response.status_code == 429:

            return "請求過於頻繁,請稍後再試"

        elif response.status_code == 401:

            return "API key 無效"

        else:

            print(f"[API Error] {response.status_code}: {response.text}")

            return f"AI 錯誤暫時無法使用,錯誤代碼:{response.status_code}"


    except requests.exceptions.Timeout:

        return "請求超時"

    except requests.exceptions.ConnectionError:

        return "網路連線失敗,請檢查網路"

    except Exception as e:

        print(f"[ERROR] 請求異常: {e}")

        return "AI 錯誤暫時無法使用"



註: 參考

簡答、摘要: 50-100 tokens
普通對話: 200-300 tokens


temperature:
0.0 完全確定,每次都一樣
0.1-0.3 非常穩定,稍有變化
0.5-0.7 平衡,自然對話 聊天機器人
0.8-1.0 有創意,多樣性



simple_chatbot.py

import os

import requests

import spacy

import json

import random

from deepseek_client import call_deepseek

from dotenv import load_dotenv


load_dotenv()


# 取得 目前 Python 檔案所在的資料夾路徑, 相對路徑

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

RESPONSES_PATH = os.path.join(BASE_DIR, "responses.json")


# 載入中文模型

nlp = spacy.load("zh_core_web_sm")


# 讀取回覆資料

with open(RESPONSES_PATH, "r", encoding="utf-8") as f:

    responses = json.load(f)


def get_response(user_input):

    return random.choice(responses.get(user_input, responses["default"]))


def respond_to_user(user_input):

    doc = nlp(user_input)

    text = user_input.lower()


    if any(word in text for word in ["你好", "哈囉", "嗨", "hello", "hi"]):

        return get_response("greeting")


    if any(word in text for word in ["你好吗", "你好嗎", "過得"]):

        return get_response("how_are_you")


    if any(word in text for word in ["你是誰", "你的名字"]):

        return get_response("name")


    if any(word in text for word in ["幫助", "能做什麼"]):

        return get_response("help")


    if any(word in text for word in ["笑話", "講個笑話", "逗我笑", "好笑的"]):

        return get_response("jokes")


    if any(word in text for word in ["謝謝", "感謝"]):

        return get_response("thanks")


    if any(word in text for word in ["再見", "掰掰", "bye"]):

        return get_response("goodbye")



    # 使用 NER(人名/地點)

    """for ent in doc.ents:

        if ent.label_ == "PERSON":

            return f"你提到了 {ent.text},他是你的朋友嗎?"

        if ent.label_ == "GPE":

            return f"{ent.text} 聽起來是個地方"

    """

    # ---------- LLM fallback ----------

    return call_deepseek(user_input)


  

if __name__ == "__main__":

    print("ChatBot 已啟動,輸入「bye」結束對話")


    while True:

        user_input = input("你:")

        if not user_input.strip():

            continue

        response = respond_to_user(user_input)

        print("ChatBot:", response)

        if user_input in ["bye","再見", "掰掰"]:

            break


測試




留言

這個網誌中的熱門文章

初探 Vue 呼叫 API 出現 CORS 跨來源資源共享 問題原因

提要:   在 {初探Vue 與 Spring boot 的對話} 專案 ,前端 Vue 應用程式 串接 後端 API 伺服器 ,axios 呼叫 API 時出現以下,”無法取得回應內容 (No 'Access-Control-Allow-Origin' header is present on the requested resource):” 錯誤訊息,根據查找相關資料 ,出現以下原因。 瀏覽器開發工具 錯誤訊息 畫面 錯誤原因: “ Access to XMLHttpRequest at ” from origin ‘http://localhost:8080’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource” 瀏覽器為了安全考量,實施了同源政策。 當您的前端應用程式 (http://localhost:8080) 嘗試呼叫一個不同來源 (不同協議、不同域名或不同埠號) 的 API 伺服器 (http://localhost:8088) 時,瀏覽器會主動阻止這個請求,除非伺服器明確地允許這個跨來源的存取。 同源政策限制(Same-Origin Policy): 同源政策限制了程式碼和不同網域資源間的互動,同源是指兩份網頁具備相同協定、埠號(如果有指定)以及主機位置 範例: 表列哪些 URL 與 URL http://www.example.com/api/p1 屬於同源: URL                                                   | 結果   | 原因 --------------------------------------------------------------------- http://www.example.com/api/p2     |...

初探 Vue 與 Spring boot 的對話之Frontend (Vue-Frontend)

  Front-end Vue 使用 REST API 建立 Vite 專案 可參考 { Vue 3 初探}  文章 danny@Danny-Yu projects % npm create vite@latest Need to install the following packages: create-vite@8.2.0 Ok to proceed? (y) y > npx > "create-vite" │ ◇   Project name: │   vue-frontend │ ◇   Select a framework: │   Vue │ ◇   Select a variant: │   TypeScript │ ◇   Use rolldown-vite (Experimental)?: │   No │ ◇   Install with npm and start now? │   Yes │ ◇   Scaffolding project in /Users/danny/Desktop/projects/vue-frontend... │ ◇   Installing dependencies with npm... added 47 packages, and audited 48 packages in 27s 6 packages are looking for funding   run `npm fund` for details found 0 vulnerabilities │ ◇   Starting dev server... > vue-frontend@0.0.0 dev > vite   VITE v7.2.4   ready in 411 ms   ➜   Local:   http://localhost:5173/   ➜   Network: use --host to expose   ➜   press h + enter to show...

初探 Spring 中的循環依賴

原因: 當兩個或多個 bean 直接或間接地相互依賴時, 就會出現 Circular Dependency (循環依賴) 如: Bean A -> Bean B -> Bean A import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class BeanA {          @Autowired     private BeanB beanB;     public String sayHi() {         return "Hi! 我是 Class A.";     } } import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class BeanB {          @Autowired     private BeanA beanA;     public String sayHi() {         return "Hi! 我是 Class B.";     } } 編譯時不會出現問題 danny@Danny-Yu demo % mvn clean install -Dmaven.test.skip=true                           ... ... [INFO] Installing /Users/danny/Desktop/projects/demo/target/dem...