feat(prompt): 优化系统提示词并增强节点验证逻辑

本次提交旨在提升大模型对行为树生成的理解能力和准确性,主要包含两方面的改进:丰富提示词内容和加强生成逻辑的验证。

具体文件变更如下:

- **backend_service/src/prompts/system_prompt.txt**:
  - 在系统提示词中,增加了更多关于可用节点的详细说明。
  - 补充了多个高质量的行为树生成示例(few-shot examples),以引导模型输出更符合预期的格式。

- **backend_service/src/py_tree_generator.py**:
  - 优化了对模型生成结果的验证规则,使其能更严格地检查节点的父子关系和参数合法性。
  - 修复了当模型生成无效节点时可能出现的潜在错误。

- **backend_service/requirements.txt**:
  - 更新了相关依赖库版本。
This commit is contained in:
2025-08-25 20:35:41 +08:00
parent 6477748c43
commit 0ef139b538
10 changed files with 397 additions and 117 deletions

View File

@@ -51,64 +51,124 @@ logging.basicConfig(
def _parse_allowed_nodes_from_prompt(prompt_text: str) -> tuple[Set[str], Set[str]]:
"""
从系统提示词中解析出允许的行动和条件节点。
从系统提示词中精确解析出允许的行动和条件节点。
"""
try:
# 使用正则表达式查找JSON代码块
match = re.search(r"```json\s*({.*?})\s*```", prompt_text, re.DOTALL)
# 使用更精确的正则表达式匹配节点定义部分
node_section_pattern = r"#### 2\. 可用节点定义.*?```json\s*({.*?})\s*```"
match = re.search(node_section_pattern, prompt_text, re.DOTALL | re.IGNORECASE)
if not match:
logging.error("在系统提示词中未找到可用节点的JSON定义块。")
return set(), set()
logging.error("在系统提示词中未找到'可用节点定义'部分的JSON代码块。")
# 备用方案尝试查找所有JSON块并识别节点定义
return _fallback_parse_nodes(prompt_text)
json_str = match.group(1)
logging.info("成功找到节点定义JSON代码块")
# 解析JSON
allowed_nodes = json.loads(json_str)
# 从对象列表中提取节点名称
actions = {action['name'] for action in allowed_nodes.get("actions", []) if 'name' in action}
conditions = {condition['name'] for condition in allowed_nodes.get("conditions", []) if 'name' in condition}
actions = set()
conditions = set()
# 提取动作节点
if "actions" in allowed_nodes and isinstance(allowed_nodes["actions"], list):
for action in allowed_nodes["actions"]:
if isinstance(action, dict) and "name" in action:
actions.add(action["name"])
# 提取条件节点
if "conditions" in allowed_nodes and isinstance(allowed_nodes["conditions"], list):
for condition in allowed_nodes["conditions"]:
if isinstance(condition, dict) and "name" in condition:
conditions.add(condition["name"])
if not actions:
logging.warning("关键错误:从提示词解析出的行动节点列表为空,无法生成任何有效任务")
logging.warning("关键错误:从提示词解析出的行动节点列表为空。")
logging.info(f"成功解析出动作节点: {sorted(actions)}")
logging.info(f"成功解析出条件节点: {sorted(conditions)}")
return actions, conditions
except json.JSONDecodeError:
logging.error("解析系统提示词中的JSON时失败。请检查格式。")
except json.JSONDecodeError as e:
logging.error(f"解析节点定义JSON时失败: {e}")
return set(), set()
except Exception as e:
logging.error(f"解析可用节点时发生未知错误: {e}")
return set(), set()
def _fallback_parse_nodes(prompt_text: str) -> tuple[Set[str], Set[str]]:
"""
备用解析方案:当精确匹配失败时使用。
"""
logging.warning("使用备用方案解析节点定义...")
# 查找所有JSON代码块
matches = re.findall(r"```json\s*({.*?})\s*```", prompt_text, re.DOTALL)
if not matches:
logging.error("在系统提示词中未找到任何JSON代码块。")
return set(), set()
# 尝试从每个JSON块中解析节点定义
for i, json_str in enumerate(matches):
try:
data = json.loads(json_str)
# 检查是否是节点定义的结构包含actions、conditions、control_flow
if ("actions" in data and isinstance(data["actions"], list) and
"conditions" in data and isinstance(data["conditions"], list) and
"control_flow" in data and isinstance(data["control_flow"], list)):
actions = set()
conditions = set()
# 提取动作节点
for action in data["actions"]:
if isinstance(action, dict) and "name" in action:
actions.add(action["name"])
# 提取条件节点
for condition in data["conditions"]:
if isinstance(condition, dict) and "name" in condition:
conditions.add(condition["name"])
if actions:
logging.info(f"从第{i+1}个JSON块中成功解析出节点定义")
logging.info(f"动作节点: {sorted(actions)}")
logging.info(f"条件节点: {sorted(conditions)}")
return actions, conditions
except json.JSONDecodeError:
continue # 尝试下一个JSON块
logging.error("在所有JSON代码块中都没有找到有效的节点定义结构。")
return set(), set()
def _generate_pytree_schema(allowed_actions: set, allowed_conditions: set) -> dict:
"""
根据允许的行动和条件节点动态生成一个JSON Schema。
"""
# 所有可能的节点类型
node_types = ["action", "condition", "Sequence", "Selector", "Parallel"]
# 递归节点定义
node_definition = {
"type": "object",
"properties": {
"type": {"type": "string", "enum": ["action", "condition", "Sequence", "Selector"]},
"name": {"type": "string"},
"type": {"type": "string", "enum": node_types},
"name": {"type": "string"}, # 放宽对name的验证
"params": {"type": "object"},
"children": {
"type": "array",
"items": {"$ref": "#/definitions/node"}
}
},
"required": ["type", "name"],
# 使用 allOf 和 if/then 来实现基于'type'字段的条件性'name'验证
"allOf": [
{
"if": {"properties": {"type": {"const": "action"}}},
"then": {"properties": {"name": {"enum": sorted(list(allowed_actions))}}}
},
{
"if": {"properties": {"type": {"const": "condition"}}},
"then": {"properties": {"name": {"enum": sorted(list(allowed_conditions))}}}
}
]
"required": ["type", "name"]
}
# 完整的Schema结构
schema = {
"$schema": "http://json-schema.org/draft-07/schema#",
@@ -122,6 +182,7 @@ def _generate_pytree_schema(allowed_actions: set, allowed_conditions: set) -> di
},
"required": ["root"]
}
return schema
def _validate_pytree_with_schema(pytree_instance: dict, schema: dict) -> bool: