战斗包子
在godot中接入大模型api,实现npc的自动对话

在godot中接入大模型api,实现npc的自动对话

在godot中接入大模型api,实现npc的自动对话

目录

概述

最近计划利用godot做一个游戏demo,其中会随机产生各种npc,然后npc之间会相互对话。
大概思路就是给每个角色一个状态机,控制其idle、moving、chatting等状态。通过Area2D的碰撞判断范围内有没有其他角色,然后发起对话请求。被接受后调用大模型的API进行对话。
初次用godot也是头回通过https去访问大模型的api(毕竟gdscript没有python的包),感谢大模型一直帮我解疑答惑顺便给我埋坑让我疯狂debug

实现思路

架构

graph TD
    A[Character Controller] --> B[State Machine]
    A --> C[Dialogue Manager]
    A --> D[Appearance System]
    B --> E[IDLE State]
    B --> F[MOVING State]
    B --> G[CHATTING State]
    C --> H[API Communication]
    C --> I[Message Processing]
    D --> J[Character Customization]

其中状态机部分基本和一般的游戏一样,此处不在赘述,主要写写接入大模型踩的坑。DialogueManager.gd代码附在最后

sequenceDiagram
    participant NPC1
    participant NPC2
    participant API
    
    NPC1->>NPC2: 发送对话请求
    NPC2->>NPC1: 接受请求
    loop 对话轮次
        NPC1->>API: 生成对话内容
        API-->>NPC1: 返回响应
        NPC1->>NPC2: 发送消息
        NPC2->>API: 生成回复
        API-->>NPC2: 返回响应
        NPC2->>NPC1: 发送回复
    end
    NPC1->>NPC2: 结束对话

对话模块()

实现要点:

  • 异步HTTP请求

  • 上下文记忆管理

  • 错误重试机制

其流程为

graph TD
    A[生成对话请求] --> B[构建消息体]
    B --> C[创建HTTPRequest]
    C --> D[发送POST请求]
    D --> E{成功?}
    E -->|是| F[解析响应]
    E -->|否| G[错误处理]
    F --> H[更新对话历史]
    G --> I[重试机制]
```    

目前做了一个简易版本,两个角色之间可以通过调用大模型的api来实现对话。
写的很烂,之后再重构吧。
后面会把这个小demo放到github上。

### 代码
```gdscript
# DialogueManager.gd
class_name DialogueManager
extends Node

## 设置APIKEY 和请求URL以及模型
const BASE_URL = "https://open.bigmodel.cn/api/paas/v4/chat/completions"
const API_KEY = "YOUR_API_KEY"
const MODEL = "glm-4-flash"
const TIMEOUT = 10

var history: Array # character_id -> Array[Message]
var character : CharacterBody2D
var is_getting : bool = false

func _init(parent:CharacterBody2D) -> void:
	character = parent

	
func generate_response(prompt: String = "hello") -> void:
	if is_getting:
		return
	var messages = prepare_messages(prompt)
	var headers = [
		"Authorization: Bearer " + API_KEY,
		"Content-Type: application/json"
		]
	print(headers)
	var payload = {
		"model": MODEL,
		"messages": messages,
		#"tags": ["glm-4", "tool"],
		"temperature": 0.7  # You can adjust this parameter as needed
	}
	var body = JSON.stringify(
	{
	  "model": "glm-4",
	  "messages": [
		{"role": "user", "content": "你好"}
	  ],
	  "temperature": 0.7
	})
	#var body = JSON.stringify(payload)
	print("body:")
	print(body)
	var request = HTTPRequest.new()
	add_child(request)
	# 等待节点初始化完成
	await get_tree().process_frame
	request.set_timeout(TIMEOUT)
	request.request_completed.connect(_on_response_received)
	var result = request.request(BASE_URL, headers, HTTPClient.METHOD_POST, body)
	print(result)
	is_getting = true
	print("request send")
	
	
func prepare_messages(prompt: String) -> Array:
	var context = [
		{"role": "system", "content": "假设你是一个普通人,模拟和其他人的对话"},
		{"role": "user", "content": prompt}
	]
	context = history + context
	
	return context

func _on_response_received(result: int, code: int, headers: Array, body: PackedByteArray):
	print("response received")
	if result != HTTPRequest.RESULT_SUCCESS:
		character.receive_message("(思考中...)")
		return
	
	var response = JSON.parse_string(body.get_string_from_utf8())
	print("response.error:")
	print(response.error)
	print("content:")
	print(response)
	if response.error != null:
		character.receive_message("(解析API响应失败,请稍后再试...)")
		is_getting = false
		return
		
	var message = response.choices[0].message.content
	character.receive_message(message)
	print("message:")
	print(message)
	
	# 保存历史记录
	var history_entry = {"role": "assistant", "content": message}
	history.append(history_entry)
	print(history)
	is_getting = false

func _clear_history():
	history.clear()
本文作者:战斗包子
本文链接:https://paipai121.github.io/2025/01/29/godot/在godot中接入大模型api,实现npc的自动对话/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可