feat(app-instance): 集成Beaver后端并更新配置管理

集成新的Beaver后端服务到应用实例中,替换原有的nanobot实现。

主要变更包括:
- 在Dockerfile和环境配置中添加Beaver相关路径和配置变量
- 更新工作目录结构从.nanobot到.beaver
- 实现Beaver引擎加载器,支持配置文件加载和工具组装
- 添加内置工具如ListDirectoryTool、ReadFileTool、SearchFilesTool
- 更新消息处理流程,支持通道适配器和网关模式
- 重构技能系统,支持显式工具提示和嵌入式检索
- 改进错误处理和生命周期管理

此变更使应用实例能够使用统一的Beaver后端进行AI代理运行时管理。
This commit is contained in:
2026-04-27 17:37:40 +08:00
parent 36882a7d7b
commit 5ba5c7e4c1
47 changed files with 2821 additions and 462 deletions

View File

@ -704,6 +704,7 @@ provider 层不要再做成“一个厂商一个世界”,而是要拆成 4
1. `beaver/tools/base.py`
2. `beaver/tools/registry/tool_registry.py`
3. `beaver/tools/assembler/task_assembler.py`
参考旧文件:
@ -732,6 +733,48 @@ provider 层不要再做成“一个厂商一个世界”,而是要拆成 4
1. registry 可以注册工具
2. provider 返回 tool call 时可以找到并执行工具
3. memory / session_search 已纳入统一工具集合
4. 本地工具描述采用 MCP-style `name/description/inputSchema`
5. `ToolAssembler` 能按 task description 用 embedding 召回本轮 top10 工具
6. activated skill frontmatter 里的 `tools` 能参与本轮工具选择
7. 只读 filesystem tools 已接入:
- `list_directory`
- `read_file`
- `search_files`
8. filesystem tools 强制限制在 `ToolContext.workspace`
9. 相对路径逃逸、绝对路径逃逸、符号链接逃逸都会拒绝
10. 二进制文件读取会拒绝,搜索会跳过二进制 / 大文件
当前工具选择规则已经定为:
1. always tools 每轮默认可用
- `memory`
- `session_search`
- `skill_view`
- `list_directory`
- `read_file`
- `search_files`
2. activated skill 可以显式声明工具:
```yaml
---
tools:
- terminal
- read_file
---
```
3. `ToolAssembler` 合并:
- always tools
- skill hints
- task embedding top10 tools
4. 第一版只信任 frontmatter / metadata 的显式 `tools`,不从正文里猜工具名
5. 如果 skill 声明了尚未注册的工具,先忽略,不阻断 run
filesystem 这一版只做只读,不做写文件 / shell
1. 先让 agent 能看见 workspace 结构、读源码、搜文本
2. 写文件和 shell 属于高风险工具,必须等 permission gates 明确后再接
3. 当前 workspace 边界只保证路径隔离,不等价于完整权限系统
### 4.5 最后实现第一版 `AgentLoop`
@ -855,6 +898,23 @@ provider 层不要再做成“一个厂商一个世界”,而是要拆成 4
- 先用 embedding 做语义召回
- 输出应该激活的 skills
6. embedding 配置通过 provider bundle 的独立 `embedding runtime` 传入;若没有显式 embedding 配置,则只有主链本身是 OpenAI-compatible 时才允许继承 `api_base/api_key`
7. skill frontmatter 可声明本 skill 推荐工具;这些 tool hints 会交给 `ToolAssembler`
当前和长期目标的关系:
1. 已完成基础入口:
- curated memory CRUD
- `session_search`
- `skill_view`
- `SkillAssembler`
- `ToolAssembler`
2. 还没完成长期智能体治理:
- 智能体定期整理 / 提示记忆
- 复杂任务完成后自主创建技能
- 技能在使用过程中自我提升
- FTS5 + LLM 摘要的跨会话回忆增强
- Honcho 风格辩证用户建模
- agentskills.io 开放标准兼容
---
@ -884,6 +944,10 @@ provider 层不要再做成“一个厂商一个世界”,而是要拆成 4
3. `ContextBuilder`
- 不再直接依赖进程内状态
- 只从 Session / curated memory / skills 中提取当前需要的上下文
4. `ToolAssembler`
- 不把所有工具无脑暴露给模型
- 按 task description / activated skill hints 选择本轮工具
- 输出 provider 可消费的 tool schema
这一步不是要一口气做完 fork / rewind / checkpoint 全套系统而是先把“Session-first, Stateless Harness”这条主线立住。
@ -926,12 +990,13 @@ provider 层不要再做成“一个厂商一个世界”,而是要拆成 4
1. `session_started/ensured`
2. `run_started`
3. `system_prompt_snapshotted`
4. `user_message_added`
5. `assistant_message_added`
6. `tool_call_requested`
7. `tool_result_recorded`
8. `run_failed` 或 `run_completed`
3. `skill_activation_snapshotted`
4. `tool_selection_snapshotted`
5. `system_prompt_snapshotted`
6. `user_message_added`
7. `assistant_message_added`
8. `tool_result_recorded`
9. `run_failed` 或 `run_completed`
并且每次 run 都要带独立 `run_id`,这样同一个 session 内的多次运行才能被切开。
@ -1016,6 +1081,31 @@ provider 层不要再做成“一个厂商一个世界”,而是要拆成 4
7. `stop()` / `shutdown()` 应支持 graceful timeout必要时允许 force cancel
8. `close()`:只有在实例已停止后才能释放 runtime 资源
这一阶段也明确了模型配置的归属:
1. 大模型 provider / api_key / api_base 属于 backend runtime config
2. Web / Gateway / Channel 不单独保存模型密钥
3. 前端请求不传 API Key只传 `message/session_id/user_id` 等业务输入
4. Docker 单实例部署时,每个用户 sandbox 读取自己的实例配置
5. 默认使用新 Beaver 实例目录:
- `/root/.beaver/config.json`
- `/root/.beaver/workspace`
6. 新 Beaver 命名优先使用:
- `BEAVER_CONFIG_PATH`
- `BEAVER_HOME/config.json`
7. 兼容迁移期旧命名:
- `NANOBOT_CONFIG_PATH`
- `NANOBOT_HOME/config.json`
app-instance 镜像也已经切到新 Beaver 后端:
1. Dockerfile 只安装 `backend/beaver`
2. 不再复制旧 `backend/nanobot`、`backend/bridge`、vendored `swarms`
3. entrypoint 通过 `python -m uvicorn beaver.interfaces.web.app:create_app --factory` 启动 Web
4. 容器内默认配置与 workspace 使用:
- `/root/.beaver/config.json`
- `/root/.beaver/workspace`
### 6.2.1 Web / Gateway 现在如何接这套 lifecycle
这一层现在已经开始落成真正的宿主层,而不是只停留在文档占位:
@ -1045,13 +1135,25 @@ provider 层不要再做成“一个厂商一个世界”,而是要拆成 4
- `run_gateway()` 启动时:
- 如果 gateway 自己创建 service则 `await service.start()`
- 持有最小 `MessageBus`
- 常驻消费 `bus.inbound`
- 调 `await service.submit_direct(...)`
- 将结果写回 `bus.outbound`
- 可选接收 `ChannelManager` / channel adapters
- `ChannelManager` 和 `channels` 参数二选一:
- 传 `ChannelManager`:外部提前配置好 channel
- 传 `channels`gateway 内部创建 `ChannelManager` 并注册这些 channel
- inbound 流向:
- channel adapter 发布 `InboundMessage`
- `MessageBus.inbound`
- gateway bridge 常驻消费
- 调 `await service.handle_inbound_message(...)`
- outbound 流向:
- `AgentService` 内部完成 `InboundMessage -> OutboundMessage` 映射
- gateway bridge 将结果写回 `MessageBus.outbound`
- 如果启用了 `ChannelManager`,则分发给对应 channel adapter
- 未启用 `ChannelManager` 时,保留直接消费 `bus.outbound` 的最小测试能力
- 同时等待 `stop_event`
- 停机时:
- 先尝试 `await service.shutdown(timeout_seconds=5.0, force=True)`
- 再等待 bridge 协程收尾;必要时取消 bridge
- 再等待 outbound dispatch 协程收尾;必要时取消 dispatch
- 如果 gateway 自己接管 lifecycle 且 `start()` 失败:
- 立即 `close()` 做 startup cleanup
- 未处理完的 inbound
@ -1068,6 +1170,16 @@ provider 层不要再做成“一个厂商一个世界”,而是要拆成 4
- `outbound`
- 还没有 broker / topic routing / retry / persistence
4. `beaver/interfaces/channels/*`
- 已经补了最小 channel adapter 层:
- `ChannelAdapter`
- `ChannelManager`
- `MemoryChannelAdapter`
- 当前 channel 职责很窄:
- 把外部输入发布成 `InboundMessage`
- 接收并投递 `OutboundMessage`
- `MemoryChannelAdapter` 只用于本地测试和内嵌接入,不是正式消息 broker
所以现在已经明确:
1. Web / Gateway 属于宿主层
@ -1082,16 +1194,18 @@ provider 层不要再做成“一个厂商一个世界”,而是要拆成 4
- 外部注入的 `AgentService`:默认不自动 start/shutdown除非显式要求接管
5. gateway 已经从“只会常驻等待”推进到“最小消息桥接层”
- external inbound message
- channel adapter
- `MessageBus.inbound`
- `service.submit_direct(...)`
- `service.handle_inbound_message(...)`
- `MessageBus.outbound`
- channel adapter outbound delivery
但这一阶段还没做:
1. channels adapter
2. realtime streaming
3. platform-level supervisor
4. 更复杂的 bus 语义retry / routing / persistence
1. realtime streaming
2. platform-level supervisor
3. 更复杂的 bus 语义retry / routing / persistence
4. 外部真实 channel adapter
### 6.3 第三步:回填 bus 模式
@ -1107,9 +1221,16 @@ provider 层不要再做成“一个厂商一个世界”,而是要拆成 4
需要补的函数:
1. 从 inbound 读取消息
2. 调用 `_process_message`
2. 通过 `AgentService.handle_inbound_message(...)` 映射到 runtime 调用
3. 发布 outbound
当前这一步的最小收口方式已经确定为:
1. `MessageBus` 只负责协议和队列
2. `gateway` 只负责宿主、常驻消费和 channel 分发
3. `InboundMessage -> AgentRunResult -> OutboundMessage` 的映射收口在 `AgentService`
4. `AgentLoop` 继续只关心 agent 执行内核,不直接感知 bus 协议
注意:
只有在 `process_direct()` 稳定,并且 6.1 / 6.2 已经把 Session-first + lifecycle 骨架立住后,才做 `run()` 的长循环版本。