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