agent功能开发增加MCP后端
This commit is contained in:
@@ -1679,6 +1679,9 @@ async def agent_chat(request: AgentChatRequest):
|
|||||||
ensure_ascii=False
|
ensure_ascii=False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 将 plan 转换为 JSON 字符串(ES 中 plan 字段是 text 类型)
|
||||||
|
plan_json = json.dumps(response.plan.dict(), ensure_ascii=False) if response.plan else None
|
||||||
|
|
||||||
es_client.save_chat_message(
|
es_client.save_chat_message(
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
user_id=request.user_id or "anonymous",
|
user_id=request.user_id or "anonymous",
|
||||||
@@ -1686,7 +1689,7 @@ async def agent_chat(request: AgentChatRequest):
|
|||||||
user_avatar=request.user_avatar or "",
|
user_avatar=request.user_avatar or "",
|
||||||
message_type="assistant",
|
message_type="assistant",
|
||||||
message=response.final_summary, # 使用 final_summary 而不是 final_answer
|
message=response.final_summary, # 使用 final_summary 而不是 final_answer
|
||||||
plan=response.plan.dict() if response.plan else None, # 转换为字典
|
plan=plan_json, # 传递 JSON 字符串而不是字典
|
||||||
steps=steps_json,
|
steps=steps_json,
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ const AgentChatV3 = () => {
|
|||||||
setMessages((prev) => [...prev, { ...message, id: Date.now() }]);
|
setMessages((prev) => [...prev, { ...message, id: Date.now() }]);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 发送消息
|
// 发送消息(流式 SSE 版本)
|
||||||
const handleSendMessage = async () => {
|
const handleSendMessage = async () => {
|
||||||
if (!inputValue.trim() || isProcessing) return;
|
if (!inputValue.trim() || isProcessing) return;
|
||||||
|
|
||||||
@@ -242,10 +242,10 @@ const AgentChatV3 = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info('AgentChat', '权限检查通过', {
|
logger.info('AgentChat', '权限检查通过', {
|
||||||
userId: user?.id,
|
userId: user?.id,
|
||||||
username: user?.username,
|
username: user?.username,
|
||||||
subscription_type: user?.subscription_type
|
subscription_type: user?.subscription_type
|
||||||
});
|
});
|
||||||
|
|
||||||
const userMessage = {
|
const userMessage = {
|
||||||
@@ -262,6 +262,7 @@ const AgentChatV3 = () => {
|
|||||||
|
|
||||||
let currentPlan = null;
|
let currentPlan = null;
|
||||||
let stepResults = [];
|
let stepResults = [];
|
||||||
|
let executingMessageId = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. 显示思考状态
|
// 1. 显示思考状态
|
||||||
@@ -273,8 +274,8 @@ const AgentChatV3 = () => {
|
|||||||
|
|
||||||
setCurrentProgress(10);
|
setCurrentProgress(10);
|
||||||
|
|
||||||
// 2. 调用后端API(非流式)
|
// 2. 使用 EventSource 接收 SSE 流式数据
|
||||||
const response = await axios.post('/mcp/agent/chat', {
|
const requestBody = {
|
||||||
message: userInput,
|
message: userInput,
|
||||||
conversation_history: messages
|
conversation_history: messages
|
||||||
.filter((m) => m.type === MessageTypes.USER || m.type === MessageTypes.AGENT_RESPONSE)
|
.filter((m) => m.type === MessageTypes.USER || m.type === MessageTypes.AGENT_RESPONSE)
|
||||||
@@ -285,54 +286,140 @@ const AgentChatV3 = () => {
|
|||||||
user_id: user?.id ? String(user.id) : 'anonymous',
|
user_id: user?.id ? String(user.id) : 'anonymous',
|
||||||
user_nickname: user?.nickname || user?.username || '匿名用户',
|
user_nickname: user?.nickname || user?.username || '匿名用户',
|
||||||
user_avatar: user?.avatar || '',
|
user_avatar: user?.avatar || '',
|
||||||
subscription_type: user?.subscription_type || 'free', // 传递订阅类型
|
subscription_type: user?.subscription_type || 'free',
|
||||||
session_id: currentSessionId,
|
session_id: currentSessionId,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 使用 fetch API 进行 SSE 请求
|
||||||
|
const response = await fetch('/mcp/agent/chat/stream', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(requestBody),
|
||||||
});
|
});
|
||||||
|
|
||||||
// 移除思考消息
|
if (!response.ok) {
|
||||||
setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
|
||||||
if (response.data.success) {
|
|
||||||
const data = response.data;
|
|
||||||
|
|
||||||
// 更新 session_id(如果是新会话)
|
|
||||||
if (data.session_id && !currentSessionId) {
|
|
||||||
setCurrentSessionId(data.session_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示执行计划
|
|
||||||
if (data.plan) {
|
|
||||||
currentPlan = data.plan;
|
|
||||||
addMessage({
|
|
||||||
type: MessageTypes.AGENT_PLAN,
|
|
||||||
content: '已制定执行计划',
|
|
||||||
plan: data.plan,
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
setCurrentProgress(30);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示执行步骤
|
|
||||||
if (data.step_results && data.step_results.length > 0) {
|
|
||||||
stepResults = data.step_results;
|
|
||||||
setCurrentProgress(70);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 显示最终结果(包含执行步骤)
|
|
||||||
addMessage({
|
|
||||||
type: MessageTypes.AGENT_RESPONSE,
|
|
||||||
content: data.final_summary || data.message || '处理完成',
|
|
||||||
plan: currentPlan,
|
|
||||||
stepResults: stepResults,
|
|
||||||
metadata: data.metadata,
|
|
||||||
timestamp: new Date().toISOString(),
|
|
||||||
});
|
|
||||||
|
|
||||||
setCurrentProgress(100);
|
|
||||||
|
|
||||||
// 重新加载会话列表
|
|
||||||
loadSessions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const reader = response.body.getReader();
|
||||||
|
const decoder = new TextDecoder();
|
||||||
|
let buffer = '';
|
||||||
|
|
||||||
|
// 读取流式数据
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
if (done) break;
|
||||||
|
|
||||||
|
buffer += decoder.decode(value, { stream: true });
|
||||||
|
const lines = buffer.split('\n');
|
||||||
|
buffer = lines.pop(); // 保留不完整的行
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
if (!line.trim() || line.startsWith(':')) continue;
|
||||||
|
|
||||||
|
if (line.startsWith('event:')) {
|
||||||
|
// 忽略事件类型行
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.startsWith('data:')) {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(line.substring(5).trim());
|
||||||
|
|
||||||
|
// 处理不同类型的事件
|
||||||
|
if (data.stage === 'planning') {
|
||||||
|
// 正在制定计划
|
||||||
|
setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
|
||||||
|
addMessage({
|
||||||
|
type: MessageTypes.AGENT_THINKING,
|
||||||
|
content: '正在制定执行计划...',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
setCurrentProgress(20);
|
||||||
|
} else if (data.goal) {
|
||||||
|
// 收到执行计划
|
||||||
|
currentPlan = data;
|
||||||
|
setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING));
|
||||||
|
addMessage({
|
||||||
|
type: MessageTypes.AGENT_PLAN,
|
||||||
|
content: '已制定执行计划',
|
||||||
|
plan: data,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
setCurrentProgress(30);
|
||||||
|
} else if (data.stage === 'executing') {
|
||||||
|
// 开始执行步骤
|
||||||
|
const msgId = Date.now();
|
||||||
|
executingMessageId = msgId;
|
||||||
|
addMessage({
|
||||||
|
id: msgId,
|
||||||
|
type: MessageTypes.AGENT_EXECUTING,
|
||||||
|
content: `正在执行 ${data.message}`,
|
||||||
|
plan: currentPlan,
|
||||||
|
stepResults: [],
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
setCurrentProgress(40);
|
||||||
|
} else if (data.step_index !== undefined && data.tool) {
|
||||||
|
// 收到步骤完成事件
|
||||||
|
const stepResult = {
|
||||||
|
step_index: data.step_index,
|
||||||
|
tool: data.tool,
|
||||||
|
status: data.status,
|
||||||
|
result: data.result,
|
||||||
|
error: data.error,
|
||||||
|
execution_time: data.execution_time,
|
||||||
|
};
|
||||||
|
stepResults.push(stepResult);
|
||||||
|
|
||||||
|
// 更新执行中的消息
|
||||||
|
setMessages((prev) =>
|
||||||
|
prev.map((m) =>
|
||||||
|
m.id === executingMessageId
|
||||||
|
? { ...m, stepResults: [...stepResults] }
|
||||||
|
: m
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 更新进度
|
||||||
|
const progress = 40 + (stepResults.length / (currentPlan?.steps?.length || 5)) * 40;
|
||||||
|
setCurrentProgress(Math.min(progress, 80));
|
||||||
|
} else if (data.stage === 'summarizing') {
|
||||||
|
// 正在生成总结
|
||||||
|
setMessages((prev) => prev.filter((m) => m.type !== MessageTypes.AGENT_EXECUTING));
|
||||||
|
addMessage({
|
||||||
|
type: MessageTypes.AGENT_THINKING,
|
||||||
|
content: '正在生成分析报告...',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
setCurrentProgress(85);
|
||||||
|
} else if (data.content) {
|
||||||
|
// 收到最终总结
|
||||||
|
setMessages((prev) =>
|
||||||
|
prev.filter((m) => m.type !== MessageTypes.AGENT_THINKING && m.type !== MessageTypes.AGENT_EXECUTING)
|
||||||
|
);
|
||||||
|
addMessage({
|
||||||
|
type: MessageTypes.AGENT_RESPONSE,
|
||||||
|
content: data.content,
|
||||||
|
plan: currentPlan,
|
||||||
|
stepResults: stepResults,
|
||||||
|
metadata: data.metadata,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
setCurrentProgress(100);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.error('解析 SSE 数据失败', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重新加载会话列表
|
||||||
|
loadSessions();
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Agent chat error', error);
|
logger.error('Agent chat error', error);
|
||||||
|
|
||||||
@@ -343,7 +430,7 @@ const AgentChatV3 = () => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const errorMessage = error.response?.data?.error || error.message || '处理失败';
|
const errorMessage = error.response?.data?.detail || error.message || '处理失败';
|
||||||
|
|
||||||
addMessage({
|
addMessage({
|
||||||
type: MessageTypes.ERROR,
|
type: MessageTypes.ERROR,
|
||||||
|
|||||||
Reference in New Issue
Block a user