任务:实现选项后续描述与卡牌名称生成函数(option_outcome_generator.py)
任务:实现选项后续描述与卡牌名称生成函数(option_outcome_generator.py)
一、功能概述
在《极妙幻境》的每一轮中,玩家做出选择后,需要生成两样东西:
- 叙事结果:描述选择带来的直接后果,增强沉浸感。
- 卡牌信息:如果该轮获得了牌(由牌获取算法决定),需要生成一张卡牌的名称和简短描述,用于收藏和BOSS战。
你需要实现一个函数 generate_option_outcome,根据当前轮次的场景描述、玩家选择的选项文本、玩家道德倾向(可选)以及卡牌类型(善/恶/中立,或None表示未得牌),调用大语言模型(Deepseek)生成相应的结果文本和卡牌信息。
二、模块位置与依赖
- 文件路径:
src/game_logic/option_outcome_generator.py - 依赖模块:
llm_hint:复用llm对象和check_api_key。langchain_core.prompts:用于构建提示词模板。logging、json、re、os等标准库。
- 复用资源:可复用
scene_generator.py中的_parse_llm_response、PROJECT_ROOT等辅助函数。
三、函数设计
3.1 函数签名
import logging
import os
import json
import re
from typing import Optional, Dict, Any
from langchain_core.prompts import ChatPromptTemplate
from .config import config
from .llm_hint import llm, check_api_key
logger = logging.getLogger(__name__)
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
TEMPLATE_PATH = os.path.join(PROJECT_ROOT, "prompts", "option_outcome_prompt.txt")
# 模块加载时读取模板
try:
with open(TEMPLATE_PATH, "r", encoding="utf-8") as f:
template_str = f.read()
logger.info(f"选项后续模板已加载: {TEMPLATE_PATH}")
except FileNotFoundError:
logger.error(f"选项后续模板文件未找到: {TEMPLATE_PATH}")
template_str = None
def generate_option_outcome(
scene_description: str,
option_text: str,
morality_ratios: Optional[Dict[str, float]] = None,
card_type: Optional[str] = None # 'good', 'evil', 'neutral' 或 None(未得牌)
) -> Dict[str, Any]:
"""
生成选项后续描述和卡牌信息。
参数:
scene_description: 当前轮次的场景描述文本
option_text: 玩家选择的选项文本
morality_ratios: 玩家道德比例,如 {'good':0.3, 'neutral':0.2, 'evil':0.5},可选
card_type: 获得的卡牌类型,'good'/'evil'/'neutral' 或 None(未得牌)
返回:
字典,包含以下字段:
{
"outcome": str, # 叙事结果文本
"card_name": Optional[str], # 如果 card_type 非 None,卡牌名称;否则 None
"card_description": Optional[str] # 如果 card_type 非 None,卡牌描述;否则 None
}
如果生成失败,返回包含默认值的字典。
"""
# 实现细节见下文
3.2 返回值说明
outcome:必选,字符串,描述选择后的直接结果,约30-100字。card_name:当card_type不为 None 时,必须提供;否则为 None。card_description:当card_type不为 None 时,必须提供;否则为 None。
四、提示词模板(option_outcome_prompt.txt)
将以下内容保存为 prompts/option_outcome_prompt.txt。
你是一位擅长修仙叙事的大师,需要根据给定的场景、玩家选择和道德倾向,生成一段结果描述,并可能为玩家获得的卡牌命名。
场景描述:{scene_description}
玩家选择:{option_text}
玩家道德倾向:善 {good_ratio:.0%},中立 {neutral_ratio:.0%},恶 {evil_ratio:.0%}
本次获得卡牌类型:{card_type_text}
请生成一个 JSON 对象,格式如下:
{
"outcome": "叙事结果,约30-100字,描述选择后的直接后果。",
"card_name": "如果获得卡牌,给卡牌起一个2-5字的名称,如'救人之心';否则为null",
"card_description": "如果获得卡牌,写一句10-20字的描述,说明卡牌的由来;否则为null"
}
要求:
1. 叙事结果要生动自然,符合修仙世界的氛围,与场景和选择紧密相关。
2. 如果获得卡牌,卡牌名称应富有修仙韵味,与事件相关;描述应简洁优雅。
3. 如果未获得卡牌(card_type 为“无”),则 card_name 和 card_description 必须为 null。
4. 道德倾向可作为微调语气的参考(例如善念高时,结果偏向慈悲;恶念高时偏向冷酷),但不要生硬套用。
5. 直接输出 JSON,不要包含额外内容。
注意:模板中的 {card_type_text} 需要在代码中根据 card_type 生成,例如:
- 如果
card_type为'good',则card_type_text = '善' - 如果为
'evil',则'恶' - 如果为
'neutral',则'中立' - 如果为
None,则'无'
五、默认值设计
当 LLM 调用失败或解析出错时,应返回默认结果,确保游戏流程不受影响。默认值应根据 card_type 生成,但为了简单,可以统一使用一组默认值,并确保字段正确。
DEFAULT_OUTCOME = "你的选择在幻境中激起一丝涟漪。"
DEFAULT_CARD_NAMES = {
'good': '善缘',
'evil': '恶果',
'neutral': '因果'
}
DEFAULT_CARD_DESCRIPTIONS = {
'good': '一次善举留下的印记。',
'evil': '一次恶行凝结的业力。',
'neutral': '一次谨慎观望的见证。'
}
在返回时,根据 card_type 填充对应的默认值。
六、实现步骤
- 检查模板:若
template_str为 None,记录错误并返回默认结果。 - 检查 LLM 和 API Key:若失败,返回默认结果。
- 准备填充数据:
good_ratio = morality_ratios.get('good', 0.0) if morality_ratios else 0.0 neutral_ratio = morality_ratios.get('neutral', 0.0) if morality_ratios else 0.0 evil_ratio = morality_ratios.get('evil', 0.0) if morality_ratios else 0.0 if card_type == 'good': card_type_text = '善' elif card_type == 'evil': card_type_text = '恶' elif card_type == 'neutral': card_type_text = '中立' else: card_type_text = '无' - 格式化提示词:
prompt = ChatPromptTemplate.from_template(template_str) formatted_prompt = prompt.format( scene_description=scene_description, option_text=option_text, good_ratio=good_ratio, neutral_ratio=neutral_ratio, evil_ratio=evil_ratio, card_type_text=card_type_text ) - 调用 LLM:使用
llm.invoke(formatted_prompt),可重试 2 次。 - 解析响应:复用
parse_llm_response(可从layer_event_generator复制或导入),去除 markdown 代码块,解析 JSON。 - 校验数据:
- 确保返回的字典包含
outcome字段。 - 如果
card_type非 None,则card_name和card_description不能为 None。 - 如果
card_type为 None,则card_name和card_description应为 None。 - 如果校验失败,记录警告并返回默认值。
- 确保返回的字典包含
- 返回结果。
七、测试建议
编写单元测试文件 tests/test_option_outcome_generator.py,至少覆盖:
- 成功生成:mock LLM 返回有效 JSON,验证返回结构正确,卡牌字段匹配
card_type。 - 无卡牌情况:
card_type=None,验证返回的card_name和card_description为 None。 - 解析错误:模拟 LLM 返回无效 JSON,验证返回默认值。
- 字段缺失:模拟 LLM 返回缺少字段的 JSON,验证返回默认值。
- 道德比例传入:验证提示词中包含正确的比例。
- 模板缺失:模拟模板文件不存在,验证返回默认值。
八、提交要求
- 创建
src/game_logic/option_outcome_generator.py,包含上述实现。 - 创建
prompts/option_outcome_prompt.txt,包含提示词内容。 - 创建
tests/test_option_outcome_generator.py,包含单元测试。 - 代码注释清晰,关键逻辑有说明。
- 确保所有测试通过。
开始实现吧!如有疑问,随时沟通。

浙公网安备 33010602011771号