
LangChain+DeepSeek动态生成推箱子游戏关卡
最后构建系统消息,为进一步调用模型做好准备,此后只需将系统消息传入模型的invoke()方法便能触发DeepSeek API 的推理过程,并获取模型的响应结果。使用pgzero库开发了一个推箱子游戏,将当前关卡中移动步数记录在变量steps中,过关时会调用loadmap()方法,该方法中将steps作为输入参数传给模型,模型会根据系统提示词生成关卡数据作为输出,游戏程序则根据模型生成的关卡数据加载
如何获取 DeepSeek API 密钥?
1. 访问 DeepSeek 官方网站
- 打开 DeepSeek 的官方网站:https://www.deepseek.com。
- 查找与 API 相关的页面或开发者文档。
2. 注册或登录账户
- 如果你还没有 DeepSeek 账户,需要先注册一个新账户。
- 如果已经有账户,直接登录。
3. 进入开发者或 API 管理页面
- 登录后,进入开发者中心或 API 管理页面。
- 通常可以在用户面板或设置中找到相关选项。
- 新注册用户赠送10元免费额度。
4. 创建 API 密钥
- 在 API 管理页面中,找到“创建 API 密钥”或“生成密钥”的选项。
- 按照提示生成一个新的 API 密钥。
- 生成的密钥通常是一串长字符(例如:sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)。
5. 保存 API 密钥
- 生成密钥后,务必将其保存到安全的地方,因为密钥只会显示一次。
- 如果丢失,可能需要重新生成。
6. 使用 API 密钥
- 将生成的 API 密钥替换到代码中的 api_key="<DeepSeek API Key>" 部分。
- 测试密钥是否有效,下面是一个简单示例。
如何使用LangChain框架调用DeepSeek的API?
LangChain是一个强大的框架,用于构建基于语言模型的应用程序,尤其适用于处理自然语言推理任务。它能够通过模型推理来生成内容或执行任务,而不是仅依赖于预定义的规则或固定内容。
安装库
pip install langchain langchain_openai openai
官方示例
这段代码的功能是测试langchain库与 DeepSeek 模型的交互。
from langchain_openai.chat_models.base import BaseChatOpenAI
llm = BaseChatOpenAI(
model='deepseek-chat',
openai_api_key='<your api key>',
openai_api_base='https://api.deepseek.com',
max_tokens=1024
)
response = llm.invoke("Hi!")
print(response.content)
扩展案例
这段代码的作用是使用 Python 语言通过langchain库与 DeepSeek API 进行交互,实现一个基于用户信息提供个性化推荐的功能。
from langchain_openai.chat_models.base import BaseChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage
# 从环境变量中获取 API 密钥
api_key = '<your api key>'
# 配置 DeepSeek API
base_url = "https://api.deepseek.com"
# 初始化 ChatOpenAI 客户端
chat_model = BaseChatOpenAI(
model="deepseek-chat", # 指定模型
openai_api_key=api_key,
openai_api_base=base_url,
temperature=0.7, # 控制生成文本的随机性
max_tokens=150, # 限制生成的最大 token 数
)
# 定义用户信息和系统提示
user_info = {
"name": "Alice",
"age": 30,
"interests": ["reading", "traveling", "technology"],
}
system_prompt = (
"You are a helpful assistant. "
"You will receive user information and provide personalized recommendations."
)
# 构建消息
messages = [
SystemMessage(content=system_prompt),
HumanMessage(content=f"User information: {user_info}. Can you recommend something based on my interests?"),
]
# 调用 DeepSeek API 进行推理
response = chat_model.invoke(messages) # 使用 .invoke() 方法调用模型
# 输出结果
print(response.content)
如何通过LangChain+deepseek动态生成关卡?
创建AIGC_level.py文件,配置推理模型
首先调用BaseChatOpenAI()方法生成推理模型,传入的参数中要替换为自己的DeepSeek API密钥。然后设置系统提示词,即按何种规则生成关卡数据。接着构建用户输入,将玩家的移动步数作为参数保存。最后构建系统消息,为进一步调用模型做好准备,此后只需将系统消息传入模型的invoke()方法便能触发DeepSeek API 的推理过程,并获取模型的响应结果。
from langchain_core.messages import HumanMessage, SystemMessage
from langchain_openai.chat_models.base import BaseChatOpenAI
# 从环境变量中获取 API 密钥
api_key = '<your api key>'
# 配置 DeepSeek API
base_url = "https://api.deepseek.com"
# 构建推理模型,配置模型参数
chat_model = BaseChatOpenAI(
model="deepseek-chat", # 指定模型
openai_api_key=api_key,
openai_api_base=base_url,
temperature=0.9, # 控制生成文本的随机性
#max_tokens=150, # 限制生成的最大 token 数
)
# 定义系统提示,指导模型生成关卡数据
system_prompt = """
你是一个推箱子游戏关卡设计师。
根据玩家在当前关卡的表现(步数),生成一个新的推箱子游戏关卡。
关卡数据应以二维列表表示,列表中的元素及含义如下:
- '1':墙壁
- '2':箱子
- '3':玩家
- '4':目标点
- '0':地板
- '-1':空白区域
请根据以下规则,以10步为单位精细调整关卡难度:
1. **步数少于10步**:
- 增加箱子数量至5 - 6个。
- 设计复杂的墙壁布局,增加玩家移动的阻碍和路线的多样性,例如设置多个狭窄通道、环形结构或死胡同。
- 目标点分散在关卡各处,且部分目标点需经过复杂的操作才能到达。
2. **步数在10 - 19步之间**:
- 箱子数量设置为4 - 5个。
- 墙壁布局有一定复杂度,存在一些分支路径,但整体路线不会过于复杂。
- 目标点分布有一定分散性,但仍可通过相对直接的操作到达部分目标点。
3. **步数在20 - 29步之间**:
- 箱子数量为3 - 4个。
- 墙壁布局相对简单,减少不必要的阻碍,玩家可活动空间较大。
- 目标点分布较为集中,便于玩家规划路线。
4. **步数在30 - 39步之间**:
- 箱子数量为2 - 3个。
- 墙壁布局简单,以直线或简单折线为主,基本不设置复杂的通道。
- 目标点集中在关卡的某一区域,降低玩家的操作难度。
5. **步数多于40步**:
- 箱子数量为1 - 2个。
- 尽量减少墙壁数量,仅设置必要的边界,使玩家可自由移动。
- 目标点明显且易于到达,玩家无需复杂操作即可完成关卡。
### 要求:
- 合理使用墙壁、箱子和目标点,使得关卡可以被解开。
- 箱子的数量应和目标点的数量相等。
- 每次生成的关卡必须具有明显的差异,不能与之前生成的关卡重复。
- 关卡尺寸为9行11列,玩家可活动区域尽量集中在关卡中部。
### 示例输出:
[
['-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1'],
['-1', '-1', '1', '1', '1', '1', '1', '1', '1', '-1', '-1'],
['-1', '-1', '1', '0', '0', '4', '0', '0', '1', '-1', '-1'],
['-1', '-1', '1', '0', '0', '2', '0', '0', '1', '-1', '-1'],
['-1', '-1', '1', '4', '2', '3', '2', '4', '1', '-1', '-1'],
['-1', '-1', '1', '0', '0', '2', '0', '0', '1', '-1', '-1'],
['-1', '-1', '1', '0', '0', '4', '0', '0', '1', '-1', '-1'],
['-1', '-1', '1', '1', '1', '1', '1', '1', '1', '-1', '-1'],
['-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1']
]
### 注意事项:仅输出二维列表,确保关卡可解并具挑战性。
"""
# 运行推理模型,参数为玩家当前关卡的步数
def run_model(player_steps):
# 构建用户输入
user_input = f"玩家本关卡的步数:{player_steps}"
# 构建消息
messages = [
SystemMessage(content=system_prompt),
HumanMessage(content=user_input),
]
# 调用 LangChain 生成关卡数据
try:
response = chat_model.invoke(messages)
if not response.content:
print("模型返回为空,检查提示词和请求设置。")
else:
# 处理响应,过滤掉空行
non_empty_lines = [line for line in response.content.splitlines() if line.strip()]
mapdata = eval('\n'.join(non_empty_lines))
print("生成的关卡数据:")
print(mapdata)
return mapdata
except Exception as e:
print("请求失败:", e)
在游戏代码调用推理模型
使用pgzero库开发了一个推箱子游戏,将当前关卡中移动步数记录在变量steps中,过关时会调用loadmap()方法,该方法中将steps作为输入参数传给模型,模型会根据系统提示词生成关卡数据作为输出,游戏程序则根据模型生成的关卡数据加载关卡图像。
import pgzrun
import AIGC_level
TILESIZE = 48 # 箱子尺寸
WIDTH = TILESIZE * 11 # 屏幕宽度
HEIGHT = TILESIZE * 9 # 屏幕高度
# 方向字典,存储各方向对应的坐标偏移值
dirs = {"east":(1, 0), "west":(-1, 0),
"north":(0, -1), "south":(0, 1), "none":(0, 0)}
level = 1 # 游戏关卡值
finished = False # 游戏过关标记
gameover = False
steps = 0
map =[
['-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1'],
['-1', '-1', '1', '1', '1', '1', '1', '1', '1', '-1', '-1'],
['-1', '-1', '1', '0', '0', '4', '0', '0', '1', '-1', '-1'],
['-1', '-1', '1', '0', '0', '2', '2', '0', '1', '-1', '-1'],
['-1', '-1', '1', '4', '0', '3', '0', '4', '1', '-1', '-1'],
['-1', '-1', '1', '0', '2', '0', '2', '0', '1', '-1', '-1'],
['-1', '-1', '1', '0', '0', '4', '0', '0', '1', '-1', '-1'],
['-1', '-1', '1', '1', '1', '1', '1', '1', '1', '-1', '-1'],
['-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1', '-1']
]
# 初始化地图,生成游戏角色
def initlevel(mapdata):
global walls, floors, boxes, targets, player
walls = [] # 墙壁列表
floors= [] # 地板列表
boxes = [] # 箱子列表
targets = [] # 目标点列表
for row in range(len(mapdata)):
for col in range(len(mapdata[row])):
x = col * TILESIZE
y = row * TILESIZE
if mapdata[row][col] >= "0" and mapdata[row][col] != "1":
floors.append(Actor("pushbox_floor", topleft=(x, y)))
if mapdata[row][col] == "1":
walls.append(Actor("pushbox_wall", topleft=(x, y)))
elif mapdata[row][col] == "2":
box = Actor("pushbox_box", topleft=(x, y))
box.placed = False
boxes.append(box)
elif mapdata[row][col] == "4":
targets.append(Actor("pushbox_target", topleft=(x, y)))
elif mapdata[row][col] == "6":
targets.append(Actor("pushbox_target", topleft=(x, y)))
box = Actor("pushbox_box_hit", topleft=(x, y))
box.placed = True
boxes.append(box)
elif mapdata[row][col] == "3":
player = Actor("pushbox_right", topleft=(x, y))
initlevel(map)
# 载入关卡地图
def loadmap():
global steps,gameover
mapdata = AIGC_level.run_model(steps)
if not mapdata:
gameover = True
else:
steps = 0
initlevel(mapdata)
# 处理键盘按下事件
def on_key_down(key):
if finished or gameover:
return
if key == keys.RIGHT:
player.direction = "east"
player.image = "pushbox_right"
elif key == keys.LEFT:
player.direction = "west"
player.image = "pushbox_left"
elif key == keys.DOWN:
player.direction = "south"
player.image = "pushbox_down"
elif key == keys.UP:
player.direction = "north"
player.image = "pushbox_up"
else:
player.direction = "none"
player_move()
player_collision()
# 移动玩家角色
def player_move():
player.oldx = player.x
player.oldy = player.y
dx, dy = dirs[player.direction]
player.x += dx * TILESIZE
player.y += dy * TILESIZE
# 玩家角色的碰撞检测与处理
def player_collision():
# 玩家与墙壁的碰撞
if player.collidelist(walls) != -1:
player.x = player.oldx
player.y = player.oldy
return
# 玩家与箱子的碰撞
index = player.collidelist(boxes)
if index == -1:
return
box = boxes[index]
if box_collision(box) == True:
box.x = box.oldx
box.y = box.oldy
player.x = player.oldx
player.y = player.oldy
return
sounds.fall.play()
# 箱子角色的碰撞检测与处理
def box_collision(box):
global steps
box.oldx = box.x
box.oldy = box.y
dx, dy = dirs[player.direction]
box.x += dx * TILESIZE
box.y += dy * TILESIZE
# 箱子与墙壁的碰撞
if box.collidelist(walls) != -1:
return True
# 箱子与其他箱子的碰撞
for bx in boxes:
if box == bx:
continue
if box.colliderect(bx):
return True
check_target(box)
steps += 1
return False
# 检测箱子是否放置在目标点上
def check_target(box):
if box.collidelist(targets) != -1:
box.image = "pushbox_box_hit"
box.placed = True
else:
box.image = "pushbox_box"
box.placed = False
# 判断是否过关
def levelup():
for box in boxes:
if not box.placed:
return False
return True
# 设置新的关卡
def setlevel():
global finished, level
finished = False
level += 1
loadmap()
# 更新游戏逻辑
def update():
global finished
if finished or gameover:
return
if levelup():
finished = True
sounds.win.play()
clock.schedule(setlevel, 5)
# 绘制游戏图像
def draw():
screen.fill((200, 255, 255))
for floor in floors:
floor.draw()
for wall in walls:
wall.draw()
for target in targets:
target.draw()
for box in boxes:
box.draw()
player.draw()
screen.draw.text("Level " + str(level), topleft=(20, 20),
fontsize=30, color="black")
screen.draw.text("Steps " + str(steps), topleft=(WIDTH-100, 20),
fontsize=30, color="black")
if gameover:
screen.draw.text("Game Over", center=(WIDTH // 2, HEIGHT // 2),
fontsize=80, color="red")
if finished:
screen.draw.text("Level Up", center=(WIDTH // 2, HEIGHT // 2),
fontsize=80, color="blue")
screen.draw.text("Genrating……", center=(WIDTH // 2, HEIGHT // 2+50),
fontsize=80, color="blue")
pgzrun.go()
说明:
- 初始关卡是指定的,后续的关卡会根据当前关卡的表现(移动步数)动态生成。
- 当前DeepSeek网络不太稳定,有时不会成功,可以多试几次或隔一段时间再试。
- 生成的关卡有时不合理,系统提示词还有进一步优化空间。
本文中的推箱子游戏的具体开发步骤在《趣学Python游戏编程》图书中有详细介绍,
本案例源代码下载链接:
更多推荐
所有评论(0)