Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Feature Request: Router 决策链路与错误来源可视化(自动路由的诊断痛点) #105

Open
Assignees

Description

问题描述:

当 PilotDeck 的 TokenSaver/自动路由模块选择了一个 provider/model 后,如果该模型调用失败(配额不足/上下文超限/认证错误等),前端 UI 或 QQ Bot 通道仅展示类似 错误:request (74815 tokens) exceeds the available context size (65536 tokens) 的消息,完全不体现是哪个 provider 和 model 报的错。

用户在前端无法直观判断:
当前错误是哪个供应商/模型产生的,比如欠费都不能立即知道应该向哪个供应商缴费、路由决策链路是怎样的(Judge 判断结果 → 选择的 tier → 最终 provider/model → fallback 链状态),出错的是主路由还是 TokenSaver Judge 模型。

当前仅有一条 console.log 路由决策日志(RouterRuntime.ts L263-265),但出错时不会与错误信息关联输出。
pilotdeck_router_execute_failed 事件(RouterRuntime.ts L569-578)已经包含了 provider 和 model,但未能传播到前端 GatewayEvent.error 事件中。

建议方案

方案一(最小侵入):

将 provider/model 注入 GatewayEvent.error 在 pilotdeck_router_execute_failed → RouterRuntime.ts L607 的 yield { type: "error", error: lastError } 前的某处,或在 execute() 方法尾部,将实际请求的 provider/model 附加到 error 对象中,使其传播到前端的 GatewayEvent.error:
CanonicalModelError 增加可选字段 routeModel?: string(或类似命名),既保留原始错误语义又不破坏兼容性;
在 fallback 链全部耗尽、最终 yield error 的节点(L569-608),将 lastAttempt 的 provider/model 填入 lastError
前端(qq-render.ts、Web UI 的 EventStream)和 QQ Channel, 消费时只需读取这些新增字段即可显示完整诊断信息 。

方案二(推荐,影响面可控)

在 GatewayEvent.error 中新增 routeInfo 字段
GatewayEvent.error(gateway/protocol/types.ts L157)的当前定义:
| { type: "error"; message: string; code?: string; recoverable: boolean }

建议扩展为:
| { type: "error"; message: string; code?: string; recoverable: boolean; routeInfo?: { provider: string; model: string; tier?: string; resolvedFrom?: string; scenarioType?: string } } ,
然后在 InProcessGateway.ts 的 turn_failed 事件映射处(L698-706)或 mapAgentEvent 的事件处理逻辑中,附加 routeInfo 数据。

具体来说:
TurnRunner.ts 的 createErrorResult() 或 AgentLoop 的 turn_failed 事件构建处可以保留 routeInfo ,
或者更简单的方案:在 RouterRuntime.ts 的 execute() 方法中 yield { type: "error", error: lastError } 之前,将 lastDecision 的 provider/model/tier 等信息注入到 error 对象 。

方案三(零侵入), 利用已有的 RouterEventBus 机制

RouterEventBus(router/protocol/events.ts)已经定义了 RouterExecuteFailedEvent,包含了 provider/model/scenarioType。
但 Producer 只在 RouterRuntime.ts L569-578 中 emit,目前没有任何 Consumer 读取它。
在 Gateway 层添加一个对 RouterExecuteFailedEvent 的 Consumer(例如在 createLocalGateway.ts 中,事件总线构建处),一旦收到该事件,将其中携带的 provider/model 注入到关联的 GatewayEvent.error 中发出。这样无需修改事件类型定义,改动量最小。

代码参考

现有路由决策日志(RouterRuntime.ts L263-265):

console.log(
 `[router] decision: tier=${tokenSaverTier}, model=${selection.provider}/${selection.model}, orchGate=${orchGate}, alreadyOrch=${alreadyOrchestrating}, resolvedFrom=${resolvedFrom}`,
);

现有失败事件(RouterRuntime.ts L569-578):

if (lastError && lastAttempt) {
 events.emit({
 type: "pilotdeck_router_execute_failed",
 sessionId: ctx.sessionId,
 turnId: ctx.turnId,
 scenarioType: lastDecision.scenarioType,
 provider: lastAttempt.provider,
 model: lastAttempt.model,
 error: lastError,
 });

现有 CanonicalModelError(model/protocol/errors.ts L14-26):

export type CanonicalModelError = {
 provider: string; // ✅ 已有 provider
 // ❌ 缺少 model 字段
 code: CanonicalModelErrorCode | (string & {});
 message: string;
 // ...
};

前端 Consumer 不通透:
QQ: qq-render.ts L13-14:只输出 event.message
Web: InProcessGateway.ts L698-706:turn_failed 只映射 event.error.code 和 event.error.message
所有 GatewayEvent.error 事件(gateway/protocol/types.ts)缺少 model/provider 字段

期望效果

当 "供应商/DeepSeek-V4-Flash" 报 insufficient_user_quota 时,管理员在前端(Web UI / QQ Bot)直接看到类似:
[路由: tokenSaver → medium → 供应商/DeepSeek-V4-Flash ]
错误:insufficient_user_quota(配额不足,余额 0円.00)

而不是现在的:
错误:request (74815 tokens) exceeds the available context size (65536 tokens)

其他相关点

 CanonicalModelError 已有 provider 字段但没有 model 字段,建议增加以保持完整诊断信息

RouterDecision 已经包含 resolvedFrom(explicit / scenario / tokenSaver / fallback),可一并纳入前端展示
此功能建议在 Gateway 层(mapAgentEvent / mapTurnCompleted)做最后的 assembly,避免将路由细节泄漏到所有 channel 实现中

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      AltStyle によって変換されたページ (->オリジナル) /