fix(dispatcher): 多智能体专家超时 —— 卡死专家不再拖垮协调(T4.E)
- specialistTool 加 timeout 字段(默认 specialistTimeout=3min,专家可多轮 react+工具故给宽) - InvokableRun 用 WithTimeout 包裹专家派发;超时(DeadlineExceeded)作为"观察" 跳过该专家(err=nil),lead 据其余专家继续综合,不中断整个协调 - 2 单测:卡死专家 ~50ms 跳过并返回超时观察 / 正常专家不受影响 - timeout=0 时不包裹(向后兼容既有 specialistTool 构造) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
package eino
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cloudwego/eino/schema"
|
||||
)
|
||||
|
||||
// 专家超时:卡死的专家应在 timeout 附近作为"观察"跳过(err=nil,不中断协调),
|
||||
// 而非无限阻塞 lead。
|
||||
func TestSpecialist_TimeoutSkips(t *testing.T) {
|
||||
o := newOrch(&fakeLLM{}, kbTool(nil), &fakeSink{}, &fakeExec{})
|
||||
st := &specialistTool{
|
||||
name: "分析专家",
|
||||
tr: o.tracer("t1"),
|
||||
timeout: 50 * time.Millisecond,
|
||||
info: &schema.ToolInfo{Name: "分析专家"},
|
||||
run: func(ctx context.Context, _ string) (string, error) {
|
||||
<-ctx.Done() // 模拟卡死:直到超时被取消
|
||||
return "", ctx.Err()
|
||||
},
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
out, err := st.InvokableRun(context.Background(), `{"brief":"干活"}`)
|
||||
elapsed := time.Since(start)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("专家超时应作为观察返回、err=nil(不中断协调),got err=%v", err)
|
||||
}
|
||||
if !strings.Contains(out, "超时") {
|
||||
t.Errorf("应返回超时观察,got %q", out)
|
||||
}
|
||||
if elapsed > 2*time.Second {
|
||||
t.Errorf("应在超时(50ms)附近返回,实际耗时 %v(疑似未生效)", elapsed)
|
||||
}
|
||||
}
|
||||
|
||||
// 正常专家不受超时影响。
|
||||
func TestSpecialist_NormalWithinTimeout(t *testing.T) {
|
||||
o := newOrch(&fakeLLM{}, kbTool(nil), &fakeSink{}, &fakeExec{})
|
||||
st := &specialistTool{
|
||||
name: "快专家",
|
||||
tr: o.tracer("t1"),
|
||||
timeout: time.Second,
|
||||
info: &schema.ToolInfo{Name: "快专家"},
|
||||
run: func(_ context.Context, brief string) (string, error) { return "结论:" + brief, nil },
|
||||
}
|
||||
out, err := st.InvokableRun(context.Background(), `{"brief":"分析X"}`)
|
||||
if err != nil || !strings.Contains(out, "结论:分析X") {
|
||||
t.Fatalf("正常专家应返回结论,got out=%q err=%v", out, err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user