共计 2238 个字符,预计需要花费 6 分钟才能阅读完成。
需求场景
最近在做一款需要 NPC 智能对话的 Unity 游戏,发现直接用预设对话太生硬。调研后决定接入 ChatGPT,但过程中遇到不少坑:API 调用不稳定、中文乱码、iOS 请求失败等。这里分享一套经过实战检验的解决方案。

架构设计
技术选型对比
- 直接调用 OpenAI API
- 优点:响应快,功能全,成本可控
-
缺点:需要处理 SSL 证书、ATS 策略等平台兼容问题
-
第三方中间件服务
- 优点:省去认证流程,自带负载均衡
- 缺点:额外费用,存在数据隐私风险
最终选择直接调用 API,因为游戏需要实时交互,且对话内容涉及核心玩法。
网络模块选择
- UnityWebRequest:全平台支持,可灵活设置 Header
- WebGL:需配置 CORS 代理,建议用反向 nginx
代码实现
API 请求封装(含完整错误处理)
// 密钥加密:使用 PlayerPrefs 保存加密后的 Key
IEnumerator SendChatRequest(string prompt) {var request = new UnityWebRequest("https://api.openai.com/v1/chat/completions", "POST");
byte[] bodyRaw = Encoding.UTF8.GetBytes(JsonUtility.ToJson(new {
model = "gpt-3.5-turbo",
messages = new[] { new { role = "user", content = prompt} }
}));
// 关键安全设置
request.uploadHandler = new UploadHandlerRaw(bodyRaw);
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
request.SetRequestHeader("Authorization", "Bearer" + DecryptAPIKey());
// 超时控制
var asyncOp = request.SendWebRequest();
float timeout = 10f;
while (!asyncOp.isDone && timeout > 0) {
timeout -= Time.deltaTime;
yield return null;
}
if (request.result == UnityWebRequest.Result.Success) {
// 流式解析 JSON 避免卡顿
var json = JsonUtility.FromJson<ChatResponse>(request.downloadHandler.text);
OnMessageReceived(json.choices[0].message.content);
} else {Debug.LogError($"API Error: {request.error}");
}
}
对话历史管理
class DialogueHistory {private List<Message> messages = new List<Message>();
private const int MAX_TOKENS = 4096;
public void AddMessage(string role, string content) {
// 自动清理最早对话保持 token 不超限
while (CalculateTotalTokens() > MAX_TOKENS * 0.9f) {messages.RemoveAt(0);
}
messages.Add(new Message(role, content));
}
private int CalculateTotalTokens() {
// 简易估算:1 汉字≈2token
return messages.Sum(m => m.content.Length) * 2;
}
}
压力测试
网络延迟测试(100 次请求平均值)
| 网络环境 | 平均延迟 | 成功率 |
|---|---|---|
| WiFi | 1.2s | 98% |
| 4G | 2.8s | 92% |
内存占用分析
- 单次请求内存峰值:3.7MB
- 持续对话 30 分钟 GC 次数:2 次(建议对象池管理 JSON 解析)
常见问题
iOS ATS 策略报错
在 Info.plist 添加:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
中文乱码解决方案
-
请求前统一编码:
string encodedPrompt = WWW.EscapeURL(prompt); -
响应处理时指定编码:
Encoding.UTF8.GetString(request.downloadHandler.data);
费用控制技巧
- 客户端缓存机制:相同问题直接返回缓存
- 速率限制:
private float lastRequestTime; public bool CanMakeRequest {get { return Time.time - lastRequestTime > 1.5f;} }
进阶方向
- 行为树整合 :将 ChatGPT 输出转换为 Behavior Designer 的节点参数
- 情感分析 :解析 API 返回的 JSON 中的情感倾向值
- 本地缓存 :使用 SQLite 存储高频对话模板
实际项目中,我们把这套系统用在了游戏任务引导 NPC 上,玩家反馈对话自然度提升明显。关键是要处理好异步响应与游戏状态的同步问题,建议用 Observer 模式管理对话状态。
正文完
