From 6009ce801ff430e9f10b4f21dcaa65f93f043cc2 Mon Sep 17 00:00:00 2001 From: JianFeeeee Date: Wed, 26 Aug 2026 13:38:27 +0800 Subject: [PATCH] =?UTF-8?q?feat(agent):=20spawn=5Fchild=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20max=5Fturns=20+=20=E5=B9=B6=E8=A1=8C=E7=AD=96?= =?UTF-8?q?=E7=95=A5=E5=BC=95=E5=AF=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. spawn_child 新增 max_turns 参数(1-30,默认 5) 子 Agent 工具轮数此前硬编码 5,复杂任务跑不完即截断。现可按任务 复杂度调整;返回消息带轮数上限提示。 2. 工具描述与 system prompt 增加并行策略引导 明确'多个互不依赖的子任务应并行 spawn 多个子 Agent,不要串行 逐个执行;长耗时任务交给子 Agent 避免阻塞对话'——针对生产实例 观察到的 agent 倾向自己串行处理所有子任务的问题。 小宅自定义 prompt 同步补充并行策略段。 --- cmd/homed/main.go | 5 ++++- internal/agent/core/spawn.go | 21 +++++++++++++++++---- internal/agent/core/tooldefs.go | 6 +++++- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/cmd/homed/main.go b/cmd/homed/main.go index dfb4067..bab8949 100644 --- a/cmd/homed/main.go +++ b/cmd/homed/main.go @@ -391,7 +391,10 @@ func main() { - output_* — 输出通道管理(切换/发送消息) - timer_set — 设置定时提醒 - plgreload — 热重载插件 -- spawn_child — 生成子 Agent 执行独立任务 +- spawn_child — 生成子 Agent 异步执行独立任务(可传 max_turns 控制工具轮数,默认 5) + +并行策略:遇到多个互不依赖的子任务时,优先并行 spawn 多个子 Agent 而非自己串行逐个执行; +长耗时任务(批量处理、多轮搜索汇总)也应交给子 Agent,避免阻塞当前对话。 - describe_image — 描述用户上传的图片 - transcribe_audio — 转写用户上传的音频 - ocr_image — 识别图片中的文字 diff --git a/internal/agent/core/spawn.go b/internal/agent/core/spawn.go index ca809b8..b20ec82 100644 --- a/internal/agent/core/spawn.go +++ b/internal/agent/core/spawn.go @@ -13,6 +13,16 @@ func (a *Agent) executeSpawnChild(tc agentAPI.ToolCall) string { if task == "" { return "请提供 task 参数" } + maxTurns := 0 + if v, ok := tc.Arguments["max_turns"].(float64); ok { + maxTurns = int(v) + } + if maxTurns < 1 { + maxTurns = defaultChildMaxTurns + } + if maxTurns > 30 { + maxTurns = 30 + } a.childMu.Lock() a.childNextID++ @@ -26,12 +36,15 @@ func (a *Agent) executeSpawnChild(tc agentAPI.ToolCall) string { parentChannel = "cli" } - go a.runChildTask(taskID, task, parentChannel) + go a.runChildTask(taskID, task, parentChannel, maxTurns) - return fmt.Sprintf("子任务已启动(ID: %s),完成后会自动通知你,届时请使用 child_result 工具查看输出", taskID) + return fmt.Sprintf("子任务已启动(ID: %s,最多 %d 轮),完成后会自动通知你,届时请使用 child_result 工具查看输出", taskID, maxTurns) } -func (a *Agent) runChildTask(taskID, task string, parentChannel string) { +// defaultChildMaxTurns 子 Agent 默认工具轮数(可被 spawn_child 的 max_turns 参数覆盖)。 +const defaultChildMaxTurns = 5 + +func (a *Agent) runChildTask(taskID, task string, parentChannel string, maxTurns int) { if a.provider == nil { log.Printf("[child] %s failed: no LLM provider configured", taskID) return @@ -66,7 +79,7 @@ func (a *Agent) runChildTask(taskID, task string, parentChannel string) { } var finalResult string - for turn := 0; turn < 5; turn++ { + for turn := 0; turn < maxTurns; turn++ { req := &agentAPI.CompletionRequest{ Messages: msgs, MaxTokens: 4096, diff --git a/internal/agent/core/tooldefs.go b/internal/agent/core/tooldefs.go index b1b9973..d657cfc 100644 --- a/internal/agent/core/tooldefs.go +++ b/internal/agent/core/tooldefs.go @@ -460,7 +460,7 @@ func (a *Agent) buildToolDefs() []interface{} { "type": "function", "function": map[string]interface{}{ "name": "spawn_child", - "description": "启动一个异步子 Agent 执行独立任务。子 Agent 后台运行,不阻塞当前对话。完成后系统会自动通知你,届时请调用 child_result 工具查看输出。", + "description": "启动一个异步子 Agent 执行独立任务。子 Agent 后台运行,不阻塞当前对话。完成后系统会自动通知你,届时请调用 child_result 工具查看输出。\n使用时机:多个互不依赖的子任务(如同时查三个网站、分别处理多个文件)应并行 spawn 多个子 Agent,不要自己串行逐个执行;长耗时任务(批量处理、多轮搜索)也应交给子 Agent,避免阻塞对话。", "parameters": map[string]interface{}{ "type": "object", "properties": map[string]interface{}{ @@ -468,6 +468,10 @@ func (a *Agent) buildToolDefs() []interface{} { "type": "string", "description": "要子 Agent 完成的任务描述。请描述清晰、完整,包含所有必要背景。", }, + "max_turns": map[string]interface{}{ + "type": "integer", + "description": "子 Agent 最大工具轮数(默认 5,范围 1-30)。复杂任务可调高。", + }, }, "required": []string{"task"}, },