diff --git a/graph_memory_tui/core/prompts/templates/system_prompt.md b/graph_memory_tui/core/prompts/templates/system_prompt.md index ae937a0..0d775eb 100644 --- a/graph_memory_tui/core/prompts/templates/system_prompt.md +++ b/graph_memory_tui/core/prompts/templates/system_prompt.md @@ -2,6 +2,33 @@ 你是TrulyMEM,一个拥有长期记忆能力的AI助手。 +## ⚠️ 工具调用限制(严格执行) + +**每轮对话工具调用次数限制:** + +### 人设图工具 +- `memory_recall` (查询人设): **最多1次** +- `persona_update` / `persona_clear`: **最多1次** + +### 工作记忆链工具 +- `memory_recall` (查询任务链): **最多10次** +- `task_create` / `task_set_state` / `task_delete` / `task_link_info`: **最多5次** + +### 一般记忆工具 +- `memory_recall` (其他查询): **最多20次** +- `memory_commit` / `memory_purge`: **最多10次** + +### 其他工具 +- `memory_introspect` / `memory_archive` / `memory_cleanup`: **最多1次** + +**重要提示:** +- 单次 `memory_recall` 可以同时查询多个关键词(用逗号分隔) +- 达到限制后立即停止工具调用,直接回复用户 +- 不要重复调用相同的工具 +- 优先合并查询,减少调用次数 + +--- + ## ⚠️ 关键约束:无传统上下文系统 **重要**: 你没有传统的对话上下文系统(没有消息历史数组)。 diff --git a/graph_memory_tui/services/chat_service.py b/graph_memory_tui/services/chat_service.py index 039e543..e8b1853 100644 --- a/graph_memory_tui/services/chat_service.py +++ b/graph_memory_tui/services/chat_service.py @@ -1,6 +1,7 @@ """聊天服务""" import asyncio +import json from datetime import datetime from typing import AsyncIterator, TYPE_CHECKING from ..core.imports import GraphMemoryClient @@ -14,6 +15,9 @@ if TYPE_CHECKING: class ChatService: """聊天业务服务""" + # 工具调用限制 + MAX_TOOL_ITERATIONS = 5 # 最多5轮工具调用 + def __init__( self, graph: "Neo4jGraph", @@ -34,29 +38,39 @@ class ChatService: } try: - # 2. 使用流式API调用 - accumulated_content = "" - tool_calls_data = [] - - # 流式处理响应 - async for chunk in self._call_api_stream_async(user_input): - # 处理内容增量 - if chunk.get("content_delta"): - accumulated_content += chunk["content_delta"] - yield { - "type": "content_delta", - "content": accumulated_content - } - - # 处理工具调用 - if chunk.get("tool_calls"): - tool_calls_data = chunk["tool_calls"] - - # 3. 处理工具调用 - tool_calls = None - tool_results = None + # 2. 处理工具调用循环 + iteration = 0 + current_input = user_input + all_tool_calls = [] + all_tool_results = [] + final_content = "" - if tool_calls_data: + while iteration < self.MAX_TOOL_ITERATIONS: + iteration += 1 + + # 流式处理响应 + accumulated_content = "" + tool_calls_data = [] + + async for chunk in self._call_api_stream_async(current_input): + # 处理内容增量 + if chunk.get("content_delta"): + accumulated_content += chunk["content_delta"] + yield { + "type": "content_delta", + "content": accumulated_content + } + + # 处理工具调用 + if chunk.get("tool_calls"): + tool_calls_data = chunk["tool_calls"] + + # 如果没有工具调用,结束循环 + if not tool_calls_data: + final_content = accumulated_content + break + + # 处理工具调用 tool_calls = [] tool_results = [] @@ -87,12 +101,18 @@ class ChatService: "log_entry": log_entry } - # 4. 返回最终回复 + all_tool_calls.extend(tool_calls) + all_tool_results.extend(tool_results) + + # 准备下一轮输入(工具结果) + current_input = self._format_tool_results(tool_calls, tool_results) + + # 3. 返回最终回复 yield { "type": "assistant_message", - "content": accumulated_content, - "tool_calls": tool_calls, - "tool_results": tool_results + "content": final_content, + "tool_calls": all_tool_calls if all_tool_calls else None, + "tool_results": all_tool_results if all_tool_results else None } except Exception as e: @@ -102,6 +122,13 @@ class ChatService: "error": str(e) } + def _format_tool_results(self, tool_calls: list[ToolCall], tool_results: list[ToolResult]) -> str: + """格式化工具结果为下一轮输入""" + results_text = [] + for tc, tr in zip(tool_calls, tool_results): + results_text.append(f"工具 {tc.name} 执行结果:\n{tr.content}") + return "\n\n".join(results_text) + async def _call_api_stream_async(self, message: str) -> AsyncIterator[dict]: """异步流式调用 API""" loop = asyncio.get_event_loop()