最近在折腾 WeKnora 的时候,我意识到了一个很实际的问题:Agent 跑起来很容易,但让它把状态留下来却很难。你在知识库里搜索、整理、生成报告,一次交互结束,一切都在;一旦 session 过期、服务重启,或者沙盒容器被回收,Agent 的记忆、任务进度、临时生成的文件全部归零,所有工作就得从头再来。这种“用完即焚”的模式,做一次性问答还行,真要把 Agent 当生产力工具来用,完全撑不住。
这篇文章记录的是我用 WeKnora 配合 CubeSandbox 搭建 Agent 持久化运行环境的全过程。WeKnora 是一个把 RAG、知识图谱、语音交互整合到一起的知识管理开源项目,CubeSandbox 则负责隔离执行 Agent 的各类工具代码。两者结合之后,Agent 的对话状态、任务状态和执行环境都可以做到持久化保存、恢复和复用。文章会涉及整体设计思路、架构选型、部署实操、状态持久化、沙盒隔离和问题排查等内容,既有原理,也有可以直接抄作业的配置,适合正在做 Agent 开发,或者准备把 WeKnora 落地到生产环境的同学参考。
先说明一点:下面所有 IP、端口、目录和参数都以我自己的测试环境为准,实际部署时请根据自己的资源和管理规范调整。
1. 项目背景与整体设计思路
1.1 WeKnora 的定位:为什么知识库系统需要 Agent 环境
刚开始接触 WeKnora 的时候,我对它的第一印象是“一个带 RAG 的知识库系统”。它能把你散落在文档、网页、笔记、语音里的信息统一索引起来,在问答时通过向量检索和重排序,把相关资料调出来,交给大模型生成回答。这个能力并不稀奇,市面上的同类项目一抓一大把。
真正让 WeKnora 区别于传统知识库的,是它把“知识检索”和“Agent 行为”结合到了一起。检索到的内容不再只是一段给人阅读的文字,而是 Agent 做决策和行动的依据。举例来说,你部署好之后可以提问:“帮我把项目文档里所有未关闭的风险项找出来,按负责人分组生成一份简报。”传统 RAG 的玩法是:向量检索命中文档片段,拼接给大模型,生成一段摘要。带 Agent 的玩法则是:Agent 先调用检索工具定位风险相关文档,再调用一个统计脚本对文档做结构化聚合,最后还可能触发一个把结果写回知识库的操作。从“被动问答”到“主动做事”,这就是本质差异。
但这个差异有代价。Agent 的行动是多轮多步的,每一步都要消耗 API 调用、CPU、内存和存储。今天没做完的事,明天要接着做;这一步生成的中间结果,下一步还要用。如果运行环境不持久,Agent 的价值就打了大折扣。所以我的核心判断是:WeKnora 这类项目要跑出真正的 Agent 能力,必须有一个配套的持久化运行环境,而不是靠它自身去硬撑。
1.2 持久化的本质:Agent 不是无状态函数
我最早做 Agent 的时候,带着写 Web 后端的惯性——请求进来、结果出去,服务本身不保留任何状态。这一套在传统 API 场景下没问题,但用在 Agent 上就各种别扭。
原因很简单,有价值的 Agent 任务几乎没有单轮对话能完成的。拿“每周自动检查知识库里的合同文档,提取到期日,生成提醒列表”这个场景来说,需要保留下来的东西至少有四类:
- 对话记忆:上一轮已经处理过哪些合同,结论是什么,新的对话里不应该重复处理;
- 任务状态:本周的任务当前执行到哪一步,是等待开始、正在检索、生成报告,还是已经完成;
- 运行环境:上次执行用的脚本、依赖、临时数据文件,下次执行需要继续用,不能重装一遍;
- 中间产物:从文档里提取出来的结构化数据、生成的图表,如果不落盘,一次会话关闭就全没了。
所以“Agent 持久化运行环境”的本质,是要解决四个问题:状态能不能存、环境能不能复用、任务能不能恢复、会话能不能续上。这四个问题不是某一个组件能全部搞定的,需要数据库、缓存、对象存储、沙盒容器和 Agent 框架协同。这也是我这次搭建的核心思路:把 WeKnora 当作中枢,外部接持久化组件,把 CubeSandbox 作为执行底座,各自负责自己擅长的事。
1.3 为什么选 CubeSandbox:隔离、资源控制与可复现性
聊完为什么需要持久化,再解释一下为什么执行环境选 CubeSandbox。
Agent 跑起来之后,最麻烦的不是调度,而是安全。Agent 的工具往往要执行命令、读写文件、调用外部接口,这些动作如果直接跑在宿主机上,一旦工具代码有 bug 或者被恶意 Prompt 诱导,后果很难收拾。所以我一直坚持一个原则:Agent 的代码执行必须进沙盒,宿主机不直接接触不可信代码。
CubeSandbox 在这个场景下的优势有三点。第一是隔离性好,每个任务分配独立的运行空间,文件系统、进程、网络互相隔离,工具爆炸也不会波及其他任务和宿主机;第二是资源可配额,能对 CPU、内存、磁盘做限制,避免某个任务把整台机器耗死;第三是可复现性,沙盒环境可以基于镜像或者声明式配置重建,同样的任务在任意时间点拉起来,环境都保持一致,这一点对持久化尤为重要。
我见过不少团队用裸 Docker 容器当沙盒,也能跑,但隔离粒度比较粗。CubeSandbox 这类专门为任务执行设计的沙盒环境,通常还会提供更细粒度的文件系统隔离、网络策略和生命周期管理接口,跟 Agent 框架对接起来更方便。当然,如果团队里已经有成熟的容器平台建设,自己用 K8s Job 也能实现类似效果,但付出的工程成本会高不少。我的建议是:初期直接采用沙盒方案快速落地,后面再根据规模决定要不要迁移到更大的容器平台。
2. 架构选型与依赖准备
2.1 整体架构:三条链路
这次搭建的整体架构我用三句话概括:知识进 WeKnora,任务出 Agent,执行进沙盒,状态落持久层。拆开来看,整个系统里有三条链路。
第一条是知识链路。文档通过 WeKnora 的导入接口进入系统,经过切片、向量化、索引,存到向量数据库。用户在问答时先召回再重排序,拿到候选片段后交给大模型生成回答。这条链路是 WeKnora 的老本行,没有太多需要额外设计的地方,重点是把嵌入模型和向量库选好。
第二条是任务链路。用户提出目标后,Agent 负责拆解任务、编排动作、调用工具。这一层需要的是 Agent 框架的工作流定义、工具注册、记忆管理等能力。WeKnora 内部已经有 Agent 相关的编排能力,但生产使用时我建议把它和任务队列结合起来,让每个 Agent 任务对应一个可追踪的执行记录,而不是只靠会话里的上下文。
第三条是执行链路。Agent 决定调用某个工具时,请求通过 API 发送到 CubeSandbox 的执行网关,由网关拉起一个沙盒实例、注入工具代码和参数,运行结束后回收资源,把标准输出、退出码、生成的文件统一返回给 Agent。执行链路是持久化的关键,因为沙盒的创建和销毁必须以可恢复的方式管理,否则任务跑到一半容器没了,状态就全丢了。
三条链路之间靠消息和数据表关联:任务记录保存 Agent 的执行计划、当前状态和下一步动作;沙盒记录保存每次执行的时间、环境指纹和产物路径;会话记录保存用户和 Agent 的完整交互历史。这样即使某个环节崩溃,也可以从记录里恢复出足够的信息继续执行。
2.2 硬件与软件依赖清单
先列我的测试环境配置,给读者一个参考基线。机器是一台 4 核 8G 的云主机,Ubuntu 22.04,系统盘 80G,数据盘单独挂载到/data。对于一个人或小团队用,这个配置刚好能跑起来;如果知识库文档量大或者 Agent 任务密集,建议至少 8 核 16G,磁盘按 200G 起步规划。
软件依赖方面,按功能模块列几个表格,方便对照使用:
核心服务组件
| 组件 | 作用 | 版本说明 |
|---|---|---|
| Docker + Docker Compose | 承载 WeKnora 及各中间件 | Docker 24+,Compose v2 |
| PostgreSQL | 保存任务状态、Agent 记录、配置信息 | 建议 14+ |
| Redis | 会话缓存、短期记忆、任务锁 | 建议 7+ |
| 向量数据库 | 保存文档向量、语义索引 | 选型后确定 |
| 对象存储 | 保存中间产物、Agent 生成文件 | 本地 MinIO 或云厂商 OSS |
运行环境组件
| 组件 | 作用 | 备注 |
|---|---|---|
| CubeSandbox | Agent 工具代码的隔离执行环境 | 提供沙盒 API 或自建部署 |
| Agent 运行时 | 执行 Agent 循环、工具调用、记忆读写 | 视框架定 |
2.3 组件选型背后的逻辑
选型的核心原则是:优先用成熟组件,避免重复造轮子。存储我选了 PostgreSQL 而不是 MySQL,主要是看中它的 JSONB 类型和更丰富的索引能力。Agent 任务状态这种东西结构并不规则,今天可能是个 JSON,明天可能变成嵌套结构,用 JSONB 存起来再配合 GIN 索引,查询和扩展都很方便。
向量数据库这里我不想把话说死。WeKnora 在部署里往往支持多种向量存储后端,我在验证阶段用的是 pgvector,因为可以直接复用现有的 PostgreSQL 实例,少维护一个组件。文档量到了几百万条以上,再考虑迁移到专门的向量库。对大多数知识库场景,pgvector 的性能已经足够。
对象存储选择 MinIO 是因为它部署简单,API 兼容 S3,后续如果迁移到云厂商对象存储,只需要改 endpoint 和密钥,代码不用动。中间产物、Agent 生成的文件都放对象存储而不是本地磁盘,还有一个额外的好处:沙盒是临时的,但产物在对象存储里的生命周期不受沙盒影响,持久化才有意义。
3. 持久化运行环境的核心实现
3.1 会话与记忆的持久化:Redis + 向量库的分工
Agent 的记忆体系我一直觉得应该分成两层:短期记忆和长期记忆,二者用不同的存储。
短期记忆对应当次会话内的上下文,包括用户最近几轮输入、Agent 的中间思考过程、最近使用的工具结果。它变化频繁、读多写多,非常适合放在 Redis 里,过期时间可以设成 24 小时或者和会话生命周期对齐。Redis 的好处是快,而且支持给 key 设置 TTL,不用担心记忆无限膨胀把内存打爆。
长期记忆对应跨会话的知识积累,比如“用户上次已经确认过这一批合同的处理状态”“这个项目的命名规则是什么”。这类信息要长期保存、要能被语义检索,所以放进向量库比较合适。具体操作是:每轮关键对话结束后,把提炼出来的事实和结论做向量化,存进向量库,并在 metadata 里带上时间戳、会话 ID、任务 ID。下次开会话时,Agent 先做一次向量检索,把和历史相关的记忆捞回来,再开始推理。
这条路径我踩过一个坑:一开始把所有对话原文都丢进向量库,结果语义检索时召回了一堆互斥的历史结论,Agent 反而变糊涂了。后来改成只对“提炼过的记忆”做向量化,效果明显好很多。记忆入库前一定要做提炼,不能直接灌原文。
3.2 任务状态的持久化:数据库表设计与恢复流程
任务状态是 Agent 持久化里最容易被忽略、也最容易翻车的部分。一个 Agent 任务从开始到结束,通常会经过多个阶段,比如:规划、检索、分析、生成、执行、验证、完成。任何一个阶段中断,都要能定位到具体位置,并且从那里继续走。
我的做法是设计一张任务表,字段包括:任务 ID、任务类型、目标描述、当前阶段、阶段详情 JSON、依赖数据引用、开始时间、更新时间、状态。阶段详情里记录当前阶段已经完成的部分和下一步要执行的参数。这张表的作用不仅仅是记录,更是 Agent 的检查点。
恢复流程是这样的:Agent 在启动或者拉起新会话时,先查任务表里有没有“未完成”的任务;如果有,就把阶段详情里记录的进度取出来,根据当前阶段选择恢复方式。比如“规划”阶段已完成的,直接跳到“检索”;“检索”阶段已完成但结果没落盘的,重新执行检索子任务把结果补上;“执行”阶段已完成的,直接从产物路径读取结果。恢复流程的关键是每个阶段的产物都必须在完成时落盘,并且把引用路径写进阶段详情里。
我把任务执行过程设计成“每个阶段幂等”的方式,目标是让任何一个阶段重跑都不会产生副作用。做法是:写操作尽量发生在阶段结束后,阶段进行中只读数据。这样即使同一阶段执行了两次,结果也一致,不会污染最终产物。
3.3 工具执行的沙盒隔离:CubeSandbox 的配置要点
CubeSandbox 的配置重点有三个:镜像(模板)、资源配额、网络策略。
镜像和模板决定了“环境能不能复用”,这和持久化直接相关。我建议把 Agent 工具依赖做成不可变的镜像或模板版本,每次执行都用同一版本,避免“昨天能跑今天不能跑”的问题。每次工具代码升级,就生成新版本模板,旧任务仍然用旧版本继续执行。这个版本控制的好处是,任务恢复到过去的时间点时,可以拉起当时那份依赖环境,而不只是恢复数据。
资源配额决定了“一个任务最多能占用多少”。配置时我给 CPU 配额设了 0.5 核、内存 1G、磁盘 2G 的默认值。知识密度高的任务(比如批量文档解析、向量化)可以放宽到 1 核 2G 内存,但必须有上限。内存配额尤其重要,Agent 的工具代码经常出幺蛾子,一个死循环就能把内存耗尽,没有配额整个宿主机都要跟着遭殃。
网络策略决定了“沙盒里的代码能访问什么”。我这里是内外两层:默认拒绝所有出网流量,只有白名单里的域名和端口才允许放行;如果 Agent 工具需要访问外部 API,就在任务创建时把域名注入白名单配置。这个策略宁可严不可松,因为沙盒里跑的代码本质上不受你控制,能接触的面越小,风险越低。
sandbox: default_resource: cpu: 0.5 memory: 1Gi disk: 2Gi network: mode: whitelist allow_domains: - api.xxx.com - model.xxx.com image_version: agent-tools-v1.2.0这是一段很简化的配置文件示例,实际会复杂一些,但核心思路是一致的:镜像版本化、资源配额化、网络白名单化。
3.4 生命周期管理:启动、恢复、回收
最后是生命周期管理。我在项目里把沙盒的生命周期分成了三类:一次性、可恢复、常驻。
一次性沙盒是默认模式:任务执行结束就销毁,一切临时数据直接清理。适合那种“检索一下、算一下、回答完就结束”的工具调用。可恢复沙盒就比较有意思:保留执行结果和产物,但容器本身销毁,只在任务表的阶段详情里记录环境版本和产物路径。下次如果同一任务要继续,就用记录的镜像版本重新拉起一个沙盒,挂载相同的数据卷,恢复产物路径,继续干活。
常驻沙盒用于真正需要长时间驻留的服务型 Agent,比如持续监听某个目录、周期性执行任务的 Agent。这类沙盒数量要严格控制,我一般会限制在几个以内,多了资源跟不上,一旦崩溃恢复起来也麻烦。
生命周期管理最关键的一点是:一定要有超时机制和心跳检测。Agent 任务卡死了,沙盒不能无限存活。我给每个沙盒绑一个最长运行时间,超时强制回收,同时通过心跳判断任务是否还在正常推进。这一个机制能避免大量“僵尸容器”吃掉整台机器的资源,我见过不止一次因为缺了这个机制导致的线上事故。
4. 部署实操与关键环节落地
4.1 WeKnora 本地部署的分步操作
WeKnora 的部署方式,最推荐的就是 Docker Compose。这里我给出一套可以落地的步骤。先准备几件事:第一,装好 Docker 和 Docker Compose 插件;第二,准备一个数据目录,比如/data/weknora,所有数据卷挂载到这个目录下;第三,准备好大模型 API 的 key 和 endpoint。
部署时我先拉取项目代码和 compose 文件,检查里面对外的端口映射。默认情况下 WeKnora 会暴露一个 Web 端口和一个 API 端口,我建议把 API 端口固定下来,比如8080对应 Web,8090对应 API,后续 Agent 和 CubeSandbox 对接都走 API 端口。
启动之后,需要进管理后台做三步基础配置。
第一步是配置知识库。创建知识库,把文档导入,设置切片策略。文档量大时建议用固定大小切片加重叠,比如每个切块 800 token、重叠 200 token,对大多数技术文档效果都不错。
第二步是配置模型。WeKnora 需要配置两套模型:嵌入模型用于向量化,对话模型用于生成回答和 Agent 推理。这里注意,很多本地化部署用户不愿意把文档内容传到外部 API,所以嵌入模型一般选择本地部署的模型,对话模型可以根据成本考虑用本地或外部 API。我一个人用的时候是两套模型都走本地,单独跑在一个 GPU 节点上,既避免文档内容出境,也省下按 token 计费的钱。
第三步是配置认证。WeKnora 有 OIDC 相关的能力,如果你所在的团队有统一身份认证系统,建议在这一步就接上。即便是自用,也至少设置好管理员密码和访问白名单,不要裸奔在公网。
以上步骤做完,WeKnora 本身已经能跑起来了。但此时它还是个“临时态”的 Agent 环境,离持久化还差两步:接入 CubeSandbox 和打通持久化层。
4.2 CubeSandbox 执行环境的接入配置
CubeSandbox 的接入分两种方式:用官方提供的托管服务,或者自己搭建。我自己测试时用的是自建部署,可以更清楚地看到沙盒的启动、执行、回收全过程。
接入的第一步是拿到执行网关的地址和认证信息。在 WeKnora 的 Agent 配置里,找到“工具执行环境”或者类似的设置项,填入 CubeSandbox 的 endpoint,比如http://sandbox-gateway:8080,以及对应的 API token。
第二步是配置沙盒模板。前面说了,模板版本化很重要。我在 CubeSandbox 里创建了一个agent-tools模板,里面放了常用的 Python 工具库,包括 requests、pandas、openpyxl 等,固定版本并打上标签。这样 Agent 每次执行都基于这个模板启动,行为和结果都可预期。
第三步是配置工具注册。把 Agent 能调用的工具在 WeKnora 侧注册好,每个工具绑定到一个沙盒模板和执行脚本。比如我注册了一个doc_summarize工具,绑定 agent-tools 模板,执行脚本是run.py,参数是文档 ID。工具注册这一步,实际上是在定义 Agent 的能力边界:什么能调、什么不能调,边界越清晰,Agent 越可靠。
配置完成后,可以做一次冒烟测试:让 Agent 调用一个简单的工具,比如“读取某个文档并统计字数”。观察沙盒的启动时间、执行输出、退出码,以及结果有没有写回 WeKnora。这一步通过了,再逐步增加工具复杂度。
4.3 持久化服务的初始化与联通性验证
持久化层是这次搭建的重头戏。我在部署时把 Redis、PostgreSQL 和 MinIO 都跑在 Docker Compose 里,和 WeKnora 同属一个网络。
Redis 初始化很简单,关键是确认密码和持久化配置。生产环境务必设置密码,并开启 AOF 持久化,否则 Redis 一重启,短期记忆全丢,会话恢复就成了一句空话。
PostgreSQL 这边,我创建了独立的数据库账号,weknora业务库和agent_task任务库分开,避免知识库数据和任务数据互相干扰。任务表在agent_task库里,通过启动时自动建表,也可以手动执行 SQL 初始化。
MinIO 初始化需要创建存储桶,比如agent-artifacts。然后生成一对 Access Key 和 Secret Key,配置到 WeKnora 的 Agent 设置里。
联通性验证我总结为一个“五分钟自查流程”:
- Redis:
redis-cli -a <密码> ping,返回 PONG 即正常。 - PostgreSQL:执行
SELECT 1,确认任务表存在。 - MinIO:用 SDK 上传一个测试文件,再下载回来对比内容。
- 联网检查:确认 WeKnora 服务、CubeSandbox 网关、模型 API 三者之间网络互通。
- 端到端跑一次:创建一个临时的多阶段任务,让它执行到一半时手动重启 WeKnora 服务,再恢复任务,确认能从断点继续。
第五步是最重要的验证,它能一次性暴露会话丢失、任务状态未保存、沙盒不可恢复等各种问题。我强烈建议做这个测试,不要在没验证过恢复能力的系统上跑真实任务。
5. 常见问题与排查技巧实录
5.1 会话中断后 Agent 状态丢失怎么办
这是一个出现频率极高的问题。现象是:对话进行到一半,服务重启或者页面刷新,新会话开始后 Agent 完全不记得之前的内容。
排查思路先从存储入手。第一步去看短期记忆还有没有,Redis 里按会话 ID 查,如果 key 不存在或者已经过期,说明短期记忆没持久化或 TTL 设置太短。第二步看任务表,如果任务记录还在但阶段详情为空,说明写入逻辑有问题,可能是任务状态只在结束回写,中途崩溃时数据就丢了。第三步看日志,确认 Agent 在会话结束时有没有主动把记忆和执行结论写入长期记忆。
这个问题的根因,绝大多数是“状态只在任务完成时回写”导致的。正确做法是把状态回写改成每个阶段完成时立即落盘。我后来设计了一个简单的“阶段回调”机制:Agent 每次阶段切换时,自动调用任务服务把最新阶段详情写库,这样即使中途崩溃,恢复时也能定位到秒级精确的断点。
另一个细节是:恢复会话时不要机械地把所有历史全部注入上下文。很常见的情况是历史太长,超过上下文窗口限制,或者注入了一堆无关对话,导致模型注意力被稀释。正确做法是从长期记忆中检索和当前任务相关的片段,只注入这些摘要,既省 token 又提高准确率。
5.2 沙盒内工具执行超时、内存溢出如何处理
超时是沙盒场景最常见的故障,尤其是一些文档解析任务,遇到超大文件时处理时间很容易超出默认值。一个关键的设计思想是:工具执行要实现“超时中断 + 降级策略”。
超时中断本身容易,沙盒层直接 kill 进程就行。难点在于 Agent 怎么处理超时后的行为。我的做法是给予 Agent 明确的错误反馈和可选的降级路径:如果文档解析超过 60 秒,则自动降级为只提取前 N 页内容,并标注结果不完整;如果内存逼近上限,则自动切换为批次处理,按页码分批解析,每批结束后把结果落盘再继续。
内存溢出的排查更麻烦一点。我遇到过几次 Agent 工具代码出现循环引用导致对象无限增长,内存几分钟内耗尽的情况。排查方法很简单:给沙盒开启指标采集,记录每条任务执行的 CPU 和内存曲线,出问题时先把指标曲线拉出来,看内存是在哪一步开始飙升的,再针对性审查代码。
这些排查经验让我越发理解一个道理:沙盒的价值不只是隔离风险,更是给你一个可以随意实验、复现问题的环境。因为每次执行的环境都是基于镜像重建的,你完全可以还原当时的环境,甚至可以在沙盒里装调试工具,慢慢查看哪里出了问题,这一点在裸环境里很难做到。
5.3 多 Agent 并发时的资源竞争与锁问题
当你的系统同时跑多个 Agent 任务时,资源竞争就开始出现了。最典型的问题是两个 Agent 同时调用同一个工具,比如同时去写一个共享文件,或者同时更新同一个任务的阶段状态,结果就是数据互相覆盖。
资源竞争的解决方案核心是加锁和服务化解耦。
加锁用于“不允许并发”的操作。我在 Redis 里用分布式锁来保护共享资源的写入,比如“同一任务同一时刻只能有一个 Agent 在推进”“同一份合同文档同一时刻只能有一个 Agent 在处理”。锁的粒度要尽量细,锁的持有时间要尽量短。特别提醒一下:分布式锁的过期时间设置要谨慎,避免 Agent 任务卡在长任务上时锁已经过期,别的 Agent 又进来重复处理这一份数据,反而造成重复写。
服务化解耦用于“可以并行但不该直接操作公共资源”的场景。我的做法是:把公共资源的操作收敛到一个独立服务里,Agent 不直接碰公共文件,而是调用服务接口。这个服务内部有队列和版本控制,冲突由服务裁决。这个设计在后续扩展时也很方便,因为 Agent 的并发量上升以后,无论如何你都需要一个中间层来协调资源。
5.4 安全加固的几条底线
最后说说安全,这块我放在所有技术问题之后,是因为它优先级最高。沙盒内跑的代码是不可信的,再怎么强调隔离都不为过。
第一条底线:宿主机上的敏感目录不挂载进沙盒。比如 SSH 私钥、云厂商凭证、数据库密码文件,这些必须严格限制,宁可任务用不到,也不要冒险暴露。
第二条底线:沙盒网络默认拒绝,白名单放行。这个在前面配置文件里已经讲了,再重复强调一遍,因为这是最容易被绕过的安全防线。如果你给了沙盒完整的网络访问权限,那你前面做的所有隔离都白费。
第三条底线:Agent 的工具权限要最小化。每个工具只给完成自己任务所需的最小权限,比如“读取指定目录文件”的工具不能拥有“删除目录”的权限。权限最小化不仅是安全要求,也是稳定性要求——权限范围越清晰,Agent 在错误方向上不小心执行破坏性操作的概率就越低。
我的个人意见是,安全加固应该放在持久化和功能开发之前。很多人一开始觉得安全无关紧要,先把功能跑通再说。但 Agent 场景的特殊性在于,它天生就有工具执行能力,工具一旦可以被自由调用,风险就会被放大。我接触到的每一次因为工具执行导致的事故,事后复盘时几乎都能归结到“隔离不到位”或“权限给多了”这两条上,这也成了我做这类系统时最铭心刻骨的教训。