Fix: Add tool call limits and fix tool call loop

This commit is contained in:
JianFeeeee
2026-04-11 22:38:27 +08:00
parent 43d1c15603
commit c0bacf240e
2 changed files with 80 additions and 26 deletions

View File

@ -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` 可以同时查询多个关键词(用逗号分隔)
- 达到限制后立即停止工具调用,直接回复用户
- 不要重复调用相同的工具
- 优先合并查询,减少调用次数
---
## ⚠️ 关键约束:无传统上下文系统
**重要**: 你没有传统的对话上下文系统(没有消息历史数组)。

View File

@ -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()