fix(dispatcher): 中文专家名导致多智能体协调 400 挂死
buildSpecialists 把专家名原样当 OpenAI function-calling 的 tools[].function.name, 而该字段受约束 ^[a-zA-Z0-9_-]+$。中文命名专家(中文产品里最自然的用法,如"条款专家") 会让模型直接 400: Invalid 'tools[0].function.name': string does not match pattern 整个协调节点挂掉,再沿 failover 链把备用模型也拖垮。 修:toolFuncName() 规范化给模型看的函数名——非法字符→下划线,清空→expert_N, 同批内撞名加序号保证唯一;展示名与执行轨迹(agent:<原名>)仍用原名不变。 模型靠 Desc(spec.Use) 判断何时调用,函数名不承载语义,故退化命名不影响派发质量。 实测(真 deepseek):修前中文名必现 tools[0].function.name 400;修后该 400 归零。 补 TestToolFuncName 覆盖:纯中文/合法ASCII/混合名/撞名唯一性。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -89,3 +89,27 @@ func TestRunCoordinatorDegrade(t *testing.T) {
|
||||
t.Fatalf("ToolCallingModel 缺失应降级 runAgent 出答案,got %q", b.answer)
|
||||
}
|
||||
}
|
||||
|
||||
// 专家名常是中文,直接当 LLM 函数名会被 OpenAI 兼容 API 400 拒绝(^[a-zA-Z0-9_-]+$),
|
||||
// 整个多智能体协调会挂。toolFuncName 负责规范化 + 保证唯一。
|
||||
func TestToolFuncName(t *testing.T) {
|
||||
used := map[string]bool{}
|
||||
if got := toolFuncName("条款专家", 0, used); got != "expert_1" {
|
||||
t.Errorf("纯中文名应退化为 expert_1,got %q", got)
|
||||
}
|
||||
if got := toolFuncName("clause_expert", 1, used); got != "clause_expert" {
|
||||
t.Errorf("合法 ASCII 名应原样保留,got %q", got)
|
||||
}
|
||||
if got := toolFuncName("法务expert", 2, used); got != "expert" {
|
||||
t.Errorf("混合名应剥出 ASCII 部分,got %q", got)
|
||||
}
|
||||
// 与上一个 "expert" 撞名 → 加序号保证唯一
|
||||
if got := toolFuncName("风控expert", 3, used); got != "expert_4" {
|
||||
t.Errorf("撞名应加序号,got %q", got)
|
||||
}
|
||||
for _, n := range []string{"expert_1", "clause_expert", "expert", "expert_4"} {
|
||||
if !used[n] {
|
||||
t.Errorf("%q 应已登记进 used", n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user