| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596 |
- """FastAPI 后端 — SSE 实时推送 Agent 执行 trace"""
- import json, asyncio
- from fastapi import FastAPI
- from fastapi.staticfiles import StaticFiles
- from fastapi.responses import FileResponse, StreamingResponse
- from pydantic import BaseModel
- from config import APP_PORT
- from orchestrator import run_supervisor, run_pipeline, run_debate
- app = FastAPI(title="Multi-Agent Demo")
- class ExecuteRequest(BaseModel):
- mode: str # supervisor | pipeline | debate
- query: str
- MODE_RUNNERS = {
- "supervisor": run_supervisor,
- "pipeline": run_pipeline,
- "debate": run_debate,
- }
- PRESETS = {
- "supervisor": {
- "title": "Agent 面试题调研 + 数据分析",
- "query": "搜索 2025 年最新的 Agent 开发面试题,重点找 RAG、多 Agent 协同、上下文工程相关的题目,统计各方向的题目数量占比",
- },
- "pipeline": {
- "title": "面试题竞品分析报告",
- "query": "搜索 LangChain、CrewAI、AutoGen 三个多 Agent 框架的核心差异、社区活跃度、适用场景,生成一份结构化的对比分析报告",
- },
- "debate": {
- "title": "技术选型辩论",
- "query": "Agent 开发应该用 LangGraph 还是从零手撸?LangGraph 框架 vs 纯代码手写,哪种更适合生产环境?",
- },
- }
- @app.get("/")
- async def index():
- return FileResponse("index.html")
- @app.get("/api/presets")
- async def get_presets():
- return PRESETS
- @app.post("/api/execute")
- async def execute(req: ExecuteRequest):
- runner = MODE_RUNNERS.get(req.mode)
- if not runner:
- return {"error": f"Unknown mode: {req.mode}"}
- async def stream():
- queue = asyncio.Queue()
- def emit(event):
- queue.put_nowait(event)
- # 在线程中运行(LLM 调用是阻塞的)
- import threading
- result_holder = {}
- def run():
- try:
- result = runner(req.query, emit=emit)
- result_holder["result"] = result
- except Exception as e:
- result_holder["error"] = str(e)
- finally:
- queue.put_nowait(None) # 结束信号
- thread = threading.Thread(target=run, daemon=True)
- thread.start()
- # 流式输出事件
- while True:
- event = await queue.get()
- if event is None:
- break
- yield f"data: {json.dumps(event, ensure_ascii=False)}\n\n"
- # 发送最终结果
- if "error" in result_holder:
- yield f"data: {json.dumps({'type': 'error', 'message': result_holder['error']}, ensure_ascii=False)}\n\n"
- elif "result" in result_holder:
- yield f"data: {json.dumps({'type': 'final', **result_holder['result']}, ensure_ascii=False)}\n\n"
- return StreamingResponse(stream(), media_type="text/event-stream")
- if __name__ == "__main__":
- import uvicorn
- uvicorn.run(app, host="0.0.0.0", port=APP_PORT)
|