# agent 通用能力接入文档

## 1. 文档目的

本文用于说明 `backend/agent` 目录下“通用能力”的职责边界、放置位置和接入约束，避免后续继续出现“同一类能力复制三份、四份”的情况。

这里的“通用能力”特指：

1. 会被两个及以上能力域复用，或者已经明确会继续扩散的基础能力。
2. 与具体业务语义弱耦合，抽出来后不会把某个 skill 的 prompt、状态字段、业务规则污染到其它模块。
3. 抽出后能显著减少样板代码、降低迁移成本，或者统一链路行为。

本文不负责描述某个具体 skill 的业务流程。业务流程、状态机、prompt 细节，仍应放在对应能力域自己的文件中。

## 2. 当前目录分层

```text
backend/agent/
  entrance.go
  chat/
  graph/
  llm/
  model/
  node/
  prompt/
  router/
  shared/
  stream/
```

### 2.1 `entrance.go`

职责：

1. 作为 `agent` 模块对上层 service 的统一入口。
2. 负责装配路由器与各能力 handler。
3. 不负责具体 graph 逻辑、不负责直接调模型、不负责工具执行。

### 2.2 `router/`

职责：

1. 负责一级分流，把请求映射到具体能力链路。
2. 维护统一的请求/响应结构和 action 定义。
3. 不承载具体 skill 的业务判断细节。

适合放入这里的能力：

1. 路由请求结构。
2. action 解析与分发。
3. 对上层稳定暴露的最小门面。

### 2.3 `graph/`

职责：

1. 只负责组图、连线和节点编排。
2. 文件里应尽量只出现节点挂载、分支和边定义。
3. 不直接写复杂业务逻辑、不直接调 DAO、不直接拼 prompt。

### 2.4 `node/`

职责：

1. 承接能力域的核心业务节点实现。
2. 按“节点逻辑文件 + 工具文件”的双文件格局组织复杂能力域。
3. 在确实存在多节点复用时，可下沉少量带业务语义的 node 内部公共 helper。

当前约定：

1. `schedule_plan.go` / `schedule_plan_tool.go` 为一组。
2. `schedule_refine.go` / `schedule_refine_tool.go` 为一组。
3. `quicknote.go` / `quicknote_tool.go`、`taskquery.go` / `taskquery_tool.go` 同理。

补充说明：

1. `node/tool_common.go` 是 node 层内部通用工具聚合点。
2. 这里只放“被两个及以上节点复用、但仍带一点节点上下文语义”的 helper。
3. 如果某个能力已经弱化到与业务无关，应继续下沉到 `shared/`，而不是长期堆在 `tool_common.go`。

### 2.5 `llm/`

职责：

1. 统一封装模型调用、JSON 解析、推理参数和模型侧协议。
2. 让上层节点尽量只关心“要什么结果”，不重复实现 SDK 样板代码。
3. 不承载具体业务状态流转。

### 2.6 `model/`

职责：

1. 统一放置 agent 内部状态结构、输入输出 DTO、默认预算等模型无关定义。
2. 不在这里写业务执行逻辑。

### 2.7 `prompt/`

职责：

1. 维护系统提示词、结构化输出模板、路由提示词等文本资产。
2. 不在 prompt 文件中写节点控制流和工具编排。

### 2.8 `stream/`

职责：

1. 统一承接 SSE chunk 包装、阶段推送、OpenAI/Ark 流式适配。
2. 保证上层 service 不需要重复拼装流协议。

### 2.9 `shared/`

职责：

1. 放置跨能力域复用的纯工具能力，例如时间、重试、深拷贝等。
2. 要求业务语义尽量弱、依赖尽量少。
3. 一旦某类逻辑已经被第二处复用，必须优先评估是否放到这里。

## 3. 什么该抽成通用能力

满足以下任一条件时，必须优先评估抽公共层：

1. 同类逻辑已经出现第二份实现。
2. 不同 skill 的实现只有参数不同，控制流基本一致。
3. 上层 service 已经开始出现重复胶水代码。
4. 继续复制会增加迁移、测试或回归排查成本。

常见应优先考虑抽取的方向：

1. 模型调用门面。
2. JSON 容错解析。
3. SSE 阶段推送与 chunk 包装。
4. 深拷贝与快照转换。
5. 缓存快照读写辅助逻辑。

## 4. 什么不该抽成通用能力

以下内容默认不应抽到公共层：

1. 某个 skill 独有的 prompt 片段。
2. 只服务单一业务的状态字段映射。
3. 带强业务语义的 ReAct 决策规则。
4. 只在一个节点里短期使用、且没有第二处复用证据的 helper。

判断原则：

1. 若抽出来后名字仍然需要带明显业务词，通常说明它还不够通用。
2. 若抽出来会让其它模块被迫理解某个 skill 的内部规则，说明抽取层级过早。

## 5. 新增能力时的落点规则

1. 纯工具、弱业务语义、跨域复用：优先放 `shared/`。
2. 只在路由阶段复用：放 `router/`。
3. 只与模型协议相关：放 `llm/`。
4. 只与流式输出相关：放 `stream/`。
5. 只在 node 层内被多个节点复用，且带少量业务上下文：放 `node/tool_common.go` 或同层 helper。
6. 仍然明显属于某个能力域：留在对应 `node/`、`prompt/`、`model/` 文件中，不要硬抽。

## 6. 变更要求

后续若在 `backend/agent` 中新增、下沉、替换任何通用能力，必须同步完成以下动作：

1. 更新本文档，说明新能力放在哪一层、为什么放这里。
2. 说明是否替代了旧实现，旧实现是否已经删除。
3. 检查是否还残留第三份及以上重复实现。
4. 若本轮只是暂时无法抽公共层，必须在代码注释或文档里写明原因。

## 7. 当前结构结论

截至当前版本，`backend/agent` 已是唯一正式实现目录，`backend/service/agentsvc` 也已与历史旧路径完全解耦。

后续重构优先级建议：

1. 继续收口 node 层内部重复的查询/校验/移动辅助逻辑。
2. 持续把 service 层里可复用的旁路读写逻辑下沉到更稳定的公共层。
3. 保持 graph 只做编排、node 只做业务、shared 只做弱语义公共能力，避免重新堆回大杂烩结构。

