本文轉載自 Unity 中文社區“月度全能戰士”菜菜丸 Penny Lu,點擊閱讀原文,可以查看菜菜丸在 Unity 中文社區的個人主頁,閱讀博主分享的更多 Unity 學習心得、技術干貨。
DeepSeek 的推出再度掀起了一波 AI 熱潮,相信大家都很期待將它與自己的項目相結合。本教程就將帶大家了解如何在 Unity 中接入 DeepSeek 的強大功能,通過簡單設置,實現 AI 對話功能。
DeepSeek 簡介
DeepSeek 是杭州深度求索人工智能基礎技術研究有限公司推出的一款大語言模型。2025 年 1 月 20 日,DeepSeek-R1 正式上線,和當前市面上的主流 AI 相比,它在僅有極少標注數據的情況下,極大提升了模型推理能力。在數學、代碼、自然語言推理等任務上,性能比肩 OpenAI o1 正式版。作為一款開源國產 AI 模型,它兼具普惠性和優越性能,非常適合大眾開發者。我們也可以在 Unity 中調用它的強大功能,接下來將用一個簡單例子介紹 DeepSeek 的接入和使用。
文檔
要了解如何編寫接入 DeepSeek 的代碼和設置相關參數,首先要來學習它的文檔。DeepSeek 的官方 API 文檔地址是:
https://api-docs.deepseek.com/zh-cn/
我們希望使用它的對話 API,文檔中給出了一些示例:
文檔沒有提供 C# 腳本示例,不過它提供了重要參數的信息,之后我們可以讓 AI 協助補全腳本。
在“對話補全”(https://api-docs.deepseek.com/zh-cn/api/create-chat-completion)中,提供了更詳細的參數含義和示例。
重要準備
(1) API Key
要在 Unity 中調用 DeepSeek,首先需要申請一個 API Key。申請地址為:
https://platform.deepseek.com/api_keys
注意:成功申請 Key 后,要在本地妥善保存。DeepSeek 后臺只能查看 Key 的列表和 token 余額等信息,完整的 Key 只會在申請成功后顯示一次。
(2)API 請求地址
我們希望使用 DeepSeek 的對話補全功能,它的 API 請求地址是:
https://api.deepseek.com/v1/chat/completions
(3)token
每個 DeepSeek 賬號有官方贈送的 10 元余額,可以用它來兌換 token。
token 是模型用來表示自然語言文本的基本單位,也是我們的計費單元,可以直觀的理解為“字”或“詞”;通常 1 個中文詞語、1 個英文單詞、1 個數字或 1 個符號計為 1 個 token。
一般情況下模型中 token 和字數的換算比例大致如下:
1 個英文字符 ≈ 0.3 個 token。
1 個中文字符 ≈ 0.6 個 token。
DeepSeek 目前的收費標準如下:
建議大家根據自己的需求來估算消耗的 token 和費用,在控制臺可以查看余額:
https://platform.deepseek.com/
模型與 UI
示例中,我們使用 Unity-Chan 模型作為對話角色,該模型可以從 Unity 資源商店中免費下載。
同時,還需要準備簡單的 UI,如圖:
下方的提問框是用 InputField 組件制作的,右上方的回答框是用 ScrollView 組件搭配 Text 組件制作的。為了方便顯示更多內容,要將 ScrollView 的窗口做大一些。美觀起見,隱藏了滾動條。
腳本與參數設置
我嘗試了用 DeepSeek 來生成相關腳本,最初生成的腳本有可能報錯,這時就要根據報錯內容讓 AI 來進行修改,要求它嚴格遵循官方文檔來編寫。
首先是對話管理器腳本:
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
using System.Collections.Generic;
public class DeepSeekDialogueManager : MonoBehaviour
{
// API配置
[Header("API Settings")]
[SerializeField] private string apiKey = "在此處填入你申請的API密鑰";// DeepSeek API密鑰
[SerializeField] private string modelName = "deepseek-chat";// 使用的模型名稱
[SerializeField] private string apiUrl = "https://api.deepseek.com/v1/chat/completions";// API請求地址
// 對話參數
[Header("Dialogue Settings")]
[Range(0, 2)] public float temperature = 0.7f;// 控制生成文本的隨機性(0-2,值越高越隨機)
[Range(1, 1000)] public int maxTokens = 150;// 生成的最大令牌數(控制回復長度)
// 角色設定
[System.Serializable]
public class NPCCharacter
{
public string name;
[TextArea(3, 10)]
public string personalityPrompt = "你是虛擬人物Unity-Chan,是個性格活潑,聰明可愛的女生。擅長Unity和C#編程知識。";// 角色設定提示詞
}
[SerializeField] public NPCCharacter npcCharacter;
// 回調委托,用于異步處理API響應
public delegate void DialogueCallback(string response, bool isSuccess);
///
/// 發送對話請求
///
/// 玩家的輸入內容
/// 回調函數,用于處理API響應
public void SendDialogueRequest(string userMessage, DialogueCallback callback)
{
StartCoroutine(ProcessDialogueRequest(userMessage, callback));
}
///
/// 處理對話請求的協程
///
/// 玩家的輸入內容
/// 回調函數,用于處理API響應
private IEnumerator ProcessDialogueRequest(string userInput, DialogueCallback callback)
{
// 構建消息列表,包含系統提示和用戶輸入
List messages = new List
{
new Message { role = "system", content = npcCharacter.personalityPrompt },// 系統角色設定
new Message { role = "user", content = userInput }// 用戶輸入
};
// 構建請求體
ChatRequest requestBody = new ChatRequest
{
model = modelName,// 模型名稱
messages = messages,// 消息列表
temperature = temperature,// 溫度參數
max_tokens = maxTokens// 最大令牌數
};
string jsonBody = JsonUtility.ToJson(requestBody);
Debug.Log("Sending JSON: " + jsonBody); // 調試用,打印發送的JSON數據
UnityWebRequest request = CreateWebRequest(jsonBody);
yield return request.SendWebRequest();
if (IsRequestError(request))
{
Debug.LogError($"API Error: {request.responseCode}\n{request.downloadHandler.text}");
callback?.Invoke(null, false);
yield break;
}
DeepSeekResponse response = ParseResponse(request.downloadHandler.text);
if (response != null && response.choices.Length > 0)
{
string npcReply = response.choices[0].message.content;
callback?.Invoke(npcReply, true);
}
else
{
callback?.Invoke(name + "(陷入沉默)", false);
}
}
///
/// 創建UnityWebRequest對象
///
/// 請求體的JSON字符串
/// 配置好的UnityWebRequest對象
private UnityWebRequest CreateWebRequest(string jsonBody)
{
byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(jsonBody);
var request = new UnityWebRequest(apiUrl, "POST");
request.uploadHandler = new UploadHandlerRaw(bodyRaw);// 設置上傳處理器
request.downloadHandler = new DownloadHandlerBuffer();// 設置下載處理器
request.SetRequestHeader("Content-Type", "application/json");// 設置請求頭
request.SetRequestHeader("Authorization", $"Bearer {apiKey}");// 設置認證頭
request.SetRequestHeader("Accept", "application/json");// 設置接受類型
return request;
}
///
/// 檢查請求是否出錯
///
/// UnityWebRequest對象
/// 如果請求出錯返回true,否則返回false
private bool IsRequestError(UnityWebRequest request)
{
return request.result == UnityWebRequest.Result.ConnectionError ||
request.result == UnityWebRequest.Result.ProtocolError ||
request.result == UnityWebRequest.Result.DataProcessingError;
}
///
/// 解析API響應
///
/// API響應的JSON字符串
/// 解析后的DeepSeekResponse對象
private DeepSeekResponse ParseResponse(string jsonResponse)
{
try
{
return JsonUtility.FromJson (jsonResponse);
}
catch (System.Exception e)
{
Debug.LogError($"JSON解析失敗: {e.Message}\n響應內容:{jsonResponse}");
return null;
}
}
// 可序列化數據結構
[System.Serializable]
private class ChatRequest
{
public string model;// 模型名稱
public List messages; // 消息列表
public float temperature;// 溫度參數
public int max_tokens;// 最大令牌數
}
[System.Serializable]
public class Message
{
public string role;// 角色(system/user/assistant)
public string content;// 消息內容
}
[System.Serializable]
private class DeepSeekResponse
{
public Choice[] choices;// 生成的選擇列表
}
[System.Serializable]
private class Choice
{
public Message message;// 生成的消息
}
}
將該腳本掛在場景中的任何一個物體(如主攝像機)上,并給相關參數賦值。
API 設置
API Key:你申請的 API 密鑰
Model Name:希望使用的模型。一般情況下用 deepseek-chat 即可,如需深度推理,可使用 deepseek-reasoner。
API Url:
https://api.deepseek.com/v1/chat/completions
對話設置
Temperature:采樣溫度,介于 0 和 2 之間。更高的值,如 0.8,會使輸出更隨機,而更低的值,如 0.2,會使其更加集中和確定。可參考官方文檔的推薦( https://api-docs.deepseek.com/zh-cn/quick_start/parameter_settings )進行設置,本例中設為 0.7。
Max Tokens:介于 1 到 8192 間的整數,限制一次請求中模型生成 completion 的最大 token 數。輸入 token 和輸出 token 的總長度受模型的上下文長度的限制。本例中設為 150。
NPC Character
Name:角色姓名,本 例中設為 “Unity-Chan”。
Personality Prompt:性格描述。本例中設為“你是虛擬人物 Unity-Chan,一個性格活潑,聰明可愛的女生,擅長 Unity 和 C# 編程知識。”
第二個腳本是角色互動腳本,它用來顯示 AI 生成的回復。
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
public class NPCInteraction : MonoBehaviour
{
//引用和配置
[Header("References")]
[SerializeField] private DeepSeekDialogueManager dialogueManager;//對話管理器
[SerializeField] private InputField inputField;//玩家問題輸入框
[SerializeField] private Text dialogueText;//角色回復的文本內容
private string characterName;
[Header("Settings")]
[SerializeField] private float typingSpeed = 0.05f; // 打字機效果的字符顯示速度
void Start()
{
characterName = dialogueManager.npcCharacter.name;//角色姓名賦值
//輸入框提交后執行的回調函數
inputField.onSubmit.AddListener((text) =>
{
dialogueManager.SendDialogueRequest(text, HandleAIResponse);//發送對話請求到DeepSeek AI
});
}
///
/// 處理AI的響應
///
/// AI的回復內容
/// 請求是否成功
private void HandleAIResponse(string response, bool success)
{
StartCoroutine(TypewriterEffect(success ? characterName +":" + response : characterName +":(通訊中斷)"));//啟動打字機效果協程
}
///
/// 打字機效果協程
///
/// 角色的回復內容
///
private IEnumerator TypewriterEffect(string text)
{
string currentText = "";//當前顯示的文本
foreach (char c in text)//遍歷每個字符
{
currentText += c;//添加字符到當前文本
dialogueText.text = currentText;//更新顯示文本
yield return new WaitForSeconds(typingSpeed);//等待一定時間
}
}
}
將這個腳本掛在角色模型上,并給參數賦值。
Reference
Dialogue Manager:拖入掛載了對話控制器的物體。
Input Field:拖入提問對話框對應的 InputField 控件。
Dialogue Text:拖入回復對話框對應的 Text 控件。
Settings
Typing Speed:打字機效果的字符顯示速度。
Demo 視頻
Unity 中文社區持續征集內容投稿,歡迎與 Unity 官方分享你的技術筆記、項目 demo、行業經驗、有趣案例,加入社區建設,繁榮內容生態,帶領百萬 Unity 中文開發者一同學習。
投稿方式:
方式一:在 Unity 中文社區首頁(https://developer.unity.cn/)創建個人賬號,點擊【寫文章】,發表文章;
方式二:聯系郵箱 learn-cn@unity.cn , 投稿技術內容。
Unity 官方微信
第一時間了解Unity引擎動向,學習進階開發技能
每一個“點贊”、“在看”,都是我們前進的動力
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.