254 lines
9.1 KiB
Python
254 lines
9.1 KiB
Python
|
|
"""
|
|||
|
|
SubAgent配置测试
|
|||
|
|
|
|||
|
|
测试所有SubAgent配置是否符合DeepAgents框架规范
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import sys
|
|||
|
|
import os
|
|||
|
|
|
|||
|
|
# 添加src目录到Python路径
|
|||
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
|||
|
|
|
|||
|
|
import pytest
|
|||
|
|
from src.agents.subagents import (
|
|||
|
|
get_subagent_configs,
|
|||
|
|
validate_subagent_config,
|
|||
|
|
get_validated_subagent_configs
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TestSubAgentConfigs:
|
|||
|
|
"""SubAgent配置测试类"""
|
|||
|
|
|
|||
|
|
def test_subagent_count(self):
|
|||
|
|
"""测试SubAgent数量"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
assert len(configs) == 6, f"应该有6个SubAgent,实际有{len(configs)}个"
|
|||
|
|
|
|||
|
|
def test_required_fields(self):
|
|||
|
|
"""测试所有必需字段是否存在"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
required_fields = ["name", "description", "system_prompt"]
|
|||
|
|
|
|||
|
|
for config in configs:
|
|||
|
|
for field in required_fields:
|
|||
|
|
assert field in config, f"SubAgent {config.get('name', 'unknown')} 缺少必需字段: {field}"
|
|||
|
|
|
|||
|
|
def test_name_format(self):
|
|||
|
|
"""测试name是否使用kebab-case格式"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
|
|||
|
|
for config in configs:
|
|||
|
|
name = config["name"]
|
|||
|
|
# 检查是否只包含小写字母和连字符
|
|||
|
|
assert all(c.islower() or c == '-' for c in name), \
|
|||
|
|
f"SubAgent name必须使用kebab-case格式: {name}"
|
|||
|
|
# 不应该以连字符开始或结束
|
|||
|
|
assert not name.startswith('-') and not name.endswith('-'), \
|
|||
|
|
f"SubAgent name不应该以连字符开始或结束: {name}"
|
|||
|
|
|
|||
|
|
def test_system_prompt_not_empty(self):
|
|||
|
|
"""测试system_prompt不为空"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
|
|||
|
|
for config in configs:
|
|||
|
|
system_prompt = config.get("system_prompt", "")
|
|||
|
|
assert system_prompt.strip(), \
|
|||
|
|
f"SubAgent {config['name']} 的system_prompt不能为空"
|
|||
|
|
# 检查system_prompt应该相当详细(至少500字符)
|
|||
|
|
assert len(system_prompt) > 500, \
|
|||
|
|
f"SubAgent {config['name']} 的system_prompt过短(应该>500字符)"
|
|||
|
|
|
|||
|
|
def test_no_prompt_field(self):
|
|||
|
|
"""测试配置中不应该使用'prompt'字段(常见错误)"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
|
|||
|
|
for config in configs:
|
|||
|
|
assert "prompt" not in config, \
|
|||
|
|
f"SubAgent {config['name']} 使用了错误的字段'prompt',应该使用'system_prompt'"
|
|||
|
|
|
|||
|
|
def test_description_present(self):
|
|||
|
|
"""测试description字段存在且有意义"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
|
|||
|
|
for config in configs:
|
|||
|
|
description = config.get("description", "")
|
|||
|
|
assert description.strip(), \
|
|||
|
|
f"SubAgent {config['name']} 的description不能为空"
|
|||
|
|
# 描述应该简洁(10-100字符)
|
|||
|
|
assert 10 <= len(description) <= 200, \
|
|||
|
|
f"SubAgent {config['name']} 的description长度不合适(应该10-200字符)"
|
|||
|
|
|
|||
|
|
def test_tools_field_type(self):
|
|||
|
|
"""测试tools字段类型正确"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
|
|||
|
|
for config in configs:
|
|||
|
|
if "tools" in config:
|
|||
|
|
assert isinstance(config["tools"], list), \
|
|||
|
|
f"SubAgent {config['name']} 的tools字段应该是列表"
|
|||
|
|
|
|||
|
|
def test_specific_subagent_names(self):
|
|||
|
|
"""测试6个SubAgent的具体名称"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
expected_names = {
|
|||
|
|
"intent-analyzer",
|
|||
|
|
"search-orchestrator",
|
|||
|
|
"source-validator",
|
|||
|
|
"content-analyzer",
|
|||
|
|
"confidence-evaluator",
|
|||
|
|
"report-generator"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
actual_names = {config["name"] for config in configs}
|
|||
|
|
assert actual_names == expected_names, \
|
|||
|
|
f"SubAgent名称不匹配。期望: {expected_names}, 实际: {actual_names}"
|
|||
|
|
|
|||
|
|
def test_system_prompt_mentions_files(self):
|
|||
|
|
"""测试system_prompt是否提到虚拟文件系统路径"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
|
|||
|
|
# 某些SubAgent应该在system_prompt中提到文件路径
|
|||
|
|
file_related_agents = [
|
|||
|
|
"intent-analyzer",
|
|||
|
|
"search-orchestrator",
|
|||
|
|
"source-validator",
|
|||
|
|
"content-analyzer",
|
|||
|
|
"confidence-evaluator",
|
|||
|
|
"report-generator"
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
for config in configs:
|
|||
|
|
if config["name"] in file_related_agents:
|
|||
|
|
system_prompt = config["system_prompt"]
|
|||
|
|
# 检查是否提到虚拟文件系统(以/开头的路径)
|
|||
|
|
assert "/" in system_prompt, \
|
|||
|
|
f"SubAgent {config['name']} 的system_prompt应该提到虚拟文件系统路径"
|
|||
|
|
|
|||
|
|
def test_search_orchestrator_has_tools(self):
|
|||
|
|
"""测试search-orchestrator应该有搜索工具"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
|
|||
|
|
search_orchestrator = next(
|
|||
|
|
(c for c in configs if c["name"] == "search-orchestrator"),
|
|||
|
|
None
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
assert search_orchestrator is not None, "未找到search-orchestrator"
|
|||
|
|
assert "tools" in search_orchestrator, "search-orchestrator应该有tools字段"
|
|||
|
|
assert len(search_orchestrator["tools"]) > 0, \
|
|||
|
|
"search-orchestrator应该至少有一个工具"
|
|||
|
|
|
|||
|
|
def test_validate_function(self):
|
|||
|
|
"""测试validate_subagent_config函数"""
|
|||
|
|
# 有效配置
|
|||
|
|
valid_config = {
|
|||
|
|
"name": "test-agent",
|
|||
|
|
"description": "测试agent",
|
|||
|
|
"system_prompt": "这是一个测试prompt"
|
|||
|
|
}
|
|||
|
|
assert validate_subagent_config(valid_config) == True
|
|||
|
|
|
|||
|
|
# 缺少必需字段
|
|||
|
|
invalid_config = {
|
|||
|
|
"name": "test-agent",
|
|||
|
|
"description": "测试agent"
|
|||
|
|
# 缺少system_prompt
|
|||
|
|
}
|
|||
|
|
with pytest.raises(ValueError, match="缺少必需字段"):
|
|||
|
|
validate_subagent_config(invalid_config)
|
|||
|
|
|
|||
|
|
# 错误的name格式
|
|||
|
|
invalid_name_config = {
|
|||
|
|
"name": "TestAgent", # 应该是kebab-case
|
|||
|
|
"description": "测试agent",
|
|||
|
|
"system_prompt": "测试"
|
|||
|
|
}
|
|||
|
|
with pytest.raises(ValueError, match="kebab-case"):
|
|||
|
|
validate_subagent_config(invalid_name_config)
|
|||
|
|
|
|||
|
|
def test_get_validated_configs(self):
|
|||
|
|
"""测试get_validated_subagent_configs函数"""
|
|||
|
|
configs = get_validated_subagent_configs()
|
|||
|
|
assert len(configs) == 6, "应该返回6个经过验证的SubAgent配置"
|
|||
|
|
|
|||
|
|
def test_system_prompt_structure(self):
|
|||
|
|
"""测试system_prompt是否有良好的结构"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
|
|||
|
|
for config in configs:
|
|||
|
|
system_prompt = config["system_prompt"]
|
|||
|
|
|
|||
|
|
# 应该有清晰的任务说明
|
|||
|
|
assert any(keyword in system_prompt for keyword in ["任务", "流程", "步骤"]), \
|
|||
|
|
f"SubAgent {config['name']} 的system_prompt应该包含任务说明"
|
|||
|
|
|
|||
|
|
# 应该有输入输出说明
|
|||
|
|
assert any(keyword in system_prompt for keyword in ["输入", "输出", "读取", "写入"]), \
|
|||
|
|
f"SubAgent {config['name']} 的system_prompt应该包含输入输出说明"
|
|||
|
|
|
|||
|
|
def test_confidence_evaluator_mentions_formula(self):
|
|||
|
|
"""测试confidence-evaluator是否提到置信度计算公式"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
|
|||
|
|
confidence_evaluator = next(
|
|||
|
|
(c for c in configs if c["name"] == "confidence-evaluator"),
|
|||
|
|
None
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
assert confidence_evaluator is not None
|
|||
|
|
system_prompt = confidence_evaluator["system_prompt"]
|
|||
|
|
|
|||
|
|
# 应该提到公式和百分比
|
|||
|
|
assert "50%" in system_prompt and "30%" in system_prompt and "20%" in system_prompt, \
|
|||
|
|
"confidence-evaluator应该包含置信度计算公式(50%+30%+20%)"
|
|||
|
|
|
|||
|
|
def test_source_validator_mentions_tiers(self):
|
|||
|
|
"""测试source-validator是否提到Tier分级"""
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
|
|||
|
|
source_validator = next(
|
|||
|
|
(c for c in configs if c["name"] == "source-validator"),
|
|||
|
|
None
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
assert source_validator is not None
|
|||
|
|
system_prompt = source_validator["system_prompt"]
|
|||
|
|
|
|||
|
|
# 应该提到Tier 1-4
|
|||
|
|
for tier in ["Tier 1", "Tier 2", "Tier 3", "Tier 4"]:
|
|||
|
|
assert tier in system_prompt or tier.replace(" ", "") in system_prompt, \
|
|||
|
|
f"source-validator应该包含{tier}分级说明"
|
|||
|
|
|
|||
|
|
|
|||
|
|
def print_subagent_summary():
|
|||
|
|
"""打印SubAgent配置摘要"""
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
print("SubAgent配置摘要")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
configs = get_subagent_configs()
|
|||
|
|
|
|||
|
|
for i, config in enumerate(configs, 1):
|
|||
|
|
print(f"\n{i}. {config['name']}")
|
|||
|
|
print(f" 描述: {config['description']}")
|
|||
|
|
print(f" System Prompt长度: {len(config['system_prompt'])} 字符")
|
|||
|
|
if "tools" in config:
|
|||
|
|
print(f" 工具数量: {len(config['tools'])}")
|
|||
|
|
else:
|
|||
|
|
print(f" 工具数量: 0")
|
|||
|
|
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
# 运行测试
|
|||
|
|
print("运行SubAgent配置测试...\n")
|
|||
|
|
|
|||
|
|
# 打印摘要
|
|||
|
|
print_subagent_summary()
|
|||
|
|
|
|||
|
|
# 使用pytest运行测试
|
|||
|
|
pytest.main([__file__, "-v", "--tb=short"])
|