fix bug: tool_calls match tool response

fix bug: tool_calls match tool response
modify: the method of memory manage
add : timer
This commit is contained in:
Sanjin
2025-06-24 00:26:57 +08:00
parent 5fef399e0b
commit 25dfb5078f
6 changed files with 157 additions and 42 deletions
+75 -9
View File
@@ -1,4 +1,4 @@
from app.core.llm.llm import LLM
from app.core.llm.llm import LLM, simple_chat
from app.utils.log_util import logger
@@ -32,8 +32,8 @@ class Agent:
self.current_chat_turns = 0 # 重置对话轮次计数器
# 更新对话历史
self.append_chat_history({"role": "system", "content": system_prompt})
self.append_chat_history({"role": "user", "content": prompt})
await self.append_chat_history({"role": "system", "content": system_prompt})
await self.append_chat_history({"role": "user", "content": prompt})
# 获取历史消息用于本次对话
response = await self.model.chat(
@@ -50,14 +50,80 @@ class Agent:
logger.error(f"Agent执行失败: {str(e)}")
return error_msg
def append_chat_history(self, msg: dict) -> None:
self.clear_memory()
async def append_chat_history(self, msg: dict) -> None:
await self.clear_memory()
self.chat_history.append(msg)
def clear_memory(self):
async def clear_memory(self):
"""当聊天历史超过最大记忆轮次时,使用 simple_chat 进行总结压缩"""
if len(self.chat_history) <= self.max_memory:
return
logger.info(f"{self.__class__.__name__}:清除记忆")
# 使用切片保留第一条和最后两条消息
self.chat_history = self.chat_history[:2] + self.chat_history[-5:]
logger.info(
f"{self.__class__.__name__}:开始清除记忆,当前记录数:{len(self.chat_history)}"
)
try:
# 保留第一条系统消息
system_msg = (
self.chat_history[0]
if self.chat_history and self.chat_history[0]["role"] == "system"
else None
)
# 构造总结提示
summarize_history = []
if system_msg:
summarize_history.append(system_msg)
# 添加要总结的对话内容跳过第一条系统消息和最后5条消息
start_idx = 1 if system_msg else 0
end_idx = len(self.chat_history) - 5
if end_idx > start_idx:
summarize_history.append(
{
"role": "user",
"content": f"请简洁总结以下对话的关键内容和重要结论,保留重要的上下文信息:\n\n{self._format_history_for_summary(self.chat_history[start_idx:end_idx])}",
}
)
# 调用 simple_chat 进行总结
summary = await simple_chat(self.model, summarize_history)
# 重构聊天历史:系统消息 + 总结 + 最后5条消息
new_history = []
if system_msg:
new_history.append(system_msg)
new_history.append(
{"role": "assistant", "content": f"[历史对话总结] {summary}"}
)
# 添加最后5条消息
new_history.extend(self.chat_history[-5:])
self.chat_history = new_history
logger.info(
f"{self.__class__.__name__}:记忆清除完成,压缩至:{len(self.chat_history)}条记录"
)
else:
logger.info(f"{self.__class__.__name__}:无需清除记忆,记录数量合理")
except Exception as e:
logger.error(f"记忆清除失败,使用简单切片策略: {str(e)}")
# 如果总结失败,回退到简单的切片策略
self.chat_history = self.chat_history[:2] + self.chat_history[-5:]
def _format_history_for_summary(self, history: list[dict]) -> str:
"""格式化历史记录用于总结"""
formatted = []
for msg in history:
role = msg["role"]
content = (
msg["content"][:500] + "..."
if len(msg["content"]) > 500
else msg["content"]
) # 限制长度
formatted.append(f"{role}: {content}")
return "\n".join(formatted)
+11 -7
View File
@@ -40,9 +40,11 @@ class CoderAgent(Agent): # 同样继承自Agent类
if self.is_first_run:
logger.info("首次运行,添加系统提示和数据集文件信息")
self.is_first_run = False
self.append_chat_history({"role": "system", "content": self.system_prompt})
await self.append_chat_history(
{"role": "system", "content": self.system_prompt}
)
# 当前数据集文件
self.append_chat_history(
await self.append_chat_history(
{
"role": "user",
"content": f"当前文件夹下的数据集文件{get_current_files(self.work_dir, 'data')}",
@@ -51,7 +53,7 @@ class CoderAgent(Agent): # 同样继承自Agent类
# 添加 sub_task
logger.info(f"添加子任务提示: {prompt}")
self.append_chat_history({"role": "user", "content": prompt})
await self.append_chat_history({"role": "user", "content": prompt})
retry_count = 0
last_error_message = ""
@@ -118,7 +120,9 @@ class CoderAgent(Agent): # 同样继承自Agent类
)
# 更新对话历史 - 添加助手的响应
self.append_chat_history(response.choices[0].message.model_dump())
await self.append_chat_history(
response.choices[0].message.model_dump()
)
logger.info(response.choices[0].message.model_dump())
# 执行工具调用
@@ -132,7 +136,7 @@ class CoderAgent(Agent): # 同样继承自Agent类
# 添加工具执行结果
if error_occurred:
# 即使发生错误也要添加tool响应
self.append_chat_history(
await self.append_chat_history(
{
"role": "tool",
"tool_call_id": tool_id,
@@ -152,14 +156,14 @@ class CoderAgent(Agent): # 同样继承自Agent类
SystemMessage(content="代码手反思纠正错误", type="error"),
)
self.append_chat_history(
await self.append_chat_history(
{"role": "user", "content": reflection_prompt}
)
# 如果代码出错,返回重新开始
continue
else:
# 成功执行的tool响应
self.append_chat_history(
await self.append_chat_history(
{
"role": "tool",
"tool_call_id": tool_id,
+4 -2
View File
@@ -19,8 +19,10 @@ class CoordinatorAgent(Agent):
async def run(self, ques_all: str) -> CoordinatorToModeler:
"""用户输入问题 使用LLM 格式化 questions"""
self.append_chat_history({"role": "system", "content": self.system_prompt})
self.append_chat_history({"role": "user", "content": ques_all})
await self.append_chat_history(
{"role": "system", "content": self.system_prompt}
)
await self.append_chat_history({"role": "user", "content": ques_all})
response = await self.model.chat(
history=self.chat_history,
+4 -2
View File
@@ -18,8 +18,10 @@ class ModelerAgent(Agent): # 继承自Agent类
self.system_prompt = MODELER_PROMPT
async def run(self, coordinator_to_modeler: CoordinatorToModeler) -> ModelerToCoder:
self.append_chat_history({"role": "system", "content": self.system_prompt})
self.append_chat_history(
await self.append_chat_history(
{"role": "system", "content": self.system_prompt}
)
await self.append_chat_history(
{
"role": "user",
"content": json.dumps(coordinator_to_modeler.questions),
+8 -6
View File
@@ -52,7 +52,9 @@ class WriterAgent(Agent): # 同样继承自Agent类
if self.is_first_run:
self.is_first_run = False
self.append_chat_history({"role": "system", "content": self.system_prompt})
await self.append_chat_history(
{"role": "system", "content": self.system_prompt}
)
if available_images:
self.available_images = available_images
@@ -65,7 +67,7 @@ class WriterAgent(Agent): # 同样继承自Agent类
logger.info(f"{self.__class__.__name__}:开始:执行对话")
self.current_chat_turns += 1 # 重置对话轮次计数器
self.append_chat_history({"role": "user", "content": prompt})
await self.append_chat_history({"role": "user", "content": prompt})
# 获取历史消息用于本次对话
response = await self.model.chat(
@@ -102,7 +104,7 @@ class WriterAgent(Agent): # 同样继承自Agent类
)
# 更新对话历史 - 添加助手的响应
self.append_chat_history(response.choices[0].message.model_dump())
await self.append_chat_history(response.choices[0].message.model_dump())
ic(response.choices[0].message.model_dump())
try:
@@ -116,7 +118,7 @@ class WriterAgent(Agent): # 同样继承自Agent类
# TODO: pass to frontend
papers_str = self.scholar.papers_to_str(papers)
logger.info(f"搜索文献结果\n{papers_str}")
self.append_chat_history(
await self.append_chat_history(
{
"role": "tool",
"content": papers_str,
@@ -143,14 +145,14 @@ class WriterAgent(Agent): # 同样继承自Agent类
总结对话内容
"""
try:
self.append_chat_history(
await self.append_chat_history(
{"role": "user", "content": "请简单总结以上完成什么任务取得什么结果:"}
)
# 获取历史消息用于本次对话
response = await self.model.chat(
history=self.chat_history, agent_name=self.__class__.__name__
)
self.append_chat_history(
await self.append_chat_history(
{"role": "assistant", "content": response.choices[0].message.content}
)
return response.choices[0].message.content
+55 -16
View File
@@ -10,10 +10,6 @@ import {
TabsList,
TabsTrigger,
} from '@/components/ui/tabs'
import {
Card,
CardContent,
} from '@/components/ui/card'
import CoderEditor from '@/components/AgentEditor/CoderEditor.vue'
import WriterEditor from '@/components/AgentEditor/WriterEditor.vue'
import ModelerEditor from '@/components/AgentEditor/ModelerEditor.vue'
@@ -33,12 +29,44 @@ const taskStore = useTaskStore()
const writerSequence = ref<string[]>([]);
// 项目运行时长相关
const startTime = ref<number>(Date.now())
const currentTime = ref<number>(Date.now())
let timer: ReturnType<typeof setInterval> | null = null
// 格式化运行时长
const formatDuration = (ms: number): string => {
const seconds = Math.floor(ms / 1000)
const hours = Math.floor(seconds / 3600)
const minutes = Math.floor((seconds % 3600) / 60)
const remainingSeconds = seconds % 60
if (hours > 0) {
return `${hours}h ${minutes}m ${remainingSeconds}s`
} else if (minutes > 0) {
return `${minutes}m ${remainingSeconds}s`
} else {
return `${remainingSeconds}s`
}
}
// 计算运行时长
const runningDuration = ref<string>('0s')
const updateDuration = () => {
currentTime.value = Date.now()
runningDuration.value = formatDuration(currentTime.value - startTime.value)
}
console.log('Task ID:', props.task_id)
onMounted(async () => {
taskStore.connectWebSocket(props.task_id)
const res = await getWriterSeque();
writerSequence.value = Array.isArray(res.data) ? res.data : [];
// 开始计时
timer = setInterval(updateDuration, 1000)
updateDuration() // 立即更新一次
})
const openFolder = async () => {
@@ -53,6 +81,11 @@ const openFolder = async () => {
onBeforeUnmount(() => {
taskStore.closeWebSocket()
// 清理计时器
if (timer) {
clearInterval(timer)
timer = null
}
})
</script>
@@ -66,19 +99,25 @@ onBeforeUnmount(() => {
<ResizableHandle />
<ResizablePanel :default-size="60" class="h-full min-w-0">
<div class="flex h-full flex-col min-w-0">
<Tabs default-value="coder" class="w-full h-full flex flex-col">
<Tabs default-value="modeler" class="w-full h-full flex flex-col">
<!-- TODO: Agent 的状态 -->
<div class="border-b px-4 py-1 flex justify-between">
<TabsList class="">
<TabsTrigger value="modeler" class="text-sm">
ModelerAgent
</TabsTrigger>
<TabsTrigger value="coder" class="text-sm">
CoderAgent
</TabsTrigger>
<TabsTrigger value="writer" class="text-sm">
WriterAgent
</TabsTrigger>
</TabsList>
<div class="flex items-center gap-4">
<div class="text-sm text-gray-600">
运行时长: <span class="font-mono text-blue-600">{{ runningDuration }}</span>
</div>
<TabsList>
<TabsTrigger value="modeler" class="text-sm">
ModelerAgent
</TabsTrigger>
<TabsTrigger value="coder" class="text-sm">
CoderAgent
</TabsTrigger>
<TabsTrigger value="writer" class="text-sm">
WriterAgent
</TabsTrigger>
</TabsList>
</div>
<!-- TODO: 其他选项 -->
<div class="flex justify-end gap-2">