| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- """
- 人设树常量点检索工具 - 根据人设名称提取所有常量点
- 用于 Agent 执行时自主提取人设树中的常量点。
- """
- import json
- from pathlib import Path
- from typing import Any, Dict, List
- from agent.tools import tool, ToolResult
- # 人设数据基础路径
- PERSONA_DATA_BASE_PATH = Path(__file__).parent.parent / "data"
- def _extract_constant_points(tree_data: Dict[str, Any], dimension: str, path_prefix: str = "") -> List[Dict[str, Any]]:
- """
- 递归提取树中所有常量点
- Args:
- tree_data: 树节点数据
- dimension: 维度类型(形式/实质/意图)
- path_prefix: 当前路径前缀
- Returns:
- 常量点列表
- """
- constant_points = []
- for node_name, node_data in tree_data.items():
- # 跳过元数据字段
- if node_name.startswith("_"):
- continue
- # 构建当前节点的路径
- current_path = f"{path_prefix}>{node_name}" if path_prefix else node_name
- # 检查是否为常量点:_type 为 "ID" 且 _is_constant 为 true
- if isinstance(node_data, dict):
- node_type = node_data.get("_type")
- is_constant = node_data.get("_is_constant", False)
- if node_type == "ID" and is_constant:
- constant_points.append({
- "点名称": node_name,
- "维度": dimension,
- "路径": current_path,
- "权重": node_data.get("_persona_weight_score", 0),
- "帖子数量": node_data.get("_post_count", 0)
- })
- # 递归处理子节点
- if "children" in node_data:
- child_points = _extract_constant_points(
- node_data["children"],
- dimension,
- current_path
- )
- constant_points.extend(child_points)
- return constant_points
- def _load_persona_tree(persona_name: str) -> Dict[str, List[Dict[str, Any]]]:
- """
- 加载人设树数据并提取所有常量点
- Args:
- persona_name: 人设名称,如 "家有大志"
- Returns:
- 包含三个维度常量点的字典
- """
- persona_dir = PERSONA_DATA_BASE_PATH / persona_name / "tree"
- if not persona_dir.exists():
- return {
- "found": False,
- "persona_name": persona_name,
- "error": f"人设目录不存在: {persona_dir}"
- }
- tree_files = {
- "形式": persona_dir / "形式_point_tree_how.json",
- "实质": persona_dir / "实质_point_tree_how.json",
- "意图": persona_dir / "意图_point_tree_how.json"
- }
- all_constant_points = {
- "形式": [],
- "实质": [],
- "意图": []
- }
- missing_files = []
- for dimension, tree_file in tree_files.items():
- if not tree_file.exists():
- missing_files.append(f"{dimension}_point_tree_how.json")
- continue
- try:
- with open(tree_file, 'r', encoding='utf-8') as f:
- tree_data = json.load(f)
- # 提取该维度的所有常量点
- constant_points = _extract_constant_points(tree_data, dimension)
- all_constant_points[dimension] = constant_points
- except Exception as e:
- return {
- "found": False,
- "persona_name": persona_name,
- "error": f"读取文件 {tree_file.name} 失败: {str(e)}"
- }
- if missing_files:
- return {
- "found": False,
- "persona_name": persona_name,
- "error": f"缺失文件: {', '.join(missing_files)}"
- }
- return {
- "found": True,
- "persona_name": persona_name,
- "constant_points": all_constant_points
- }
- @tool(
- description="根据人设名称检索该人设树中的所有常量点(_is_constant=true的点)。",
- display={
- "zh": {
- "name": "人设常量点检索",
- "params": {
- "persona_name": "人设名称(如:家有大志)",
- },
- },
- },
- )
- async def search_person_tree_constants(persona_name: str) -> ToolResult:
- """
- 根据人设名称检索该人设树中的所有常量点。
- 常量点是指人设树中 _type 为 "ID" 且 _is_constant 为 true 的节点。
- 这些点代表了该人设的核心特征和固定属性。
- Args:
- persona_name: 人设名称,如 "家有大志"
- Returns:
- ToolResult: 包含三个维度(形式、实质、意图)的常量点列表
- """
- if not persona_name:
- return ToolResult(
- title="人设常量点检索失败",
- output="",
- error="请提供人设名称",
- )
- try:
- result = _load_persona_tree(persona_name)
- except Exception as e:
- return ToolResult(
- title="人设常量点检索失败",
- output="",
- error=f"检索异常: {str(e)}",
- )
- if not result.get("found"):
- return ToolResult(
- title="人设常量点检索失败",
- output="",
- error=result.get("error", "未知错误"),
- )
- constant_points = result["constant_points"]
- # 统计信息
- total_count = sum(len(points) for points in constant_points.values())
- # 格式化输出
- output_data = {
- "人设名称": persona_name,
- "常量点总数": total_count,
- "形式常量点": constant_points["形式"],
- "实质常量点": constant_points["实质"],
- "意图常量点": constant_points["意图"],
- "统计": {
- "形式点数": len(constant_points["形式"]),
- "实质点数": len(constant_points["实质"]),
- "意图点数": len(constant_points["意图"])
- }
- }
- output = json.dumps(output_data, ensure_ascii=False, indent=2)
- return ToolResult(
- title=f"人设常量点检索 - {persona_name}",
- output=output,
- long_term_memory=f"检索到 {total_count} 个常量点(形式:{len(constant_points['形式'])},实质:{len(constant_points['实质'])},意图:{len(constant_points['意图'])})",
- )
|