Files
smartmate/backend/newAgent/prompt/plan.go
Losita a1b2ffedb8 Version: 0.9.22.dev.260416
后端:
1. 品牌文案与聊天定位统一切到 SmartMate,并放宽非排程问答能力
   - 系统人设、路由、排程、查询、交付提示统一从 SmartFlow 改为 SmartMate
   - 明确普通问答/生活建议/开放讨论可正常回答,deep_answer 不再输出“让我想想”等占位话术
   - thinkingMode=auto 时,deep_answer 默认开启 thinking,execute 继续跟随路由决策,其余路由默认关闭
2. Memory 读取链路升级为“结构化强约束 + 语义候选”hybrid 模式,并补齐注入渲染 / Execute 消费
   - 新增 read.mode、四类记忆预算、inject.renderMode 等配置及默认值
   - 落地 HybridRetrieve,统一 MySQL/RAG 读侧作用域、三级去重(ID/hash/text)、统一重排与按类型预算裁剪
   - 新增 FindPinnedByUser、content_hash DTO/兜底补算、legacy/RAG 共用读侧查询口径与 fallback 逻辑
   - 记忆注入支持 flat/typed_v2 两种渲染,execute msg3 正式消费 memory_context,主链路注入 MemoryReader 时同步透传 memory 配置
3. Memory 第二步/第三步 handoff 与治理文档补齐
   - HANDOFF_Memory向Mem0靠拢三步冲刺计划.md 从 newAgent 迁到 memory 目录,并补充“我的记忆”增删改查与最小留痕口径
   - 新增 backend/memory/记忆模块第二步计划.md、backend/memory/第三步治理与观测落地计划.md,分别拆解 hybrid 读取注入闭环与治理/观测/清理路线
   - 同步更新 backend/memory/Log.txt 调试日志
前端:
1. 助手输入区新增“智能编排”任务类选择器,并把 task_class_ids 作为请求 extra 透传
   - 新建 frontend/src/components/assistant/TaskClassPlanningPicker.vue,支持拉取任务类列表、临时勾选、已选标签回显与清空
   - 更新 frontend/src/components/dashboard/AssistantPanel.vue、frontend/src/types/dashboard.ts:Chat extra 正式建模 task_class_ids / retry 字段;当本轮带编排任务类时强制新起会话,避免把现有会话历史误混入新编排
2. 会话上下文窗口统计接入前端展示
   - 更新 frontend/src/api/agent.ts、新建 frontend/src/components/assistant/ContextWindowMeter.vue、更新 frontend/src/components/dashboard/AssistantPanel.vue、frontend/src/types/dashboard.ts:接入 /agent/context-stats,兼容 object/string/null 三种返回;在输入工具栏展示 msg0~msg3 占比与预算使用率
3. 助手面板交互细节优化
   - 更新 frontend/src/components/dashboard/AssistantPanel.vue:thinking 开关改为 auto/true/false 三态选择;切会话与重试后同步刷新 context stats;历史列表首屏不足时自动继续分页直到形成滚动区
仓库:无
2026-04-16 18:29:17 +08:00

154 lines
6.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package newagentprompt
import (
"fmt"
"strconv"
"strings"
newagentmodel "github.com/LoveLosita/smartflow/backend/newAgent/model"
"github.com/cloudwego/eino/schema"
)
const planSystemPrompt = `
你是 SmartMate 的规划器。
你的职责不是直接执行任务,而是先把用户意图拆成一组清晰、稳定、可逐步执行的自然语言计划,并严格按后端约定的 JSON 协议输出。
请遵守以下规则:
1. 只负责规划,不要假装已经调用了工具,也不要伪造执行结果。
2. 每一轮只推进一步规划;如果信息不足,应明确转成 ask_user而不是继续硬猜。
3. 若当前计划仍不完整,就继续围绕当前任务补全计划,不要跳去执行细节。
4. 若你认为计划已经完整可执行,请返回 action=plan_done并附带完整 plan_steps。
5. plan_steps 必须使用自然语言,便于后端将完整 plan 重新注入到后续上下文顶部。
6. 只输出 JSON不要输出 markdown不要输出额外解释不要在 JSON 外再补文字。
7. 每次输出前先评估任务复杂度simple简单明确无复杂依赖、moderate多步操作需要一定推理、complex需要深度推理、多方案比较或复杂依赖关系
8. 根据复杂度判断 need_thinking你是否需要深度思考才能生成高质量计划当不确定时倾向于 false。
9. 粗排识别规则:若满足以下两个条件,在 action=plan_done 时附加 needs_rough_build=true 和 task_class_ids
条件1用户输入中存在"任务类 ID"字段(见上下文"任务类 ID"部分);
条件2用户意图明确是"批量安排/帮我排课/把任务类排进日程"等批量调度需求。
满足时:后端会在用户确认计划后自动运行粗排算法(硬性约束已由算法保证,无需 LLM 校验)。
你的 plan_steps 应聚焦于"用读写工具优化方案",建议两步:
第1步用 get_overview / query_target_tasks / query_available_slots 等读工具审视粗排结果,找出可优化的点(时段分布不均、空位未利用等);
第2步用 move / batch_move 等写工具微调后,将最终方案展示给用户确认。
禁止安排任何"校验/验证约束"步骤——硬性约束由算法兜底LLM 不需要操心。
你会看到:
- 当前阶段与轮次信息
- 已有完整 plan如果之前已经规划过
- 当前步骤(如果已存在)
- 置顶上下文块
- 可用工具摘要
- 历史对话
请基于这些输入继续规划,而不是重复忽略既有 plan。
`
// BuildPlanSystemPrompt 返回规划阶段系统提示词。
func BuildPlanSystemPrompt() string {
return strings.TrimSpace(planSystemPrompt)
}
// BuildPlanMessages 组装规划阶段的 messages。
//
// 职责边界:
// 1. 负责把 state + context 收敛成规划阶段模型输入;
// 2. 负责把置顶上下文和工具摘要放在 history 前面,降低模型跑偏概率;
// 3. 不负责解析模型输出,也不负责判断规划质量。
func BuildPlanMessages(state *newagentmodel.CommonState, ctx *newagentmodel.ConversationContext, userInput string) []*schema.Message {
return buildStageMessages(
BuildPlanSystemPrompt(),
ctx,
BuildPlanUserPrompt(state, userInput),
)
}
// BuildPlanUserPrompt 构造规划阶段的用户提示词。
func BuildPlanUserPrompt(state *newagentmodel.CommonState, userInput string) string {
var sb strings.Builder
sb.WriteString("请继续当前任务的规划阶段。\n")
sb.WriteString(renderStateSummary(state))
sb.WriteString("\n")
sb.WriteString("本轮目标:围绕当前任务继续规划,直到形成一份稳定、可执行的自然语言 plan或在信息不足时明确追问用户。\n\n")
sb.WriteString(BuildPlanDecisionContractText())
sb.WriteString("\n")
if state != nil && len(state.TaskClassIDs) > 0 {
parts := make([]string, len(state.TaskClassIDs))
for i, id := range state.TaskClassIDs {
parts[i] = strconv.Itoa(id)
}
sb.WriteString(fmt.Sprintf("\n本次排课请求涉及的任务类 ID前端传入[%s]\n", strings.Join(parts, ", ")))
sb.WriteString("规划时请结合上述任务类 ID 判断是否需要粗排needs_rough_build并在 plan_steps 中体现排课意图。\n")
}
trimmedInput := strings.TrimSpace(userInput)
if trimmedInput != "" {
sb.WriteString("\n用户本轮输入\n")
sb.WriteString(trimmedInput)
sb.WriteString("\n")
}
return strings.TrimSpace(sb.String())
}
// BuildPlanDecisionContractText 返回规划阶段的输出协议说明。
func BuildPlanDecisionContractText() string {
return strings.TrimSpace(fmt.Sprintf(`
输出协议(严格 JSON
- speak给用户看的话若 action=%s这里通常就是要追问用户的问题
- action只能是 %s / %s / %s
- reason给后端和日志看的简短说明
- complexity任务复杂度只能是 simple / moderate / complex
- need_thinking是否需要深度思考才能生成高质量计划只能是 true / false
- plan_steps仅当 action=%s 时允许返回;返回时必须是完整计划,不是增量
- plan_steps[].content步骤正文必填
- plan_steps[].done_when可选建议写"什么情况下算这一步做完"
- needs_rough_build仅当满足粗排识别规则时为 true否则省略为 true 时后端自动运行粗排算法
- task_class_idsneeds_rough_build=true 时必填,从上下文"任务类 ID"字段读取
合法示例:
{
"speak": "我先把计划再收束一下。",
"action": "%s",
"reason": "当前信息已足够继续规划",
"complexity": "moderate",
"need_thinking": false
}
{
"speak": "你更希望我优先安排今天,还是按整周来规划?",
"action": "%s",
"reason": "当前时间范围仍不明确",
"complexity": "simple",
"need_thinking": false
}
{
"speak": "计划已经整理好了,我先给你确认一下。",
"action": "%s",
"reason": "当前计划已具备执行条件",
"complexity": "simple",
"need_thinking": false,
"plan_steps": [
{
"content": "先确认本周可用时间范围",
"done_when": "拿到明确的可用时间段列表"
},
{
"content": "基于可用时间生成执行安排",
"done_when": "得到一份用户可确认的安排方案"
}
]
}
`,
newagentmodel.PlanActionAskUser,
newagentmodel.PlanActionContinue,
newagentmodel.PlanActionAskUser,
newagentmodel.PlanActionDone,
newagentmodel.PlanActionDone,
newagentmodel.PlanActionContinue,
newagentmodel.PlanActionAskUser,
newagentmodel.PlanActionDone,
))
}