后端: 1. execute 主链路重构为“上下文工具域 + 主动优化候选闭环”——移除 order_guard,粗排后默认进入主动微调,先诊断再从后端候选中选择 move/swap,避免 LLM 自由全局乱搜 2. 工具体系升级为动态注入协议——新增 context_tools_add / remove、工具域与二级包映射、主动优化白名单;schedule / taskclass / web 工具按域按包暴露,msg0 规则包与 execute 上下文同步重写 3. analyze_health 升级为主动优化唯一裁判入口——补齐 rhythm / tightness / profile / feasibility 指标、候选扫描与复诊打分、停滞信号、forced imperfection 判定,并把连续优化状态写回运行态 4. 任务类能力并入新 Agent 执行链——新增 upsert_task_class 写工具与启动注入事务写入;任务类模型补充学科画像与整天屏蔽配置,粗排支持 excluded_days_of_week,steady 策略改为基于目标位置/单日负载/分散度/缓冲的候选打分 5. 运行态与路由补齐优化模式语义——新增 active tool domain/packs、pending context hook、active optimize only、taskclass 写入回盘快照;区分 first_full / global_reopt / local_adjust,并完善首次粗排后默认 refine 的判定 前端: 6. 助手时间线渲染细化——推理内容改为独立 reasoning block,支持与工具/状态/正文按时序交错展示,自动收口折叠,修正 confirm reject 恢复动作 仓库: 7. newAgent 文档整体迁入 docs/backend,补充主动优化执行规划与顺序约束拆解文档,删除旧调试日志文件 PS:这次科研了2天,总算是有些进展了——LLM永远只适合做选择题、判断题,不适合做开放创新题。
137 lines
4.5 KiB
Go
137 lines
4.5 KiB
Go
package newagentnode
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
|
||
newagentmodel "github.com/LoveLosita/smartflow/backend/newAgent/model"
|
||
"github.com/cloudwego/eino/schema"
|
||
)
|
||
|
||
const (
|
||
correctionHistoryKindKey = "newagent_history_kind"
|
||
correctionHistoryKindCorrectionUser = "llm_correction_prompt"
|
||
)
|
||
|
||
// AppendLLMCorrection 追加 LLM 修正提示到对话历史。
|
||
//
|
||
// 设计目的:
|
||
// 1. 当 LLM 输出不符合预期(如不支持的 action、格式错误等),不应直接报错终止;
|
||
// 2. 应该给 LLM 一个自我修正的机会,把错误反馈写回历史,让它重新生成;
|
||
// 3. 该函数封装了"追加 assistant 消息 + 追加纠正提示"的通用流程。
|
||
//
|
||
// 参数说明:
|
||
// - conversationContext: 对话上下文,用于追加历史消息;
|
||
// - llmOutput: LLM 的原始输出内容,会作为 assistant 消息追加;
|
||
// - validOptionsDesc: 合法选项的描述,用于构造纠正提示。
|
||
//
|
||
// 使用示例:
|
||
//
|
||
// AppendLLMCorrection(conversationContext, decision.Speak, "合法的 action 包括:continue、ask_user、next_plan、done")
|
||
//
|
||
// 返回值:
|
||
// - 返回 nil 表示修正流程完成,调用方应继续 Graph 循环;
|
||
// - 该函数不会返回 error,因为追加历史失败不影响主流程。
|
||
func AppendLLMCorrection(
|
||
conversationContext *newagentmodel.ConversationContext,
|
||
llmOutput string,
|
||
validOptionsDesc string,
|
||
) {
|
||
if conversationContext == nil {
|
||
return
|
||
}
|
||
|
||
// 1. 构造 assistant 消息,让 LLM 知道自己刚才输出了什么。
|
||
// 2. 空输出不回灌,避免把占位文本写进历史造成噪音。
|
||
// 3. 与最近一条 assistant 完全相同则跳过,避免重复回灌放大复读。
|
||
assistantContent := strings.TrimSpace(llmOutput)
|
||
appendCorrectionAssistantIfNeeded(conversationContext, assistantContent)
|
||
|
||
// 2. 构造纠正提示,明确告知 LLM 哪里错了、合法选项有哪些。
|
||
// 不做硬编码的错误类型,由调用方通过 validOptionsDesc 传入。
|
||
correctionContent := fmt.Sprintf(
|
||
"你的输出不符合预期。%s 请重新分析当前状态,输出正确的内容。",
|
||
validOptionsDesc,
|
||
)
|
||
conversationContext.AppendHistory(&schema.Message{
|
||
Role: schema.User,
|
||
Content: correctionContent,
|
||
Extra: map[string]any{
|
||
correctionHistoryKindKey: correctionHistoryKindCorrectionUser,
|
||
},
|
||
})
|
||
}
|
||
|
||
// AppendLLMCorrectionWithHint 追加 LLM 修正提示(带自定义错误描述)。
|
||
//
|
||
// 相比 AppendLLMCorrection,该函数允许调用方提供更详细的错误描述,
|
||
// 适用于需要明确告知 LLM 具体哪里出错的场景。
|
||
//
|
||
// 参数说明:
|
||
// - conversationContext: 对话上下文;
|
||
// - llmOutput: LLM 的原始输出内容;
|
||
// - errorDesc: 具体的错误描述,如 "action \"invalid\" 不是合法的执行动作";
|
||
// - validOptionsDesc: 合法选项的描述。
|
||
func AppendLLMCorrectionWithHint(
|
||
conversationContext *newagentmodel.ConversationContext,
|
||
llmOutput string,
|
||
errorDesc string,
|
||
validOptionsDesc string,
|
||
) {
|
||
if conversationContext == nil {
|
||
return
|
||
}
|
||
|
||
assistantContent := strings.TrimSpace(llmOutput)
|
||
appendCorrectionAssistantIfNeeded(conversationContext, assistantContent)
|
||
|
||
correctionContent := fmt.Sprintf(
|
||
"%s %s 请重新分析当前状态,输出正确的内容。",
|
||
errorDesc,
|
||
validOptionsDesc,
|
||
)
|
||
conversationContext.AppendHistory(&schema.Message{
|
||
Role: schema.User,
|
||
Content: correctionContent,
|
||
Extra: map[string]any{
|
||
correctionHistoryKindKey: correctionHistoryKindCorrectionUser,
|
||
},
|
||
})
|
||
}
|
||
|
||
// appendCorrectionAssistantIfNeeded 在纠错回灌前做最小降噪。
|
||
//
|
||
// 1. 空文本直接跳过,避免写入“占位噪音”;
|
||
// 2. 若与“最近一条 assistant 文本”完全一致则跳过,避免同句反复回灌;
|
||
// 3. 仅负责“是否回灌”判定,不负责生成纠错 user 提示。
|
||
func appendCorrectionAssistantIfNeeded(
|
||
conversationContext *newagentmodel.ConversationContext,
|
||
assistantContent string,
|
||
) {
|
||
if conversationContext == nil {
|
||
return
|
||
}
|
||
assistantContent = strings.TrimSpace(assistantContent)
|
||
if assistantContent == "" {
|
||
return
|
||
}
|
||
|
||
history := conversationContext.HistorySnapshot()
|
||
for i := len(history) - 1; i >= 0; i-- {
|
||
msg := history[i]
|
||
if msg == nil || msg.Role != schema.Assistant {
|
||
continue
|
||
}
|
||
if strings.TrimSpace(msg.Content) == assistantContent {
|
||
return
|
||
}
|
||
// 只看最近一条 assistant,避免误去重很久以前的正常重复表达。
|
||
break
|
||
}
|
||
|
||
conversationContext.AppendHistory(&schema.Message{
|
||
Role: schema.Assistant,
|
||
Content: assistantContent,
|
||
})
|
||
}
|