来源:原文;作者或维护方:DSPy 官方教程(原页未署个人作者)。中文编译整理与技术核对:未完纪。核对日期:2026-10-05。

文字冒险游戏很适合展示语言模型与普通程序怎样分工:模型负责描述场景、扮演 NPC、解释行动结果,Python 程序保存角色数据、显示菜单并管理游戏循环。本教程把三类生成任务拆成 DSPy 模块,再用 Rich 和 Typer 搭建终端界面,最后加入 JSON 存档与恢复。
原教程希望得到动态故事、分支叙事、角色互动、随玩家选择变化的游戏过程,以及背包、成长和存档功能。本文完整保留其四部分代码,在中文说明中区分已经实现的状态管理与尚未实现的游戏系统。代码来自 DSPy 官方教程,原页未署个人作者;下面的界面和英文提示保持原例形式,便于对照。
准备依赖与模型
原文使用以下安装命令:
pip install dspy rich typer
建议在独立虚拟环境中准备依赖,并记录实际版本,避免一个未固定版本的命令日后得到不同结果。DSPy 配置使用原例的 openai/gpt-4o-mini;这是原教程的模型选择,并非本文验证后的可用性或效果推荐。模型服务需要按供应方方式配置凭据,不要把真实密钥写进代码、文章或存档。
每轮先生成场景,再按选择调用对话或行动模块;查看背包、角色状态或保存后,循环也会重新生成场景。若这些请求实际发往远端服务,会产生调用成本,角色名、数值、行动和相关叙事也会离开本机。请只使用适合提交给该服务的内容,并自行设置合理预算。
第一步:定义角色、场景上下文和存档
Player 保存姓名、生命值、等级、经验、背包和四项技能。初始生命值是 100,等级是 1,四项技能各为 10。背包和技能都通过 default_factory 创建,避免不同玩家实例共享同一个可变容器。获得经验后,等级按 1 + experience // 100 计算。
GameContext 保存当前地点、故事进度、访问地点、见过的 NPC、完成任务和布尔标志。GameState 定义菜单、游戏中、背包、角色和结束状态;后续主循环实际主要分派菜单、游戏中和结束三个状态,背包及角色页面由函数直接显示。
GameEngine.save_game() 把玩家与上下文的字段写入 JSON。load_game() 读取这些字段并重新创建数据类实例,找不到文件或遇到其他异常时返回 False。保存文件默认是当前目录下的 savegame.json。
import dspy
import json
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, field
from enum import Enum
import random
from rich.console import Console
from rich.panel import Panel
from rich.text import Text
import typer
# Configure DSPy
lm = dspy.LM(model='openai/gpt-4o-mini')
dspy.configure(lm=lm)
console = Console()
class GameState(Enum):
MENU = "menu"
PLAYING = "playing"
INVENTORY = "inventory"
CHARACTER = "character"
GAME_OVER = "game_over"
@dataclass
class Player:
name: str
health: int = 100
level: int = 1
experience: int = 0
inventory: list[str] = field(default_factory=list)
skills: dict[str, int] = field(default_factory=lambda: {
"strength": 10,
"intelligence": 10,
"charisma": 10,
"stealth": 10
})
def add_item(self, item: str):
self.inventory.append(item)
console.print(f"[green]Added {item} to inventory![/green]")
def remove_item(self, item: str) -> bool:
if item in self.inventory:
self.inventory.remove(item)
return True
return False
def gain_experience(self, amount: int):
self.experience += amount
old_level = self.level
self.level = 1 + (self.experience // 100)
if self.level > old_level:
console.print(f"[bold yellow]Level up! You are now level {self.level}![/bold yellow]")
@dataclass
class GameContext:
current_location: str = "Village Square"
story_progress: int = 0
visited_locations: list[str] = field(default_factory=list)
npcs_met: list[str] = field(default_factory=list)
completed_quests: list[str] = field(default_factory=list)
game_flags: dict[str, bool] = field(default_factory=dict)
def add_flag(self, flag: str, value: bool = True):
self.game_flags[flag] = value
def has_flag(self, flag: str) -> bool:
return self.game_flags.get(flag, False)
class GameEngine:
def __init__(self):
self.player = None
self.context = GameContext()
self.state = GameState.MENU
self.running = True
def save_game(self, filename: str = "savegame.json"):
"""Save current game state."""
save_data = {
"player": {
"name": self.player.name,
"health": self.player.health,
"level": self.player.level,
"experience": self.player.experience,
"inventory": self.player.inventory,
"skills": self.player.skills
},
"context": {
"current_location": self.context.current_location,
"story_progress": self.context.story_progress,
"visited_locations": self.context.visited_locations,
"npcs_met": self.context.npcs_met,
"completed_quests": self.context.completed_quests,
"game_flags": self.context.game_flags
}
}
with open(filename, 'w') as f:
json.dump(save_data, f, indent=2)
console.print(f"[green]Game saved to {filename}![/green]")
def load_game(self, filename: str = "savegame.json") -> bool:
"""Load game state from file."""
try:
with open(filename, 'r') as f:
save_data = json.load(f)
# Reconstruct player
player_data = save_data["player"]
self.player = Player(
name=player_data["name"],
health=player_data["health"],
level=player_data["level"],
experience=player_data["experience"],
inventory=player_data["inventory"],
skills=player_data["skills"]
)
# Reconstruct context
context_data = save_data["context"]
self.context = GameContext(
current_location=context_data["current_location"],
story_progress=context_data["story_progress"],
visited_locations=context_data["visited_locations"],
npcs_met=context_data["npcs_met"],
completed_quests=context_data["completed_quests"],
game_flags=context_data["game_flags"]
)
console.print(f"[green]Game loaded from {filename}![/green]")
return True
except FileNotFoundError:
console.print(f"[red]Save file {filename} not found![/red]")
return False
except Exception as e:
console.print(f"[red]Error loading game: {e}![/red]")
return False
# Initialize game engine
game = GameEngine()
这份存档是明文,写入模式 w 会覆盖现有文件。读取时也没有验证字段类型、生命值范围、技能集合或输入文件大小;类型注解不会自动约束从 JSON 读入的数据。它没有使用会直接执行对象构造的 pickle,也没有在片段中对内容调用 eval,但这并不意味着任意存档都安全或合法。
更可靠的实现应在完整校验后一次性替换内存状态,并采用临时文件加提交的保存策略。原例先构造玩家、再构造上下文,如果后一步失败,先前赋值可能已经发生;不要把宽泛捕获异常理解成事务回滚。这些是编辑审查建议,本文未暗中修改原存档逻辑。
第二步:把叙事、对话和行动分成三个 DSPy 签名
StoryGenerator 接收地点、角色信息、故事进度和最近行动,输出场景描述、可选行动、在场 NPC 和可见物品。DialogueGenerator 接收 NPC 名称、性格、玩家输入和上下文,输出台词、情绪变化、是否提供任务及透露的信息。ActionResolver 接收行动、角色属性、上下文和难度,输出成功与否、结果描述、属性变化、获得的物品和经验。
GameAI 为这三个签名分别创建 dspy.ChainOfThought。包装方法把数据类字段转换为输入字符串,再把预测结果整理为字典,让后面的界面代码不必直接处理 DSPy 的结果对象。
对话模块为村长、商人、守卫、盗贼和巫师设置固定性格;未知 NPC 使用一个默认村民性格。行动难度由简单的英文关键词决定:包含 fight、battle 或 attack 时为 hard,包含 look、examine 或 talk 时为 easy,其余为 medium。这只是示例规则,不是经过平衡验证的战斗判定。
class StoryGenerator(dspy.Signature):
"""Generate dynamic story content based on current game state."""
location: str = dspy.InputField(desc="Current location")
player_info: str = dspy.InputField(desc="Player information and stats")
story_progress: int = dspy.InputField(desc="Current story progress level")
recent_actions: str = dspy.InputField(desc="Player's recent actions")
scene_description: str = dspy.OutputField(desc="Vivid description of current scene")
available_actions: list[str] = dspy.OutputField(desc="List of possible player actions")
npcs_present: list[str] = dspy.OutputField(desc="NPCs present in this location")
items_available: list[str] = dspy.OutputField(desc="Items that can be found or interacted with")
class DialogueGenerator(dspy.Signature):
"""Generate NPC dialogue and responses."""
npc_name: str = dspy.InputField(desc="Name and type of NPC")
npc_personality: str = dspy.InputField(desc="NPC personality and background")
player_input: str = dspy.InputField(desc="What the player said or did")
context: str = dspy.InputField(desc="Current game context and history")
npc_response: str = dspy.OutputField(desc="NPC's dialogue response")
mood_change: str = dspy.OutputField(desc="How NPC's mood changed (positive/negative/neutral)")
quest_offered: bool = dspy.OutputField(desc="Whether NPC offers a quest")
information_revealed: str = dspy.OutputField(desc="Any important information shared")
class ActionResolver(dspy.Signature):
"""Resolve player actions and determine outcomes."""
action: str = dspy.InputField(desc="Player's chosen action")
player_stats: str = dspy.InputField(desc="Player's current stats and skills")
context: str = dspy.InputField(desc="Current game context")
difficulty: str = dspy.InputField(desc="Difficulty level of the action")
success: bool = dspy.OutputField(desc="Whether the action succeeded")
outcome_description: str = dspy.OutputField(desc="Description of what happened")
stat_changes: dict[str, int] = dspy.OutputField(desc="Changes to player stats")
items_gained: list[str] = dspy.OutputField(desc="Items gained from this action")
experience_gained: int = dspy.OutputField(desc="Experience points gained")
class GameAI(dspy.Module):
"""Main AI module for game logic and narrative."""
def __init__(self):
super().__init__()
self.story_gen = dspy.ChainOfThought(StoryGenerator)
self.dialogue_gen = dspy.ChainOfThought(DialogueGenerator)
self.action_resolver = dspy.ChainOfThought(ActionResolver)
def generate_scene(self, player: Player, context: GameContext, recent_actions: str = "") -> Dict:
"""Generate current scene description and options."""
player_info = f"Level {player.level} {player.name}, Health: {player.health}, Skills: {player.skills}"
scene = self.story_gen(
location=context.current_location,
player_info=player_info,
story_progress=context.story_progress,
recent_actions=recent_actions
)
return {
"description": scene.scene_description,
"actions": scene.available_actions,
"npcs": scene.npcs_present,
"items": scene.items_available
}
def handle_dialogue(self, npc_name: str, player_input: str, context: GameContext) -> Dict:
"""Handle conversation with NPCs."""
# Create NPC personality based on name and context
personality_map = {
"Village Elder": "Wise, knowledgeable, speaks in riddles, has ancient knowledge",
"Merchant": "Greedy but fair, loves to bargain, knows about valuable items",
"Guard": "Dutiful, suspicious of strangers, follows rules strictly",
"Thief": "Sneaky, untrustworthy, has information about hidden things",
"Wizard": "Mysterious, powerful, speaks about magic and ancient forces"
}
personality = personality_map.get(npc_name, "Friendly villager with local knowledge")
game_context = f"Location: {context.current_location}, Story progress: {context.story_progress}"
response = self.dialogue_gen(
npc_name=npc_name,
npc_personality=personality,
player_input=player_input,
context=game_context
)
return {
"response": response.npc_response,
"mood": response.mood_change,
"quest": response.quest_offered,
"info": response.information_revealed
}
def resolve_action(self, action: str, player: Player, context: GameContext) -> Dict:
"""Resolve player actions and determine outcomes."""
player_stats = f"Level {player.level}, Health {player.health}, Skills: {player.skills}"
game_context = f"Location: {context.current_location}, Progress: {context.story_progress}"
# Determine difficulty based on action type
difficulty = "medium"
if any(word in action.lower() for word in ["fight", "battle", "attack"]):
difficulty = "hard"
elif any(word in action.lower() for word in ["look", "examine", "talk"]):
difficulty = "easy"
result = self.action_resolver(
action=action,
player_stats=player_stats,
context=game_context,
difficulty=difficulty
)
return {
"success": result.success,
"description": result.outcome_description,
"stat_changes": result.stat_changes,
"items": result.items_gained,
"experience": result.experience_gained
}
# Initialize AI
ai = GameAI()
需要留意实际传入模型的内容。handle_dialogue() 的上下文只包含地点和故事进度,不包含完整对话记录;npcs_met 列表也没有传给它。场景模块的 recent_actions 只是最近的一段摘要,而不是持久化历史。输出里的 mood 随后没有被保存;任务标志只是用于显示提示。
带类型的输出字段能表达预期结构,但不能保证游戏规则成立。模型可能给出很大的奖励、不合理的物品或与场景冲突的描述;玩家输入或存档内容也可能通过提示影响模型输出。这里的风险主要是叙事和数值被操纵,源例没有把模型输出当作 Python 或 shell 代码执行。要维护游戏规则,应由确定性的本地代码校验并裁决数值和物品,而不是让模型拥有最终权限。
第三步:显示终端界面并创建角色
Rich 的 Panel 用来显示标题、角色状态、地点、行动和背包。get_player_choice() 通过 Typer 读取数字,只有输入位于菜单范围内才返回从零开始的下标。主菜单提供新游戏、读取存档、帮助和退出。
新角色有 10 点额外技能点,按力量、智力、魅力、潜行的顺序分配。每次输入会检查整数及剩余点数范围。不过这段循环只遍历技能一次,如果每项都没有分完,剩余点数不会强制继续分配;它是一个可以后续完善的交互细节。
def display_game_header():
"""Display the game header."""
header = Text("🏰 MYSTIC REALM ADVENTURE 🏰", style="bold magenta")
console.print(Panel(header, style="bright_blue"))
def display_player_status(player: Player):
"""Display player status panel."""
status = f"""
[bold]Name:[/bold] {player.name}
[bold]Level:[/bold] {player.level} (XP: {player.experience})
[bold]Health:[/bold] {player.health}/100
[bold]Skills:[/bold]
• Strength: {player.skills['strength']}
• Intelligence: {player.skills['intelligence']}
• Charisma: {player.skills['charisma']}
• Stealth: {player.skills['stealth']}
[bold]Inventory:[/bold] {len(player.inventory)} items
"""
console.print(Panel(status.strip(), title="Player Status", style="green"))
def display_location(context: GameContext, scene: Dict):
"""Display current location and scene."""
location_panel = f"""
[bold yellow]{context.current_location}[/bold yellow]
{scene['description']}
"""
if scene['npcs']:
location_panel += f"\n\n[bold]NPCs present:[/bold] {', '.join(scene['npcs'])}"
if scene['items']:
location_panel += f"\n[bold]Items visible:[/bold] {', '.join(scene['items'])}"
console.print(Panel(location_panel.strip(), title="Current Location", style="cyan"))
def display_actions(actions: list[str]):
"""Display available actions."""
action_text = "\n".join([f"{i+1}. {action}" for i, action in enumerate(actions)])
console.print(Panel(action_text, title="Available Actions", style="yellow"))
def get_player_choice(max_choices: int) -> int:
"""Get player's choice with input validation."""
while True:
try:
choice = typer.prompt("Choose an action (number)")
choice_num = int(choice)
if 1 <= choice_num <= max_choices:
return choice_num - 1
else:
console.print(f"[red]Please enter a number between 1 and {max_choices}[/red]")
except ValueError:
console.print("[red]Please enter a valid number[/red]")
def show_inventory(player: Player):
"""Display player inventory."""
if not player.inventory:
console.print(Panel("Your inventory is empty.", title="Inventory", style="red"))
else:
items = "\n".join([f"• {item}" for item in player.inventory])
console.print(Panel(items, title="Inventory", style="green"))
def main_menu():
"""Display main menu and handle selection."""
console.clear()
display_game_header()
menu_options = [
"1. New Game",
"2. Load Game",
"3. How to Play",
"4. Exit"
]
menu_text = "\n".join(menu_options)
console.print(Panel(menu_text, title="Main Menu", style="bright_blue"))
choice = typer.prompt("Select an option")
return choice
def show_help():
"""Display help information."""
help_text = """
[bold]How to Play:[/bold]
• This is a text-based adventure game powered by AI
• Make choices by selecting numbered options
• Talk to NPCs to learn about the world and get quests
• Explore different locations to find items and adventures
• Your choices affect the story and character development
• Use 'inventory' to check your items
• Use 'status' to see your character info
• Type 'save' to save your progress
• Type 'quit' to return to main menu
[bold]Tips:[/bold]
• Different skills affect your success in various actions
• NPCs remember your previous interactions
• Explore thoroughly - there are hidden secrets!
• Your reputation affects how NPCs treat you
"""
console.print(Panel(help_text.strip(), title="Game Help", style="blue"))
typer.prompt("Press Enter to continue")
帮助文字与实现不一致:原例帮助页说可以直接输入 inventory、status、save、quit,但实际游戏选择函数要求输入数字。用户应选择菜单里的对应编号。帮助页还说 NPC 会记住以前的互动、声誉会影响态度;代码并没有实现完整对话记忆或声誉状态,不能把这些句子当作已经存在的功能。本文为便于比对保留了原始帮助字符串,并在这里明确纠正说明。
另一个需要修改后再使用的边界是终端文本。原例把玩家姓名、模型描述、NPC 名称和物品名拼接进 Rich 标记字符串;不可信内容中的方括号标记可能改变显示样式,某些内容也可能使渲染报错。应对动态文本使用 rich.markup.escape,或使用纯文本 Text/关闭相应的 markup 解析。它不同于操作系统命令注入,但依然是一个真实的显示与可靠性问题。
第四步:连接游戏循环
游戏进行时,每一轮先生成场景,显示角色和地点,再把四个固定操作追加到模型生成的行动之后。背包、状态和保存操作处理完后继续循环;退出操作把状态切回主菜单。
其他行动会先按字符串检查是否含有在场 NPC 名称:如果命中,就进入对话分支,否则交给行动解析器。这个匹配策略很粗糙,例如“攻击某个 NPC”也可能因为包含名字而被归入对话,不能把它当作成熟的意图分类器。
在普通行动分支中,原例只在 success 为真时应用属性、物品和经验变化。生命值被限制在 0 至 100,技能变化没有同样的上下界;经验只在返回值大于零时添加,但没有奖励上限。成功后故事进度加一,失败时仅打印失败提示。随后检查生命值,归零就切到结束状态。
def create_new_character():
"""Create a new player character."""
console.clear()
display_game_header()
name = typer.prompt("Enter your character's name")
# Character creation with skill point allocation
console.print("\n[bold]Character Creation[/bold]")
console.print("You have 10 extra skill points to distribute among your skills.")
console.print("Base skills start at 10 each.\n")
skills = {"strength": 10, "intelligence": 10, "charisma": 10, "stealth": 10}
points_remaining = 10
for skill in skills.keys():
if points_remaining > 0:
console.print(f"Points remaining: {points_remaining}")
while True:
try:
points = int(typer.prompt(f"Points to add to {skill} (0-{points_remaining})"))
if 0 <= points <= points_remaining:
skills[skill] += points
points_remaining -= points
break
else:
console.print(f"[red]Enter a number between 0 and {points_remaining}[/red]")
except ValueError:
console.print("[red]Please enter a valid number[/red]")
player = Player(name=name, skills=skills)
console.print(f"\n[green]Welcome to Mystic Realm, {name}![/green]")
return player
def game_loop():
"""Main game loop."""
recent_actions = ""
while game.running and game.state == GameState.PLAYING:
console.clear()
display_game_header()
# Generate current scene
scene = ai.generate_scene(game.player, game.context, recent_actions)
# Display game state
display_player_status(game.player)
display_location(game.context, scene)
# Add standard actions
all_actions = scene['actions'] + ["Check inventory", "Character status", "Save game", "Quit to menu"]
display_actions(all_actions)
# Get player choice
choice_idx = get_player_choice(len(all_actions))
chosen_action = all_actions[choice_idx]
# Handle special commands
if chosen_action == "Check inventory":
show_inventory(game.player)
typer.prompt("Press Enter to continue")
continue
elif chosen_action == "Character status":
display_player_status(game.player)
typer.prompt("Press Enter to continue")
continue
elif chosen_action == "Save game":
game.save_game()
typer.prompt("Press Enter to continue")
continue
elif chosen_action == "Quit to menu":
game.state = GameState.MENU
break
# Handle game actions
if chosen_action in scene['actions']:
# Check if it's dialogue with an NPC
npc_target = None
for npc in scene['npcs']:
if npc.lower() in chosen_action.lower():
npc_target = npc
break
if npc_target:
# Handle NPC interaction
console.print(f"\n[bold]Talking to {npc_target}...[/bold]")
dialogue = ai.handle_dialogue(npc_target, chosen_action, game.context)
console.print(f"\n[italic]{npc_target}:[/italic] \"{dialogue['response']}\"")
if dialogue['quest']:
console.print(f"[yellow]💼 Quest opportunity detected![/yellow]")
if dialogue['info']:
console.print(f"[blue]ℹ️ {dialogue['info']}[/blue]")
# Add NPC to met list
if npc_target not in game.context.npcs_met:
game.context.npcs_met.append(npc_target)
recent_actions = f"Talked to {npc_target}: {chosen_action}"
else:
# Handle general action
result = ai.resolve_action(chosen_action, game.player, game.context)
console.print(f"\n{result['description']}")
# Apply results
if result['success']:
console.print("[green]✅ Success![/green]")
# Apply stat changes
for stat, change in result['stat_changes'].items():
if stat in game.player.skills:
game.player.skills[stat] += change
if change > 0:
console.print(f"[green]{stat.title()} increased by {change}![/green]")
elif stat == "health":
game.player.health = max(0, min(100, game.player.health + change))
if change > 0:
console.print(f"[green]Health restored by {change}![/green]")
elif change < 0:
console.print(f"[red]Health decreased by {abs(change)}![/red]")
# Add items
for item in result['items']:
game.player.add_item(item)
# Give experience
if result['experience'] > 0:
game.player.gain_experience(result['experience'])
# Update story progress
game.context.story_progress += 1
else:
console.print("[red]❌ The action didn't go as planned...[/red]")
recent_actions = f"Attempted: {chosen_action}"
# Check for game over conditions
if game.player.health <= 0:
console.print("\n[bold red]💀 You have died! Game Over![/bold red]")
game.state = GameState.GAME_OVER
break
typer.prompt("\nPress Enter to continue")
def main():
"""Main game function."""
while game.running:
if game.state == GameState.MENU:
choice = main_menu()
if choice == "1":
game.player = create_new_character()
game.context = GameContext()
game.state = GameState.PLAYING
console.print("\n[italic]Your adventure begins...[/italic]")
typer.prompt("Press Enter to start")
elif choice == "2":
if game.load_game():
game.state = GameState.PLAYING
typer.prompt("Press Enter to continue")
elif choice == "3":
show_help()
elif choice == "4":
game.running = False
console.print("[bold]Thanks for playing! Goodbye![/bold]")
elif game.state == GameState.PLAYING:
game_loop()
elif game.state == GameState.GAME_OVER:
console.print("\n[bold]Game Over[/bold]")
restart = typer.confirm("Would you like to return to the main menu?")
if restart:
game.state = GameState.MENU
else:
game.running = False
if __name__ == "__main__":
main()
由此可以看到几个能力边界。失败行动返回的伤害或其他数值变化不会被应用;如果模型说“失败并受伤”,叙事与状态可能不一致。current_location 没有在行动后更新,所以“前往森林”的文字不等于地图状态真的迁移。visited_locations、completed_quests 和 game_flags 虽然被保存,却没有形成完整的探索或任务推进逻辑。
要修正这些问题,应先定义清晰的规则:哪些行动能移动地点,失败是否也允许扣生命值,哪些属性和物品可更改,以及每次变化的上下界;然后在应用任何模型返回值之前校验类型、白名单、数值和列表长度。不要只在提示词里要求“合理”,也不要为了让示例看起来可用而声称这些规则已经实现。
退出游戏不会自动保存。读档后主循环会把状态设置为游戏中,但最近行动摘要和之前那一轮场景并没有持久化,下一次会重新生成。因此 JSON 存档保留的是代码列出的玩家与上下文字段,不是完整剧情重放。
原文展示的游戏片段
以下三个片段是官方教程展示的示例内容,不是本次执行记录,也不能保证模型每次产生相同文本。第一个例子创建角色 Aria,并把 10 点依次分配为 2、4、3、1:
🏰 MYSTIC REALM ADVENTURE 🏰
Enter your character's name: Aria
Character Creation
You have 10 extra skill points to distribute among your skills.
Base skills start at 10 each.
Points remaining: 10
Points to add to strength (0-10): 2
Points to add to intelligence (0-8): 4
Points to add to charisma (0-4): 3
Points to add to stealth (0-1): 1
Welcome to Mystic Realm, Aria!
场景示例描述 Willowbrook 村庄广场:喷泉、商贩、孩子和一名神秘兜帽人物,并列出村长、商人以及可见物品。可选动作包括接近人物、与村长交谈、查看商品、检查吊坠、采草药或前往林间小路:
┌──────────── Current Location ────────────┐
│ Village Square │
│ │
│ You stand in the bustling heart of │
│ Willowbrook Village. The ancient stone │
│ fountain bubbles cheerfully as merchants │
│ hawk their wares and children play. A │
│ mysterious hooded figure lurks near the │
│ shadows of the old oak tree. │
│ │
│ NPCs present: Village Elder, Merchant │
│ Items visible: Strange Medallion, Herbs │
└──────────────────────────────────────────┘
┌────────── Available Actions ─────────────┐
│ 1. Approach the hooded figure │
│ 2. Talk to the Village Elder │
│ 3. Browse the merchant's wares │
│ 4. Examine the strange medallion │
│ 5. Gather herbs near the fountain │
│ 6. Head to the forest path │
└───────────────────────────────────────────┘
对话示例让村长用预言式语气回应旅人,并显示有任务机会及相关信息。这里的任务提示仍只是生成结果和 UI 提示:
Talking to Village Elder...
Village Elder: "Ah, young traveler, I sense a great destiny
surrounds you like morning mist. The ancient prophecy speaks
of one who would come bearing the mark of courage. Tell me,
have you noticed anything... unusual in your travels?"
💼 Quest opportunity detected!
ℹ️ The Village Elder knows about an ancient prophecy that might involve you
继续扩展时,先补规则再增加内容
原文给出的扩展方向包括:带策略的回合制战斗、具有资源约束的法术系统、支持协作冒险的多人网络、具有分支结果的多阶段任务、程序化地点与角色,以及音效和背景音乐。这些都是后续工作,不是本教程已经提供的功能。
这个原型展示了 DSPy 的模块组合方式:把创造性内容生成拆成清楚的输入输出,让普通程序管理界面和持久化。真正要维持规则一致性,还需加入状态验证、可复现的测试样例、异常与重试边界、模型调用预算及安全的文本渲染。本文完整保存原始实现,所有缺口和建议均与原文行为分开标注;没有给出未经测试的“已修复完整游戏”。
代码许可说明
DSPy 仓库的 LICENSE 为 MIT,版权署名为 Stanford Future Data Systems。下方保留其许可文本。模型生成内容和第三方服务条款不由这份仓库许可自动覆盖。
MIT 许可与原版权声明
MIT License
Copyright (c) 2023 Stanford Future Data Systems
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
来源、许可与核验说明
来源 DSPy 官方教程,原页未署个人作者;代码仓库 MIT 许可与 Copyright (c) 2023 Stanford Future Data Systems 完整保留在正文中。正文翻译、技术解释与局限核对由未完纪完成;自绘图归未完纪。
本文经授权翻译、整理和转载,保留原作者署名与适用许可。本次仅阅读来源并静态审查代码,没有执行本文应用示例、安装依赖、调用模型服务或改变网络配置。未发现某类问题并不代表代码无漏洞。












暂无评论内容