mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-15 12:15:16 +00:00
feat(prompt): 提示词声明「同轮默认并行」及其例外(阶段 2.5)
⚠️ 本阶段有硬性顺序约束:必须在并行执行(阶段 2d)落地**之后**。 反序(先说"并发"、内核仍串行)会让提示词**对模型说谎** —— 模型据 "并发执行"推断安全性,写出真正依赖顺序的调用。宁可晚改,不可错改。 改动(tooldefs.go,buildSystemPrompt): · 新增【工具执行顺序】段,讲清四件事: 1. 同一条回复里的多个工具调用**默认并行**(同时跑),不是依次执行 2. **不要依赖执行顺序** —— 参数依赖前一个结果就分两轮 3. **例外一:同通道 output_send__ 保序**(用户可见消息顺序敏感) 4. **例外二:不并发安全的工具整批退回串行**(写类工具 / 未声明者) · 顺带说明并发安全由**工具自己声明**(ParallelSafe),不由模型判断 · 改掉 spawn_child 的落空表述:原文「应并行 spawn,不要自己串行逐个执行」 在并行化之前是**落空**的(模型照做,内核仍串行)。改为机制性表述, 并补一句「一次 spawn 只是启动动作,要拿结果仍需另一次 child_result」。 ⚠️ 措辞刻意与 batchRunnable 的**真实**判据一致(全批 ParallelSafe 才并发 + 同通道保序),而不是理想化表述 —— 提示词与实现不符,比不说更坏。 判据(prompt_parallel_test.go,5 条): · 四要点齐全(并行 / 顺序 / 保序 / 并发安全声明) · ★ 必须同时讲**例外** —— 只讲并行就是"说谎"的那一种 · 同通道保序须显式说明(保序是内核兜底,模型不知情就会浪费它) · spawn_child 不再含旧的落空措辞 · 回归防护:既有要点(输出规则 / output_list_channels / 工具能力 / 记忆清理)不丢 ★ 判据里的一次自伤:先写了 spawnChildDescription(a) 这个**不存在**的 helper("工具名反查描述"),编译失败后改为 toolDefDescription —— 内部 遍历 buildToolDefs 的**真实产物**。判据必须对着代码真实输出,不能另建一套 注册表。 变异验证:把两条例外改写成"以上适用于所有工具"⇒ 3 条判据 FAIL (缺"保序"、缺"例外"、同通道未说明)。即"提示词说谎"这一失败模式 现已被判据覆盖。 回归:internal/agent/... internal/sdk/... internal/plugins/... 全绿(15 包)。
This commit is contained in:
@ -163,6 +163,18 @@ func (a *Agent) buildSystemPrompt(memContext string, userInput string) string {
|
||||
|
||||
prompt += "\n\n【中断消息】长任务执行期间,工具/插件/定时器等会通过中断机制向你发送提醒(如 QQ 新消息、终端输出到达、定时器到点等)。中断消息以 system 角色注入,内容带 [中断消息] 前缀,**不是用户发言,但也必须认真处理**:优先停下当前长任务,针对中断内容作出响应或决定继续执行。不要忽略带 [中断消息] 前缀的 system 消息。"
|
||||
|
||||
// 工具执行顺序(阶段 2.5)。必须在**并行执行落地之后**才加:
|
||||
// 反序会让本段对模型说谎——说"并发"而内核仍串行,模型据此推断
|
||||
// 安全性并写出真正依赖顺序的调用。宁可晚改,不可错改。
|
||||
//
|
||||
// ⚠️ 措辞必须与 batchRunnable 的**真实**判据一致(全批 ParallelSafe
|
||||
// 才并发 + 同通道保序),否则只是把"没说"换成"说错"。
|
||||
prompt += "\n\n【工具执行顺序】同一条回复里给出多个工具调用时,内核**默认并行执行**(同时跑),不是依次执行。这带来三条你必须知道的规则:\n"
|
||||
prompt += "- **不要依赖执行顺序**:若某个调用的参数需要另一个调用的结果,就**分两轮**——先发前一个,看到结果后再发下一个。写在同一轮里就等于假设了不存在的先后。\n"
|
||||
prompt += "- **例外一:同一通道的输出发送会保序**。对**同一个**通道连续调用多次 `output_send__`,内核会**按你发出的顺序依次执行**(用户可见消息顺序敏感),不会并发打乱。所以「先发回执、再发结论」这类有序发送可以放在同一轮;但若后续内容依赖前一条的用户反应,仍应分轮。\n"
|
||||
prompt += "- **例外二:不并发安全的工具不会并发**。写类工具(记忆/知识/文档写入等)与未声明并发安全的工具,**整批会退回依次执行**——同一批里只要有一个这样的工具,这一批就全部串行。这对你是透明的:你不需要判断,只需知道「同轮并发」不是无条件保证的。\n"
|
||||
prompt += "- 工具是否并发安全由**工具自己声明**(`ParallelSafe`),不由你决定;你只需按上面第 1 条判断能否同轮发出。\n"
|
||||
|
||||
prompt += "\n\n【输出规则】消息不会自动发送到对话来源通道,你必须自己决定如何回复:\n"
|
||||
prompt += "- **不要假设当前通道是某个固定值**:同一会话里可能同时有多个来源(多设备、多通道、子任务)。\n"
|
||||
prompt += " 先看这条消息本身与上下文里的来源信息,再决定往哪里回;不确定有哪些通道时先调 output_list_channels。\n"
|
||||
@ -463,7 +475,7 @@ func (a *Agent) buildToolDefs() []interface{} {
|
||||
"plugin_name": map[string]interface{}{"type": "string", "description": "插件名,如 qq / remotedevice / weather", "default": ""},
|
||||
}))
|
||||
|
||||
tools = append(tools, toolDef("spawn_child", "启动一个异步子 Agent 执行独立任务。子 Agent 后台运行,不阻塞当前对话。完成后系统会自动通知你,届时请调用 child_result 工具查看输出。\n使用时机:多个互不依赖的子任务(如同时查三个网站、分别处理多个文件)应并行 spawn 多个子 Agent,不要自己串行逐个执行;长耗时任务(批量处理、多轮搜索)也应交给子 Agent,避免阻塞对话。", map[string]interface{}{
|
||||
tools = append(tools, toolDef("spawn_child", "启动一个异步子 Agent 执行独立任务。子 Agent 后台运行,不阻塞当前对话。完成后系统会自动通知你,届时请调用 child_result 工具查看输出。\n使用时机:多个互不依赖的子任务(如同时查三个网站、分别处理多个文件)可以在**同一轮**里一次 spawn 多个子 Agent——同轮调用默认并行,子 Agent 会各自后台启动(是否真正并发取决于工具的并发安全声明)。长耗时任务(批量处理、多轮搜索)也应交给子 Agent,避免阻塞对话。注意:一次 spawn 只是一个启动动作;要立刻拿到结果仍需另一次 `child_result` 调用。", map[string]interface{}{
|
||||
"task": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "要子 Agent 完成的任务描述。请描述清晰、完整,包含所有必要背景。",
|
||||
|
||||
Reference in New Issue
Block a user