- 集成MCP连接管理器,支持MCP服务器连接 - 添加多种内置工具:ClarifyTool、CronTool、DelegateTool、ExecuteCodeTool、 PatchFileTool、ProcessTool、SendMessageTool、SpawnTool、TerminalTool、 TodoTool、WebFetchTool、WebSearchTool、WriteFileTool等 - 实现工具注册和装配功能 - 添加技能选择上下文参数 - 支持思考模式控制参数thinking_enabled feat(coordinator): 重构任务执行计划器参数命名 - 将learning_candidate_enabled重命名为allow_candidate_generation - 更新TeamGraphScheduler中的参数传递 - 修改LocalAgentRunner中的相关参数处理 - 更新README文档中的相应描述 refactor(context): 标准化工具调用参数格式 - 添加_json导入用于参数序列化 - 实现_provider_tool_calls方法标准化OpenAI兼容的工具调用载荷 - 修复工具调用中参数非字符串类型的序列化问题 refactor(session): 优化消息历史记录过滤逻辑 - 修改get_messages_as_conversation为基于运行状态过滤消息 - 排除未完成、失败或错误结束的运行记录 - 改进对话历史的可见性控制机制 fix(store): 修复FTS索引重建逻辑 - 添加异常处理防止FTS索引创建失败 - 实现_rebuild_fts_index方法重新构建全文搜索索引 - 优化索引触发器和表的维护流程
900 lines
37 KiB
Markdown
900 lines
37 KiB
Markdown
# Beaver Backend Flow
|
||
|
||
这份文档只保留**树形运行结构**。
|
||
|
||
- 原理、参考项目边界、长期蓝图:看 `change.md`
|
||
- 施工顺序、阶段目标、完成标准:看 `施工指南.md`
|
||
|
||
---
|
||
|
||
## 1. 总入口
|
||
|
||
```text
|
||
用户输入(用户在不同入口发来一句话或一个任务)
|
||
│
|
||
├─ CLI(命令行入口)
|
||
├─ Web(网页前端入口)
|
||
├─ Gateway(消息通道入口,比如以后接 Slack / Telegram)
|
||
└─ future channels(未来扩展入口)
|
||
│
|
||
└─ AgentService(统一服务层:所有入口都先汇总到这里)
|
||
├─ MainAgentRouter(LLM 语义判断 simple / continue task / new task / close / abandon)
|
||
├─ create_loop()(创建 AgentLoop 运行核心)
|
||
├─ start()(启动后台运行模式)
|
||
├─ submit_direct()(把任务提交到运行队列)
|
||
├─ process_direct()(直接处理一次任务,不走队列)
|
||
├─ submit_feedback()(记录聊天反馈并驱动内部 Task 状态)
|
||
├─ stop()(停止接收新任务,并等待队列收尾)
|
||
├─ shutdown()(停止运行并释放资源)
|
||
└─ close()(关闭已经创建的 runtime)
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Boot / Loader
|
||
|
||
```text
|
||
AgentService.create_loop()(服务层创建运行核心)
|
||
│
|
||
└─ AgentLoop(profile, loader)(Agent 主循环:真正跑任务的核心对象)
|
||
│
|
||
└─ AgentLoop.boot()(启动前装配依赖)
|
||
│
|
||
└─ EngineLoader.load()(加载所有运行时模块)
|
||
├─ SessionManager(会话管理:保存聊天记录和隐藏事件)
|
||
├─ MemoryStore(长期记忆存储:真正落盘的 curated memory)
|
||
├─ MemoryService(记忆服务:运行时访问 memory 的唯一入口)
|
||
├─ RunMemoryStore(运行记录存储:保存每次 run 的结果)
|
||
├─ SkillLearningStore(技能学习存储:保存表现统计和学习候选)
|
||
├─ ToolRegistry(工具注册表:登记系统有哪些工具)
|
||
├─ ToolAssembler(工具选择器:决定本轮暴露哪些工具)
|
||
├─ ToolExecutor(工具执行器:真正调用工具)
|
||
├─ SkillsLoader(技能目录加载器:只加载可用技能)
|
||
├─ SkillAssembler(技能选择器:决定本轮激活哪些 skill)
|
||
├─ SkillSpecStore(技能生命周期存储:保存版本、草稿、审核)
|
||
├─ DraftService(草稿服务:创建 skill draft)
|
||
├─ ReviewService(审核服务:approve / reject draft)
|
||
├─ SkillPublisher(发布服务:publish / disable / rollback)
|
||
├─ EvidenceSelector(证据选择器:为学习闭环挑选历史证据)
|
||
├─ SkillDraftSynthesizer(草稿合成器:让 LLM 生成 skill draft)
|
||
├─ SkillLearningService(技能学习服务:生成学习候选和草稿)
|
||
├─ TaskService(内部 Task 服务:自动 Task 化、状态、事件、反馈)
|
||
├─ TaskExecutionPlanner(Task 执行规划器:决定 single / team)
|
||
├─ ValidationService(结果验证服务:Task run 完成后的自动验证)
|
||
└─ ContextBuilder(上下文构建器:拼 system prompt 和 messages)
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Main Agent Routing / Internal Task
|
||
|
||
```text
|
||
AgentService.process_direct / submit_direct(聊天入口统一进入服务层)
|
||
│
|
||
├─ resolve session_id(复用请求 session,或生成新 session)
|
||
├─ task_service.get_latest_open_task(session_id)(查找同会话未关闭 Task)
|
||
├─ MainAgentRouter.classify(message, active_task, recent_messages)(LLM 语义分类)
|
||
│ ├─ simple(简单问题)
|
||
│ │ └─ runner(message, include_skill_assembly=False, include_tools=False)(不创建 Task,不跑 skills/tools)
|
||
│ │
|
||
│ ├─ continue_task(继续当前 Task)
|
||
│ │ └─ reuse active Task(只要话题没有完全无关,就继续当前 open Task)
|
||
│ │
|
||
│ ├─ new_task(明确开启新任务)
|
||
│ │ └─ TaskService.create_task(...)(内部创建 Task,并保存 short_title)
|
||
│ │
|
||
│ ├─ close_task / abandon_task(用户明确结束或放弃)
|
||
│ │ └─ TaskService.close_task / abandon_task(关闭当前 Task)
|
||
│ │
|
||
│ └─ task execution
|
||
│ └─ AgentService._run_task_mode(...)(进入 Task 模式执行)
|
||
```
|
||
|
||
```text
|
||
TaskService(内部 Task 状态机)
|
||
│
|
||
├─ TaskRecord
|
||
│ ├─ task_id
|
||
│ ├─ session_id
|
||
│ ├─ goal / description / constraints
|
||
│ ├─ metadata.short_title(5-15 字左右的短标题,用于前端当前任务标识)
|
||
│ ├─ status
|
||
│ │ ├─ open
|
||
│ │ ├─ running
|
||
│ │ ├─ validating
|
||
│ │ ├─ awaiting_feedback
|
||
│ │ ├─ needs_revision
|
||
│ │ ├─ closed
|
||
│ │ └─ abandoned
|
||
│ ├─ run_ids
|
||
│ ├─ skill_names
|
||
│ ├─ validation_result
|
||
│ └─ feedback
|
||
│
|
||
└─ TaskEvent
|
||
├─ created
|
||
├─ run_started
|
||
├─ run_completed
|
||
├─ validated
|
||
├─ feedback_satisfied
|
||
├─ feedback_revise
|
||
└─ feedback_abandon
|
||
```
|
||
|
||
```text
|
||
Task Mode Execution(复杂任务执行)
|
||
│
|
||
├─ attempt 1
|
||
│ ├─ task_service.start_run(...)
|
||
│ ├─ TaskExecutionPlanner.plan(...)(LLM 规划 single / team)
|
||
│ ├─ session hidden event: task_execution_planned
|
||
│ ├─ if plan.mode == team
|
||
│ │ ├─ TeamService.run_team(parent_task_id=task_id, parent_session_id=session_id)
|
||
│ │ ├─ sub-agent runs -> parent Task run_ids
|
||
│ │ ├─ session hidden event: task_team_run_completed / task_team_run_failed
|
||
│ │ └─ team summary + node results -> 主 Agent synthesis execution_context
|
||
│ ├─ AgentLoop.process_direct / submit_direct(..., task_id, task_mode=True, attempt_index=1)
|
||
│ ├─ ValidationService.validate_task_result(..., team_summaries=...)
|
||
│ ├─ TaskService.record_validation(...)
|
||
│ ├─ RunMemoryStore.update_run_record(validation_result=...)
|
||
│ └─ session hidden event: task_validation_snapshotted
|
||
│
|
||
├─ if validation accepted
|
||
│ └─ return result with task_id / task_status / validation_result
|
||
│
|
||
└─ if validation failed
|
||
├─ session_manager.set_run_context_visible(run_id, false)(隐藏失败草稿尝试)
|
||
├─ attempt 2 重新规划 single / team
|
||
├─ revision request + team result -> 主 Agent synthesis execution_context
|
||
└─ 第二次结果无论验证是否通过,都返回并等待用户反馈
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Direct Run
|
||
|
||
```text
|
||
AgentLoop.process_direct(task)(直接执行一轮用户任务)
|
||
│
|
||
├─ 生成 session_id(确定这句话属于哪个会话)
|
||
├─ 生成 run_id(给本次运行生成唯一编号)
|
||
├─ memory_service.capture_snapshot_for_run()(每个 run 捕获独立记忆快照)
|
||
│ └─ fresh MemoryStore(root).load_from_disk()(不写共享 `_snapshot`,避免并发串记忆)
|
||
│
|
||
├─ session_manager.ensure_session(session_id)(确保会话存在)
|
||
├─ session_manager.append_message(event_type="run_started", hidden)(记录隐藏事件:本轮开始)
|
||
│
|
||
├─ make_provider_bundle()(装配模型 provider 组合)
|
||
│ ├─ main_runtime(主模型配置)
|
||
│ ├─ main_provider(主模型调用器)
|
||
│ ├─ fallback_runtime(备用模型配置)
|
||
│ ├─ fallback_provider(备用模型调用器)
|
||
│ ├─ auxiliary_runtime(辅助模型配置)
|
||
│ ├─ auxiliary_provider(辅助模型调用器,用于选 skill 等)
|
||
│ └─ embedding_runtime(向量模型配置,用于语义召回)
|
||
│
|
||
├─ if include_skill_assembly=False(simple_chat 默认关闭)
|
||
│ └─ skip SkillAssembler(不激活 skill,不注入 skill 正文)
|
||
│
|
||
├─ if include_skill_assembly=True(Task mode 默认开启,在 Task 创建/复用和规划之后执行)
|
||
│ └─ skill_assembler.assemble(...)(选择本轮应该激活哪些 published skill)
|
||
│ ├─ input task_description = skill_selection_context or current user input
|
||
│ │ ├─ Task goal / description
|
||
│ │ ├─ current user request
|
||
│ │ ├─ attempt / revision / team synthesis phase
|
||
│ │ ├─ validation feedback(重试时)
|
||
│ │ ├─ team summary / plan(team synthesis 时)
|
||
│ │ └─ previously activated skills(只作为 reuse bias,不是 pinned)
|
||
│ ├─ SkillsLoader.build_selection_candidates()(列出候选技能摘要)
|
||
│ ├─ embedding retrieve skill candidates(用向量召回相关技能)
|
||
│ ├─ LLM shortlist candidate names(先用摘要粗选少量候选)
|
||
│ │ └─ if retrieved candidates <= max_detailed_candidates -> skip shortlist
|
||
│ ├─ SkillsLoader.load_published_skill(...)(系统侧内部读取粗选候选正文,不暴露 skill_view 给主 Agent)
|
||
│ ├─ LLM final select activated skills(结合候选正文做最终选择)
|
||
│ ├─ if no matching skill -> return [] and continue run without skills
|
||
│ └─ 返回 activated skills(返回本轮被激活的技能)
|
||
│ ├─ name(技能名称)
|
||
│ ├─ content(技能正文)
|
||
│ ├─ version(技能版本)
|
||
│ ├─ content_hash(技能内容哈希,用于追踪)
|
||
│ ├─ activation_reason(为什么激活)
|
||
│ └─ tool_hints(技能建议使用哪些工具)
|
||
│
|
||
├─ ContextBuilder.build_skill_activation_messages(...)(把激活技能变成模型可读消息)
|
||
├─ 构造 SkillActivationReceipt[](构造技能激活收据)
|
||
├─ session_manager.append_message(...)(记录隐藏事件:本轮用了哪些技能)
|
||
│ ├─ event_type="skill_activation_snapshotted"(技能激活快照)
|
||
│ ├─ hidden(不进入普通聊天上下文)
|
||
│ └─ payload(隐藏数据)
|
||
│ ├─ receipts(技能激活收据)
|
||
│ └─ activation_messages(实际注入给模型的技能消息)
|
||
│
|
||
├─ tool_assembler.assemble(...)(选择本轮应该暴露哪些工具;simple_chat 默认跳过)
|
||
│ ├─ always tools(默认总是可用的工具)
|
||
│ ├─ activated skill tool hints(被激活技能推荐的工具)
|
||
│ ├─ embedding retrieve tools(用向量召回相关工具)
|
||
│ └─ 返回 selected ToolSpec[](返回本轮工具列表)
|
||
│
|
||
├─ session_manager.append_message(event_type="tool_selection_snapshotted", hidden)(记录隐藏事件:工具选择快照)
|
||
│
|
||
├─ ContextBuilder.build_messages(...)(构造发给模型的完整 messages)
|
||
│ ├─ build_system_prompt()(构造 system prompt)
|
||
│ │ ├─ base system prompt(基础系统提示词)
|
||
│ │ ├─ session metadata(当前会话元信息)
|
||
│ │ ├─ execution context(本轮额外执行上下文)
|
||
│ │ └─ frozen memory snapshot(冻结记忆快照)
|
||
│ ├─ insert activated skill messages(插入已激活技能正文)
|
||
│ ├─ append visible history(追加可见历史聊天)
|
||
│ └─ append current user input(追加当前用户输入)
|
||
│
|
||
├─ session_manager.update_system_prompt(...)(把本轮 system prompt 快照写回会话)
|
||
├─ session_manager.append_message(event_type="skill_selection_context_snapshotted", hidden)(完整记录 skill query)
|
||
├─ session_manager.append_message(event_type="system_prompt_snapshotted", hidden)(记录隐藏事件:system prompt 快照)
|
||
├─ session_manager.append_message(event_type="user_message_added")(记录可见事件:用户消息)
|
||
│
|
||
├─ 进入 tool loop(进入模型回答和工具调用循环)
|
||
│
|
||
├─ 成功时(模型正常结束)
|
||
│ ├─ session_manager.append_message(event_type="run_completed", hidden)(记录隐藏事件:运行完成)
|
||
│ └─ _record_run_receipts(...)(记录运行证据,不生成学习候选)
|
||
│
|
||
├─ 失败时(运行中出现异常)
|
||
│ ├─ append assistant error message(写入 assistant 错误消息)
|
||
│ ├─ session_manager.append_message(event_type="run_failed", hidden)(记录隐藏事件:运行失败)
|
||
│ └─ _record_run_receipts(...)(即使失败也记录运行证据)
|
||
│
|
||
└─ return AgentRunResult(返回本轮结果)
|
||
├─ session_id(会话编号)
|
||
├─ run_id(运行编号)
|
||
├─ output_text(最终回复文本)
|
||
├─ finish_reason(结束原因)
|
||
├─ tool_iterations(工具循环次数)
|
||
├─ provider_name(模型供应商)
|
||
├─ model(模型名称)
|
||
├─ usage(token 用量)
|
||
├─ task_id(Task 模式下返回)
|
||
├─ task_status(Task 模式下返回)
|
||
└─ validation_result(Task 模式下返回)
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Tool Loop
|
||
|
||
```text
|
||
tool loop(工具调用循环)
|
||
│
|
||
├─ session_manager.append_message(event_type="llm_request_snapshotted", hidden)(完整记录本次 provider messages / tools)
|
||
├─ provider.chat(messages, tools=schemas)(把消息和工具 schema 发给模型)
|
||
├─ session_manager.update_usage(...)(累计 token 用量)
|
||
├─ session_manager.append_message(event_type="assistant_message_added")(记录 assistant 回复)
|
||
├─ ContextBuilder.add_assistant_message(...)(把 assistant 回复追加到本轮 messages)
|
||
│
|
||
├─ if no tool calls(如果模型没有要求调用工具)
|
||
│ └─ finish(结束本轮回答)
|
||
│
|
||
└─ if tool calls(如果模型要求调用工具)
|
||
├─ ToolExecutor.execute_tool_call(...)(执行一个工具调用)
|
||
├─ session_manager.append_message(event_type="tool_result_recorded")(记录工具结果)
|
||
├─ ContextBuilder.add_tool_result(...)(把工具结果追加到 messages)
|
||
└─ 回到 provider.chat(...)(带着工具结果继续问模型)
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Run Evidence / Skill Effect Recording
|
||
|
||
```text
|
||
AgentLoop._record_run_receipts(...)(记录本轮运行证据;不直接学习)
|
||
│
|
||
├─ 构造 RunRecord(构造本轮运行记录)
|
||
│ ├─ run_id(运行编号)
|
||
│ ├─ session_id(会话编号)
|
||
│ ├─ task_text(用户原始任务)
|
||
│ ├─ task_id(内部 Task 编号,简单问题可为空)
|
||
│ ├─ attempt_index(Task 模式下的尝试序号)
|
||
│ ├─ started_at(开始时间)
|
||
│ ├─ ended_at(结束时间)
|
||
│ ├─ success(是否成功)
|
||
│ ├─ finish_reason(结束原因)
|
||
│ ├─ validation_result(Task 模式下的验证结果)
|
||
│ ├─ feedback(用户反馈)
|
||
│ └─ activated_skills(本轮激活过的技能收据)
|
||
│
|
||
├─ 构造 SkillEffectRecord[](构造技能效果记录)
|
||
│ └─ 每个 activated skill 一条(每个被用到的技能都单独记一条)
|
||
│
|
||
├─ skill_learning_service.collect_run_receipts(...)(收集运行收据)
|
||
│ ├─ RunMemoryStore.append_run_record(...)(把 RunRecord 写入 memory/runs/runs.jsonl)
|
||
│ ├─ RunMemoryStore.append_skill_effect(...)(把 SkillEffectRecord 写入 memory/runs/skill-effects.jsonl)
|
||
│ ├─ SkillLearningService.rescore_skill_versions()(重新统计每个技能版本表现)
|
||
│ │ └─ SkillLearningStore.update_performance_snapshot(...)(更新表现快照)
|
||
│ └─ never build learning candidates in runtime hot path(运行完成时永不生成候选)
|
||
│
|
||
└─ session_manager.append_message(...)(记录隐藏事件:技能效果快照)
|
||
├─ event_type="skill_effects_snapshotted"(技能效果已快照)
|
||
├─ hidden(不进入普通聊天上下文)
|
||
└─ payload(隐藏数据)
|
||
├─ run_record(本轮运行记录)
|
||
├─ skill_effects(技能效果记录)
|
||
├─ candidate_generation_allowed(本轮是否允许生成候选;runtime 固定 false)
|
||
└─ learning_candidates(学习候选;默认空)
|
||
```
|
||
|
||
```text
|
||
runtime invariant(运行期不直接学习)
|
||
│
|
||
├─ run completed / run failed
|
||
│ └─ 只写 RunRecord + SkillEffectRecord + performance snapshot
|
||
│
|
||
├─ simple chat
|
||
│ └─ 不创建 Task,不触发 learning candidate
|
||
│
|
||
└─ Task attempt / sub-agent run
|
||
└─ 只留下证据,等待 feedback gate 决定是否学习
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Chat Feedback / Learning Gate
|
||
|
||
```text
|
||
POST /api/chat/feedback(聊天反馈接口,不是 Task 管理 API)
|
||
│
|
||
├─ input
|
||
│ ├─ session_id
|
||
│ ├─ run_id
|
||
│ ├─ feedback_type
|
||
│ │ ├─ satisfied
|
||
│ │ ├─ revise
|
||
│ │ └─ abandon
|
||
│ └─ comment?
|
||
│
|
||
├─ AgentService.submit_feedback(...)
|
||
│ ├─ TaskService.get_task_by_run_id(run_id)
|
||
│ ├─ reject if task/session mismatch
|
||
│ ├─ reject conflicting feedback for same run
|
||
│ ├─ same feedback is idempotent
|
||
│ └─ TaskService.add_feedback(...)
|
||
│
|
||
├─ satisfied
|
||
│ ├─ if validation accepted
|
||
│ │ ├─ Task status -> closed
|
||
│ │ └─ SkillLearningService.build_learning_candidates_for_task(task_id, trigger_run_id)
|
||
│ └─ if validation not accepted
|
||
│ └─ 记录人工接受但保留验证风险;不自动生成 learning candidate
|
||
│
|
||
├─ revise
|
||
│ ├─ Task status -> needs_revision
|
||
│ ├─ 更新 run / skill effect 为需修订证据
|
||
│ └─ 下一条用户消息默认复用该 Task;不生成 learning candidate
|
||
│
|
||
└─ abandon
|
||
├─ Task status -> abandoned
|
||
├─ 更新 run / skill effect 为失败证据
|
||
├─ 追加 task_failure_evidence_recorded 隐藏事件
|
||
└─ 默认不写主 memory,不生成成功 Skill draft
|
||
```
|
||
|
||
---
|
||
|
||
## 8. Agent Team v1 / Local Coordinator
|
||
|
||
```text
|
||
TeamService.run_team(...)(内部 team 执行入口,不暴露产品级 Task API)
|
||
│
|
||
├─ validate parent task(如果传 parent_task_id,先校验 Task 存在且 session 匹配)
|
||
│
|
||
├─ TeamGraphScheduler.run(...)
|
||
│ ├─ graph.validate()
|
||
│ │ ├─ v1 implemented strategies: sequence / parallel / dag
|
||
│ │ └─ reserved strategies: moa / hierarchy / heavy / group_chat / forest / maker / router
|
||
│ ├─ provider_bundle_factory(node)(推荐:每个节点拿 fresh provider bundle)
|
||
│ ├─ inherited_pinned_skills(主 agent 明确委派给 sub-agent 的 pinned skills)
|
||
│ ├─ inherited_pinned_skill_contexts(missing skill 生成的一次性 ephemeral guidance)
|
||
│ └─ allow_candidate_generation=False(默认只写 receipts,不绕过 Task feedback gate)
|
||
│
|
||
├─ LocalAgentRunner.run(envelope)
|
||
│ ├─ 生成 child_session_id
|
||
│ ├─ parent_session_id -> 主 session(建立 session lineage)
|
||
│ ├─ AgentLoop.process_direct / submit_direct(...)(复用主 AgentLoop / ContextBuilder / ToolAssembler / SkillAssembler / MemoryService)
|
||
│ ├─ pinned_skill_names -> AgentLoop(published pinned skill 必须注入)
|
||
│ ├─ pinned_skill_contexts -> AgentLoop(ephemeral guidance 只在本次 run 注入)
|
||
│ └─ provider_bundle + node model/provider override 禁止混用
|
||
│
|
||
├─ strategy execution
|
||
│ ├─ sequence:前一节点成功输出进入后一节点 dependency_outputs
|
||
│ ├─ parallel:同层节点 asyncio.gather 真并发执行
|
||
│ └─ dag:按依赖拓扑分批并发;失败节点会阻断依赖它的后续节点
|
||
│
|
||
├─ node-level failure normalization
|
||
│ ├─ provider factory / runner 普通异常 -> NodeRunResult(success=False, finish_reason="error")
|
||
│ ├─ asyncio.CancelledError 继续抛出
|
||
│ └─ blocked dependency -> NodeRunResult(success=False, finish_reason="blocked")
|
||
│
|
||
├─ TeamRunResult
|
||
│ ├─ success
|
||
│ ├─ summary(只聚合成功节点输出;失败节点列入 Failed nodes)
|
||
│ ├─ node_results
|
||
│ ├─ run_ids
|
||
│ ├─ session_ids
|
||
│ └─ task_id(父 Task)
|
||
│
|
||
└─ attach runs to parent Task
|
||
└─ TaskService.append_run(parent_task_id, sub_run_id, skill_names=...)
|
||
```
|
||
|
||
```text
|
||
Team v1 scope(当前边界)
|
||
│
|
||
├─ 已实现
|
||
│ ├─ Beaver 自有 coordinator models
|
||
│ ├─ sequence / parallel / dag 三个执行原语
|
||
│ ├─ pinned skill 继承 + open skill assembly
|
||
│ ├─ per-run memory snapshot,支持真并发 prompt 构建
|
||
│ ├─ per-node provider factory 语义
|
||
│ ├─ parent Task 一致性校验
|
||
│ └─ 节点失败归一和 summary 失败区块
|
||
│
|
||
├─ 已接入 Task mode 内部执行链
|
||
│ ├─ TaskExecutionPlanner 先决定 single / team
|
||
│ ├─ team run 只作为内部 sub-agent 执行策略
|
||
│ ├─ TeamRunResult 不直接返回给用户
|
||
│ └─ 主 Agent synthesis run 生成用户可见最终回答
|
||
│
|
||
└─ 仍不暴露产品级 team / Task API
|
||
└─ 外部仍只使用聊天入口和反馈入口
|
||
```
|
||
|
||
---
|
||
|
||
## 9. Session Module
|
||
|
||
```text
|
||
SessionManager(会话管理门面)
|
||
│
|
||
├─ ensure_session(...)(确保会话存在)
|
||
├─ append_message(...)(追加一条事件或聊天消息)
|
||
├─ get_event_records(session_id)(获取完整事件流)
|
||
├─ get_run_event_records(session_id, run_id)(获取某次 run 的事件)
|
||
├─ update_latest_assistant_event_payload(...)(把 task/validation/feedback 状态投影到最新 assistant 消息)
|
||
├─ set_run_context_visible(session_id, run_id, visible)(隐藏失败重试草稿等 run)
|
||
├─ list_run_ids(session_id)(列出某个会话下所有 run_id)
|
||
├─ get_messages_as_conversation(session_id)(获取可作为聊天展示的消息)
|
||
├─ get_visible_history(session_id)(获取可进入 prompt 的历史)
|
||
├─ update_system_prompt(...)(更新当前会话 system prompt 快照)
|
||
├─ update_usage(...)(更新 token 用量)
|
||
├─ end_session(...)(结束会话)
|
||
├─ reopen_session(...)(重新打开会话)
|
||
├─ list_sessions_rich(...)(列出带摘要的会话)
|
||
├─ search_messages(...)(搜索历史消息)
|
||
└─ resolve_session_id(...)(根据前缀解析 session_id)
|
||
```
|
||
|
||
```text
|
||
SessionStore (SQLite)(SQLite 会话数据库)
|
||
│
|
||
├─ sessions table(会话表)
|
||
├─ messages table(消息和事件表)
|
||
├─ messages_fts(全文搜索索引)
|
||
├─ WAL(SQLite 写入日志模式)
|
||
├─ parent_session_id(父会话字段,给未来分支会话用)
|
||
└─ hidden / visible event split(隐藏事件和可见消息分离)
|
||
```
|
||
|
||
```text
|
||
hidden events(隐藏事件类型)
|
||
│
|
||
├─ run_started(运行开始)
|
||
├─ skill_activation_snapshotted(技能激活快照)
|
||
├─ tool_selection_snapshotted(工具选择快照)
|
||
├─ system_prompt_snapshotted(系统提示词快照)
|
||
├─ run_completed(运行完成)
|
||
├─ run_failed(运行失败)
|
||
├─ skill_effects_snapshotted(技能效果快照)
|
||
├─ task_validation_snapshotted(Task 验证快照)
|
||
└─ task_feedback_recorded(Task 用户反馈快照)
|
||
```
|
||
|
||
---
|
||
|
||
## 10. Memory Module
|
||
|
||
```text
|
||
MemoryService(记忆服务)
|
||
│
|
||
├─ initialize()(初始化记忆存储)
|
||
├─ reload_for_new_run()(每轮开始前刷新记忆快照)
|
||
├─ get_snapshot()(获取本轮冻结记忆快照)
|
||
└─ get_store()(获取底层 MemoryStore)
|
||
```
|
||
|
||
```text
|
||
MemoryStore(长期记忆存储)
|
||
│
|
||
├─ target: memory(项目/任务级长期记忆)
|
||
├─ target: user(用户偏好记忆)
|
||
├─ add(...)(新增记忆)
|
||
├─ replace(...)(替换记忆)
|
||
├─ remove(...)(删除记忆)
|
||
├─ load_from_disk()(从磁盘读取)
|
||
├─ save_to_disk()(保存到磁盘)
|
||
└─ format_for_system_prompt(...)(格式化成 system prompt 段落)
|
||
```
|
||
|
||
```text
|
||
memory runtime semantics(记忆运行语义)
|
||
│
|
||
├─ run start(本轮开始)
|
||
│ └─ refresh live state -> capture frozen snapshot(刷新 live memory,并冻结本轮快照)
|
||
│
|
||
├─ run middle(本轮进行中)
|
||
│ ├─ memory tool may write durable state(memory 工具可以写入长期记忆)
|
||
│ └─ current run prompt snapshot stays frozen(但本轮 prompt 里的记忆不变)
|
||
│
|
||
└─ next run(下一轮)
|
||
└─ newly written memory becomes visible(上一轮写入的新记忆开始可见)
|
||
```
|
||
|
||
---
|
||
|
||
## 11. Skills Module
|
||
|
||
```text
|
||
SkillsLoader(技能加载器)
|
||
│
|
||
├─ workspace published catalog(工作区正式发布的技能目录)
|
||
├─ workspace legacy skills/*/SKILL.md(旧格式技能文件)
|
||
├─ builtin skills(内置技能)
|
||
├─ list_skills()(列出运行时可见技能)
|
||
├─ list_published_skills()(只列正式发布技能)
|
||
├─ get_current_version()(获取当前正式版本)
|
||
├─ load_published_skill()(加载正式版本正文)
|
||
├─ get_skill_record()(获取技能元数据记录)
|
||
├─ get_skill_metadata()(获取 frontmatter 元数据)
|
||
├─ get_skill_tool_hints()(获取技能推荐工具)
|
||
├─ load_skills_for_context()(把多个技能加载成上下文块)
|
||
├─ build_skills_summary()(构造技能摘要索引)
|
||
├─ build_selection_candidates()(构造给 SkillAssembler 的候选摘要)
|
||
├─ list_skill_supporting_files()(列出技能支持文件)
|
||
└─ get_always_skills()(获取 always 类型技能)
|
||
```
|
||
|
||
```text
|
||
SkillAssembler(技能选择器)
|
||
│
|
||
├─ input(输入)
|
||
│ ├─ task_description(Task-aware query:Task 描述 / 当前用户消息 / previous skills / attempt context / validation revision context / team context)
|
||
│ ├─ candidate skill summaries(候选技能摘要)
|
||
│ ├─ embedding runtime(向量模型配置)
|
||
│ └─ selector provider/model(用于选择技能的模型)
|
||
│
|
||
├─ embedding retrieve candidates(先用向量召回相关技能)
|
||
├─ LLM shortlist names(用摘要粗选需要查看正文的候选)
|
||
│ └─ skip when candidate count <= max_detailed_candidates(候选很少时直接读取正文)
|
||
├─ internal load shortlisted SKILL.md(SkillAssembler 内部读取候选正文)
|
||
├─ LLM final select names(结合候选正文选择最终技能名)
|
||
├─ no match returns [](没有对应 published skill 时返回空,不阻塞任务)
|
||
└─ return SkillContext[](返回技能上下文)
|
||
├─ name(技能名)
|
||
├─ content(技能正文)
|
||
├─ version(技能版本)
|
||
├─ content_hash(内容哈希)
|
||
├─ activation_reason(激活原因)
|
||
└─ tool_hints(推荐工具)
|
||
```
|
||
|
||
```text
|
||
skills lifecycle baseline(技能生命周期基线)
|
||
│
|
||
├─ SkillSpecStore(技能生命周期文件存储)
|
||
│ ├─ skill.json(技能总信息)
|
||
│ ├─ current.json(当前版本指针)
|
||
│ ├─ versions/(正式版本目录)
|
||
│ ├─ drafts/(草稿目录)
|
||
│ ├─ reviews/(审核记录目录)
|
||
│ └─ archive/(归档目录)
|
||
│
|
||
├─ DraftService(草稿服务)
|
||
│ ├─ create_new_skill_draft(...)(创建新技能草稿)
|
||
│ ├─ create_revision_draft(...)(创建修订草稿)
|
||
│ ├─ create_merge_draft(...)(创建合并草稿)
|
||
│ ├─ create_retire_proposal(...)(创建退役提案)
|
||
│ ├─ list_drafts(...)(列出草稿)
|
||
│ └─ get_draft(...)(读取单个草稿)
|
||
│
|
||
├─ ReviewService(审核服务)
|
||
│ ├─ submit_for_review(...)(提交审核)
|
||
│ ├─ approve(...)(批准草稿)
|
||
│ └─ reject(...)(拒绝草稿)
|
||
│
|
||
└─ SkillPublisher(发布服务)
|
||
├─ publish(...)(发布 approved 草稿为正式版本)
|
||
├─ apply_retire_proposal(...)(应用退役提案,不创建新版本)
|
||
├─ disable(...)(禁用技能)
|
||
└─ rollback(...)(回滚到旧版本)
|
||
```
|
||
|
||
---
|
||
|
||
## 12. Tools Module
|
||
|
||
```text
|
||
ToolRegistry(工具注册表)
|
||
│
|
||
├─ echo(回显工具)
|
||
├─ memory(写入/管理长期记忆)
|
||
├─ session_search(搜索会话历史)
|
||
├─ list_directory(列目录)
|
||
├─ read_file(读文件)
|
||
└─ search_files(搜索文件)
|
||
```
|
||
|
||
```text
|
||
ToolAssembler(工具选择器)
|
||
│
|
||
├─ selected = always tools(先加入默认工具)
|
||
├─ selected += activated skill tool hints(再加入技能推荐工具)
|
||
├─ selected += embedding top-k tools(再用向量召回任务相关工具)
|
||
└─ return ToolSpec[](返回本轮可用工具列表;不通过工具动态加载 skill)
|
||
```
|
||
|
||
```text
|
||
ToolExecutor(工具执行器)
|
||
│
|
||
├─ normalize tool call(规范化模型发来的工具调用)
|
||
├─ resolve tool(找到对应工具)
|
||
├─ invoke tool(执行工具)
|
||
└─ return ToolResult(返回工具结果)
|
||
```
|
||
|
||
```text
|
||
filesystem tool boundary(文件系统工具边界)
|
||
│
|
||
├─ workspace scoped(只能访问 workspace 范围)
|
||
├─ realpath enforcement(用真实路径校验)
|
||
├─ reject path escape(拒绝路径逃逸)
|
||
├─ reject symlink escape(拒绝软链接逃逸)
|
||
└─ reject binary file reads(拒绝读取二进制文件)
|
||
```
|
||
|
||
---
|
||
|
||
## 13. Provider Module
|
||
|
||
```text
|
||
make_provider_bundle(...)(创建模型调用组合)
|
||
│
|
||
├─ main_runtime(主模型配置)
|
||
├─ main_provider(主模型调用器)
|
||
├─ fallback_runtime(备用模型配置)
|
||
├─ fallback_provider(备用模型调用器)
|
||
├─ auxiliary_runtime(辅助模型配置)
|
||
├─ auxiliary_provider(辅助模型调用器)
|
||
└─ embedding_runtime(向量模型配置)
|
||
```
|
||
|
||
```text
|
||
provider roles(模型角色分工)
|
||
│
|
||
├─ main(主模型)
|
||
│ └─ assistant/tool loop(负责正常回答和工具循环)
|
||
├─ fallback(备用模型)
|
||
│ └─ main failure recovery(主模型失败时兜底)
|
||
├─ auxiliary(辅助模型)
|
||
│ └─ skill selection / future helper tasks(负责选择技能等辅助任务)
|
||
└─ embedding(向量模型)
|
||
└─ skill/tool semantic retrieval(负责 skill / tool 的语义召回)
|
||
```
|
||
|
||
---
|
||
|
||
## 14. Service Lifecycle
|
||
|
||
```text
|
||
AgentService(服务生命周期)
|
||
│
|
||
├─ MainAgentRouter(请求进入 AgentLoop 前先分类 simple / task)
|
||
├─ submit_feedback(...)(聊天反馈入口,内部更新 Task 状态)
|
||
│
|
||
├─ direct mode(直接模式:适合 CLI / 单次调用)
|
||
│ └─ process_direct(...)(直接处理一次任务)
|
||
│
|
||
└─ running mode(后台运行模式:适合 Web / Gateway)
|
||
├─ start()(启动 AgentLoop.run)
|
||
├─ submit_direct(...)(向队列提交任务)
|
||
├─ stop(timeout_seconds, force)(停止并等待任务收尾)
|
||
├─ shutdown(timeout_seconds, force)(停止并释放 runtime)
|
||
└─ close()(关闭已停止的 loop)
|
||
```
|
||
|
||
```text
|
||
running mode semantics(后台运行语义)
|
||
│
|
||
├─ start()(启动)
|
||
│ └─ AgentLoop.run()(进入队列消费循环)
|
||
│
|
||
├─ submit_direct()(提交任务)
|
||
│ └─ enqueue _DirectRunRequest(把任务放入队列)
|
||
│
|
||
├─ stop()(停止)
|
||
│ ├─ stop accepting new tasks(不再接收新任务)
|
||
│ └─ drain queued tasks(等待已排队任务处理完)
|
||
│
|
||
└─ close()(关闭)
|
||
└─ requires loop already stopped(必须先 stop,才能 close)
|
||
```
|
||
|
||
---
|
||
|
||
## 15. Task Team Registry / Process / Learning 闭环
|
||
|
||
```text
|
||
TaskExecutionPlanner(Task 内部执行规划)
|
||
│
|
||
├─ LLM planner
|
||
│ ├─ 输出 single / team
|
||
│ └─ team 只允许 sequence / parallel / dag
|
||
│
|
||
├─ TaskSkillResolver
|
||
│ ├─ 从 published skill catalog 检索候选
|
||
│ ├─ 按 skill_query / required_capabilities / node task 选择 skill
|
||
│ ├─ 命中 published skill 后写入 graph.nodes[].inherited_pinned_skills
|
||
│ └─ 无命中时创建 ephemeral guidance,并写入 graph.nodes[].inherited_pinned_skill_contexts
|
||
│
|
||
└─ TaskExecutionPlan
|
||
├─ graph.nodes[].agent 只是 generic runtime trace identity
|
||
└─ to_event_payload() 写入 skill_queries / selected_skill_names / ephemeral_guidance_ids / skill_resolution_report
|
||
```
|
||
|
||
```text
|
||
Task mode attempt(每次 Task attempt)
|
||
│
|
||
├─ task_execution_planned(隐藏事件)
|
||
│ └─ plan_mode / strategy / node_ids / skill_resolution_report
|
||
│
|
||
├─ team run(仅 team plan)
|
||
│ ├─ sub-agent run_ids 回填父 Task
|
||
│ ├─ team summary 只进入主 Agent synthesis context
|
||
│ └─ task_team_run_completed / task_team_run_failed(隐藏事件)
|
||
│
|
||
├─ main Agent synthesis
|
||
│ ├─ 输出最终用户可见回答
|
||
│ └─ task_synthesis_completed(隐藏事件)
|
||
│
|
||
└─ validation
|
||
├─ task_validation_snapshotted(隐藏事件)
|
||
├─ 第一次失败隐藏草稿并重试一次
|
||
└─ 第二次或验证通过后等待反馈
|
||
```
|
||
|
||
```text
|
||
Frontend process projection
|
||
│
|
||
├─ GET /api/sessions/{session_id}/process
|
||
│ ├─ 读取隐藏 Task/team/validation 事件
|
||
│ ├─ 合并 run memory records
|
||
│ └─ 输出 processRuns / processEvents / processArtifacts / agents
|
||
│
|
||
└─ ChatWorkbench
|
||
├─ 桌面端显示 ProcessLane
|
||
├─ 移动端显示 Process tab
|
||
└─ 不直接暴露隐藏事件原始 JSON
|
||
```
|
||
|
||
```text
|
||
Learning pipeline
|
||
│
|
||
├─ evidence recording
|
||
│ ├─ every run -> RunRecord
|
||
│ ├─ activated skills -> SkillEffectRecord
|
||
│ └─ no candidates generated here
|
||
│
|
||
├─ feedback gate
|
||
│ ├─ validation accepted + satisfied -> scoped learning candidate
|
||
│ ├─ validation rejected + satisfied -> 记录人工接受风险,不生成候选
|
||
│ ├─ revise -> 保持 Task 打开,不生成候选
|
||
│ └─ abandon -> 失败证据,不写主 memory,不生成成功候选
|
||
│
|
||
├─ scoped candidate generation
|
||
│ ├─ source = current task run_ids
|
||
│ ├─ no published skill -> new_skill
|
||
│ └─ published skill used -> revise_skill
|
||
│
|
||
├─ SkillLearningPipelineService
|
||
│ ├─ candidate -> queued / synthesizing
|
||
│ ├─ worker/run-once -> draft
|
||
│ ├─ draft -> safety report
|
||
│ ├─ draft -> lightweight eval report
|
||
│ ├─ safety_failed / eval_failed 阻断发布
|
||
│ ├─ draft -> submit review
|
||
│ ├─ approve / reject
|
||
│ ├─ approved + safety passed + eval not failed -> publish
|
||
│ ├─ retire proposal -> apply retire
|
||
│ └─ rollback / disable
|
||
│
|
||
├─ SkillLearningWorker
|
||
│ ├─ 默认按配置定时扫描 open candidates
|
||
│ ├─ 自动生成 draft_ready / safety_failed / eval_failed
|
||
│ └─ 永不自动 approve / publish
|
||
│
|
||
├─ Web review workbench
|
||
│ ├─ Candidates
|
||
│ ├─ Draft detail
|
||
│ ├─ Safety report
|
||
│ └─ Eval report
|
||
│
|
||
└─ Runtime catalog
|
||
└─ 只有 published skill 进入运行时选择;draft 不生效
|
||
```
|
||
|
||
---
|
||
|
||
## 16. Web / Gateway
|
||
|
||
```text
|
||
Web(网页入口)
|
||
│
|
||
├─ FastAPI lifespan(FastAPI 生命周期)
|
||
│ ├─ create or receive AgentService(创建或接收 AgentService)
|
||
│ ├─ start() when app owns lifecycle(如果 Web app 拥有生命周期,就启动 service)
|
||
│ ├─ start SkillLearningWorker when enabled(按配置启动技能学习 worker)
|
||
│ └─ shutdown() when app owns lifecycle(如果 Web app 拥有生命周期,就关闭 service / worker)
|
||
│
|
||
├─ GET /api/ping(健康检查接口)
|
||
│ └─ return status / running / mode(返回状态、是否运行、运行模式)
|
||
│
|
||
├─ POST /api/chat(聊天接口)
|
||
│ ├─ validate WebChatRequest(校验请求体)
|
||
│ ├─ agent_service.submit_direct(...)(把用户消息提交给 AgentService)
|
||
│ └─ return WebChatResponse(返回模型回复 + run/task/validation 元数据)
|
||
│
|
||
├─ WS /ws/{session_id}(网页 WebSocket 适配层)
|
||
│ ├─ ping -> pong
|
||
│ ├─ message -> agent_service.submit_direct(...)
|
||
│ ├─ return status / assistant message(携带 run/task/validation 元数据)
|
||
│ └─ return session_updated(通知前端刷新 session/process)
|
||
│
|
||
└─ POST /api/chat/feedback(聊天反馈接口)
|
||
├─ validate WebChatFeedbackRequest
|
||
├─ agent_service.submit_feedback(...)
|
||
└─ return WebChatFeedbackResponse
|
||
|
||
Skills learning admin API
|
||
│
|
||
├─ GET /api/skills/candidates
|
||
├─ POST /api/skills/candidates/{candidate_id}/draft
|
||
├─ POST /api/skills/candidates/{candidate_id}/regenerate
|
||
├─ POST /api/skills/learning/run-once
|
||
├─ GET /api/skills/{skill_name}/drafts/{draft_id}/safety
|
||
├─ GET /api/skills/{skill_name}/drafts/{draft_id}/eval
|
||
└─ POST /api/skills/{skill_name}/drafts/{draft_id}/publish
|
||
└─ requires approved review + safety passed + eval not failed
|
||
```
|
||
|
||
```text
|
||
Gateway(消息通道入口)
|
||
│
|
||
├─ MessageBus(内部消息总线)
|
||
├─ ChannelAdapter(Telegram / Slack / Email / WhatsApp 等只作为 adapter)
|
||
├─ inbound -> AgentService.handle_inbound_message(...)(外部消息进入 AgentService)
|
||
├─ outbound <- OutboundMessage(AgentService 返回结构化输出消息)
|
||
└─ ChannelManager(按 message.channel 分发 outbound)
|
||
```
|
||
|
||
---
|
||
|
||
## 17. Bus Mode Skeleton
|
||
|
||
```text
|
||
AgentLoop.run()(后台队列运行模式)
|
||
│
|
||
├─ create queue(创建任务队列)
|
||
├─ mark running(标记为运行中)
|
||
├─ consume _DirectRunRequest(消费一个任务请求)
|
||
├─ call _process_direct_impl(...)(调用真正的单轮执行逻辑)
|
||
├─ set future result / exception(把结果或异常写回等待方)
|
||
├─ stop() -> enqueue sentinel(停止时放入结束标记)
|
||
└─ drain pending queue on exit(退出时清理未处理任务)
|
||
```
|