Files
aiagent/backend/app/api/agent_chat.py
renjianbo 09467568ec feat: Agent 运行时、对话 API、作业助手与引擎修复及前端执行超时
- agent_runtime 模块与 agent_chat API,前端 AgentChat 视图与路由对接
- workflow_engine: code 节点命名空间与 json 引用修复
- llm_service: 工具调用 extra_body(如 DeepSeek)
- create_homework_manager_agent / _3 脚本与测试脚本扩展
- frontend: WORKFLOW_EXECUTION_HTTP_TIMEOUT_MS、AgentChatPreview/MainLayout 等
- 文档:架构说明与自主 Agent 改造完成情况

Made-with: Cursor
2026-05-01 11:31:48 +08:00

138 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Agent 独立聊天 API — 不依赖工作流 DAG直接与 Agent Runtime 对话。
POST /api/v1/agent-chat/bare
{"message": "你好,帮我..."}
{"content": "...", "iterations": 3, "tool_calls": 5}
"""
from __future__ import annotations
import logging
from typing import Any, Dict, Optional
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
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.agent_runtime import (
AgentRuntime,
AgentConfig,
AgentLLMConfig,
AgentToolConfig,
)
from app.core.config import settings
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/v1/agent-chat", tags=["agent-chat"])
class ChatRequest(BaseModel):
message: str
session_id: Optional[str] = None
model: Optional[str] = None
temperature: Optional[float] = None
max_iterations: Optional[int] = None
class ChatResponse(BaseModel):
content: str
iterations_used: int
tool_calls_made: int
truncated: bool
session_id: str
agent_id: Optional[str] = None
@router.post("/bare", response_model=ChatResponse)
async def chat_bare(
req: ChatRequest,
current_user: User = Depends(get_current_user),
):
"""无需 Agent 配置,使用默认设置直接对话。"""
config = AgentConfig(
name="bare_agent",
system_prompt="你是一个有用的AI助手。请使用可用工具来帮助用户完成任务。",
llm=AgentLLMConfig(
model=req.model or (
"gpt-4o-mini" if settings.OPENAI_API_KEY and settings.OPENAI_API_KEY != "your-openai-api-key"
else "deepseek-v4-flash"
),
temperature=req.temperature or 0.7,
max_iterations=req.max_iterations or 10,
),
user_id=current_user.id,
)
runtime = AgentRuntime(config=config)
result = await runtime.run(req.message)
return ChatResponse(
content=result.content,
iterations_used=result.iterations_used,
tool_calls_made=result.tool_calls_made,
truncated=result.truncated,
session_id=runtime.context.session_id,
)
@router.post("/{agent_id}", response_model=ChatResponse)
async def chat_with_agent(
agent_id: str,
req: ChatRequest,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""与指定的 Agent 对话。Agent 的工作流配置会用于构建 Runtime。"""
agent = db.query(Agent).filter(Agent.id == agent_id).first()
if not agent:
raise HTTPException(status_code=404, detail="Agent 不存在")
if agent.user_id and agent.user_id != current_user.id and current_user.role != "admin":
raise HTTPException(status_code=403, detail="无权访问该 Agent")
# 从 Agent 配置构建 Runtime
wc = agent.workflow_config or {}
nodes = wc.get("nodes", [])
# 查找 agent 节点的配置(或第一个 llm 节点的配置)
agent_node_cfg = _find_agent_node_config(nodes)
config = AgentConfig(
name=agent.name,
system_prompt=agent_node_cfg.get("system_prompt") or agent.description or "你是一个有用的AI助手。",
llm=AgentLLMConfig(
provider=agent_node_cfg.get("provider", "openai"),
model=req.model or agent_node_cfg.get("model", "gpt-4o-mini"),
temperature=req.temperature or float(agent_node_cfg.get("temperature", 0.7)),
max_iterations=req.max_iterations or int(agent_node_cfg.get("max_iterations", 10)),
),
tools=AgentToolConfig(
include_tools=agent_node_cfg.get("tools", []),
exclude_tools=agent_node_cfg.get("exclude_tools", []),
),
user_id=current_user.id,
)
runtime = AgentRuntime(config=config)
result = await runtime.run(req.message)
return ChatResponse(
content=result.content,
iterations_used=result.iterations_used,
tool_calls_made=result.tool_calls_made,
truncated=result.truncated,
session_id=runtime.context.session_id,
agent_id=agent_id,
)
def _find_agent_node_config(nodes: list) -> Dict[str, Any]:
"""从工作流节点列表中查找第一个 agent 类型或 llm 类型的节点配置。"""
if not nodes:
return {}
for node in nodes:
typ = node.get("type", "")
if typ in ("agent", "llm", "template"):
return node.get("data") or {}
return {}