feat(agent): strengthen planning, tool discovery and recovery

This commit is contained in:
jxxghp
2026-09-09 16:54:09 +08:00
parent cde05f4afc
commit c0ed78e168
19 changed files with 1808 additions and 146 deletions

41
docs/agent.md Normal file
View File

@@ -0,0 +1,41 @@
# Agent 复杂任务执行与恢复
MoviePilot Agent 通过模型、Skills、工具和会话状态共同完成任务。本次增强关注长任务的连续性:明确目标和检查结果,按需补充工具,并在执行中断后保留已知事实。
## 任务计划
复杂任务可以使用内部 `update_plan` 工具保存目标、步骤、状态、检查依据和阻塞原因。例如“排查下载后未入库”可以依次检查下载状态、整理队列、目标目录和媒体库。
- 简单查询不需要创建计划。
- 步骤支持 `pending`、`in_progress`、`completed`、`blocked`;完成和阻塞状态需要填写依据。
- 计划单独保存在会话图状态中,每次模型请求都能读取;压缩旧消息不会删除计划。
- 计划快照随聊天消息保存,在会话图重建后恢复。用户询问进度时继续当前目标,明确开始新任务时替换计划。
- 计划是模型记录的工作状态,不代表工具执行结果或写操作授权。仍需通过工具核实实际结果。
## 按需发现工具
设置 `LLM_MAX_TOOLS > 0` 时,Agent 首轮仍只筛选一批相关工具。后续读取 Skill 或发现新问题后,可以通过内部 `search_tools(search, limit)` 按名称、说明或标签搜索当前会话工具目录,并在下一次模型调用获得匹配工具的完整参数定义。
每次最多返回并启用 8 个匹配工具;没有匹配结果时不会展开全部工具。发现状态仅作用于当前用户请求,新的用户请求重新筛选。`LLM_MAX_TOOLS` 约束首轮筛选数量,显式按需发现可以增加工具。发现不会安装工具、连接新的 MCP 服务或扩大执行权限。
`update_plan` 和 `search_tools` 是 Agent 内部会话能力,不通过外部 MCP 或 `moviepilot tool` 发布。
## 异常和取消后的继续
对已启用聊天持久化的会话,执行异常或用户取消时,Agent 在释放会话图之前尝试保存脱敏恢复快照。已收到的工具回执保留;未收到结果的调用明确标记为“结果未知”,不能当成未执行或已成功。
用户随后说“继续”时,Agent 可以读取已有结果和计划,从剩余工作继续。下载、修改配置、删除文件等操作如缺少回执,应先只读核验实际状态,再决定是否重试。取消仍会终止当前轮次,不会自动重放工具。
快照保存采用有界等待。进程强制退出、持久化失败,或工具在中断后才完成的外部副作用,不能保证被该快照记录。它不是外部操作的事务日志,也不保证恰好执行一次。
## 子代理连续工作
一轮结束会回收未完成的子任务,正常收敛后同一会话下一轮仍可委派。会话关闭时永久停止接收子任务;无法在等待上限内收敛的任务仍由原 owner 持有并封闭新提交。
子代理沿用主 Agent 的最终请求预算和上下文压缩机制。长调查可以压缩旧消息;最新单条工具事务或固定提示本身超过模型窗口时仍会明确失败,不会静默删除关键内容。
## 验证范围
自动化测试使用脚本模型和真实 LangGraph 执行图,覆盖工具发现后的实际调用、并行发现合并、计划更新和消息序列化恢复、执行中断以及连续两轮子代理委派。测试不调用付费模型或外部服务。
这些机制提高执行可靠性;真实任务的理解、规划质量和成功率仍取决于所选模型、上下文窗口、工具权限及外部服务状态。模型能力需要用真实业务场景单独评估。

View File

@@ -583,6 +583,8 @@ flowchart LR
## 七、AI Agent 子系统
复杂任务的计划、工具发现和中断恢复使用说明见 [Agent 复杂任务执行与恢复](agent.md)。
Agent 采用**门面 + 惰性物化**设计,避免 `application → agent` 形成静态依赖边:
```mermaid
@@ -754,8 +756,8 @@ flowchart LR
| 指标 | 当前值 |
|---|---:|
| Python 模块 | 986 |
| 内部导入边 | 8,385 |
| Python 模块 | 987 |
| 内部导入边 | 8,395 |
| 非平凡 SCC | 1(精确 containment 的 TMDB 移植包环) |
| Application / Chain 具体 Adapter 直连 | 0 / 0 |
| Direct egress | 53(债务已清零,53 条精确 containment) |

View File

@@ -94,7 +94,7 @@ ARCH-201 至 ARCH-204 均达到实现、验证、提交、推送和远端门禁
| 指标 | 当前值 | 解释 |
|---|---:|---|
| 宿主 Python 模块 / 内部依赖边 | 986 / 8,385 | `dependency-baseline.json` 当前快照;分类、下载资源归类、订阅搜索与整理任务恢复模块的受控依赖 |
| 宿主 Python 模块 / 内部依赖边 | 987 / 8,395 | `dependency-baseline.json` 当前快照;分类、下载资源归类、订阅搜索、整理恢复与 Agent 计划模块的受控依赖 |
| 非平凡 SCC | 1 | 仅保留精确 containment 的 29 模块 TMDB 移植包环 |
| 跨层 DB 边界债务 | 0 | Application、Chain、API、Agent、Runtime、Workflow 到 DB 的受控债务均为零 |
| Model/Oper 事务债务 | 0 | 自建 Session、自动事务装饰器、直接 commit/rollback 等基线均为零 |

View File

@@ -35,6 +35,8 @@ MCP 使用系统配置中的 `API_TOKEN` 作为认证密钥,文档中的 API K
### 动态插件工具
内置 Agent 的 `update_plan`、`search_tools` 为会话中间件工具,不通过外部 `tools/list` 发布;它们只维护计划或发现当前目录内的工具,不能授予业务操作权限。使用与恢复语义见 [Agent 复杂任务执行与恢复](agent.md)。
`tools/list` 会同时返回 MoviePilot 内置工具和已启用插件通过 `get_agent_tools()` 声明的工具。插件启动、停止、重载或配置生效后,MCP 工具管理器会在下一次列出或调用工具时按注册表版本惰性刷新,避免继续暴露已移除的工具或遗漏新工具。
MCP 当前不会主动发送工具列表变更通知(`listChanged=false`)。如果客户端缓存了工具列表,插件状态变化后需要让客户端重新请求 `tools/list`;无法手动刷新的客户端应重新连接 MCP 服务或新建会话。

View File

@@ -86,6 +86,8 @@ to make the directory tree look symmetrical.
| `app/agent/lifecycle.py` | Runtime generation admission, initialization, idle-session collection and bounded manager shutdown |
| `app/agent/tasks.py` | Background prompts, durable scheduled-task execution and heartbeat wakeups |
| `app/agent/orchestrator.py` | One `MoviePilotAgent` execution instance: prompt/tool/middleware assembly, model invocation, streaming and per-agent state |
| `app/agent/middleware/plan.py` | Current task objective, step status and evidence in graph state; sanitized snapshots travel through existing message persistence and never authorize tool effects |
| `app/agent/middleware/selection.py` | First-turn tool selection and bounded, on-demand discovery within the same authorized catalog; discovered tool names remain local to the current user request |
| `app/agent/shell.py` | Agent command-shell selection and subprocess text-encoding policy; Windows prefers Git Bash, then PowerShell 7, while POSIX keeps native shell/PTY behavior |
| `app/agent/policy/api.py` | Fixed `moviepilot_api` operation registry, HTTP route templates and per-operation authorization/effect policy; no arbitrary URL or method input |
| `app/agent/policy/mcp.py` | Generated external MCP input-contract builder for the fixed API registry; owns exact English oneOf parameter projection, not runtime authorization |