|
|
@@ -22,7 +22,7 @@ root_dir = os.path.dirname(current_dir)
|
|
|
sys.path.insert(0, root_dir)
|
|
|
|
|
|
from utils.gemini_client import generate_text
|
|
|
-from knowledge_v2.tools_library import call_tool, save_tool_info, get_all_tool_infos, get_tool_info
|
|
|
+from knowledge_v2.tools_library import call_tool, save_tool_info, get_all_tool_infos, get_tool_info, get_tool_params
|
|
|
from knowledge_v2.multi_search_knowledge import get_knowledge as get_multi_search_knowledge
|
|
|
from knowledge_v2.cache_manager import CacheManager
|
|
|
|
|
|
@@ -55,7 +55,7 @@ class FunctionKnowledge:
|
|
|
logger.info("=" * 80)
|
|
|
|
|
|
def _save_execution_detail(self, cache_key: str):
|
|
|
- """保存执行详情到缓存(支持合并旧记录)"""
|
|
|
+ """保存执行详情到缓存"""
|
|
|
if not self.use_cache or not self.cache:
|
|
|
return
|
|
|
|
|
|
@@ -70,37 +70,8 @@ class FunctionKnowledge:
|
|
|
os.makedirs(detail_dir, exist_ok=True)
|
|
|
|
|
|
detail_file = os.path.join(detail_dir, 'execution_detail.json')
|
|
|
-
|
|
|
- # 准备最终要保存的数据,默认为当前内存中的数据
|
|
|
- final_detail = self.execution_detail.copy()
|
|
|
-
|
|
|
- # 尝试读取旧文件进行合并
|
|
|
- if os.path.exists(detail_file):
|
|
|
- try:
|
|
|
- with open(detail_file, 'r', encoding='utf-8') as f:
|
|
|
- old_detail = json.load(f)
|
|
|
-
|
|
|
- # 智能合并逻辑:保留更有价值的历史信息
|
|
|
- for key, new_val in self.execution_detail.items():
|
|
|
- # 跳过非字典字段或旧文件中不存在的字段
|
|
|
- if not isinstance(new_val, dict) or key not in old_detail:
|
|
|
- continue
|
|
|
-
|
|
|
- old_val = old_detail[key]
|
|
|
- if not isinstance(old_val, dict):
|
|
|
- continue
|
|
|
-
|
|
|
- # 核心逻辑:如果新记录是缓存命中(cached=True),而旧记录包含prompt(说明是当初生成的)
|
|
|
- # 则保留旧记录,防止被简略信息覆盖
|
|
|
- if new_val.get("cached", False) is True and "prompt" in old_val:
|
|
|
- # logger.debug(f" 保留 {key} 的历史详细记录")
|
|
|
- final_detail[key] = old_val
|
|
|
-
|
|
|
- except Exception as e:
|
|
|
- logger.warning(f" ⚠ 读取旧详情失败,将使用新记录: {e}")
|
|
|
-
|
|
|
with open(detail_file, 'w', encoding='utf-8') as f:
|
|
|
- json.dump(final_detail, f, ensure_ascii=False, indent=2)
|
|
|
+ json.dump(self.execution_detail, f, ensure_ascii=False, indent=2)
|
|
|
|
|
|
logger.info(f"✓ 执行详情已保存: {detail_file}")
|
|
|
|
|
|
@@ -138,7 +109,11 @@ class FunctionKnowledge:
|
|
|
|
|
|
try:
|
|
|
prompt_template = self._load_prompt("function_generate_query_prompt.md")
|
|
|
- prompt = prompt_template.replace("{question}", question)
|
|
|
+ prompt = prompt_template.format(
|
|
|
+ question=question,
|
|
|
+ post_info=post_info,
|
|
|
+ persona_info=persona_info
|
|
|
+ )
|
|
|
|
|
|
logger.info("→ 调用Gemini生成Query...")
|
|
|
query = generate_text(prompt=prompt)
|
|
|
@@ -172,20 +147,8 @@ class FunctionKnowledge:
|
|
|
"""
|
|
|
logger.info(f"[步骤2] 选择工具...")
|
|
|
|
|
|
- # 尝试从缓存读取
|
|
|
- if self.use_cache:
|
|
|
- cached_tool = self.cache.get(combined_question, 'function_knowledge', 'selected_tool.txt')
|
|
|
- if cached_tool:
|
|
|
- logger.info(f"✓ 使用缓存的工具: {cached_tool}")
|
|
|
- # 记录缓存命中
|
|
|
- self.execution_detail["select_tool"].update({
|
|
|
- "cached": True,
|
|
|
- "tool_name": cached_tool
|
|
|
- })
|
|
|
- return cached_tool
|
|
|
-
|
|
|
try:
|
|
|
- all_tool_infos = self._load_prompt("all_tools_infos.md")
|
|
|
+ all_tool_infos = get_all_tool_infos()
|
|
|
if not all_tool_infos:
|
|
|
logger.info(" 工具库为空,无可用工具")
|
|
|
return "None"
|
|
|
@@ -194,36 +157,48 @@ class FunctionKnowledge:
|
|
|
logger.info(f" 当前可用工具数: {tool_count}")
|
|
|
|
|
|
prompt_template = self._load_prompt("function_knowledge_select_tools_prompt.md")
|
|
|
- prompt = prompt_template.replace("{all_tool_infos}", all_tool_infos)
|
|
|
+ prompt = prompt_template.format(
|
|
|
+ query=query,
|
|
|
+ tool_infos=all_tool_infos
|
|
|
+ )
|
|
|
+
|
|
|
+ # 尝试从缓存读取
|
|
|
+ if self.use_cache:
|
|
|
+ cached_tool = self.cache.get(combined_question, 'function_knowledge', 'selected_tool.txt')
|
|
|
+ if cached_tool:
|
|
|
+ logger.info(f"✓ 使用缓存的工具: {cached_tool}")
|
|
|
+ # 记录缓存命中
|
|
|
+ self.execution_detail["select_tool"].update({
|
|
|
+ "cached": True,
|
|
|
+ "response": json.loads(cached_tool),
|
|
|
+ "prompt": prompt,
|
|
|
+ })
|
|
|
+ return json.loads(cached_tool)
|
|
|
|
|
|
logger.info("→ 调用Gemini选择工具...")
|
|
|
result = generate_text(prompt=prompt)
|
|
|
- result_json = json.loads(result)
|
|
|
- tool_name = result_json.get('工具名', '')
|
|
|
- tool_mcp_name = result_json.get('工具调用ID', '')
|
|
|
- tool_instructions = result_json.get('使用方法', '')
|
|
|
-
|
|
|
- logger.info(f"✓ 选择结果: {tool_name}")
|
|
|
+ result_json = result.loads(result)
|
|
|
+
|
|
|
+ logger.info(f"✓ 选择结果: {result_json.get('工具名', 'None')}")
|
|
|
|
|
|
# 写入缓存
|
|
|
if self.use_cache:
|
|
|
- self.cache.set(combined_question, 'function_knowledge', 'selected_tool.txt', tool_name)
|
|
|
+ self.cache.set(combined_question, 'function_knowledge', 'selected_tool.txt', result)
|
|
|
|
|
|
# 记录详情
|
|
|
self.execution_detail["select_tool"] = {
|
|
|
"cached": False,
|
|
|
"prompt": prompt,
|
|
|
- "response": tool_name,
|
|
|
- "tool_name": tool_name,
|
|
|
+ "response": result_json,
|
|
|
"available_tools_count": tool_count
|
|
|
}
|
|
|
|
|
|
- return tool_name
|
|
|
+ return result_json
|
|
|
except Exception as e:
|
|
|
logger.error(f"✗ 选择工具失败: {e}")
|
|
|
return "None"
|
|
|
|
|
|
- def extract_tool_params(self, combined_question: str, tool_name: str, query: str) -> dict:
|
|
|
+ def extract_tool_params(self, combined_question: str, query: str, tool_id: str, tool_instructions: str) -> dict:
|
|
|
"""
|
|
|
根据工具信息和查询提取调用参数
|
|
|
|
|
|
@@ -251,18 +226,16 @@ class FunctionKnowledge:
|
|
|
|
|
|
try:
|
|
|
# 获取工具信息
|
|
|
- tool_info = get_tool_info(tool_name)
|
|
|
- if not tool_info:
|
|
|
- logger.warning(f" ⚠ 未找到工具 {tool_name} 的信息,使用默认参数")
|
|
|
+ tool_params = get_tool_params(tool_id)
|
|
|
+ if not tool_params:
|
|
|
+ logger.warning(f" ⚠ 未找到工具 {tool_id} 的信息,使用默认参数")
|
|
|
return {"keyword": query}
|
|
|
|
|
|
- logger.info(f" 工具 {tool_name} 信息长度: {len(tool_info)}")
|
|
|
-
|
|
|
# 加载prompt
|
|
|
prompt_template = self._load_prompt("function_knowledge_extract_tool_params_prompt.md")
|
|
|
prompt = prompt_template.format(
|
|
|
query=query,
|
|
|
- tool_info=tool_info
|
|
|
+ # tool_info=tool_info
|
|
|
)
|
|
|
|
|
|
# 调用LLM提取参数
|
|
|
@@ -367,15 +340,17 @@ class FunctionKnowledge:
|
|
|
query = self.generate_query(question, post_info, persona_info)
|
|
|
|
|
|
# 步骤2: 选择工具
|
|
|
- tool_name = self.select_tool(combined_question, query)
|
|
|
-
|
|
|
- if tool_name and tool_name != "None":
|
|
|
+ tool_info = self.select_tool(combined_question, query)
|
|
|
+ # tool_name = tool_info.get("工具名")
|
|
|
+ tool_id = tool_info.get("工具调用ID")
|
|
|
+ tool_instructions = tool_info.get("使用方法")
|
|
|
+ if tool_id and tool_instructions:
|
|
|
# 路径A: 使用工具
|
|
|
# 步骤3: 提取参数
|
|
|
- arguments = self.extract_tool_params(combined_question, tool_name, query)
|
|
|
-
|
|
|
+ arguments = self.extract_tool_params(combined_question, query, tool_id, tool_instructions)
|
|
|
+
|
|
|
# 步骤4: 调用工具
|
|
|
- logger.info(f"[步骤4] 调用工具: {tool_name}")
|
|
|
+ logger.info(f"[步骤4] 调用工具: {tool_id}")
|
|
|
|
|
|
# 检查工具调用缓存
|
|
|
if self.use_cache:
|
|
|
@@ -385,13 +360,15 @@ class FunctionKnowledge:
|
|
|
tool_result = cached_tool_result
|
|
|
else:
|
|
|
logger.info(f" → 调用工具,参数: {arguments}")
|
|
|
- tool_result = call_tool(tool_name, arguments)
|
|
|
+ tool_result = call_tool(tool_id, arguments)
|
|
|
# 缓存工具调用结果
|
|
|
self.cache.set(combined_question, 'function_knowledge', 'tool_result.json', tool_result)
|
|
|
else:
|
|
|
logger.info(f" → 调用工具,参数: {arguments}")
|
|
|
- tool_result = call_tool(tool_name, arguments)
|
|
|
-
|
|
|
+ tool_result = call_tool(tool_id, arguments)
|
|
|
+ # 缓存工具调用结果
|
|
|
+ self.cache.set(combined_question, 'function_knowledge', 'tool_result.json', tool_result)
|
|
|
+
|
|
|
logger.info(f"✓ 工具调用完成")
|
|
|
|
|
|
else:
|