Files
smartmate/agent代码复用清单.md
LoveLosita f4ef6fb256 Version: 0.7.5.dev.260324
🐛 fix(agent/schedulerefine): 修复复合微调分支链路问题,并将 MinContextSwitch 重构为固定坑位重排语义

- 🔧 修复 `schedulerefine` 复合路由中参数透传不完整、缺少 deterministic objective 时错误降级,以及“复合工具执行成功”与“终审通过”语义混淆的问题
-  保证新的独立复合分支能够正确执行、正确出站,并统一交由 `hard_check` 裁决最终结果
- 🔍 排查时发现 `MinContextSwitch` 上游 `context_tag` 存在整体退化为 `General` 的风险,影响MinContextSwitch
- 🛡️ 为 `MinContextSwitch` 增加兜底策略:当标签整体退化时,按任务名关键词推断学科分组,避免分组能力失效
- ♻️ 将 `MinContextSwitch` 从“整周重新寻找新坑位”调整为“坑位不变,任务顺序改变”
- 🎯 将落地方式从顺序 `BatchMove` 改为固定坑位原子重写,避免出现远距离跳位、跨天错迁、异常嵌入课位及循环换位冲突
- 🧹 修复 `hard_check` 在 `MinContextSwitch` 成功后仍执行 `origin_rank` 顺序归位、并导致逆序终审误判的问题
- 🚦 命中该分支后跳过顺序归位与顺序硬校验,避免 `summary` / `hard_check` 将有效重排结果误判为失败

📈 当前连续微调规划涉及的全部功能已可以稳定运行;下一步将继续扩展能力边界,并进一步优化 `schedule_plan` 流程

♻️ refactor: 重整 agent2 架构,并迁移 quicknote/chat 新链路,目前还剩3个模块未迁移,后续迁移完成后会删除原agent并将此目录命名为agent

- 🏗️ 明确 `agent2` 采用“统一分层目录 + 文件分层 + 依赖注入”的重构方案,不再沿用模块目录多层嵌套结构
- 🧩 完善 `agent2` 基础骨架,统一收口 `entrance` / `router` / `llm` / `stream` / `shared` / `model` / `prompt` / `node` / `graph` 等层级职责
- 🚚 将通用路由能力迁移至 `agent2/router`,沉淀统一的 `Action`、`RoutingDecision`、控制码解析,以及 `Dispatcher` / `Resolver` 抽象
- 💬 将普通聊天链路迁移至 `agent2/chat`,复用 `stream` 的 OpenAI 兼容输出协议与 LLM usage 聚合能力
- 📝 将 `quicknote` 链路迁移到 `agent2` 新结构,拆分为 `model` / `prompt` / `llm` / `node` / `graph` 多层实现,替换对旧 `agent/quicknote` 的直接依赖
- 🔌 调整 `agentsvc` 对 `agent2` 的引用,普通聊天、通用分流与 `quicknote` 全部切换到新链路
- ✂️ 去除 graph 内部 `runner` 转接层,改为由 node 层直接持有请求级依赖,并向 graph 暴露节点方法
- 🧹 合并 `graph/quicknote` 与 `graph/quicknote_run`,删除冗余骨架文件,收敛为单一 `quicknote graph` 文件
- 📚 新增 `agent2`《通用能力接入文档》,明确公共能力边界、接入方式以及 graph/node 协作约定
- 📝 更新 `AGENTS.md`,要求后续扩展 `agent2` 通用能力时必须同步维护接入文档

♻️ refactor: 删除了现Agent目录内Chat模块的两条冗余Prompt
2026-03-24 21:35:22 +08:00

449 lines
13 KiB
Markdown
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.
# Agent 代码复用清单(施工备忘)
## 1. 文档目的
- 这份文档只做一件事:记录当前 `backend/agent``backend/service/agentsvc` 中“明明可以复用、却被重复实现”的代码点。
- 目标不是立刻改代码,而是防止后续压缩上下文后忘记哪些地方最值得先收口。
- 这里优先关注“公共能力重复实现”,不讨论具体业务对错。
## 2. 当前最明显的重复结论
- 重复最严重的不是某一个 skill而是“每个 skill 都在各自实现一套模型调用、JSON 解析、阶段推送、兜底、深拷贝、缓存快照读写、工具分发”。
- `quicknote``taskquery``scheduleplan``schedulerefine` 已经形成了“四套相似但不统一的 agent 基建”。
- `service/agentsvc` 里也开始出现重复胶水层逻辑,尤其是排程预览和连续微调相关读写。
---
## 3. 高优先级复用点
## 3.1 模型调用封装重复
### 现状
- `quicknote` 自己实现了 `callModelForJSON` / `callModelForJSONWithMaxTokens`
- `taskquery` 自己实现了 `callTaskQueryModelForJSON`
- `scheduleplan` 自己实现了 `callScheduleModelForJSON`
- `schedulerefine` 自己实现了 `callModelText`,而且附带了一整套 JSON contract 变体。
### 证据
- [quicknote/nodes.go](E:/SmartFlow-Agent/backend/agent/quicknote/nodes.go)
- [taskquery/nodes.go](E:/SmartFlow-Agent/backend/agent/taskquery/nodes.go)
- [scheduleplan/nodes.go](E:/SmartFlow-Agent/backend/agent/scheduleplan/nodes.go)
- [schedulerefine/nodes.go](E:/SmartFlow-Agent/backend/agent/schedulerefine/nodes.go)
### 问题
- 都在做同一类事情:
-`system + user` 消息
- 关闭/开启 thinking
- 设置 `temperature/maxTokens`
-`Generate`
- 判空响应
- 返回文本
- 现在每个模块一套,导致:
- 参数风格不统一
- 错误文案不统一
- token 统计与 callback 复用也难进一步规范
### 建议抽取
- 抽到统一的 `agent/core/modelx` 或类似目录。
- 至少统一三个入口:
- `GenerateText`
- `GenerateJSON`
- `GenerateJSONWithContract`
### 优先级
- `P0`
---
## 3.2 JSON 解析与对象提取重复
### 现状
- `quicknote` 自己实现了 `parseJSONPayload` + `extractJSONObject`
- `taskquery` 有自己的 `parseTaskQueryJSON`
- `scheduleplan` 有自己的 `parseScheduleJSON`
- `schedulerefine` 有自己的 `parseJSON`,并且带重试解析逻辑。
### 证据
- [quicknote/nodes.go](E:/SmartFlow-Agent/backend/agent/quicknote/nodes.go)
- [taskquery/nodes.go](E:/SmartFlow-Agent/backend/agent/taskquery/nodes.go)
- [scheduleplan/nodes.go](E:/SmartFlow-Agent/backend/agent/scheduleplan/nodes.go)
- [schedulerefine/nodes.go](E:/SmartFlow-Agent/backend/agent/schedulerefine/nodes.go)
### 问题
- 都在解决“模型返回不是纯 JSON需要做容错提取”。
- 解析失败后的兜底策略也高度相似,只是文案不同。
### 建议抽取
- 抽统一的 `agent/core/jsonx`
- `ParseJSONObject[T]`
- `ExtractJSONObject`
- `ParseWithRetryHint`(后续可选)
### 优先级
- `P0`
---
## 3.3 阶段推送EmitStage重复
### 现状
- `quicknote/graph.go` 自己封装 `EmitStage` 判空。
- `taskquery/graph.go` 自己写 `runner.emit`
- `scheduleplan/graph.go` 自己包一层 `emitStage`
- `schedulerefine/graph.go` 也自带一套。
### 证据
- [quicknote/graph.go](E:/SmartFlow-Agent/backend/agent/quicknote/graph.go)
- [taskquery/graph.go](E:/SmartFlow-Agent/backend/agent/taskquery/graph.go)
- [scheduleplan/graph.go](E:/SmartFlow-Agent/backend/agent/scheduleplan/graph.go)
- [schedulerefine/graph.go](E:/SmartFlow-Agent/backend/agent/schedulerefine/graph.go)
### 问题
- 所有 graph 都在做相同事情:封装一个 `func(stage, detail string)`,把 nil 判断藏起来。
- 这一层目前很轻,但 skill 一多就会持续复制。
### 建议抽取
- 抽统一的 `agent/core/progress`
- `type Emitter func(stage, detail string)`
- `func WrapEmitter(fn func(string, string)) Emitter`
- `func NoopEmitter() Emitter`
### 优先级
- `P1`
---
## 3.4 OpenAI 兼容流式包装能力重复调用方式不统一
### 现状
- 统一实现其实已经有了,在 [chat/stream.go](E:/SmartFlow-Agent/backend/agent/chat/stream.go) 里:
- `ToOpenAIStream`
- `ToOpenAIFinishStream`
-`agentsvc` 侧又额外自己实现了“阶段推送器”和“单条 assistant completion 包装”。
### 证据
- [chat/stream.go](E:/SmartFlow-Agent/backend/agent/chat/stream.go)
- [agent_quick_note.go](E:/SmartFlow-Agent/backend/service/agentsvc/agent_quick_note.go)
### 问题
- 现在虽然底层函数复用了,但“如何构造阶段消息 / 一次性正文 / finish chunk”的协议层仍散落在 service 层。
- 后续 schedule、memory、websearch 也大概率继续复制。
### 建议抽取
- 抽统一的 `agent/core/streamx`
- `EmitReasoningStage`
- `EmitSingleAssistantReply`
- `EmitErrorChunk`
### 优先级
- `P1`
---
## 3.5 深拷贝函数重复
### 现状
- `agentsvc/agent_schedule_preview.go` 有:
- `cloneWeekSchedules`
- `cloneHybridEntries`
- `cloneTaskClassItems`
- `schedulerefine/state.go` 又复制了一份同类深拷贝函数。
- `scheduleplan` 侧也多处依赖同样的拷贝语义。
### 证据
- [agent_schedule_preview.go](E:/SmartFlow-Agent/backend/service/agentsvc/agent_schedule_preview.go)
- [schedulerefine/state.go](E:/SmartFlow-Agent/backend/agent/schedulerefine/state.go)
### 问题
- 这是非常典型的“纯工具函数”重复实现。
- 后面只要结构体字段一变,就容易出现一边更新一边漏更。
### 建议抽取
- 抽统一的 `agent/core/clone``agent/core/snapshot`
### 优先级
- `P0`
---
## 3.6 预览快照读取/回填逻辑重复
### 现状
- `runSchedulePlanFlow` 自己在做:
- 查 Redis 预览
- miss 后查 MySQL snapshot
- 回填 Redis
- 清旧 preview
- `runScheduleRefineFlow` 又通过 `loadSchedulePreviewContext` 再做一套类似的逻辑。
- `GetSchedulePlanPreview` 也重复做:
- 查 Redis
- miss 查 MySQL
- 回填 Redis
### 证据
- [agent_schedule_plan.go](E:/SmartFlow-Agent/backend/service/agentsvc/agent_schedule_plan.go)
- [agent_schedule_refine.go](E:/SmartFlow-Agent/backend/service/agentsvc/agent_schedule_refine.go)
- [agent_schedule_preview.go](E:/SmartFlow-Agent/backend/service/agentsvc/agent_schedule_preview.go)
### 问题
- 这是同一个“排程预览仓储语义”,却被 service 层复制成了三种读法。
- 长期会导致缓存行为不一致。
### 建议抽取
- 抽成统一 `schedule preview repository/gateway`
- `LoadPreviewContext`
- `SavePreviewContext`
- `DeletePreviewContext`
- `LoadPreviewForRead`
### 优先级
- `P0`
---
## 3.7 fallback 文案与早退逻辑重复
### 现状
- `quicknote` 有自己的 fallback reply / persisted 判定。
- `taskquery``buildTaskQueryFallbackReply`
- `scheduleplan``schedulerefine` 里也散落大量“解析失败/模型失败/回退继续”的逻辑。
### 证据
- [quicknote/nodes.go](E:/SmartFlow-Agent/backend/agent/quicknote/nodes.go)
- [taskquery/nodes.go](E:/SmartFlow-Agent/backend/agent/taskquery/nodes.go)
- [scheduleplan/nodes.go](E:/SmartFlow-Agent/backend/agent/scheduleplan/nodes.go)
- [schedulerefine/nodes.go](E:/SmartFlow-Agent/backend/agent/schedulerefine/nodes.go)
### 问题
- 不是所有 fallback 文案都能共用,但 fallback 模式本身是共性的:
- 模型失败 -> 本地兜底
- JSON 失败 -> 本地兜底
- 工具失败 -> 重试 / 降级
### 建议抽取
- 不建议直接抽“文案”。
- 但建议抽“失败策略框架”:
- `FallbackPolicy`
- `RetryOrFallback`
- `ParseOrFallback`
### 优先级
- `P1`
---
## 3.8 时间解析能力重复 / 分散
### 现状
- `quicknote/tool.go` 内有一整套时间解析:
- 相对时间
- 中文时间
- deadline hint
- 默认时刻
- 排程链路后续也非常可能要继续用类似时间语义。
### 证据
- [quicknote/tool.go](E:/SmartFlow-Agent/backend/agent/quicknote/tool.go)
### 问题
- 目前还没出现“多份复制”,但这是非常明确的“已形成公共能力、却还放在 skill 私有目录”的情况。
- 如果不提前抽schedule / memory / websearch 接进来后一定复制。
### 建议抽取
- 提前迁出到 `agent/core/timeparse`
### 优先级
- `P1`
---
## 3.9 runner 形态重复
### 现状
- `quicknote/runner.go`
- `scheduleplan/runner.go`
- `schedulerefine/runner.go`
### 问题
- 本质都在做同一件事:把 graph 输入依赖注入到每个步骤函数。
- 结构相似,但没有统一约定。
### 建议抽取
- 不一定要抽通用基类。
- 但至少要统一 runner 模板风格,减少 skill 间阅读切换成本。
### 优先级
- `P2`
---
## 3.10 route 控制码能力与 skill 判定方式分裂
### 现状
- 统一路由已经在 [route/route.go](E:/SmartFlow-Agent/backend/agent/route/route.go)。
- 但 skill 内部仍有不少二次意图确认 / fallback 判定。
### 问题
- 这不是完全重复代码问题,而是“判定责任分裂”。
- 结果是:
- route 做一遍
- skill 首节点再做一遍
- service 再决定回不回聊天
### 建议抽取
- 统一成:
- `route` 只做一级分流
- skill 只做 skill 内业务判定
- service 不再写 skill 特有 fallback 判定
### 优先级
- `P1`
---
## 4. 中优先级复用点
## 4.1 Extra 参数解析工具只在 scheduleplan 私有
### 现状
- `scheduleplan/tool.go``ExtraInt``ExtraIntSlice`
### 问题
- 这明显属于通用 agent 请求参数解析能力,不该锁死在某个 skill 下。
### 建议抽取
- 抽到 `agent/core/extrax`
### 优先级
- `P2`
---
## 4.2 工具分发 dispatch 逻辑重复
### 现状
- `scheduleplan/tools_react.go``dispatchReactTool``dispatchWeeklySingleActionTool`
- `scheduleplan/daily_refine.go``dispatchDailyReactTool`
- `schedulerefine/tool.go``dispatchRefineTool`
### 问题
- 都在做“执行工具调用 -> 应用结果 -> 返回标准结果”的模式。
- 虽然业务不同,但骨架高度类似。
### 建议抽取
- 抽公共的 `tool dispatcher` 框架,业务只实现 apply。
### 优先级
- `P2`
---
## 4.3 preview/snapshot DTO 映射重复
### 现状
- `snapshotToSchedulePlanPreviewCache`
- `snapshotToSchedulePlanPreviewResponse`
- `buildSchedulePlanSnapshotFromState`
- `convertRefineStateToPlanState`
### 问题
- 同一批结构在 service 层到处转来转去。
- 说明“排程预览状态”还没有独立成一个稳定模型层。
### 建议抽取
-`schedule snapshot mapper`
### 优先级
- `P2`
---
## 5. 已经出现“文件承担过多职责”的区域
### 5.1 `schedulerefine/nodes.go`
- 3140 行。
- 当前同时承担:
- 模型调用
- JSON 解析
- 规则归一化
- planner
- react loop
- hard check
- summary
- 这是最先需要拆的文件。
### 5.2 `schedulerefine/tool.go`
- 1768 行。
- 当前同时承担:
- tool 定义
- tool 分发
- payload 解析
- policy
- fallback query
- slot hint 构造
- 应拆成:
- `tool_defs`
- `tool_dispatch`
- `tool_payload`
- `tool_policy`
### 5.3 `scheduleplan/nodes.go`
- 713 行。
- 当前已经开始混:
- plan
- rough build
- preview return
- model call helper
- 现在还来得及拆。
---
## 6. 建议的第一批收口顺序
### 第一批(先抽公共层,不碰业务语义)
- `P0-1` 抽模型调用公共层。
- `P0-2` 抽 JSON 解析公共层。
- `P0-3` 抽深拷贝公共层。
- `P0-4` 抽排程预览加载/保存 gateway。
### 第二批(统一 skill 编排骨架)
- `P1-1` 统一 `EmitStage`
- `P1-2` 统一流式阶段输出辅助。
- `P1-3` 统一 fallback/retry 框架。
### 第三批(拆超大文件)
- `P2-1``schedulerefine/nodes.go`
- `P2-2``schedulerefine/tool.go`
- `P2-3``scheduleplan/nodes.go`
---
## 7. 可以考虑直接删除/合并的嫌疑区域
### 7.1 `scheduleplan` 与 `schedulerefine` 的边界可能切得过细
- 这两个包共享大量状态与工具语义。
- 后续大概率应该合并成一个 `schedule` 能力域,内部再区分 `create/refine` flow。
### 7.2 `agentsvc` 侧的排程桥接文件可能过多
- 当前已有:
- [agent_schedule_plan.go](E:/SmartFlow-Agent/backend/service/agentsvc/agent_schedule_plan.go)
- [agent_schedule_refine.go](E:/SmartFlow-Agent/backend/service/agentsvc/agent_schedule_refine.go)
- [agent_schedule_preview.go](E:/SmartFlow-Agent/backend/service/agentsvc/agent_schedule_preview.go)
- 这些文件后续应下沉部分逻辑到 gateway / repository / snapshot service。
---
## 8. 后续重构时的硬约束
- 先抽公共能力,再动 skill 业务逻辑,避免一边搬家一边改语义导致回归难查。
- 每抽一类公共件,都优先让 `quicknote``taskquery` 先接一次,确认不是只为 `schedule` 定制。
- 抽公共层时,不要先追求“最优抽象”,先追求“把四份重复收成一份”。
## 9. 一句话版本
- 当前 agent 代码最该先收口的 4 个点是:
- 模型调用
- JSON 解析
- 深拷贝/快照
- 排程预览缓存与快照读写
- 当前最该先拆的 2 个大文件是:
- [nodes.go](E:/SmartFlow-Agent/backend/agent/schedulerefine/nodes.go)
- [tool.go](E:/SmartFlow-Agent/backend/agent/schedulerefine/tool.go)