Repository navigation
Expand file tree
/
Copy pathmain.py
More file actions
152 lines (121 loc) · 4.45 KB
/
Copy pathmain.py
File metadata and controls
152 lines (121 loc) · 4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
"""
Multi-Agent E-Commerce Recommendation System — FastAPI Entry Point
Endpoints:
POST /api/v1/recommend - 获取个性化推荐
POST /api/v1/recommend/graph - 通过LangGraph pipeline推荐
GET /api/v1/experiments - 查看A/B实验状态
GET /api/v1/metrics - 查看系统监控指标
GET /health - 健康检查
"""
from __future__ import annotations
import sys
import os
sys.path.insert(0, os.path.dirname(__file__))
from contextlib import asynccontextmanager
from typing import Any
import structlog
import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from config import get_settings
from models.schemas import RecommendationRequest, RecommendationResponse
from orchestrator.supervisor import SupervisorOrchestrator
from orchestrator.graph import build_recommendation_graph
from services.ab_test import ABTestEngine
from services.metrics import MetricsCollector
logger = structlog.get_logger()
settings = get_settings()
ab_engine = ABTestEngine()
metrics_collector = MetricsCollector()
supervisor = SupervisorOrchestrator(ab_engine=ab_engine)
rec_graph = None
@asynccontextmanager
async def lifespan(app: FastAPI):
global rec_graph
rec_graph = build_recommendation_graph()
logger.info("app.startup", model=settings.llm_model)
yield
logger.info("app.shutdown")
app = FastAPI(
title="Multi-Agent E-Commerce Recommendation System",
description="用户画像Agent + 商品推荐Agent + 营销文案Agent + 库存决策Agent,并行+聚合模式",
version="1.0.0",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/health")
async def health():
return {"status": "healthy", "model": settings.llm_model}
@app.post("/api/v1/recommend", response_model=RecommendationResponse)
async def recommend(request: RecommendationRequest):
"""使用Supervisor编排器进行推荐 (生产推荐用法)"""
response = await supervisor.recommend(request)
_collect_metrics(response)
return response
@app.post("/api/v1/recommend/graph")
async def recommend_via_graph(request: RecommendationRequest):
"""使用LangGraph状态图进行推荐 (展示LangGraph能力)"""
if not rec_graph:
return {"error": "Graph not initialized"}
state = {
"user_id": request.user_id,
"scene": request.scene,
"num_items": request.num_items,
"context": request.context,
}
result = await rec_graph.ainvoke(state)
return {
"request_id": result.get("request_id"),
"user_id": result.get("user_id"),
"products": [p.model_dump() for p in result.get("final_products", [])],
"marketing_copies": result.get("marketing_copies", []),
"experiment_group": result.get("experiment_group", "control"),
"total_latency_ms": round(result.get("total_latency_ms", 0), 1),
}
@app.get("/api/v1/experiments")
async def get_experiments():
"""查看所有A/B实验状态"""
experiments = {}
for exp_id, exp in ab_engine.experiments.items():
experiments[exp_id] = {
"name": exp.name,
"enabled": exp.enabled,
"groups": [
{
"name": g.name,
"weight": g.weight,
"config": g.config,
"successes": g.successes,
"failures": g.failures,
}
for g in exp.groups
],
"stats": ab_engine.get_stats(exp_id),
}
return experiments
@app.get("/api/v1/metrics")
async def get_metrics():
"""查看系统监控指标"""
return {
"agents": metrics_collector.get_agent_stats(),
"business": metrics_collector.get_business_stats(),
}
@app.post("/api/v1/experiments/{experiment_id}/outcome")
async def record_outcome(experiment_id: str, group: str, success: bool):
"""记录A/B测试结果,更新Thompson Sampling"""
ab_engine.record_outcome(experiment_id, group, success)
return {"status": "recorded"}
def _collect_metrics(response: RecommendationResponse):
for name, result in response.agent_results.items():
metrics_collector.record_agent_call(
agent_name=name,
success=result.success,
latency_ms=result.latency_ms,
)
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)