fix: 更新聊天代理处理逻辑,增强敏感内容检测和中断提示

- 在 chat_agent 函数中,优化了敏感内容检测后的响应,添加了时间成本的记录。
- 修改了前端 AgentChatComponent 和 AgentMessageComponent,以正确处理和显示敏感内容中断的提示信息。
- 移除了不必要的代码注释和冗余逻辑,提升了代码可读性。
This commit is contained in:
Wenjie Zhang 2025-11-08 14:20:19 +08:00
parent 685f48272b
commit 214bcb8d3e
4 changed files with 16 additions and 40 deletions

View File

@ -375,7 +375,6 @@ async def get_agent(current_user: User = Depends(get_required_user)):
return {"agents": agents}
# TODO:[未完成]这个thread_id在前端是直接生成的1234最好传入thread_id时做校验只允许uuid4
@chat.post("/agent/{agent_id}")
async def chat_agent(
agent_id: str,
@ -472,7 +471,8 @@ async def chat_agent(
if conf.enable_content_guard and await content_guard.check_with_keywords(full_msg.content[-20:]):
logger.warning("Sensitive content detected in stream")
await save_partial_message(conv_manager, thread_id, full_msg, "content_guard_blocked")
yield make_chunk(message="检测到敏感内容,已中断输出", status="error")
meta["time_cost"] = asyncio.get_event_loop().time() - start_time
yield make_chunk(status="interrupted", message="检测到敏感内容,已中断输出", meta=meta)
return
yield make_chunk(content=msg.content, msg=msg.model_dump(), metadata=metadata, status="loading")
@ -487,7 +487,8 @@ async def chat_agent(
):
logger.warning("Sensitive content detected in final message")
await save_partial_message(conv_manager, thread_id, full_msg, "content_guard_blocked")
yield make_chunk(message="检测到敏感内容,已中断输出", status="error")
meta["time_cost"] = asyncio.get_event_loop().time() - start_time
yield make_chunk(status="interrupted", message="检测到敏感内容,已中断输出", meta=meta)
return
# After streaming finished, check for interrupts and save messages
@ -512,16 +513,6 @@ async def chat_agent(
# 客户端主动中断连接,检查中断并保存已生成的部分内容
logger.warning(f"Client disconnected, cancelling stream: {e}")
# 断开连接时不检查中断,直接保存部分消息
langgraph_config = {"configurable": input_context}
# 尝试从 LangGraph state 保存消息(可能没有,因为中断了)
await save_messages_from_langgraph_state(
agent_instance=agent,
thread_id=thread_id,
conv_mgr=conv_manager,
config_dict=langgraph_config,
)
# 如果有手动维护的 full_msg直接保存到数据库
if full_msg:
@ -539,16 +530,6 @@ async def chat_agent(
except Exception as e:
logger.error(f"Error streaming messages: {e}, {traceback.format_exc()}")
# 异常情况下也不检查中断,直接保存部分消息
langgraph_config = {"configurable": input_context}
# 尝试从 LangGraph state 保存消息(可能没有,因为异常了)
await save_messages_from_langgraph_state(
agent_instance=agent,
thread_id=thread_id,
conv_mgr=conv_manager,
config_dict=langgraph_config,
)
# 如果有手动维护的 full_msg直接保存到数据库
if full_msg:

View File

@ -64,7 +64,7 @@ class AttachmentMiddleware(AgentMiddleware[AttachmentState]):
self, request: ModelRequest, handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
# Read from State: get uploaded files metadata
logger.debug(f"inject_attachment_context: request.state = {request.state}")
# logger.debug(f"inject_attachment_context: request.state = {request.state}")
attachments = request.state.get("attachments", [])
if attachments:

View File

@ -470,7 +470,7 @@ const resetOnGoingConv = (threadId = null, preserveMessages = false) => {
};
const _processStreamChunk = (chunk, threadId) => {
const { status, msg, request_id, message } = chunk;
const { status, msg, request_id, message: chunkMessage } = chunk;
const threadState = getThreadState(threadId);
// console.log('Processing stream chunk:', chunk, 'for thread:', threadId);
@ -489,7 +489,7 @@ const _processStreamChunk = (chunk, threadId) => {
}
return false;
case 'error':
handleChatError({ message }, 'stream');
handleChatError({ message: chunkMessage }, 'stream');
// Stop the loading indicator
if (threadState) {
threadState.isStreaming = false;
@ -525,6 +525,10 @@ const _processStreamChunk = (chunk, threadId) => {
if (threadState) {
threadState.isStreaming = false;
}
// message
if (chunkMessage) {
message.info(chunkMessage);
}
fetchThreadMessages({ agentId: currentAgentId.value, threadId: threadId })
.finally(() => {
resetOnGoingConv(threadId, true);

View File

@ -30,9 +30,10 @@
<div v-else-if="parsedData.reasoning_content" class="empty-block"></div>
<!-- 错误提示块 -->
<div v-if="message.error_type" class="error-hint" :class="{ 'error-interrupted': message.error_type === 'interrupted', 'error-unexpect': message.error_type === 'unexpect' }">
<div v-if="message.error_type" class="error-hint">
<span v-if="message.error_type === 'interrupted'">回答生成已中断</span>
<span v-else-if="message.error_type === 'unexpect'">生成过程中出现异常</span>
<span v-else-if="message.error_type === 'content_guard_blocked'">检测到敏感内容已中断输出</span>
</div>
<div v-if="validToolCalls && validToolCalls.length > 0" class="tool-calls-container">
@ -365,19 +366,9 @@ const toggleToolCall = (toolCallId) => {
display: flex;
align-items: center;
gap: 8px;
&.error-interrupted {
background-color: #fffbeb;
// border: 1px solid #fbbf24;
color: #92400e;
}
&.error-unexpect {
background-color: #fef2f2;
// border: 1px solid #f87171;
color: #991b1b;
}
background-color: #fef2f2;
// border: 1px solid #f87171;
color: #991b1b;
span {
line-height: 1.5;
}