feat:优化增量执行、工具调用容错与评测体系

This commit is contained in:
2026-10-11 04:40:25 -07:00
parent cd5a2b4d8f
commit dadd797391
22 changed files with 2198 additions and 578 deletions
+32 -18
View File
@@ -1,39 +1,49 @@
"""调用 screen agent,按它的回复和最后一次提交的结果写回状态
"""调用 screen agent,按它的回复和成功提交的动作写回状态
kind 由模型决定;代码只在"回复 done 但最后一次提交失败"时不采纳,因为此时没有能交付的动作
kind 由模型决定;代码只在"回复 done 但最后一次提交失败"时不采纳:最后想做的修改没有写入草稿,
模型却说已完成。这是保守做法,last_write_failed 只看工具结果,任务是否完成仍以模型的结论和评测为准
agent 正常结束却没有结论时(调用次数用尽、只回了文本或空回复)补一次只读收尾;取消和异常照常抛出,不收尾
"""
import json
from langchain_core.messages import HumanMessage
from app.agent.screen_agent import AgentReply, get_screen_agent
from app.agent.tools import ScreenAgentContext
from app.agent.screen_agent import (
AgentReply,
finalize_reply,
get_screen_agent,
reached_call_limit,
)
from app.agent.tools import ScreenAgentContext, last_write_failed
from app.processor.base import BaseNode
from app.processor.history import history_messages
from app.processor.state import QueryState, run_data
from app.processor.summary import request_summary
from app.resources.component import get_catalog_cache
# 评测按这句话识别"草稿因最后一次提交失败没有交付",单独核对草稿本身是否满足要求
DRAFT_REJECTED = "修改没有通过校验,这次没有生效,可以换个说法再试"
def reply_update(result: dict) -> QueryState:
def reply_update(result: dict, *, limit_hit: bool = False) -> QueryState:
"""把 agent 的运行结果转换成 QueryState 的更新"""
reply: AgentReply | None = result.get("structured_response")
if reply is None:
# 调用次数用尽等情况,agent 没有给出结论
return {
"status": "failed",
"answer": "处理步骤超出上限,这次没有完成,可以换个说法再试",
}
# 收尾也没有给出合法的结论;按真实原因说明,不再一律说超出上限
answer = (
"处理步骤超出上限,这次没有完成,修改没有生效,可以换个说法再试"
if limit_hit
else "这次没有得出结论,修改没有生效,可以换个说法再试"
)
return {"status": "failed", "answer": answer}
if reply.kind == "clarify":
return {"status": "waiting_for_input", "clarification": reply.clarification}
if reply.kind == "unable":
return {"status": "failed", "answer": reply.message}
if result.get("apply_error"):
return {
"status": "failed",
"answer": "修改没有通过校验,这次没有生效,可以换个说法再试",
}
if last_write_failed(result.get("messages", [])):
return {"status": "failed", "answer": DRAFT_REJECTED}
# 各次成功提交的动作按顺序拼接;clarify、unable 不交付,下次请求从原始大屏重新执行
return {
"status": "completed",
"actions": result.get("actions") or [],
@@ -70,12 +80,16 @@ class ScreenAgentNode(BaseNode):
data=run_data(),
),
)
limit_hit = False
if result.get("structured_response") is None:
limit_hit = reached_call_limit(result["messages"])
last = result["messages"][-1]
self.logger.warning(
f"agent 没有给出结论: {last.type} {str(last.content)[:500]} "
f"tool_calls={getattr(last, 'tool_calls', None)} "
f"agent 没有给出结论({'调用次数用尽' if limit_hit else '没有调用 AgentReply'}),收尾一次: "
f"{last.type} {str(last.content)[:500]} "
f"metadata={getattr(last, 'response_metadata', None)}"
)
updated_state.update(reply_update(result))
reply = await finalize_reply(result, limit_hit=limit_hit)
result = {**result, "structured_response": reply}
updated_state.update(reply_update(result, limit_hit=limit_hit))
return updated_state