本文转载自 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.