diff --git a/a2s-v1.3.md b/a2s-v1.3.md deleted file mode 100644 index 585433c..0000000 --- a/a2s-v1.3.md +++ /dev/null @@ -1,35 +0,0 @@ - -# 需求背景 - -为了满足用户的skill调试需求,让用户在**个人空间**下为agent添加**调试版本**的skill。调试版本的skill有两种结局,永远不提交发布或者提交发布流程并最终审核通过。 - -## 源码入口 - -| 功能 | 文件 | 方法名 | -| --- | --- | --- | -| 查看个人空间的skill分页列表 | mis-visual/mis-tool-server/src/main/java/com/lcfc/mcp/service/impl/SkillServiceImpl.java | getPersonalSpaceByPage | -| 保存并发布skill | mis-visual/mis-tool-server/src/main/java/com/lcfc/mcp/service/impl/ToolApplyServiceImpl.java | addSkillApply | - -## 新增Skill的变更 - -### 修改前 - -```mermaid -graph LR - A[用户提交] --> B[发布] - B --> C[待审核] - D --> D[审核通过(正式版本)] - D --> E[结束] -``` - -### 修改后 - -```mermaid -graph LR - A[用户提交] --> B[保存(调试版本)] - A --> C[发布] - C --> D[待审核] - D --> E[审核通过(正式版本)] - B --> F[结束] - E --> F -``` \ No newline at end of file diff --git a/agentscope-sandbox.md b/agentscope-sandbox.md deleted file mode 100644 index 6c5ac61..0000000 --- a/agentscope-sandbox.md +++ /dev/null @@ -1,93 +0,0 @@ -# Intro - -分析 agentscope、agentscope-java 对于容器沙箱的支持。 - -## 支持的沙箱类型 - -| 沙箱类型 | agentscope | agentscope-java | -| --- | --- | --- | -| Docker | ✅ `DockerWorkspace` | ✅ `DockerFilesystemSpec` | -| Kubernetes | ✅ `K8sWorkspace`| ✅ `KubernetesFilesystemSpec` | -| E2B | ✅ `E2BWorkspace` | ✅ `E2bFilesystemSpec` | -| Daytona | ✅ `DaytonaWorkspace` | ✅ `DaytonaFilesystemSpec` | -| AgentRun | ❌ | ✅ `AgentRunFilesystemSpec` | -| OpenSandbox | ✅ `OpenSandboxWorkspace` | ❌ | -| Bubblewrap | ✅(依赖操作系统) | ❌ | - -## 架构对比 - -### agentscope - -Workspace + Backend + Gateway - -``` -WorkspaceManager (服务侧缓存 / TTL / IsolationPolicy) - │ - ▼ -SandboxedWorkspaceBase.initialize() - ├─ _provision_backend() ← Docker/E2B/K8s/Daytona/OpenSandbox 各实现 - ├─ _ensure_workspace_layout() (/workspace、skills、sessions、data、.mcp) - └─ _setup_mcp_gateway() ← 容器内 FastAPI MCP Gateway - │ - ▼ -BackendBase (exec_shell / read_file / write_file) - └─ 内置工具 Bash/Read/Write/Edit/Grep/Glob 透明落到沙箱内 -``` - -关键设计:通过 MCP 网关收敛文件系统相关 tool 的访问,采用空闲 TTL 驱逐的方案释放沙箱资源。 - -### agentscope-java - -Filesystem Spec + SandboxManager - -``` -HarnessAgent.Builder.filesystem(DockerFilesystemSpec / …) - │ - ▼ -SandboxFilesystemSpec.toSandboxContext(hostWorkspaceRoot) - └─ SandboxContext(client, options, snapshotSpec, workspaceSpec, isolationScope) - │ - ▼ -SandboxLifecycleHook - PreCall → SandboxManager.acquire → Sandbox.start() - PostCall → Sandbox.stop() (tar 快照) → persist state → release - │ - ▼ -SandboxBackedFilesystem + ShellExecuteTool - └─ 文件工具 / execute -``` - -关键设计:在ReAct生命周期内,通过 hook 机制(2.0版本叫中间件)start、stop 沙箱。 - -## Docker沙箱双端对照表 - -| 对比项 | agentscope | agentscope-java | -| --- | --- | --- | -| API 形态 | Docker Engine API | CLI | -| 保活命令 | `sleep infinity` | `while :; do sleep 3600; done` | -| 镜像策略 | all-in-one镜像,自动构建并内容哈希缓存 | 用户指定 | -| 默认网络 | Docker 默认| 用户指定 | -| 持久化 | Bind-mount(可选) | Tar 快照为主 + 可选 bind-mount | -| 生命周期 | Workspace 长生命周期 | 按 Agent `call` 借还 | -| MCP | 容器内 Gateway | Harness 侧注册;沙箱只做 FS/Shell | -| 资源限制 | 较弱(构造参数少) | memory / cpu / ports / network | -| 水平扩展 | 不适合 | 需外置快照/状态存储 | - -### 优点 - -- agentscope: - - 通过 HTTP API 与 Docker 引擎交互,除了与本机 Docker 引擎交互之外,还可以访问远程服务器上的 Docker 引擎。 - - 自动构建镜像,且可以随着依赖库的增删不断迭代 Dockerfile。 -- agentscope-java: - - 每次 call 的时候都会在 start/stop/snapshot 生成 tar 包快照。 - - 隔离级别更贴近多租户场景(SESSION/USER/AGENT/GLOBAL)覆盖多租户常见模型。 - -### 弊端 - -- agentscope: - - 文件沙箱的生命周期过长,强依赖 TTL 清扫。 - - 工作区没有快照或副本能力,可以自行开发。 -- agentscope-java: - - 随着工作区目录越来越大,会导致快照越来越慢(tar命令)可以自定义这个逻辑规避。 - - 没有 agentscope 那样不断迭代镜像的能力,需要人工干预(私以为自动迭代沙箱镜像是个伪需求) - - 若隔离级别会 session 级别,每个 session 都会被拉起一个容器(要控制一台服务器的会话总数量) \ No newline at end of file diff --git a/api.md b/api.md deleted file mode 100644 index d800886..0000000 --- a/api.md +++ /dev/null @@ -1 +0,0 @@ -123 \ No newline at end of file diff --git a/claw-v260921.md b/claw-v260921.md new file mode 100644 index 0000000..28a41f4 --- /dev/null +++ b/claw-v260921.md @@ -0,0 +1,36 @@ +# 服务 + +| 服务名称 | 分支 | 描述 | +| --- | --- | --- | +| mis-paw | dev_lab | 用户添加Agent到个人中心(添加次数+1)| +| mis-tool-server | dev_lab | MCP、Skill、Agent 数据统计 | + +## SQL脚本 + +```sql +-- 初始化智能体被添加次数 +INSERT INTO `mis-mcp-paw-claw`.`resource_operate_count`(`tag`, `resource_id`, `like_count`, `comment_count`, `personal_space_add_count`, `create_time`, `update_time`, `create_at`, `update_at`, `delete_flag`) +VALUES +SELECT 'agent', `parent_agent_id`, 0, 0, count(`agent_id`), now(), now(), 'admin', 'admin', '0' +FROM `mis-paw-claw`.`agent` +WHERE `del_flag` = '0' AND `version_lane` = 'PUBLISHED' +GROUP BY `parent_agent_id`; + +-- 初始化MCP被添加次数 +INSERT INTO `mis-mcp-paw-claw`.`resource_operate_count`(`tag`, `resource_id`, `like_count`, `comment_count`, `personal_space_add_count`, `create_time`, `update_time`, `create_at`, `update_at`, `delete_flag`) +VALUES +SELECT 'mcp_server', `mcp_server_uuid`, 0, 0, count(`mcp_square_pull_record_id`), now(), now(), 'admin', 'admin', '0' +FROM `mis-mcp-paw-claw`.`mcp_square_pull_record` +WHERE `use_state` = 3 +GROUP BY `mcp_server_uuid`; + +-- 初始化Skill被添加次数 +INSERT INTO `mis-mcp-paw-claw`.`resource_operate_count`(`tag`, `resource_id`, `like_count`, `comment_count`, `personal_space_add_count`, `create_time`, `update_time`, `create_at`, `update_at`, `delete_flag`) +VALUES +SELECT 'skill', skill.`skill_id`, 0, 0, count(pr.`skill_square_pull_record_id`), now(), now(), 'admin', 'admin', '0' +FROM `mis-mcp-paw-claw`.`skill_square_pull_record` AS pr +LEFT JOIN `mis-mcp-paw-claw`.`skill_release` AS sr ON pr.`skill_release_id` = sr.`skill_release_id` +LEFT JOIN `mis-mcp-paw-claw`.`skill` AS skill ON sr.`skill_id` = skill.`skill_id` +WHERE pr.`use_state` = 3 +GROUP BY skill.`skill_id`; +``` \ No newline at end of file diff --git a/err.txt b/err.txt deleted file mode 100644 index da61ade..0000000 --- a/err.txt +++ /dev/null @@ -1,106 +0,0 @@ -处理ossId为 1786088786754637257 的文件失败: {"statusCode":401,"message":"Invalid API-key provided.","code":"InvalidApiKey","isJson":true,"requestId":"eeeeb262-073e-90c1-9eeb-5ae21d5642bb"} -com.alibaba.dashscope.exception.ApiException: {"statusCode":401,"message":"Invalid API-key provided.","code":"InvalidApiKey","isJson":true,"requestId":"eeeeb262-073e-90c1-9eeb-5ae21d5642bb"} - at com.alibaba.dashscope.utils.OSSUtils.get_upload_certificate(OSSUtils.java:111) - at com.alibaba.dashscope.utils.OSSUtils.upload(OSSUtils.java:39) - at com.alibaba.dashscope.utils.PreprocessMessageInput.checkAndUploadMultiModalMessage(PreprocessMessageInput.java:64) - at com.alibaba.dashscope.utils.PreprocessMessageInput.preProcessMultiModalMessageInputs(PreprocessMessageInput.java:87) - at com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation.preprocessInput(MultiModalConversation.java:193) - at com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation.call(MultiModalConversation.java:83) - at com.lcfc.agent.agents.controller.ChatController.getAudioTranscriptionStr(ChatController.java:284) - at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) - at java.base/java.lang.reflect.Method.invoke(Method.java:580) - at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:355) - at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) - at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768) - at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) - at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768) - at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) - at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768) - at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:58) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:173) - at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768) - at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) - at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) - at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:768) - at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:720) - at com.lcfc.agent.agents.controller.ChatController$$SpringCGLIB$$0.getAudioTranscriptionStr() - at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) - at java.base/java.lang.reflect.Method.invoke(Method.java:580) - at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:255) - at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:188) - at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:926) - at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:831) - at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) - at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) - at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) - at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) - at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) - at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:547) - at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) - at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614) - at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129) - at cn.dev33.satoken.filter.SaServletFilter.doFilter(SaServletFilter.java:150) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at cn.dev33.satoken.filter.SaServletFilter.doFilter(SaServletFilter.java:150) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at cn.dev33.satoken.filter.SaFirewallCheckFilterForJakartaServlet.doFilter(SaFirewallCheckFilterForJakartaServlet.java:68) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at org.springframework.web.filter.ServerHttpObservationFilter.doFilterInternal(ServerHttpObservationFilter.java:113) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) - at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at com.lcfc.common.encrypt.filter.CryptoFilter.doFilter(CryptoFilter.java:72) - at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67) - at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131) - at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84) - at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62) - at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68) - at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) - at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68) - at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117) - at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57) - at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) - at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46) - at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64) - at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60) - at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77) - at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43) - at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) - at io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52) - at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43) - at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:276) - at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135) - at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:132) - at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48) - at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43) - at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:256) - at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:101) - at io.undertow.server.Connectors.executeRootHandler(Connectors.java:393) - at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:859) - at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18) - at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513) - at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538) - at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282) - at java.base/java.lang.Thread.run(Thread.java:1583) -Caused by: com.alibaba.dashscope.exception.ApiException: {"statusCode":401,"message":"Invalid API-key provided.","code":"InvalidApiKey","isJson":true,"requestId":"eeeeb262-073e-90c1-9eeb-5ae21d5642bb"} - ... 102 common frames omitted \ No newline at end of file diff --git a/log_chat_agent.md b/log_chat_agent.md deleted file mode 100644 index 80a22f2..0000000 --- a/log_chat_agent.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -name: 智能体会话日志相关操作 -desc - -会话ID=2085195979274911745去查 \ No newline at end of file diff --git a/mis-qwpaw.md b/mis-qwpaw.md deleted file mode 100644 index bab0cbd..0000000 --- a/mis-qwpaw.md +++ /dev/null @@ -1,204 +0,0 @@ -# 内置的安全能力总览 - -| 安全能力 | v1.x | v2.x | 说明 | -| --- | --- | --- | --- | -| 工具守卫 (Tool Guard) | ✅ | ✅ | 运行时工具调用检测 | -| 文件防护 (File Guard) | ✅ | ✅ | 敏感文件/目录访问拒绝列表 | -| 技能扫描器 (Skill Scanner) | ✅ | ✅ | 技能启用前安全预检 | -| Web 登录认证 | ✅ | ✅ | 控制台可选身份验证 | -| 沙箱隔离 (Sandbox) | ❌ | ✅ | **新增**:OS 内核级 Shell 执行隔离 | -| 访问策略 (Access Policy) | ❌ | ✅ | **新增**:声明式 allow/deny/ask 策略引擎 | - -## 已经做的安全加固 - -- 操作系统层面,已启用 SE Linux 的 Enforcing 模式。其 MAC(Mandatory Access Control)防御机制,可以遏制传统 DAC 机制下被恶意攻击,提权到 root 劫持系统控制权。在 MAC 机制下,权限受限于访问策略,而非文件所有者或用户。即便是 root 权限启动的进程,也必须遵守规则,无法绕过。 -- QwenPaw Linux 的实例运行在 Docker 容器中而非直接运行在宿主机,通过目录挂载的方式,将运行时生成的文件、数据持久化至宿主机上。宿主机磁盘目录不删除的前提下,容器实例宕机、重启数据不会丢失。 - -## 还能做的安全防护 - -- 定期备份数据目录: - - 方案一、每天定时全量备份数据目录,生成压缩包上传至OSS。 - - 方案二、将数据目录挂载到NAS [点此查看方案明细](https://git.jkwlstv.cn/doc/container/src/branch/main/nas-to-nfs-linux-docker.md) -- 除此之外,还能把 Docker 也启用 SE Linux 更精细的控制文件访问权限。 -- [点击跳转查看 agentscope、agentscope-java 对于容器沙箱的支持](./agentscope-sandbox.md) - -## 工具守卫 (Tool Guard) - -| Item | 详细说明 | -| --- | --- | -| 核心作用 | Agent 调用工具**之前**扫描参数,检测危险命令、路径遍历、数据外泄等,阻止恶意操作 | -| 主要检测对象 | 重点针对 `execute_shell_command`;结合 YAML 正则规则 + `ShellEvasionGuardian`(引号感知的 Shell 规避分析) | -| 检测示例 | `rm -rf /`、SQL 注入片段、命令替换 `$()`/`` ` ``、路径遍历 `../`、`sudo`/`su`、反向 Shell、Fork 炸弹、标志位混淆、Unicode 空白绕过等 | -| 严重级别 | CRITICAL / HIGH / MEDIUM / LOW / INFO;CRITICAL/HIGH 在交互环境进入待审批,无会话时记日志(可用 `denied_tools` 强制禁止) | -| 守护范围 (`guarded_tools`) | `null`=守护全部内置工具;`[]`=不守护;指定列表=仅守护列出工具 | -| 禁止工具 (`denied_tools`) | 无条件阻止,不提供审批 | -| 自定义规则 | 支持正则、威胁类别、严重级别、排除模式;类别含 command_injection、data_exfiltration、path_traversal 等 10 类 | -| Shell 规避检查 | 7 项独立开关(默认全关):命令替换、混淆标志、反斜杠空白/操作符、换行、注释引号不同步、引号内换行 | -| 执行级别 (`approval_level`) | STRICT(全审批)/ SMART(高风险审批)/ AUTO(仅规则命中审批,默认)/ OFF(关闭) | -| 控制台 | 设置 → 安全 → 工具防护:启停、守护范围、禁止工具、内置/自定义规则管理;改完立即生效 | -| 环境变量 | `QWENPAW_TOOL_GUARD_ENABLED`(优先于配置文件) | - -### 内置 YAML 规则 - -| 类别 | 规则 ID | 严重级别 | 检测目标 | -| --- | --- | --- | --- | -| 命令注入与文件操作 | `TOOL_CMD_DANGEROUS_RM` | HIGH | `rm` 危险删除 | -| 命令注入与文件操作 | `TOOL_CMD_DANGEROUS_MV` | HIGH | `mv` 移动/覆盖 | -| 命令注入与文件操作 | `TOOL_CMD_UNSAFE_PERMISSIONS` | HIGH | `chmod -R 777`、`chattr` | -| 低级别磁盘操作 | `TOOL_CMD_FS_DESTRUCTION` | CRITICAL | `mkfs`、`dd of=/dev/` 等 | -| 资源滥用 | `TOOL_CMD_DOS_FORK_BOMB` | CRITICAL | Fork 炸弹、`kill -9 -1` | -| 资源滥用 | `TOOL_CMD_SYSTEM_REBOOT` | CRITICAL | `reboot`/`shutdown`/`halt`/`init 0/6` | -| 资源滥用 | `TOOL_CMD_SERVICE_RESTART` | HIGH | `systemctl`/`service` 重启停止 | -| 资源滥用 | `TOOL_CMD_PROCESS_KILL` | HIGH | `pkill`/`killall`/`kill` | -| 代码执行 | `TOOL_CMD_PIPE_TO_SHELL` | CRITICAL | `curl/wget \| bash` | -| 代码执行 | `TOOL_CMD_OBFUSCATED_EXEC` | HIGH | `base64 -d \| bash` | -| 代码执行 | `TOOL_CMD_IFS_INJECTION` | HIGH | `$IFS` 绕过 | -| 代码执行 | `TOOL_CMD_CONTROL_CHARS` | CRITICAL | 不可见控制字符 | -| 代码执行 | `TOOL_CMD_UNICODE_WHITESPACE` | HIGH | Unicode 空白绕过 | -| 代码执行 | `TOOL_CMD_PROC_ENVIRON` | HIGH | `/proc/*/environ` 读环境 | -| 代码执行 | `TOOL_CMD_JQ_SYSTEM` | HIGH | `jq` 中 `system(` | -| 代码执行 | `TOOL_CMD_JQ_FILE_FLAGS` | HIGH | `jq` 任意读文件/加载代码 | -| 代码执行 | `TOOL_CMD_ZSH_DANGEROUS` | HIGH | zsh 危险内建 | -| 权限提升 | `TOOL_CMD_PRIVILEGE_ESCALATION` | CRITICAL | `sudo`/`su`/`doas`/`pkexec` | -| 权限提升 | `TOOL_CMD_SYSTEM_TAMPERING` | HIGH | crontab、authorized_keys、sudoers | -| 网络滥用 | `TOOL_CMD_REVERSE_SHELL` | CRITICAL | `/dev/tcp`、`nc -e`、`socat EXEC:` | - -### Shell 规避 - -严重级别均为 **HIGH** - -| 规则 ID | 说明 | -| --- | --- | -| `SHELL_EVASION_COMMAND_SUBSTITUTION` | 单引号外的反引号/命令/进程替换 | -| `SHELL_EVASION_OBFUSCATED_FLAGS` | ANSI-C/区域化引号、空引号标志技巧 | -| `SHELL_EVASION_BACKSLASH_WHITESPACE` | 引号外反斜杠转义空白 | -| `SHELL_EVASION_BACKSLASH_OPERATOR` | 引号外反斜杠转义 `;\|&<>` | -| `SHELL_EVASION_NEWLINE` | 裸换行/`\r` 拆分命令 | -| `SHELL_EVASION_COMMENT_QUOTE_DESYNC` | `#` 注释与引号状态不同步 | -| `SHELL_EVASION_QUOTED_NEWLINE` | 引号内换行后接伪注释行 | - -## 文件防护 (File Guard) - -| 能力项 | 详细说明 | -| --- | --- | -| 核心作用 | 阻止 Agent 工具访问敏感文件和目录;每次工具调用自动扫描路径参数 | -| 独立性 | 即使 `tool_guard.enabled=false`,只要 `file_guard.enabled=true` 仍会检查 | -| 路径提取策略 | 已知文件工具检查 `file_path`;Shell 从命令串提取(含重定向);其他工具扫描类路径字符串 | -| 路径处理 | 相对路径解析、`~` 展开、规范化为绝对路径;以 `/` 结尾的目录递归保护 | -| 默认保护 | `{WORKING_DIR}.secret/`(默认 `~/.qwenpaw.secret/`,存 API 密钥与凭据) | -| 阻止级别 | 匹配时以 HIGH 级别发现阻止 | -| 配置字段 | `enabled`(默认 true)、`sensitive_files`(绝对/相对/`~/`/目录路径) | -| 控制台 | 设置 → 安全 → 文件防护:启停、增删保护路径、保存/重置;立即生效 | - -## 技能扫描器 (Skill Scanner) - -| 能力项 | 详细说明 | -| --- | --- | -| 核心作用 | 技能启用/安装前扫描恶意代码、硬编码密钥、社会工程等威胁 | -| 触发时机 | 创建新技能、启用已禁用技能、从 Skill Hub 导入 | -| 扫描机制 | YAML 正则签名 + PatternAnalyzer;支持自定义 ScanPolicy | -| 智能缓存 | 基于文件 mtime,未变更不重复扫描 | -| 超时保护 | 默认 30 秒(可配 5–300 秒) | -| 文件安全 | 跳过符号链接、校验路径边界、默认跳过二进制/归档 | -| 扫描模式 | **Block** 拦截不可用;**Warn** 警告但可用(默认);**Off** 关闭 | -| 配置优先级 | 环境变量 `QWENPAW_SKILL_SCAN_MODE` > 控制台 > `config.json` | -| 扫描告警 | 查看详情(文件/行号/模式)、加白名单、删单条/清全部 | -| 白名单 | SHA-256 内容哈希版本锁定;文件变更后白名单失效需重扫 | -| 内置威胁类别 | command_injection、data_exfiltration、hardcoded_secrets、prompt_injection、social_engineering、supply_chain_attack、obfuscation、resource_abuse、unauthorized_tool_use | -| 自定义规则 | YAML 签名(id/category/severity/patterns/exclude_patterns/file_types 等) | -| 控制台 | 设置 → 安全 → 技能扫描器;模式与超时改完立即生效 | - -### Web 登录认证 - -| 能力项 | 详细说明 | -| --- | --- | -| 核心作用 | 可选保护控制台,防未授权访问;**默认关闭**,需 `QWENPAW_AUTH_ENABLED=true` | -| 账户模式 | 单用户管理员;首次网页注册,或环境变量自动注册(适合 Docker/K8s) | -| 令牌 | HMAC-SHA256 签名,有效期 7 天,存 localStorage | -| 密码存储 | 加盐 SHA-256,不存明文;`auth.json` 权限 `0o600` | -| 本地免认证 | `127.0.0.1` / `::1` 跳过认证;CLI 无需令牌 | -| 豁免主机 | `security.allow_no_auth_hosts`(默认 localhost) | -| 环境变量 | `QWENPAW_AUTH_ENABLED`(必填启用);`QWENPAW_AUTH_USERNAME` / `QWENPAW_AUTH_PASSWORD`(可选自动注册) | -| 运维能力 | `qwenpaw auth reset-password`(轮换签名密钥使所有会话失效);侧边栏退出登录 | -| 路由保护 | 仅 `/api/*` 需认证;登录/注册/status/version 与静态资源公开;WebSocket 令牌经查询参数 | - -## 沙箱隔离 (Sandbox) - -**沙箱隔离来自操作系统支持** - -| 能力项 | 详细说明 | -| --- | --- | -| 核心作用 | 为 Shell 命令提供 **OS 内核级**执行隔离;命令只能访问已声明的文件系统视图 | -| 在链路中的位置 | 工具守卫(静态检测)→ 治理引擎(ALLOW/DENY/ASK/SANDBOX_FALLBACK)→ **沙箱隔离(运行时强制)** → 违规检测 | -| 与既有层关系 | 即使通过工具守卫与文件防护,沙箱仍从内核层限制白名单外访问 | -| 隔离模型 | 默认拒绝 + 白名单:`mounts` 控制可写;`deny_paths` 额外阻止;最小化 `/dev`;Bubblewrap 支持 PID 隔离 | -| 配置来源 | 由治理策略引擎自动编译,用户通常无需手写;含 mode、workspace_dir、mounts、deny_paths、allow_read_all、timeout 等 | -| 违规处理 | 解析 stderr 模式填充 `sandbox_violation`;记治理日志;可按策略提示审批扩展权限 | - -### 不同平台的沙箱隔离机制 - -| 平台 | 后端 | 机制 | 选用条件 | -| --- | --- | --- | --- | -| macOS | Seatbelt | `sandbox-exec` + S-expression 策略 | PATH 有 `sandbox-exec` | -| Linux | Bubblewrap(首选) | Mount/User/PID namespace | `bwrap` + user namespace | -| Linux | Landlock(回退) | Landlock LSM(内核 5.13+) | 无 bwrap 时回退 | -| Windows | AppContainer | AppContainer + `icacls` ACL | `allow_read_all=False`,Win10+ | -| Windows | Restricted_token | 受限令牌 + WFP 防火墙 | `allow_read_all=True`(默认),需管理员 | -| 所有 | None | 无隔离直接执行 | 无可用后端时 | - -### 不同隔离机制的能力对比 - -| 能力 | Seatbelt | Bubblewrap | Landlock | AppContainer | Restricted_token | -| --- | --- | --- | --- | --- | --- | -| 文件系统(读) | ✅ | ✅ | ✅ | ✅ | ✅ | -| 文件系统(写) | ✅ | ✅ | ✅ | ✅ | ✅(受限令牌) | -| deny_paths 不可见 | ❌(拒绝访问) | ✅(未挂载) | ❌(拒绝访问) | ❌ | ❌ | -| PID 命名空间隔离 | ❌ | ✅ | ❌ | ❌ | ❌ | -| 最小化 /dev | ✅ | ✅ | ❌ | ❌ | ❌ | -| 网络控制 | ✅(允许/拒绝) | 计划中 | ❌ | ✅ | ✅(WFP) | - -最小化 /dev 指的是沙箱里不挂载完整的 /dev 只挂载: - -```text -/dev/null -/dev/zero -/dev/urandom -/dev/tty -``` - -这样命令仍能做重定向、读随机数、写终端等常规操作,但碰不到磁盘分区、真实网卡设备等更危险的节点。 - -### 沙箱目前的限制 - -| 限制项 | 说明 | -| --- | --- | -| 网络隔离 | 当前未真正强制;`network_allow` 暂不影响;bubblewrap 网络命名空间已规划 | -| 资源限制 | `max_processes` / `max_memory_mb` 字段存在但后端未强制 | -| Windows 要求 | 需 Windows 10 build 10240+;AppContainer/Restricted_token 常需管理员权限 | -| AppContainer 删文件 | `allow_read_all=False` 时沙箱内可能无法删除工作区文件 | - -## 访问策略 (Access Policy) - -| 能力项 | 详细说明 | -| --- | --- | -| 核心作用 | 声明式策略引擎:对每次能力调用裁定 **allow / deny / ask** | -| 适用范围 | 每个服务客户端独立策略;当前已在 **MCP** 落地,设计可扩展到其他协议 | -| 三种效果 | `allow` 立即执行;`deny` 阻止并返回错误;`ask` 挂起等待控制台人工审批 | -| 两级粒度 | **客户端级**默认效果;**工具级**可为特定工具覆盖(如禁 `dangerous_tool`) | -| 来源感知 | 按 `principal` 匹配来源渠道(console、dingtalk 等)与身份(user 等) | -| Subject 模式 | `user:xxx`、`session:xxx`、`channel:xxx`、`*` | -| 默认效果 | `default_effect`:无规则匹配时生效,默认 `deny` | -| 优先级裁决 | 目标名精确 > 目标类型 > Principal 具体度 > Subject 精确度 > 严格程度(deny > ask > allow) | -| 审批流程 | ask 时挂起并出审批卡片(工具/参数/身份/来源/客户端);超时未响应则拒绝 | -| 配置位置 | MCP 客户端 YAML 的 `policy` 段;控制台 **智能体 → MCP → 工具&权限** | -| 控制台能力 | 设默认效果、客户端级规则、工具级默认与覆盖规则;保存立即生效 | -| 注意 | YAML 中高级 subject(如 `user:admin`)会保留但控制台不可编辑,显示为「未管理规则」 | - -### 策略裁决示例 - -| 请求场景 | 结果 | 原因 | -| --- | --- | --- | -| `user:admin` 调用任意工具 | ALLOW | 精确 subject 匹配 | -| 任何人调用 `dangerous_tool` | DENY | 精确目标名称优先 | -| 控制台用户调用 `safe_tool` | ALLOW | 目标 + principal 双重匹配 | -| 钉钉用户调用 `other_tool`(无规则) | ASK | 回落到 `default_effect` | \ No newline at end of file diff --git a/msg.md b/msg.md index 7596d96..d800886 100644 --- a/msg.md +++ b/msg.md @@ -1,354 +1 @@ -# AgentScope vs AgentScope-Java:Workspace 文件系统与沙箱集成分析 - -> 对比版本:`agentscope` **v2.0.5** · `agentscope-java` **v2.0.0** -> 重点:Docker 沙箱;兼顾 Kubernetes / E2B / Daytona / OpenSandbox / AgentRun - ---- - -## 1. 结论摘要 - -两套框架都把「Agent 读写文件 / 执行命令」从本机磁盘解耦到可替换的隔离后端,但抽象重心不同: - -| 维度 | agentscope (Python) | agentscope-java | -| --- | --- | --- | -| 核心抽象 | **Workspace**(长期运行的工作区 + 进程内 MCP Gateway) | **Filesystem Spec**(声明式配置)→ 每次 `call` 借出/归还沙箱 | -| 生命周期粒度 | Workspace 级:`initialize` → 长期复用 → `close` | Call 级:`PreCall acquire/start` → `PostCall stop(快照)/release` | -| Docker 接入方式 | **aiodocker**(Docker Engine HTTP API) | **`docker` CLI**(`ProcessBuilder`,无 docker-java 依赖) | -| 持久化主路径 | Bind mount / 云沙箱 pause / K8s PVC | **Workspace tar 快照**(Local/Redis/OSS/…)+ 可选 bind mount | -| 分布式能力 | 依赖云沙箱 metadata 重连或 K8s 集群资源 | 依赖 `SandboxStateStore` + 分布式快照后端 | -| 独有后端 | OpenSandbox、Bubblewrap | AgentRun(阿里云) | - -**选型直觉:** 需要「常驻工作区 + MCP 网关 + Python Agent 服务」→ agentscope;需要「HarnessAgent 按次隔离、快照跨副本恢复、Java 生态」→ agentscope-java。 - ---- - -## 2. 总体架构对比 - -### 2.1 agentscope:Workspace + Backend + Gateway - -``` -WorkspaceManager (服务侧缓存 / TTL / IsolationPolicy) - │ - ▼ -SandboxedWorkspaceBase.initialize() - ├─ _provision_backend() ← Docker/E2B/K8s/Daytona/OpenSandbox 各实现 - ├─ _ensure_workspace_layout() (/workspace、skills、sessions、data、.mcp) - └─ _setup_mcp_gateway() ← 容器内 FastAPI MCP Gateway - │ - ▼ -BackendBase (exec_shell / read_file / write_file) - └─ 内置工具 Bash/Read/Write/Edit/Grep/Glob 透明落到沙箱内 -``` - -关键设计点: - -1. **模板方法**:子类只实现 `_provision_backend` / `_teardown_backend` / `_bootstrap_commands`。 -2. **容器内 MCP Gateway**:宿主机通过 `GatewayClient` + `backend.exec_shell` 驱动网关(一般不依赖宿主机到沙箱的端口映射)。 -3. **WorkspaceManager**:`PER_AGENT` / `PER_SESSION` / `PER_USER`,空闲 TTL 驱逐;云后端可按 metadata/label 跨节点重连。 - -### 2.2 agentscope-java:Filesystem Spec + SandboxManager - -``` -HarnessAgent.Builder.filesystem(DockerFilesystemSpec / …) - │ - ▼ -SandboxFilesystemSpec.toSandboxContext(hostWorkspaceRoot) - └─ SandboxContext(client, options, snapshotSpec, workspaceSpec, isolationScope) - │ - ▼ -SandboxLifecycleHook - PreCall → SandboxManager.acquire → Sandbox.start() (四分支恢复) - PostCall → Sandbox.stop() (tar 快照) → persist state → release - │ - ▼ -SandboxBackedFilesystem + ShellExecuteTool - └─ 文件工具 / execute 全部转发到沙箱 -``` - -关键设计点: - -1. **声明式 Spec**:`DockerFilesystemSpec` 等只描述「如何创建」,不是运行时文件系统本身。 -2. **Call 边界生命周期**:每次推理前后自动 acquire/start/stop,适合多租户按次计费与快照恢复。 -3. **快照与执行后端正交**:换 Docker/K8s/E2B 不影响 `LocalSnapshotSpec` / `RedisSnapshotSpec` / `OssSnapshotSpec` 的选择。 -4. **Workspace Projection**:启动时把宿主 `AGENTS.md`、`skills/`、`subagents/`、`knowledge/` 等打 tar 注入沙箱,按内容 SHA-256 增量跳过。 - ---- - -## 3. Docker 集成深挖(重点) - -### 3.1 agentscope · `DockerWorkspace` - -**源码入口:** `src/agentscope/workspace/_docker/_docker_workspace.py` -**配套:** `_docker_backend.py`、`_make_dockerfile.py` - -#### 实现原理 - -1. **镜像构建(内容哈希缓存)** - - `prepare_build_context()` 渲染 Dockerfile,打包 gateway 脚本、`requirements.txt`、glob helper。 - - Tag 形如 `agentscope-workspace:<12hex>`,对 Dockerfile + COPY 文件做 SHA-256;本地已有则跳过 build。 - - 默认基础镜像 `python:3.11-slim`,镜像内预装 gateway venv + agentscope(Docker 路径**不做**首次 bootstrap)。 - - 可选 `node_version` 从官方 Node slim 镜像拷贝 `node`/`npm`(供 npx MCP)。 - -2. **容器启动** - - 通过 **aiodocker** `containers.create_or_replace`。 - - `Cmd: ["sleep", "infinity"]`,工作目录 `/workspace`。 - - Label:`agentscope.workspace=true`、`agentscope.workspace.id=`。 - - **Gateway 端口仅容器内监听,不做 host port 映射**;宿主经 `DockerBackend.exec` 访问。 - -3. **持久化** - - 可选 `host_workdir` bind-mount → `/workspace`(`is_persistent`)。 - - 无 mount 则为 ephemeral 容器文件系统。 - - Linux 上 teardown 时尝试 `chown` 把 bind-mount 文件所有权还给宿主用户。 - -4. **I/O 原语(`DockerBackend`)** - - `exec_shell`:容器 `exec` API,直传 argv(无中间 shell,需要时包 `sh -c`)。 - - `read_file` / `write_file`:`get_archive` / `put_archive`(tar)。 - -5. **服务侧** - - `DockerWorkspaceManager`:`basedir` 下为每个 workspace 建宿主目录并 bind-mount;TTL sweeper 回收空闲容器。 - -#### 使用限制 - -| 限制 | 说明 | -| --- | --- | -| 依赖 Docker daemon | 需本机/远端可达的 Docker Engine + aiodocker | -| 基础镜像须含 `python3` | Gateway 与工具链假设 Python 可用 | -| **单节点** | 官方文档明确:Docker/Local/Bubblewrap 不适配水平扩容;跨节点请用 E2B/Daytona/OpenSandbox/K8s | -| 首次镜像构建成本 | 缓存未命中时 build 较慢;构建失败需解读 docker stream 日志 | -| 无细粒度 CPU/内存 API | 构造参数侧重镜像与环境变量,资源限额不如 Java Spec 直接 | -| Linux bind-mount 权限 | 容器内 root 写文件可能留下错误 uid;框架仅在 teardown 做 chown 尽力修复 | - -#### 好处 - -- 镜像内预置 gateway,**冷启动无需 apt/uv/pip bootstrap**(对比 E2B/K8s/OpenSandbox)。 -- 内容哈希镜像缓存,Dockerfile 不变则秒级复用。 -- Workspace 长期存活,MCP / skills / sessions 与服务模型一致。 -- Bind-mount 可把工作区落在宿主磁盘,便于调试与备份。 -- 与 `WorkspaceManager` 隔离策略(PER_AGENT 等)无缝衔接。 - -#### 弊端 - -- 强依赖本机 Docker,水平扩展与多副本亲和困难。 -- 常驻 `sleep infinity` 容器占用资源,依赖 TTL 清扫。 -- Gateway 健康检查失败时排查需看容器内日志路径。 -- 与 Java 版相比,缺少一等公民的「跨 call tar 快照后端」抽象。 - ---- - -### 3.2 agentscope-java · `DockerFilesystemSpec` / `DockerSandbox` - -**源码入口:** -- Spec:`.../sandbox/impl/docker/DockerFilesystemSpec.java` -- 运行时:`DockerSandbox.java`、`DockerSandboxClient.java` - -#### 实现原理 - -1. **配置层(Spec)** - Fluent API:`image`、`workspaceRoot`(默认 `/workspace`)、`memorySizeBytes`、`cpuCount`、`exposedPorts`、`network`、`environment`、`additionalRunArgs`、`snapshotSpec`、`workspaceSpec`。 - -2. **创建与客户端** - - `DockerSandboxClient.create(...)` 生成 `DockerSandboxState`(sessionId、镜像、资源参数、快照句柄)。 - - **不引入 docker-java**:一律 `docker run` / `exec` / `inspect` / `stop` / `rm` CLI。 - - 要求宿主 `PATH` 上有 `docker`,且 daemon 可达。 - -3. **容器命令** - ```text - docker run -d --name agentscope-sandbox- - [--memory] [--cpus] [-p] [--network=none|...] [-v bind...] - sh -c "while :; do sleep 3600; done" - ``` - - 默认 **`--network=none`**(未配置 network 时),比 Python 版更偏「默认断网隔离」。 - - 支持 `WorkspaceSpec` 中的 `BindMountEntry` → `-v host:container:ro|rw`。 - - `exec`:`docker exec -w sh -c `。 - -4. **工作区 tar 快照** - - Persist:`docker exec tar -cf - -C /workspace .`(并对 bind-mount 路径 `--exclude`)。 - - Hydrate:`docker exec -i tar -xf - -C /workspace`。 - - `AbstractBaseSandbox` **四分支恢复**:容器是否仍保留目录 × 是否有可恢复快照。 - -5. **Call 级编排** - - `start()`:确保容器 running → 四分支初始化 → workspace projection。 - - `stop()`:写快照,**容器可继续跑**。 - - `shutdown()`:自管容器则 `docker stop` + `docker rm --force`。 - -#### 使用限制 - -| 限制 | 说明 | -| --- | --- | -| 依赖 Docker CLI | 无嵌入式 Engine API;Windows/远程 Docker 场景需确保 CLI 行为一致 | -| 默认无网络 | `network` 未设时为 `none`;需要拉包/访问外网必须显式配置 | -| 镜像需自备 | 不像 Python 那样自动构建含 gateway 的专用镜像;由用户指定(如 `ubuntu:24.04`) | -| 输出截断 | stdout/stderr 单流约 512KB 上限 | -| 并发语义 | 同一 IsolationScope 并发 call 可起多个容器,stop 时 **last-write-wins** 覆盖快照 | -| 多副本 | 本地 Docker + 本地快照会成单点;生产需 Redis/OSS 快照 + 分布式 `AgentStateStore` | -| AgentRun/K8s 等扩展 | Docker 在 harness 核心;其它后端在 extension 模块,需单独依赖 | - -#### 好处 - -- **零额外 Java Docker 库依赖**,部署简单。 -- 资源限额(CPU/内存)、端口、网络、额外 run args 一等配置。 -- 快照体系成熟,可跨 call / 跨副本恢复 `node_modules` 等重状态。 -- Workspace projection 把静态资产与运行态分离,宿主改 skills 可增量注入。 -- `IsolationScope`(SESSION/USER/AGENT/GLOBAL)覆盖多租户 SaaS 常见模型。 -- `executionGuard` 可对 AGENT/GLOBAL 做串行化,缓解快照互踩。 - -#### 弊端 - -- 每次 call 的 start/stop/snapshot 有固定开销(尤其大工作区 tar)。 -- CLI 进程模型:高并发时大量 `docker exec` 子进程与线程池开销。 -- 无内置 MCP Gateway;MCP 走 Harness 侧 `tools.json` 注册,与沙箱内进程模型不同。 -- 默认断网 + 裸镜像,冷启动后常需 agent 自己装依赖(靠快照摊销)。 - ---- - -### 3.3 Docker 双端对照表 - -| 对比项 | agentscope v2.0.5 | agentscope-java v2.0.0 | -| --- | --- | --- | -| API 形态 | aiodocker(Engine API) | docker CLI | -| 保活命令 | `sleep infinity` | `while :; do sleep 3600; done` | -| 镜像策略 | 自动构建并内容哈希缓存 | 用户指定现成镜像 | -| 默认网络 | Docker 默认(通常有网) | **`none`** | -| 持久化 | Bind-mount(可选) | Tar 快照为主 + 可选 bind-mount | -| 生命周期 | Workspace 长生命周期 | 按 Agent `call` 借还 | -| MCP | 容器内 Gateway | Harness 侧注册;沙箱只做 FS/Shell | -| 资源限制 | 较弱(构造参数少) | memory / cpu / ports / network | -| 水平扩展 | 不适合 | 需外置快照/状态存储 | - ---- - -## 4. 其它沙箱类型 - -### 4.1 支持矩阵 - -| 沙箱类型 | agentscope v2.0.5 | agentscope-java v2.0.0 | 共同点 | -| --- | --- | --- | --- | -| Docker | ✅ `DockerWorkspace` | ✅ `DockerFilesystemSpec`(harness 内置) | 本地隔离、需 Docker | -| Kubernetes | ✅ `K8sWorkspace`(Pod + PVC) | ✅ `KubernetesFilesystemSpec`(extension) | 集群级资源、适合生产 K8s | -| E2B | ✅ `E2BWorkspace` | ✅ `E2bFilesystemSpec` | 云沙箱 SDK、metadata/API 重连 | -| Daytona | ✅ `DaytonaWorkspace` | ✅ `DaytonaFilesystemSpec` | 云沙箱、标签/API 重挂接 | -| AgentRun | ❌ 暂未支持 | ✅ `AgentRunFilesystemSpec`(阿里云) | — | -| OpenSandbox | ✅ `OpenSandboxWorkspace` | ❌ 暂未支持 | — | -| Bubblewrap | ✅(另有 Local) | ❌(有 LocalFilesystemSpec) | Linux 轻量沙箱 / 本机模式 | - -### 4.2 agentscope 各后端要点 - -| 后端 | 供给方式 | 持久化 | Teardown | Bootstrap | -| --- | --- | --- | --- | --- | -| **Docker** | aiodocker 建容器 | Bind-mount 或 ephemeral | kill + delete 容器 | 镜像已含 gateway | -| **K8s** | Pod + PVC(`as-ws-{id}`) | PVC 跨 Pod 存活 | 删 Pod,默认可保留 PVC | 首次 apt + uv + gateway | -| **E2B** | `AsyncSandbox.create/connect` | pause 保留磁盘 | `pause()` | 首次 bootstrap | -| **Daytona** | SDK create / label 查找 | `stop(force=False)` | stop + close client | 首次 bootstrap(路径由 SDK 推导) | -| **OpenSandbox** | `Sandbox.create` / resume / connect | `pause()` | pause + close | 首次 bootstrap | - -云后端共性:用 `agentscope.workspace.id`(或等价 metadata/label)索引;Manager 缓存 miss 时可跨服务副本重连——这是文档推荐的**分布式部署**路径。 - -### 4.3 agentscope-java 各后端要点 - -| 后端 | 模块位置 | 交互方式 | 持久化侧重 | -| --- | --- | --- | --- | -| **Docker** | harness 核心 | CLI | Tar 快照 + 可选 bind | -| **Kubernetes** | extension | fabric8 / Pod 侧 exec+tar(文档侧亦描述 agent-sandbox WarmPool 演进) | 快照 Spec;集群侧还可结合 PVC/模板 | -| **E2B** | extension | E2B HTTP + envd;支持 TAR / NATIVE_SNAPSHOT 等持久化模式 | 平台快照或 tar | -| **Daytona** | extension | Control Plane HTTP API | 快照 Spec;不应用 host bind-mount(有则 WARN) | -| **AgentRun** | extension | 阿里云 AgentRun API;可配 NAS/OSS mount、MCP URL | 云侧空闲超时 + 快照 Spec | - -公共能力均来自 `SandboxFilesystemSpec`:`isolationScope`、`snapshotSpec`、`executionGuard`、`workspaceProjection*`。 - -### 4.4 OpenSandbox 补充(仅 Python) - -[OpenSandbox](https://open-sandbox.ai/getting-started) 是通用沙箱平台(Docker/K8s 运行时 + 多语言 SDK)。agentscope 通过官方 `opensandbox` SDK: - -- 按 metadata 过滤 RUNNING/PAUSED 沙箱并 resume/connect; -- close 时 **pause** 保文件系统; -- 与 E2B 类似走 `_bootstrap_commands` 安装 gateway。 - -Java 侧 v2.0.0 **未集成**,若要在 Java 使用需自研 `SandboxClient` 或等待官方 extension。 - ---- - -## 5. 隔离模型对比 - -| | agentscope `IsolationPolicy` | agentscope-java `IsolationScope` | -| --- | --- | --- | -| 会话级 | `PER_SESSION` | `SESSION`(沙箱默认) | -| 用户级 | `PER_USER`(跨 agent 慎用) | `USER`(跨 session 共享记忆/快照) | -| Agent 级 | `PER_AGENT`(默认,按 user+agent) | `AGENT`(按 agent 名共享) | -| 全局 | 无对等枚举 | `GLOBAL` | -| 绑定时机 | Session 创建时写入 `workspace_id` | 每次 call 用 RuntimeContext 算 isolation key | - -Java 另强调:**沙箱模式下的 scope 是「顺序复用 + 快照」,不是同一容器实时共享**;并发需 `executionGuard`。 - ---- - -## 6. 好处与弊端总览 - -### 6.1 agentscope(Python)Workspace 沙箱体系 - -**好处** - -- 统一 `SandboxedWorkspaceBase`,后端可插拔,服务侧一行切换 Manager。 -- MCP Gateway 与文件工具同处沙箱,安全边界清晰。 -- Docker 镜像预烘焙,稳态性能好;云后端天然支持多副本重连。 -- OpenSandbox / Bubblewrap 覆盖「自托管云」与「轻量 Linux 沙箱」。 - -**弊端** - -- Docker/Local 单节点限制明显。 -- 非 Docker 后端首次 bootstrap 重(网络、时间、镜像权限)。 -- 缺少 Java 那种可插拔「快照存储后端」产品化抽象。 -- 无 AgentRun。 - -### 6.2 agentscope-java Harness 沙箱体系 - -**好处** - -- Filesystem 三模式(Local / Remote KV / Sandbox)切换不改 Agent 业务代码。 -- Call 级生命周期 + 多快照后端,适合多租户与水平扩展。 -- Docker 资源/网络控制细;扩展点(自定义 `SandboxClient`)文档化完整。 -- AgentRun 对接阿里云;projection 解决静态资产分发。 - -**弊端** - -- Docker CLI 与大 tar 快照带来延迟与运维开销。 -- 默认 `network=none`、裸镜像,开发体验需额外配置。 -- 并发 last-write-wins 需业务侧理解。 -- 无 OpenSandbox;MCP 不在沙箱内统一托管(与 Python Gateway 模型不同)。 - ---- - -## 7. 实践建议 - -1. **本地可信开发** - - Python:`LocalWorkspace` / `BubblewrapWorkspace` - - Java:`LocalFilesystemSpec`(默认) - -2. **单机强隔离、可调试** - - 两边都用 **Docker**;Python 适合长期 workspace + MCP;Java 适合按次执行 + 快照实验。 - -3. **多副本生产** - - Python:E2B / Daytona / OpenSandbox / K8s Manager - - Java:任意 `SandboxFilesystemSpec` + **分布式** `snapshotSpec` + `AgentStateStore`(否则 build 会强制提醒单点风险) - -4. **中国云 / AgentRun** - - 仅 Java `AgentRunFilesystemSpec`。 - -5. **自托管沙箱平台** - - 仅 Python `OpenSandboxWorkspace`;需先部署 OpenSandbox Server。 - ---- - -## 8. 参考链接 - -| 资源 | URL | -| --- | --- | -| agentscope DockerWorkspace | https://github.com/agentscope-ai/agentscope/blob/v2.0.5/src/agentscope/workspace/_docker/_docker_workspace.py | -| agentscope Workspace Manager 文档 | https://docs.agentscope.io/versions/2.0.5/zh/deploy/workspace-manager | -| agentscope-java DockerFilesystemSpec | https://github.com/agentscope-ai/agentscope-java/blob/v2.0.0/agentscope-harness/src/main/java/io/agentscope/harness/agent/sandbox/impl/docker/DockerFilesystemSpec.java | -| agentscope-java Filesystem 文档 | https://java.agentscope.io/v2/zh/docs/harness/filesystem.html | -| OpenSandbox 入门 | https://open-sandbox.ai/getting-started | -| OpenSandbox GitHub | https://github.com/opensandbox-group/OpenSandbox | - ---- - -*报告基于上述版本标签源码与官方文档整理;若文档站点已超前于 tag,以对应 Git tag 源码为准。* +123 \ No newline at end of file diff --git a/sql.md b/sql.md deleted file mode 100644 index d800886..0000000 --- a/sql.md +++ /dev/null @@ -1 +0,0 @@ -123 \ No newline at end of file