agent功能开发增加MCP后端

This commit is contained in:
2025-11-07 20:23:54 +08:00
parent f01eff6eb7
commit 322b1dd845
3 changed files with 332 additions and 58 deletions

View File

@@ -6,9 +6,9 @@ MCP Server for Financial Data Search
from fastapi import FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi.responses import JSONResponse, StreamingResponse
from pydantic import BaseModel, Field
from typing import List, Dict, Any, Optional, Literal
from typing import List, Dict, Any, Optional, Literal, AsyncGenerator
from datetime import datetime, date
import logging
import httpx
@@ -16,6 +16,7 @@ from enum import Enum
import mcp_database as db
from openai import OpenAI
import json
import asyncio
# 配置日志
logging.basicConfig(level=logging.INFO)
@@ -1327,7 +1328,7 @@ class MCPAgentIntegrated:
tools: List[dict],
tool_handlers: Dict[str, Any],
) -> AgentResponse:
"""主流程"""
"""主流程(非流式)"""
logger.info(f"[Agent] 处理查询: {user_query}")
try:
@@ -1368,6 +1369,131 @@ class MCPAgentIntegrated:
message=f"处理失败: {str(e)}",
)
async def process_query_stream(
self,
user_query: str,
tools: List[dict],
tool_handlers: Dict[str, Any],
) -> AsyncGenerator[str, None]:
"""主流程(流式输出)- 逐步返回执行结果"""
logger.info(f"[Agent Stream] 处理查询: {user_query}")
try:
# 发送开始事件
yield self._format_sse("status", {"stage": "start", "message": "开始处理查询"})
# 阶段1: Kimi 制定计划
yield self._format_sse("status", {"stage": "planning", "message": "正在制定执行计划..."})
plan = await self.create_plan(user_query, tools)
# 发送计划
yield self._format_sse("plan", {
"goal": plan.goal,
"reasoning": plan.reasoning,
"steps": [
{"tool": step.tool, "arguments": step.arguments, "reason": step.reason}
for step in plan.steps
],
})
# 阶段2: 执行工具(逐步返回)
yield self._format_sse("status", {"stage": "executing", "message": f"开始执行 {len(plan.steps)} 个步骤"})
step_results = []
collected_data = {}
for i, step in enumerate(plan.steps):
# 发送步骤开始事件
yield self._format_sse("step_start", {
"step_index": i,
"tool": step.tool,
"arguments": step.arguments,
"reason": step.reason,
})
start_time = datetime.now()
try:
# 替换占位符
arguments = step.arguments.copy()
if step.tool == "summarize_news":
if arguments.get("data") in ["前面的新闻数据", "前面收集的所有数据"]:
arguments["data"] = json.dumps(collected_data, ensure_ascii=False, indent=2)
# 执行工具
result = await self.execute_tool(step.tool, arguments, tool_handlers)
execution_time = (datetime.now() - start_time).total_seconds()
step_result = StepResult(
step_index=i,
tool=step.tool,
arguments=arguments,
status="success",
result=result,
execution_time=execution_time,
)
step_results.append(step_result)
collected_data[f"step_{i+1}_{step.tool}"] = result
# 发送步骤完成事件(包含结果)
yield self._format_sse("step_complete", {
"step_index": i,
"tool": step.tool,
"status": "success",
"result": result,
"execution_time": execution_time,
})
except Exception as e:
execution_time = (datetime.now() - start_time).total_seconds()
step_result = StepResult(
step_index=i,
tool=step.tool,
arguments=step.arguments,
status="failed",
error=str(e),
execution_time=execution_time,
)
step_results.append(step_result)
# 发送步骤失败事件
yield self._format_sse("step_complete", {
"step_index": i,
"tool": step.tool,
"status": "failed",
"error": str(e),
"execution_time": execution_time,
})
# 阶段3: Kimi 生成总结
yield self._format_sse("status", {"stage": "summarizing", "message": "正在生成最终总结..."})
final_summary = await self.generate_final_summary(user_query, plan, step_results)
# 发送最终总结
yield self._format_sse("summary", {
"content": final_summary,
"metadata": {
"total_steps": len(plan.steps),
"successful_steps": len([r for r in step_results if r.status == "success"]),
"failed_steps": len([r for r in step_results if r.status == "failed"]),
"total_execution_time": sum(r.execution_time for r in step_results),
},
})
# 发送完成事件
yield self._format_sse("done", {"message": "处理完成"})
except Exception as e:
logger.error(f"[Agent Stream] 错误: {str(e)}", exc_info=True)
yield self._format_sse("error", {"message": f"处理失败: {str(e)}"})
def _format_sse(self, event: str, data: dict) -> str:
"""格式化 SSE 消息"""
return f"event: {event}\ndata: {json.dumps(data, ensure_ascii=False)}\n\n"
# 创建 Agent 实例(全局)
agent = MCPAgentIntegrated()
@@ -1406,7 +1532,7 @@ async def chat(request: ChatRequest):
@app.post("/agent/chat", response_model=AgentResponse)
async def agent_chat(request: AgentChatRequest):
"""智能代理对话端点"""
"""智能代理对话端点(非流式)"""
logger.info(f"Agent chat: {request.message}")
# 获取工具列表
@@ -1441,6 +1567,49 @@ async def agent_chat(request: AgentChatRequest):
return response
@app.post("/agent/chat/stream")
async def agent_chat_stream(request: AgentChatRequest):
"""智能代理对话端点(流式 SSE"""
logger.info(f"Agent chat stream: {request.message}")
# 获取工具列表
tools = [tool.dict() for tool in TOOLS]
# 添加特殊工具summarize_news
tools.append({
"name": "summarize_news",
"description": "使用 DeepMoney 模型总结新闻数据,提取关键信息",
"parameters": {
"type": "object",
"properties": {
"data": {
"type": "string",
"description": "要总结的新闻数据JSON格式"
},
"focus": {
"type": "string",
"description": "关注点,例如:'市场影响''投资机会'"
}
},
"required": ["data"]
}
})
# 返回流式响应
return StreamingResponse(
agent.process_query_stream(
user_query=request.message,
tools=tools,
tool_handlers=TOOL_HANDLERS,
),
media_type="text/event-stream",
headers={
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"X-Accel-Buffering": "no", # 禁用 Nginx 缓冲
},
)
# ==================== 健康检查 ====================
@app.get("/health")