feat: Agent 监控与编排、仪表盘/配置页及文档更新

- agent_runtime: orchestrator、core/memory/schemas 调整
- agent_monitoring API、service、agent_llm_log 模型与 database 注册
- 前端 AgentDashboard、AgentConfig、Agents/MainLayout/路由与 AgentChat
- 文档:(红头)项目核心文档汇总、自主AI Agent改造完成情况、AI agent改造计划

Made-with: Cursor
This commit is contained in:
renjianbo
2026-05-01 19:32:59 +08:00
parent 09467568ec
commit 036f533881
21 changed files with 2601 additions and 411 deletions

View File

@@ -8,20 +8,24 @@ POST /api/v1/agent-chat/bare
from __future__ import annotations
import logging
from typing import Any, Dict, Optional
from typing import Any, Dict, List, Optional
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from pydantic import BaseModel, Field
from app.core.database import get_db
from sqlalchemy.orm import Session
from app.api.auth import get_current_user
from app.models.user import User
from app.models.agent import Agent
from app.models.agent_llm_log import AgentLLMLog
from app.agent_runtime import (
AgentRuntime,
AgentConfig,
AgentLLMConfig,
AgentToolConfig,
AgentStep,
AgentOrchestrator,
OrchestratorAgentConfig,
)
from app.core.config import settings
@@ -29,6 +33,37 @@ logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/v1/agent-chat", tags=["agent-chat"])
def _make_llm_logger(
db: Session,
agent_id: Optional[str] = None,
user_id: Optional[str] = None,
):
"""创建 LLM 调用日志回调,写入 AgentLLMLog 表。"""
def _log(metrics: dict):
try:
log = AgentLLMLog(
agent_id=agent_id,
session_id=metrics.get("session_id"),
user_id=user_id,
model=metrics.get("model", ""),
provider=metrics.get("provider"),
prompt_tokens=metrics.get("prompt_tokens", 0),
completion_tokens=metrics.get("completion_tokens", 0),
total_tokens=metrics.get("total_tokens", 0),
latency_ms=metrics.get("latency_ms", 0),
iteration_number=metrics.get("iteration_number", 0),
step_type=metrics.get("step_type"),
tool_name=metrics.get("tool_name"),
status=metrics.get("status", "success"),
error_message=metrics.get("error_message"),
)
db.add(log)
db.commit()
except Exception as e:
logger.warning("写入 AgentLLMLog 失败: %s", e)
return _log
class ChatRequest(BaseModel):
message: str
session_id: Optional[str] = None
@@ -44,12 +79,103 @@ class ChatResponse(BaseModel):
truncated: bool
session_id: str
agent_id: Optional[str] = None
steps: List[AgentStep] = Field(default_factory=list, description="执行追踪步骤")
class OrchestrateAgentItem(BaseModel):
"""编排中单个 Agent 的定义"""
id: str
name: str = "Agent"
system_prompt: str = "你是一个有用的AI助手。"
model: str = "deepseek-v4-flash"
provider: str = "deepseek"
temperature: float = 0.7
max_iterations: int = 10
tools: List[str] = Field(default_factory=list)
description: str = ""
class OrchestrateRequest(BaseModel):
"""多 Agent 编排请求"""
message: str
mode: str = "debate"
agents: List[OrchestrateAgentItem] = Field(..., min_length=1)
model: Optional[str] = None
class OrchestrateStepItem(BaseModel):
"""编排步骤"""
agent_id: str
agent_name: str
input: str = ""
output: str = ""
iterations_used: int = 0
tool_calls_made: int = 0
error: Optional[str] = None
class OrchestrateResponse(BaseModel):
"""多 Agent 编排响应"""
mode: str
final_answer: str
steps: List[OrchestrateStepItem] = Field(default_factory=list)
agent_results: List[Dict[str, Any]] = Field(default_factory=list)
@router.post("/orchestrate", response_model=OrchestrateResponse)
async def orchestrate_agents(
req: OrchestrateRequest,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""多 Agent 编排:支持 route / sequential / debate 三种模式。"""
agents = [
OrchestratorAgentConfig(
id=a.id, name=a.name,
system_prompt=a.system_prompt,
model=req.model or a.model,
provider=a.provider,
temperature=a.temperature,
max_iterations=a.max_iterations,
tools=a.tools,
description=a.description,
)
for a in req.agents
]
on_llm_call = _make_llm_logger(db, agent_id=None, user_id=current_user.id)
orchestrator = AgentOrchestrator(
default_llm_config=AgentLLMConfig(
model=req.model or "deepseek-v4-flash",
temperature=0.3,
),
)
result = await orchestrator.run(req.mode, req.message, agents, on_llm_call=on_llm_call)
return OrchestrateResponse(
mode=result.mode,
final_answer=result.final_answer,
steps=[
OrchestrateStepItem(
agent_id=s.agent_id,
agent_name=s.agent_name,
input=s.input,
output=s.output,
iterations_used=s.iterations_used,
tool_calls_made=s.tool_calls_made,
error=s.error,
)
for s in result.steps
],
agent_results=result.agent_results,
)
@router.post("/bare", response_model=ChatResponse)
async def chat_bare(
req: ChatRequest,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""无需 Agent 配置,使用默认设置直接对话。"""
config = AgentConfig(
@@ -65,7 +191,8 @@ async def chat_bare(
),
user_id=current_user.id,
)
runtime = AgentRuntime(config=config)
on_llm_call = _make_llm_logger(db, agent_id=None, user_id=current_user.id)
runtime = AgentRuntime(config=config, on_llm_call=on_llm_call)
result = await runtime.run(req.message)
return ChatResponse(
@@ -74,6 +201,7 @@ async def chat_bare(
tool_calls_made=result.tool_calls_made,
truncated=result.truncated,
session_id=runtime.context.session_id,
steps=result.steps,
)
@@ -113,7 +241,8 @@ async def chat_with_agent(
user_id=current_user.id,
)
runtime = AgentRuntime(config=config)
on_llm_call = _make_llm_logger(db, agent_id=agent_id, user_id=current_user.id)
runtime = AgentRuntime(config=config, on_llm_call=on_llm_call)
result = await runtime.run(req.message)
return ChatResponse(
@@ -123,6 +252,7 @@ async def chat_with_agent(
truncated=result.truncated,
session_id=runtime.context.session_id,
agent_id=agent_id,
steps=result.steps,
)