feat(admin): Agent 并发 - 后台可调同时对话上限并展示 Agent 服务状态

新增运行策略 agentMaxSessions(默认 30,范围 1-64),保存后同时下发到内嵌进程闸门与独立 yingce-agent 的 /v1/limit,降低上限不会中断已开始的对话。系统性能页展示 Agent 服务健康、进行中/排队数量,并可直接修改上限。
This commit is contained in:
ddcat666
2026-09-30 03:37:54 +08:00
parent b59317415d
commit 0ac61434df
17 changed files with 408 additions and 29 deletions

View File

@@ -77,6 +77,14 @@ const agentFields: PolicyField[] = [
min: 0,
max: 3_600,
},
{
group: "task",
name: "agentMaxSessions",
label: "同时对话上限",
extra: "同时进行中的画布 Agent 轮次,新安装默认 30。审批等待不占名额,降低上限不会中断已开始的对话。",
unit: "个",
max: 64,
},
];
const rateFields: PolicyField[] = [

View File

@@ -1,8 +1,8 @@
import { App, Button, Progress, Skeleton, Switch } from "antd";
import { Activity, AlertTriangle, Cpu, Database, Gauge, HardDrive, MemoryStick, RefreshCw, Server, ShieldCheck, Trash2, Wifi } from "lucide-react";
import { App, Button, InputNumber, Progress, Skeleton, Switch } from "antd";
import { Activity, AlertTriangle, Bot, Cpu, Database, Gauge, HardDrive, MemoryStick, RefreshCw, Server, ShieldCheck, Trash2, Wifi } from "lucide-react";
import { useCallback, useEffect, useRef, useState, type ReactNode } from "react";
import { clearRuntimeCache, getSystemPerformance, type SystemPerformance } from "@/services/api/system-performance";
import { clearRuntimeCache, getSystemPerformance, updateAgentSessionLimit, type SystemPerformance } from "@/services/api/system-performance";
import { AdminPageFrame } from "../components/admin-shell";
import { AdminStatusBadge, SettingsSectionCard } from "../components/admin-ui";
@@ -61,6 +61,8 @@ export default function SystemPerformancePage() {
const [loading, setLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false);
const [clearing, setClearing] = useState(false);
const [savingAgentLimit, setSavingAgentLimit] = useState(false);
const [agentLimitDraft, setAgentLimitDraft] = useState<number | null>(null);
const [autoRefresh, setAutoRefresh] = useState(true);
const [loadError, setLoadError] = useState("");
const mountedRef = useRef(true);
@@ -149,7 +151,7 @@ export default function SystemPerformancePage() {
return (
<AdminPageFrame
title="系统性能"
description="紧凑查看主机、数据库、Redis 和安全运行时缓存;敏感连接信息不会在此展示。"
description="紧凑查看主机、数据库、Redis、画布 Agent 和安全运行时缓存;敏感连接信息不会在此展示。"
scroll
actions={<><label className="admin-performance-auto"><Switch size="small" checked={autoRefresh} onChange={setAutoRefresh} /><span>15 秒刷新</span></label><Button icon={<RefreshCw className="size-4" />} loading={refreshing} onClick={() => void load(false)}>刷新</Button></>}
>
@@ -213,6 +215,30 @@ export default function SystemPerformancePage() {
</div>
</div>
{(data.agents || []).map((agent) => {
const draft = agentLimitDraft ?? agent.configuredLimit;
return <SettingsSectionCard key={agent.id} layout="stacked" icon={<Bot className="size-4" />} title="画布 Agent 服务" description="同时进行中的对话占用一个名额。审批等待不占用。降低上限不会中断已经开始的对话,也不会在这台机器上再启动容器。" status={{ label: agent.healthy ? "服务可连接" : "服务不可达", color: agent.healthy ? "success" : "error" }} footer={<><span className="admin-performance-cache-note"><Gauge className="size-3.5" />新安装默认 30,一般不用再改</span><span style={{ display: "flex", gap: 8, alignItems: "center" }}><InputNumber min={1} max={64} precision={0} value={draft} onChange={(value) => setAgentLimitDraft(typeof value === "number" ? value : draft)} /><Button type="primary" loading={savingAgentLimit} disabled={draft === agent.configuredLimit} onClick={() => {
setSavingAgentLimit(true);
void updateAgentSessionLimit(draft).then(() => {
message.success("已应用 Agent 同时对话上限");
setAgentLimitDraft(null);
return load(false);
}).catch((error: unknown) => {
message.error(error instanceof Error ? error.message : "保存 Agent 上限失败");
}).finally(() => setSavingAgentLimit(false));
}}>保存上限</Button></span></>}>
<FactGrid>
<Fact label="服务" value={agent.name} />
<Fact label="运行位置" value={agent.mode === "remote" ? "独立服务" : "后端进程"} />
<Fact label="地址" value={agent.endpoint} mono />
<Fact label="进行中 / 上限" value={`${formatNumber(agent.active)} / ${formatNumber(agent.limit)}`} />
<Fact label="排队" value={formatNumber(agent.queued)} />
<Fact label="已保存上限" value={formatNumber(agent.configuredLimit)} />
<Fact label="说明" value={agent.statusMessage || "同一台机器提高上限即可,不需要再启动容器。"} />
</FactGrid>
</SettingsSectionCard>;
})}
<SettingsSectionCard layout="stacked" icon={<ShieldCheck className="size-4" />} title="缓存维护" description="只清理可安全重建的运行时状态,保留业务数据与活动并发租约。" status={<AdminStatusBadge label="白名单清理" tone="success" />} footer={<><span className="admin-performance-cache-note"><Gauge className="size-3.5" />清理后频控与线路健康状态会重新计算</span><Button danger icon={<Trash2 className="size-4" />} loading={clearing} onClick={requestClear}>清理运行时缓存</Button></>}>
<div className="admin-performance-cache-groups">
{(data?.redis.cacheGroups || []).map((group) => <div key={group.id}><span>{group.label}</span><strong>{formatNumber(group.keys)}</strong><small>keys</small></div>)}

View File

@@ -350,6 +350,8 @@ export type RuntimeTaskPolicy = {
agentStepMaxOutputTokens: number;
/** 画布 Agent 单步模型调用的秒级墙钟;0 表示沿用文本任务超时。 */
agentStepTimeoutSeconds: number;
/** 同时进行中的画布 Agent 轮次上限。审批等待不占用名额。 */
agentMaxSessions: number;
};
export type RuntimeRequestPolicy = {

View File

@@ -105,9 +105,23 @@ export type SystemPerformance = {
cacheGroups: SystemPerformanceCacheGroup[];
statusMessage?: string;
};
agents: SystemPerformanceAgent[];
build: { version: string; commit: string; buildTime: string; goVersion: string };
};
export type SystemPerformanceAgent = {
id: string;
name: string;
mode: "remote" | "embedded";
endpoint: string;
healthy: boolean;
active: number;
limit: number;
queued: number;
configuredLimit: number;
statusMessage?: string;
};
export type RuntimeCacheClearResult = {
scope: "runtime";
deletedKeys: number;
@@ -120,6 +134,10 @@ export function getSystemPerformance(signal?: AbortSignal) {
return http.get<SystemPerformance>("/admin/system-performance", { signal });
}
export function updateAgentSessionLimit(maxSessions: number) {
return http.put<SystemPerformanceAgent>("/admin/system-performance/agent-limit", { maxSessions });
}
export function clearRuntimeCache() {
return http.post<RuntimeCacheClearResult>("/admin/system-performance/cache/clear", { scope: "runtime" });
}