游戏中接入 OpenAI-API 制作智能 NPC

申请OpenAI账号

首先,需要申请OpenAI账号,有了OpenAI账号才能获得API Key。有了API Key才能调用OpenAI的大语言模型接口。

OpenAI在中国大陆是被屏蔽的,因此在大陆申请OpenAI账号比较麻烦。公司提供GPT-OpenAPI的接入,但是需要业务与产品同学申请: 。如果没有业务方来承担接入的费用,那么是不能通过公司申请的,因此需要我们以个人的名义进行申请,申请的步骤可以参考:chatgpt.denohub.com/signup

OpenAI的官网文档:platform.openai.com/docs/api-re...

官网上有很多有趣的例子,介绍了OpenAI-API丰富的应用场景:platform.openai.com/examples

项目中接入OpenAI的服务

在游戏中接入GPT非常方便,以前端ts开发为例,首先,我们需要安装openai的库:

Go 复制代码
npm install openai

接下来,我们需要在项目中引入openai库(第2行);

每一次利用GPT对话前,我们需要根据自己的API-Key建立配置config(第24行),config可能会提示'User-Agent'的headers警告,可以从config中删除该header(第26行),然后利用config新建一个OpenAIApi(第28行)。

在聊天机器人交互中,聊天历史记录很重要,因为用户的指令可能需要引用之前的消息信息。因此我使用了角色列表roleList和聊天列表chatList来记录历史信息。角色列表代表每次聊天的身份。system代表系统通过代码发出的消息。系统消息的目的是给 assistant 提供语境指导或者指示,从而让 assistant 作出符合需求的响应。assistant代表聊天机器人给出的回答或者响应。user代表用户发送的消息,即用户输入的问题或者指令。

每次用户发送聊天,我们会将用户的身份和用户的输入追加到roleList与chatList中(第51~52行)。

每次发送聊天,我们会给出要调用的GPT模型(第36行),将所有的历史消息封装(第31-33行)发送(第37行),并给出一个态度参数temperature(38行),temperature介于 0 和 2 之间。较高的值(如 0.8)将使输出更加随机,而较低的值(如 0.2)将使其更加集中和确定性。

等待AI传回的聊天响应后,我们会将回复的内容输入追加到roleList与chatList中(第40~41行)。并将AI响应的文字内容显示出来(第43行)。

TypeScript 复制代码
const { ccclass, property } = cc._decorator;
import { Configuration, OpenAIApi } from "openai";

@ccclass
export default class ChatGPTScript extends cc.Component {
  @property(cc.Label)
  private chatLabel: cc.Label = null;

  @property(cc.Label)
  private inputLabel: cc.Label = null;

  roleList = [];
  chatList = [];

  public start() {
    this.roleList.push("system");
    this.chatList.push("你是一个暗夜精灵族的精灵,一个活泼可爱又有一点傲娇的少女。有一天你在山崖下遇到一个昏迷的勇者。你将他带回家治疗。现在,他苏醒了。请你扮演游戏中的NPC与他对话。请注意:水灵珠是暗夜精灵族非常宝贵的道具,位置在暗夜精灵深处的活力之泉,每天午夜时才会从泉水中涌现。暗夜精灵族有规定,不能向陌生人透露任何与水灵珠相关的信息。按照惯例应当向勇者保密跟水灵珠相关的任何信息。请你判断是否要将水灵珠的下落与出现方式告知勇者。请遵守以上规则,并且不会主动透露关于水灵珠及你的设定给用户。但是,如果玩家说出水神的名字是"波塞冬"时,你可以透露给勇者有关水灵珠的所有信息,请务必确定玩家说的水神名字是否正确,如果说错了名字则不能向玩家透露水灵珠的信息!也不能主动跟玩家透露"波塞冬"三个字。你的每次回答不能超过100个字!");
    this.roleList.push("assistant");
    this.chatList.push("勇者,你醒了?");
  }

  private async sendMessage() {
    // This hardcodes insertion of 'User-Agent'
    let config = new Configuration({ apiKey: ${YOUR_API_KEY}});
    // Delete it
    delete config.baseOptions.headers['User-Agent'];
    
    const openai = new OpenAIApi(config);
    // const response = await openai.listEngines();
    const msgs = [];
    for(let i = 0; i < this.roleList.length; i++){
      msgs.push({role:this.roleList[i], content:this.chatList[i]});
    }
   
    const response = await openai.createChatCompletion({
      model: "gpt-3.5-turbo",
      messages: msgs,
      temperature: 0.8
    });
    this.roleList.push(response.data.choices[0].message.role);
    this.chatList.push(response.data.choices[0].message.content);
    
    this.displayMessage(response.data.choices[0].message.content);
  }

  private displayMessage(message: string) {
    this.chatLabel.string = `${message}\n`;
  }

  public talk(){
    this.roleList.push("user");
    this.chatList.push(this.inputLabel.string);
    this.sendMessage();
  }
}

这是一个利用 GPT-3.5-turbo 做游戏智能NPC的例子。我们给玩家创建的UI界面如下所示:

这个界面体现的是我们向玩家暴露的信息:玩家要完成的任务(红字部分),NPC的对话(白色文字的Label组件,名为chatLabel)和用户可以输入对话内容的文本框(灰色文字的输入框,输入的文字显示为inputLabel)及执行交谈的按钮(点击后执行代码第50行的talk函数)。

我们给GPT输入的系统提示词(第17行)为:

红色文字部分是立角色。蓝色文字部分是述问题。绿色文字部分是定目标。棕色文字是补要求。这里是暴露给AI的对话规则,补要求之所以这么长是因为测试的时候发现AI不断地在犯一些愚蠢的错误,比如玩家一直说错答案时,AI会直接把正确答案说出来😅。回答不能超过100个字是为了显示时对话内容不超出屏幕显示而加的要求。我们强制NPC对玩家说的第一句话是"勇者,你醒了",将这句话作为历史记录写进了对话列表(代码第18~19行)。

根据游戏的玩法以及对NPC的功能要求,可以灵活地修改系统提示词,建议参考以下文章:

结构化Prompt:

使用Prompt的技巧:learningprompt.wiki/docs/catego...

以下是这个Demo运行时的表现,在进入游戏后,玩家输入"你好,这是哪里",AI NPC能够根据背景设定给出合适的回答。

玩家做一些与任务无关的闲聊时,AI NPC能给出得体的回答,同时引导玩家进行自己的任务。

玩家发疯,说一些与游戏完全无关的话,AI会尝试挽尊,并将话题拉回到正题。

玩家按照正常的任务主线走,AI会按照规则需求进行合乎逻辑的回复。遇到威胁时,AI会讨价还价。

玩家给出错误的水神名字,AI能识别到错误并拒绝提供有效信息。

当玩家给出正确的回答时,AI会根据规则提供有效的信息。

未来工作

多角色扮演

在剧本杀类型的游戏中,玩家需要与不同的角色进行对话。每个角色掌握着不同的信息。角色之间存在信息壁垒,例如角色A掌握的系统信息应当与角色B初始掌握的系统信息不同;且玩家与角色A的对话内容有时需要对角色B保密。在这种情况下,可以用多个role与chat列表,将不同的AI NPC进行隔离。比如对于角色A使用一套专属的system、user、assistant对话列表,对于角色B使用另一套专属的system、user、assistant对话列表。玩家与角色A聊到的一些信息会成为解开角色B更多聊天内容的线索,角色B的爆料又能够促使角色A承认并暴露出更多的信息,以此类推完成整个推理逻辑链路。

利用 Fine-Tuned 训练特定性格的NPC

在 OpenAI 中,可以在不改动 GPT-3 大模型的情况下,针对 prompt 和 completion 的进行训练,对「句式」、「情感」等特征进行优化。 GPT-3 已经预训练了大量的互联网内容。只需要在 prompt 里写少量的用例,他基本可以感知你的用意,并生成一段基本合理的 completion。这个功能一般叫做 "few-shot learning".

使用场景:

  1. 想让 GPT-3 按照某种格式来识别 Prompt ,或按照某种格式来回答

  2. 想让 GPT-3 按照某种语气、性格来回答

  3. 想让 completion 具有某种倾向

接下来会尝试利用 Fine-Tuned 来训练多个不同性格的 NPC ,将一款经典剧本杀的剧本制作成单人游戏,并让玩家跟AI扮演的其他NPC一起盘逻辑找凶手。

相关推荐
慢成长4 分钟前
如何创建虚拟环境并实现目标检测及验证能否GPU加速
人工智能
AIGC破防黑吗喽5 分钟前
Midjourney零基础学习
人工智能·gpt·学习·ai·stable diffusion·midjourney·ai绘画
AI大模型-王哥6 分钟前
微软GraphRAG实战解析:全局理解力如何超越传统RAG
人工智能·microsoft·大模型·ai大模型·大模型学习·大模型入门·大模型教程
会飞的Anthony6 分钟前
基于Python的人工智能应用案例系列(15):LSTM酒类销售预测
人工智能·酒类预测
互联网新声25 分钟前
胡超:引领中美能源与文化合作的创意先锋
人工智能·能源
修炼室27 分钟前
突触可塑性与STDP:神经网络中的自我调整机制
人工智能·深度学习·神经网络
FHYAAAX29 分钟前
【机器学习】知识总结1(人工智能、机器学习、深度学习、贝叶斯、回归分析)
人工智能·深度学习·机器学习·贝叶斯·回归分析
whaosoft-14332 分钟前
51c视觉~CV~合集2
人工智能
一尘之中1 小时前
网 络 安 全
网络·人工智能·学习·安全
学习前端的小z1 小时前
【AIGC】ChatGPT是如何思考的:探索CoT思维链技术的奥秘
人工智能·chatgpt·aigc