|
@@ -6,17 +6,90 @@
|
|
|
|
|
|
|
|
import os
|
|
import os
|
|
|
import logging
|
|
import logging
|
|
|
|
|
+import subprocess
|
|
|
import httpx
|
|
import httpx
|
|
|
|
|
+from dataclasses import dataclass
|
|
|
from typing import List, Dict, Optional, Any
|
|
from typing import List, Dict, Optional, Any
|
|
|
from agent.tools import tool, ToolResult, ToolContext
|
|
from agent.tools import tool, ToolResult, ToolContext
|
|
|
|
|
+from agent.core.prompts import build_reflect_prompt, COMPLETION_REFLECT_PROMPT
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
-# KnowHub Server API 地址
|
|
|
|
|
-KNOWHUB_API = os.getenv("KNOWHUB_API", "http://43.106.118.91:9999")
|
|
|
|
|
|
|
+# KnowHub Server API 地址(去除末尾斜杠)
|
|
|
|
|
+KNOWHUB_API = os.getenv("KNOWHUB_API", "http://localhost:8000").rstrip("/")
|
|
|
|
|
|
|
|
|
|
|
|
|
-@tool(hidden_params=["context"])
|
|
|
|
|
|
|
+# ===== 知识管理配置 =====
|
|
|
|
|
+
|
|
|
|
|
+@dataclass
|
|
|
|
|
+class KnowledgeConfig:
|
|
|
|
|
+ """知识提取与注入的配置"""
|
|
|
|
|
+
|
|
|
|
|
+ # 压缩时提取(消息量超阈值触发压缩时,在 Level 1 过滤前用完整 history 反思)
|
|
|
|
|
+ enable_extraction: bool = True # 是否在压缩触发时提取知识
|
|
|
|
|
+ reflect_prompt: str = "" # 自定义反思 prompt;空则使用默认,见 agent/core/prompts/knowledge.py:REFLECT_PROMPT
|
|
|
|
|
+
|
|
|
|
|
+ # agent运行完成后提取(不代表任务完成,agent 可能中途退出等待人工评估)
|
|
|
|
|
+ enable_completion_extraction: bool = True # 是否在运行完成后提取知识
|
|
|
|
|
+ completion_reflect_prompt: str = "" # 自定义复盘 prompt;空则使用默认,见 agent/core/prompts/knowledge.py:COMPLETION_REFLECT_PROMPT
|
|
|
|
|
+
|
|
|
|
|
+ # 知识注入(agent切换当前工作的goal时,自动注入相关知识)
|
|
|
|
|
+ enable_injection: bool = True # 是否在 focus goal 时自动注入相关知识
|
|
|
|
|
+
|
|
|
|
|
+ # 默认字段(保存/搜索时自动注入)
|
|
|
|
|
+ owner: str = "" # 所有者(空则尝试从 git config user.email 获取,再空则用 agent:{agent_id})
|
|
|
|
|
+ default_tags: Optional[Dict[str, str]] = None # 默认 tags(会与工具调用参数合并)
|
|
|
|
|
+ default_scopes: Optional[List[str]] = None # 默认 scopes(空则用 ["org:cybertogether"])
|
|
|
|
|
+ default_search_types: Optional[List[str]] = None # 默认搜索类型过滤
|
|
|
|
|
+ default_search_owner: str = "" # 默认搜索 owner 过滤(空则不过滤,支持多个owner用逗号分隔,如 "user1@example.com,user2@example.com")
|
|
|
|
|
+
|
|
|
|
|
+ def get_reflect_prompt(self) -> str:
|
|
|
|
|
+ """压缩时反思 prompt"""
|
|
|
|
|
+ return self.reflect_prompt if self.reflect_prompt else build_reflect_prompt()
|
|
|
|
|
+
|
|
|
|
|
+ def get_completion_reflect_prompt(self) -> str:
|
|
|
|
|
+ """任务完成后复盘 prompt"""
|
|
|
|
|
+ return self.completion_reflect_prompt if self.completion_reflect_prompt else COMPLETION_REFLECT_PROMPT
|
|
|
|
|
+
|
|
|
|
|
+ @property
|
|
|
|
|
+ def resolved_owner(self) -> str:
|
|
|
|
|
+ """解析后的 owner(优先级:配置 > git email > 'agent')
|
|
|
|
|
+
|
|
|
|
|
+ 供 inject_params key path 使用:knowledge_config.resolved_owner
|
|
|
|
|
+ """
|
|
|
|
|
+ if self.owner:
|
|
|
|
|
+ return self.owner
|
|
|
|
|
+
|
|
|
|
|
+ # 尝试从 git config 获取
|
|
|
|
|
+ try:
|
|
|
|
|
+ result = subprocess.run(
|
|
|
|
|
+ ["git", "config", "user.email"],
|
|
|
|
|
+ capture_output=True,
|
|
|
|
|
+ text=True,
|
|
|
|
|
+ timeout=2,
|
|
|
|
|
+ )
|
|
|
|
|
+ if result.returncode == 0 and result.stdout.strip():
|
|
|
|
|
+ return result.stdout.strip()
|
|
|
|
|
+ except Exception:
|
|
|
|
|
+ pass
|
|
|
|
|
+
|
|
|
|
|
+ return "agent"
|
|
|
|
|
+
|
|
|
|
|
+ def get_owner(self, agent_id: str = "agent") -> str:
|
|
|
|
|
+ """获取 owner(优先级:配置 > git email > agent:{agent_id})"""
|
|
|
|
|
+ owner = self.resolved_owner
|
|
|
|
|
+ if owner == "agent" and agent_id != "agent":
|
|
|
|
|
+ return f"agent:{agent_id}"
|
|
|
|
|
+ return owner
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@tool(
|
|
|
|
|
+ hidden_params=["context"],
|
|
|
|
|
+ inject_params={
|
|
|
|
|
+ "types": {"mode": "default", "key": "knowledge_config.default_search_types"},
|
|
|
|
|
+ "owner": {"mode": "default", "key": "knowledge_config.default_search_owner"},
|
|
|
|
|
+ }
|
|
|
|
|
+)
|
|
|
async def knowledge_search(
|
|
async def knowledge_search(
|
|
|
query: str,
|
|
query: str,
|
|
|
top_k: int = 5,
|
|
top_k: int = 5,
|
|
@@ -33,7 +106,7 @@ async def knowledge_search(
|
|
|
top_k: 返回数量(默认 5)
|
|
top_k: 返回数量(默认 5)
|
|
|
min_score: 最低评分过滤(默认 3)
|
|
min_score: 最低评分过滤(默认 3)
|
|
|
types: 按类型过滤(user_profile/strategy/tool/usecase/definition/plan)
|
|
types: 按类型过滤(user_profile/strategy/tool/usecase/definition/plan)
|
|
|
- owner: 按所有者过滤(可选)
|
|
|
|
|
|
|
+ owner: 按所有者过滤(可选,支持多个owner用逗号分隔的字符串,如 "user1@example.com,user2@example.com")
|
|
|
context: 工具上下文
|
|
context: 工具上下文
|
|
|
|
|
|
|
|
Returns:
|
|
Returns:
|
|
@@ -72,8 +145,8 @@ async def knowledge_search(
|
|
|
eval_data = item.get("eval", {})
|
|
eval_data = item.get("eval", {})
|
|
|
score = eval_data.get("score", 3)
|
|
score = eval_data.get("score", 3)
|
|
|
output_lines.append(f"\n### {idx}. [{item['id']}] (⭐ {score})")
|
|
output_lines.append(f"\n### {idx}. [{item['id']}] (⭐ {score})")
|
|
|
- output_lines.append(f"**任务**: {item['task'][:150]}...")
|
|
|
|
|
- output_lines.append(f"**内容**: {item['content'][:200]}...")
|
|
|
|
|
|
|
+ output_lines.append(f"**任务**: {item['task']}")
|
|
|
|
|
+ output_lines.append(f"**内容**: {item['content']}")
|
|
|
|
|
|
|
|
return ToolResult(
|
|
return ToolResult(
|
|
|
title="✅ 知识检索成功",
|
|
title="✅ 知识检索成功",
|
|
@@ -98,12 +171,9 @@ async def knowledge_search(
|
|
|
@tool(
|
|
@tool(
|
|
|
hidden_params=["context", "owner"],
|
|
hidden_params=["context", "owner"],
|
|
|
inject_params={
|
|
inject_params={
|
|
|
- "owner": lambda ctx: ctx.get("knowledge_config", {}).get("owner") if ctx else None,
|
|
|
|
|
- "tags": lambda ctx, args: {
|
|
|
|
|
- **ctx.get("knowledge_config", {}).get("default_tags", {}),
|
|
|
|
|
- **(args.get("tags") or {})
|
|
|
|
|
- } if ctx else args.get("tags"),
|
|
|
|
|
- "scopes": lambda ctx, args: (args.get("scopes") or []) + (ctx.get("knowledge_config", {}).get("default_scopes") or []) if ctx else args.get("scopes"),
|
|
|
|
|
|
|
+ "owner": {"mode": "default", "key": "knowledge_config.resolved_owner"},
|
|
|
|
|
+ "tags": {"mode": "merge", "key": "knowledge_config.default_tags"},
|
|
|
|
|
+ "scopes": {"mode": "merge", "key": "knowledge_config.default_scopes"},
|
|
|
}
|
|
}
|
|
|
)
|
|
)
|
|
|
async def knowledge_save(
|
|
async def knowledge_save(
|