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