Unity游戏开发实战:如何通过HTTP API接入大语言模型为NPC注入灵魂

📅 2026/8/24 6:36:55
Unity游戏开发实战:如何通过HTTP API接入大语言模型为NPC注入灵魂
1. 项目概述当游戏引擎遇见大语言模型最近在捣鼓一个Unity项目想给里面的NPC加点“灵魂”让它们能跟玩家进行更自然、更有深度的对话。直接写死对话树那太僵硬了。于是我把目光投向了当下火热的大语言模型。你可能听说过ChatGPT、文心一言或者通义千问它们背后的技术核心就是LLM。简单来说LLM就是一个经过海量文本训练的“超级大脑”能理解你的问题并生成连贯、有逻辑的回复。把LLM接入Unity听起来像是把两个不同次元的东西硬凑到一起——一个是处理图形渲染和物理模拟的游戏引擎另一个是处理自然语言的人工智能模型。但仔细一想这恰恰是游戏交互进化的一个绝佳方向。想象一下你游戏里的每一个NPC都拥有独特的性格和知识库能根据玩家的实时对话做出独一无二的反应或者你的游戏内置了一个智能引导助手能理解玩家用自然语言提出的任何问题。这不再是科幻电影的桥段而是我们今天就可以动手实现的技术融合。这个“新手版”教程的核心思路就是在Unity客户端和LLM服务端之间架起一座桥梁。我们不会在Unity里直接运行一个几十GB的模型那不现实。主流且高效的做法是让Unity作为一个“提问者”通过HTTP网络请求将玩家的输入发送到远端的LLM API服务API服务处理完请求后再将生成的文本回复传回Unity最后由Unity展示给玩家。这个过程本质上和你用手机App调用天气API没有区别只是传输的内容从天气数据变成了富有创造力的文本。所以无论你用的是Python、Java、Go还是任何其他语言搭建的LLM服务只要它提供了标准的HTTP API接口Unity都能通过相同的方式与之通信。本教程将聚焦于最通用、最核心的流程手把手带你完成从零到一的接入让你能快速在自己的项目中体验到AI对话的魅力。2. 核心思路与架构设计在开始写代码之前我们必须把整个通信流程想清楚。一个健壮的Unity-LLM集成架构关键在于职责分离和异步处理。Unity是实时渲染引擎它的主线程绝不能因为等待一个网络回复而卡住否则游戏就会掉帧甚至卡死。2.1 核心通信流程拆解整个交互可以分解为以下几个清晰步骤玩家输入玩家在游戏内的UI输入框比如一个聊天窗口中输入一段文字例如“你好你是谁”。Unity客户端组装请求Unity脚本捕获这段文本并按照目标LLM API的要求将其封装成一个结构化的HTTP请求。这通常是一个POST请求请求体Body是JSON格式里面包含了对话历史、系统提示词System Prompt、用户消息等。发起网络调用Unity使用UnityWebRequest或HttpClient在较新版本中向LLM服务的API地址发起异步网络请求。这一步必须是非阻塞的。LLM服务端处理请求到达远端的LLM服务器可能是你本地部署的也可能是云服务商如OpenAI、DeepSeek、智谱AI等提供的。服务器加载模型根据请求内容进行推理计算生成回复文本。接收并解析响应LLM服务器将生成的回复同样以JSON格式包装在HTTP响应中发回给Unity客户端。Unity在收到响应后需要解析这个JSON提取出我们需要的“回复文本”字段。Unity客户端展示最后Unity将提取到的文本显示在游戏UI上完成一次完整的对话轮次。这个过程形成了一个清晰的“请求-响应”闭环。对于Unity开发者来说我们主要关注第2、3、5步即如何正确地组装请求、稳定地发送请求、以及准确地解析响应。2.2 为什么选择API调用而非本地部署你可能会问为什么不把LLM模型直接放进Unity项目里运行这里有几个关键考量性能与资源当前主流的LLM模型动辄数GB甚至数十GB对内存和算力要求极高。在玩家五花八门的设备尤其是移动端上实时运行这样的模型几乎不可能会导致应用崩溃或极度卡顿。开发与更新成本模型部署、优化、更新是一项复杂的系统工程。通过调用API我们将这部分复杂性转移给了专业的服务提供商自己只需关注接口调用极大地降低了开发门槛和维护成本。灵活性API方式让你可以随时切换不同的模型提供商或者轻松升级到更新的模型版本而无需改动客户端的大量代码。因此对于绝大多数游戏和应用场景通过HTTP API进行远程调用是唯一务实且高效的选择。我们的架构设计也完全围绕这一点展开。2.3 关键组件与数据格式为了实现上述流程我们需要在Unity中准备几个核心组件一个管理类LLM Client这是大脑负责协调所有网络请求管理对话状态处理回调。它应该是一个单例Singleton方便在游戏各处访问。请求/响应数据类为了便于序列化对象转JSON和反序列化JSON转对象我们需要定义与API接口匹配的C#类。例如一个最简单的请求类可能包含一个messages列表而响应类包含一个choices列表里面才有我们需要的content。UI交互部分一个输入框InputField用于玩家输入一个文本显示区域Text或TextMeshPro用于展示AI回复一个发送按钮。数据格式是通信的基石。目前绝大多数LLM API都遵循OpenAI API的格式或与之类似。一个标准的请求体看起来像这样{ model: gpt-3.5-turbo, messages: [ {role: system, content: 你是一个乐于助人的游戏NPC。}, {role: user, content: 你好请问附近有什么可以冒险的地方} ], temperature: 0.7, max_tokens: 150 }我们需要在C#中定义对应的类结构以便使用JsonUtility或Newtonsoft.Json库来方便地生成和解析它。3. 实战准备Unity环境与API选择理论清楚了我们开始动手。第一步不是写代码而是把“战场”准备好。3.1 Unity项目设置创建一个新的Unity项目建议使用较新版本如2021 LTS或2022 LTS选择通用的3D或2D模板即可。这里没有特殊要求。接下来我们需要处理网络权限。因为我们的游戏需要访问外部网络API所以必须声明网络权限。对于PC、Mac、Linux平台通常无需额外设置。但对于移动端iOS/Android和部分WebGL平台这是必须步骤。Android在Player Settings Android Publishing Settings下勾选Internet Access为Require。iOS在Player Settings iOS Other Settings下确保Allow downloads over HTTP非HTTPS时和相关的后台模式配置正确。更安全的方式是始终使用HTTPS。WebGL由于浏览器的同源策略限制直接调用外部API可能会遇到CORS跨域资源共享错误。解决方案通常是在服务端设置CORS头部或者使用一个同域的后端作为代理。对于新手初期建议先在PC平台测试。3.2 选择你的LLM API服务这是关键一步。你需要一个能够提供HTTP API的LLM服务。主要有以下几类选择大型云服务商OpenAI行业标杆API稳定文档齐全。需要海外支付方式且可能面临网络访问问题。国内大厂如百度文心一言、阿里通义千问、智谱AIChatGLM、月之暗面Kimi、深度求索DeepSeek等。它们都提供了公开API访问速度快支付方便是大多数国内开发者的首选。选择建议优先考虑文档是否清晰、是否有免费的试用额度、以及API调用是否稳定。对于新手我强烈推荐从提供免费额度的国内服务开始比如DeepSeek或智谱AI这样可以零成本进行大量测试。本地部署高级选项如果你有性能不错的显卡如NVIDIA RTX 3060 12G以上可以尝试在本地电脑上使用Ollama、LM Studio或text-generation-webui等工具部署一个开源模型如Llama 3、Qwen、ChatGLM3等。这些工具通常会提供一个类似OpenAI格式的本地API地址通常是http://localhost:11434/v1/chat/completions。优点数据完全私有无网络延迟无使用费用。缺点部署有门槛模型性能取决于硬件且需要自己解决模型下载和运行环境问题。适合对隐私要求极高或希望深度定制的研究者。重要提示无论选择哪种服务第一件事就是去其官方网站注册账号并获取你的API Key。这个Key就像一把钥匙每次调用API时都需要放在请求头Header里用于身份验证和计费。请妥善保管不要把它硬编码在客户端代码中然后发布出去否则会被他人盗用导致财产损失。安全的方式是通过你自己的后端服务器中转但对于新手原型阶段我们可以先在Unity里测试发布前务必移除或改用安全方案。3.3 Unity中处理JSONUnity内置了JsonUtility类可以方便地在C#对象和JSON字符串之间转换。但它功能相对基础对于复杂的嵌套JSON或需要灵活处理的场景可能力不从心。更强大、更通用的选择是Newtonsoft.Json也称为Json.NET。我推荐使用Newtonsoft.Json因为它更健壮错误信息更友好社区支持也更好。你可以通过Unity的包管理器Package Manager从Git URL添加它https://github.com/jilleJr/Newtonsoft.Json-for-Unity.git#upm。安装后你就可以在代码中使用Newtonsoft.Json命名空间了。4. 核心代码实现构建Unity LLM客户端现在进入最核心的编码环节。我们将创建一个名为LLMClient的单例管理器。4.1 定义数据结构首先我们根据常见的API响应格式定义C#类。以OpenAI兼容格式为例using System; using System.Collections.Generic; // 表示单条消息 [Serializable] public class ChatMessage { public string role; // system, user, assistant public string content; } // 表示发送给API的请求体 [Serializable] public class ChatCompletionRequest { public string model gpt-3.5-turbo; // 模型名称根据你的服务修改 public ListChatMessage messages new ListChatMessage(); public float temperature 0.7f; // 创造性0-2越高越随机 public int max_tokens 500; // 生成的最大令牌数 // 还可以添加其他参数如 stream, top_p 等 } // 表示API返回的响应体中的单个选择 [Serializable] public class ChatChoice { public ChatMessage message; public int index; public string finish_reason; } // 表示完整的API响应体 [Serializable] public class ChatCompletionResponse { public string id; public string object; public long created; public ListChatChoice choices; public Usage usage; } [Serializable] public class Usage { public int prompt_tokens; public int completion_tokens; public int total_tokens; }这些类使用了[Serializable]特性使得JsonUtility可以处理它们。如果你使用Newtonsoft.Json则不需要这个特性但保留也无妨。4.2 实现LLM客户端管理器接下来是核心的LLMClient类。它将负责管理对话历史、发送请求和处理响应。using UnityEngine; using UnityEngine.Networking; using System.Collections; using System.Collections.Generic; using System.Text; using Newtonsoft.Json; // 如果使用了Newtonsoft.Json public class LLMClient : MonoBehaviour { public static LLMClient Instance; // 单例实例 [Header(API 配置)] public string apiUrl https://api.openai.com/v1/chat/completions; // 替换为你的API地址 public string apiKey YOUR_API_KEY_HERE; // 在此处填入你的API Key public string modelName gpt-3.5-turbo; [Header(对话设置)] public ListChatMessage conversationHistory new ListChatMessage(); public int maxHistoryLength 10; // 保留最近N轮对话防止上下文过长 [Header(系统提示词)] [TextArea(3, 10)] public string systemPrompt 你是一个生活在奇幻世界里的智慧老法师说话风格幽默而神秘喜欢用比喻。; private void Awake() { if (Instance null) { Instance this; DontDestroyOnLoad(gameObject); InitializeConversation(); } else { Destroy(gameObject); } } // 初始化对话加入系统提示 private void InitializeConversation() { conversationHistory.Clear(); if (!string.IsNullOrEmpty(systemPrompt)) { conversationHistory.Add(new ChatMessage { role system, content systemPrompt }); } } // 主要的调用方法传入用户消息并注册一个回调函数处理AI回复 public void SendMessageToLLM(string userMessage, System.Actionstring onResponseReceived, System.Actionstring onError null) { StartCoroutine(SendChatRequestCoroutine(userMessage, onResponseReceived, onError)); } private IEnumerator SendChatRequestCoroutine(string userMessage, System.Actionstring onResponseReceived, System.Actionstring onError) { // 1. 将用户消息加入历史 conversationHistory.Add(new ChatMessage { role user, content userMessage }); // 2. 组装请求数据 ChatCompletionRequest requestData new ChatCompletionRequest { model modelName, messages new ListChatMessage(conversationHistory), // 发送整个历史 temperature 0.8f, max_tokens 300 }; string jsonData JsonUtility.ToJson(requestData); // 如果使用Newtonsoft.Json: string jsonData JsonConvert.SerializeObject(requestData); byte[] bodyRaw Encoding.UTF8.GetBytes(jsonData); // 3. 创建并配置UnityWebRequest using (UnityWebRequest 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); // 关键添加认证头 // 4. 发送请求并等待 yield return request.SendWebRequest(); // 5. 处理响应 if (request.result UnityWebRequest.Result.Success) { string jsonResponse request.downloadHandler.text; Debug.Log(API Response: jsonResponse); // 反序列化响应 ChatCompletionResponse response JsonUtility.FromJsonChatCompletionResponse(jsonResponse); // 如果使用Newtonsoft.Json: ChatCompletionResponse response JsonConvert.DeserializeObjectChatCompletionResponse(jsonResponse); if (response.choices ! null response.choices.Count 0) { string aiReply response.choices[0].message.content; // 将AI回复加入历史 conversationHistory.Add(new ChatMessage { role assistant, content aiReply }); // 限制历史长度移除最早的非系统消息 TrimConversationHistory(); // 调用成功回调 onResponseReceived?.Invoke(aiReply); } else { string errorMsg API响应中没有有效的回复内容。; Debug.LogError(errorMsg); onError?.Invoke(errorMsg); } } else { string errorMsg $API请求失败: {request.error}\n响应码: {request.responseCode}\n响应体: {request.downloadHandler?.text}; Debug.LogError(errorMsg); onError?.Invoke(errorMsg); // 可选从历史中移除刚才添加的失败用户消息 if (conversationHistory.Count 0 conversationHistory[conversationHistory.Count - 1].role user) { conversationHistory.RemoveAt(conversationHistory.Count - 1); } } } } // 修剪对话历史防止上下文过长导致API调用失败或成本过高 private void TrimConversationHistory() { // 保留系统提示通常在索引0然后保留最新的N条用户/助手对话 int startIndex conversationHistory.FindIndex(m m.role system) 1; if (startIndex 0) startIndex 0; if (conversationHistory.Count - startIndex maxHistoryLength) { int itemsToRemove conversationHistory.Count - startIndex - maxHistoryLength; conversationHistory.RemoveRange(startIndex, itemsToRemove); } } // 清空对话历史除了系统提示 public void ClearConversationHistory() { ChatMessage systemMsg conversationHistory.Find(m m.role system); conversationHistory.Clear(); if (systemMsg ! null) { conversationHistory.Add(systemMsg); } } }这段代码是核心中的核心。它做了以下几件关键事情单例模式确保全局只有一个LLMClient实例。协程异步请求使用StartCoroutine和yield return确保网络请求不会阻塞游戏主线程。请求组装将对话历史包含系统提示、过往问答序列化成JSON。身份验证在请求头中正确添加Authorization: Bearer YOUR_API_KEY。响应处理与错误处理成功时解析回复并更新历史失败时记录详细错误信息并安全地回滚对话状态如移除未成功的用户消息。历史管理自动修剪过长的对话历史这是一个非常重要的优化和成本控制措施。4.3 创建简单的UI进行测试现在我们创建一个简单的UI来调用这个客户端。在场景中创建一个Canvas。在Canvas下创建一个InputField重命名为ChatInputField用于输入一个Button重命名为SendButton用于发送一个Text或TextMeshPro - Text重命名为ChatOutputText用于显示对话。创建一个新的C#脚本ChatUIController并挂载到Canvas或一个空物体上。using UnityEngine; using UnityEngine.UI; using TMPro; // 如果使用TextMeshPro public class ChatUIController : MonoBehaviour { public TMP_InputField chatInputField; // 或 InputField public Button sendButton; public TMP_Text chatOutputText; // 或 Text public ScrollRect scrollRect; private void Start() { sendButton.onClick.AddListener(OnSendButtonClicked); // 也可以监听输入框的回车键 chatInputField.onSubmit.AddListener((_) OnSendButtonClicked()); chatOutputText.text 系统对话已就绪。\n; } private void OnSendButtonClicked() { string userMessage chatInputField.text.Trim(); if (string.IsNullOrEmpty(userMessage)) { return; } // 显示用户消息 AppendToChatLog($你{userMessage}); chatInputField.text ; chatInputField.interactable false; sendButton.interactable false; // 调用LLM客户端 LLMClient.Instance.SendMessageToLLM( userMessage, (aiReply) { // 成功回调 AppendToChatLog($AI{aiReply}); chatInputField.interactable true; sendButton.interactable true; chatInputField.Select(); chatInputField.ActivateInputField(); }, (error) { // 失败回调 AppendToChatLog($colorred错误{error}/color); chatInputField.interactable true; sendButton.interactable true; chatInputField.Select(); chatInputField.ActivateInputField(); } ); } private void AppendToChatLog(string message) { chatOutputText.text message \n\n; // 强制滚动到底部 Canvas.ForceUpdateCanvases(); scrollRect.verticalNormalizedPosition 0f; } }在Unity编辑器中将对应的UI组件拖拽到ChatUIController脚本的公开字段上。运行游戏输入文字并点击发送你应该就能看到AI的回复了5. 参数调优与高级配置基础的对话跑通了但要让AI的表现符合你的游戏设定还需要调整一些“旋钮”。这些参数直接影响LLM的回复风格和质量。5.1 核心参数详解在ChatCompletionRequest类中我们已经看到了几个关键参数temperature温度0.0 ~ 2.0控制回复的随机性。值越低如0.1输出越确定、保守、一致。对于需要精确答案的场景如代码生成、事实问答很有用。值越高如0.9输出越随机、有创意、出人意料。适合写故事、生成角色对话。游戏应用给一个严肃的学者NPC可以设为0.3给一个疯癫的小丑NPC可以设为1.2。max_tokens最大令牌数限制AI单次回复的最大长度。1个token大约相当于0.75个英文单词或半个汉字。设置过小会导致回复被截断设置过大会浪费token增加成本并可能收到冗长的回复。如何设定根据UI显示区域的大小来估算。通常一段简短的NPC对话设置在150-300 tokens足够。如果需要生成长文本如任务描述可以设置到500-800。top_p核采样0.0 ~ 1.0另一种控制随机性的方法与temperature可以配合使用。它从概率质量最高的token中采样直到累积概率超过top_p。例如top_p0.9意味着模型只考虑概率累积和占前90%的token。通常建议要么调整temperature要么调整top_p不要两者都大幅度调整。一般保持top_p1.0默认即可。system提示词这是塑造AI角色行为的最重要工具。在对话历史的第一条消息中role设为systemcontent里详细描述你希望AI扮演的角色、背景、说话风格、知识范围和禁忌。示例“你是一名中世纪的铁匠性格粗犷但手艺精湛。你只知道关于锻造武器和盔甲的知识对魔法一窍不通。说话简短有力常用‘小子’、‘伙计’称呼顾客。绝对不要谈论政治或皇室秘闻。”技巧指令越具体AI的表现越可控。你可以把游戏的世界观、角色设定直接写进去。5.2 管理对话上下文LLM没有记忆它只基于你提供的上下文即messages列表来生成下一个回复。因此管理好这个列表至关重要。上下文长度限制所有LLM API都有一个最大上下文长度如4096、8192、16384 tokens。你发送的整个messages列表的总token数不能超过这个限制。我们的TrimConversationHistory方法这就是为了应对此限制。我们只保留最近的若干轮对话maxHistoryLength确保每次请求的token数不会超标。否则你会收到类似“maximum context length is X tokens”的400错误。更智能的修剪策略对于长对话简单的“保留最近N轮”可能会丢失关键早期信息比如系统提示中设定的角色性格。更高级的策略可以是1) 永远保留系统提示2) 优先保留用户最近的消息和AI对应的回复3) 如果还是太长可以尝试用AI总结之前的对话然后将总结作为一条新消息放入历史替换掉大量旧消息。但这实现起来更复杂。5.3 处理流式响应Streaming上面的代码使用的是非流式响应即等待AI完全生成所有文本后一次性返回给我们。这可能会导致较长的等待时间尤其是生成长文本时用户界面会卡住。流式响应则不同AI每生成一小段文本如一个词或一句话服务器就发送一段数据过来。这样客户端可以近乎实时地显示回复用户体验更好。实现流式响应需要在请求参数中设置stream: true。使用UnityWebRequest或HttpClient以流的方式读取响应体通常是Server-Sent Events格式。解析每一段数据块提取出增量文本并实时更新UI。这涉及到更复杂的网络数据处理和UI线程同步对于新手来说挑战较大。建议先实现基础的非流式版本待项目稳定后再考虑升级为流式。大多数LLM API都支持流式模式。6. 错误处理、调试与性能优化在实际开发中你会遇到各种问题。一套完善的错误处理和调试机制能帮你快速定位问题。6.1 常见API错误及排查当UnityWebRequest.result不是Success时你需要仔细检查request.error和request.downloadHandler.text。常见的HTTP错误码有400 Bad Request你的请求格式错了。检查JSON格式是否正确字段名是否拼写错误参数值是否在有效范围内如temperature是否为数字。错误信息通常会给出具体原因例如“the thinking_budget parameter must be a positive integer”或“this model‘s maximum context length is ... tokens”。401 UnauthorizedAPI Key错误或过期。请确认Key是否正确是否有空格以及是否有访问该API的权限。403 Forbidden权限不足。可能是Key没有对应模型的访问权限或者账号欠费。429 Too Many Requests请求频率超限。免费账号或低级别API套餐有每分钟/每天的调用次数限制。你需要加入请求间隔如用WaitForSeconds或升级套餐。500/502/503/504服务器内部错误、网关错误或超时。这通常是服务提供商那边的问题等待一段时间后重试即可。你可以实现一个简单的重试机制。实操心得在开发阶段务必在控制台打印出完整的错误响应体。很多错误信息如具体的参数错误都藏在里面只看HTTP状态码是找不到原因的。6.2 超时与重试机制网络是不稳定的。你需要为UnityWebRequest设置一个超时时间并实现重试逻辑。using UnityEngine.Networking; using System.Collections; public IEnumerator SendRequestWithRetry(string url, string jsonData, int maxRetries 2) { int retryCount 0; float timeoutSeconds 30f; // 设置超时时间 while (retryCount maxRetries) { using (UnityWebRequest request new UnityWebRequest(url, POST)) { // ... 配置request同上... request.timeout (int)timeoutSeconds; yield return request.SendWebRequest(); if (request.result UnityWebRequest.Result.Success) { // 处理成功... yield break; // 成功则退出循环 } else if (request.result UnityWebRequest.Result.ConnectionError || request.result UnityWebRequest.Result.ProtocolError) { Debug.LogWarning($请求失败第{retryCount 1}次重试。错误{request.error}); retryCount; if (retryCount maxRetries) { yield return new WaitForSeconds(2f * retryCount); // 等待时间递增 } else { // 重试次数用尽最终失败处理 Debug.LogError($请求最终失败{request.error}); // 触发错误回调... } } } } }6.3 性能优化要点对象池化频繁创建和销毁ChatMessage对象会产生GC垃圾回收压力。对于对话历史这种频繁增删的结构可以考虑使用对象池来复用对象。避免每帧调用确保SendMessageToLLM只在用户操作时触发不要放在Update循环里。关闭请求务必使用using语句包裹UnityWebRequest对象确保请求完成后相关资源被及时释放。压缩上下文如前所述有效管理对话历史长度是控制单次请求延迟和成本的最有效手段。可以尝试在历史过长时主动总结或丢弃一些不重要的早期对话。缓存常用回复对于一些固定、通用的问候语或简单问答如“你好”、“再见”可以不调用LLM直接在客户端缓存回复以提升响应速度和节省API调用次数。7. 安全部署与进阶方向当你的原型测试完毕准备集成到正式项目或发布时安全问题就变得至关重要。7.1 API Key的安全隐患与解决方案绝对不要将API Key硬编码在Unity的C#脚本中然后打包发布。因为Unity的C#代码很容易被反编译你的Key将暴露无遗。一旦泄露他人就可以用你的Key疯狂调用API导致巨额账单。安全的解决方案是使用一个后端服务器作为中转架构变更Unity客户端不再直接调用LLM服务商的API而是调用你自己搭建的后端服务器的一个接口。后端职责你的后端服务器可以用Python Flask、Node.js、C# ASP.NET Core等任何语言快速搭建接收来自Unity客户端的请求然后在服务器端加上你的API Key再去调用真正的LLM API。最后将结果返回给Unity。优势密钥安全API Key永远保存在你的服务器上客户端无法触及。请求管控你可以在服务器端实现频率限制、内容过滤、日志记录、成本监控等功能。统一入口方便未来切换LLM服务商只需修改后端代码客户端无需更新。对于新手可以先在本地用Python Flask快速搭建一个这样的代理服务这本身也是一个很好的学习项目。7.2 功能扩展思路基础对话实现后你可以探索更多有趣的方向多角色对话系统为不同的NPC维护不同的conversationHistory和systemPrompt实现角色间的差异化对话。结合游戏状态将游戏内的变量如玩家等级、任务进度、物品库存动态插入到系统提示或用户消息中让AI的回复能与游戏世界状态联动。例如“[玩家当前拥有‘黄金橡果’] 玩家问这个橡果有什么用”文本驱动游戏内容生成让AI根据玩家的输入动态生成任务描述、物品简介、甚至简单的剧情分支。你可以将AI生成的文本再通过Unity解析成游戏内可执行的数据结构。集成语音结合语音识别SDK如Unity的UnityEngine.Windows.Speech或第三方插件实现语音输入再结合语音合成服务将AI的文本回复转为语音播放打造沉浸式的语音交互NPC。使用Function Calling许多LLM支持“函数调用”功能。你可以定义一些游戏内可执行的动作如open_door,give_item让AI在回复时不仅生成文本还能返回一个结构化的函数调用请求。Unity客户端解析这个请求后再真正执行游戏内的逻辑。这能实现更强大的“对话即操作”体验。接入LLM为Unity应用打开了通往“智能”交互的大门。从今天这个简单的聊天窗口开始你可以逐步构建出拥有丰富灵魂的虚拟角色、动态生成的故事线以及前所未有的玩家体验。关键在于迈出第一步并理解其核心——它只是一个通过网络发送文本并接收文本的接口。剩下的就交给你的想象力了。