我花了大半年时间,用 Rust 写了一个我称为 Agent-Reach 的 AI Agent 框架。名字起得没什么玄机,就是 Agent + Reach,希望智能体真正“触达”外部世界:能读写本地文件、能把网页整理成 markdown、能在沙箱里安全执行代码、能把自己的记忆落到 Obsidian 仓库里。如果你正打算做 agent 开发、或者已经被“agent 框架这么多到底该选谁”折磨过,这篇文章大概能给你一点不一样的参考。
先说清楚 Agent-Reach 是什么。它不是又一个 LangChain 的低配版,而是一个更偏“运行时”与“工作台”的 agent 基础设施。我的目标用户是两类人:一类是像你我这样想自己搭 AI Agent、又不想被上层框架绑死的开发者;另一类是希望把 agent 接进自己的笔记系统、知识库流程的重度用户。项目核心由四个模块组成:harness 运行时、skill 插件体系、多 agent 编排器、评测集驱动。下面我按实际开发顺序,把每个模块的设计思路、踩坑过程和最终落地实现,一次讲透。
1. 为什么我还要折腾一个 Rust 写的 Agent 框架
1.1 先从“Agent-Reach”这个名字说起
这个项目最初的代码名是agent-runtime,后来改成了 Agent-Reach。改名的原因是,我发现真正决定一个 agent 好不好用的,不是模型推理多聪明,而是它能不能稳定地“够到”外部资源。
你可以把 agent 想象成一个实习生。模型是他的脑子,但脑子再聪明,如果手伸不到文件系统、浏览器、数据库、笔记应用,他也只能空谈。Agent-Reach 想解决的就是“手”的问题:用一套统一的 skill 机制让 agent 操作任何工具,用 harness 限制它的行动范围,用沙箱保证它乱来的时候不至于把家拆了。
曾经我跑过一个最失败的 demo:让 agent 去“整理本周项目周报”,结果它一口气调了十几个 API、写了三个临时脚本、把输出存到了乱七八糟的目录,最后还忘了告诉我看哪份文件。问题不在模型弱,而在于整个运行环境缺少边界和协议。Agent-Reach 的架构,就是为了根治这类“失控感”。
1.2 市面上框架那么多,为什么不全盘照搬
这是每个做 agent 项目的人都必须回答的问题。LangChain、Dify、CrewAI 我都正儿八经用过,也拿它们搭过内部分享的原型。它们擅长的事情很明确:LangChain 生态全、整合快;Dify 对非程序员友好,可视化编排;CrewAI 让“多角色协作”写起来很爽。
但真把它们用在个人知识库、本地自动化、长期记忆这类场景里,问题也很具体。
第一,重量级依赖太多。一个 hello-world 级别的 agent,装完依赖能给你拖出几百 MB。我想要的 agent 是一个跑在命令行里、按需启动、用完即走的工具,而不是常驻服务。
第二,抽象层侵入太强。底层调用的直接逻辑被包了太多层,调试时你根本不知道是模型输出错了,还是某个 chain 把上下文截断了。出问题以后追踪链路非常痛苦。
第三,自定义 skill 的成本高。LangChain 里加一个工具,你得继承类、写 pydantic 模型、注册进 toolkit,流程繁琐不说,新加技能还要重新审视整个链路的兼容性。
我做 Agent-Reach 时给自己定了几条铁律:整个运行时尽量无重量级依赖;skill 用简单声明式文件描述;harness 和 agent 逻辑严格分离;所有行为可观测、可复现。所以它不是“替代 LangChain”的框架,而是“如果你想自己掌控运行时,可以照着这个思路搭”的参考实现。
1.3 为什么偏偏选 Rust
选择 Rust 有几个非常现实的理由,不是为了技术潮流。
内存安全是第一位。agent 要执行来自外部输入的代码、处理不可信的网页内容、解析一堆来路不明的 JSON,这正是内存安全问题高发区。Rust 的所有权模型和严格类型系统,能在编译期挡住一大批空指针、野指针、数组越界的问题。你真把 agent 挂在公网上当服务跑的时候,会感激这个决定。
第二是单二进制分发。cargo build --release出来一个二进制文件,拷到任何 Linux 机器上就能跑。这对“把 agent 部署到树莓派、NAS、别人服务器”这类场景极其友好。我甚至把 Agent-Reach 放到一个没有 Python 环境的干净容器里跑过,毫无压力。
第三是 tokio 带来的异步能力。agent 经常需要并行抓多个网页、同时监听多个事件源,tokio 的异步模型让我写出高并发代码时不用像传统多线程那样小心锁竞争。
当然,Rust 的代价也明显:开发速度比 Python 慢,生态相比 Python 仍然偏少。好在 agent 项目的核心库依赖并不多,我主要靠serde、tokio、reqwest、rodash这几个库打天下。对一个基础设施型项目来说,开发速度换来的稳定性,我觉得非常划算。
2. 核心架构:harness 与 agent 的边界在哪里
2.1 harness 到底管什么、agent 又管什么
这是我被问得最多的一个问题,也是 Agent-Reach 架构里我认为最关键的设计决策。很多人把 harness 和 agent 混为一谈,导致项目最后变成一锅粥。
先说结论:agent 是“大脑”,负责推理、决策、生成下一步动作;harness 是“骨骼和肌肉”,负责拉起环境、调度工具、控制上下文、保障安全。二者通过一个固定协议交互。
我画过一张简化的通信图,帮你理解它们的协作方式。agent 接收一个任务,输出一个“动作意图”,比如“读取文件 /path/to/notes.md”;harness 收到后去校验、执行、返回结果;agent 再基于结果决定下一步动作。整个循环中,agent 从不直接访问文件系统或网络,它只能提出请求,真正的副作用全部发生在 harness 这一侧。
| 维度 | Harness | Agent |
|---|---|---|
| 职责 | 环境准备、工具执行、安全边界 | 任务理解、规划、动作选择 |
| 状态 | 维护执行上下文、会话状态 | 维护思维链、短期目标 |
| 知识 | 不涉及业务推理 | 不涉及副作用操作 |
| 错误处理 | 捕获执行异常、重试、降级 | 根据错误信息调整策略 |
| 可替换性 | 同一 agent 可换不同 harness | 同一 harness 可换不同模型/agent |
这个分离带来的最大好处是可测试性。harness 的逻辑是确定的,我可以用纯单元测试覆盖;agent 的行为是不确定的,需要评测集来验证。要是哪天想从 Claude 换成 GPT,或者换成本地小模型,只需要保证 agent 输出端和 harness 输入端对齐即可。
2.2 进程隔离:我的 agent 跑在沙箱里
既然 agent 要执行代码、读写文件,那安全就是生死线。我的思路是“宁可信它坏,不可信它好”,也就是默认所有 agent 动作都不可信。
Agent-Reach 的沙箱分三层。
第一层是本地权限边界。harness 启动时读取一个权限清单(policy file),里面写清楚 agent 可以访问哪些路径、允许执行哪些命令、禁止访问哪些网络地址。路径用 glob 规则匹配,所有越权操作直接返回错误。这一层足够挡住 90% 的“手滑”和无心之失。
第二层是系统级隔离。可执行代码默认丢进一个独立的容器里运行,容器只有最小镜像、无网络权限、挂载只读卷。容器技术在这里的好处不是“部署”,而是“回收”。每次执行完,直接销毁容器,残留进程和状态一并清理干净。
第三层是流量控制。所有出站网络请求都经过一个 proxy 模块,Agent-Reach 会维护一个域名白名单。比如 skill 里如果写明“只允许访问 example.com 和 localhost”,那么任何其他请求都会被 harness 拦截并打上警告。
沙箱不是一劳永逸的,它是一套纵深防御。即便某天某个 skill 写得有漏洞,被恶意利用,攻击者面对的也不是一个裸奔的宿主机,而是一个受控的、无持久化权限的环境。
2.3 工具协议:skill 就是最小可复用单元
在 Agent-Reach 里,我管单个工具/能力叫“skill”。skill 的概念借鉴了社区里“function calling”和“tool”的思路,但做得更轻、更独立。
一个 skill 本质是一个文件夹,里面包含三样东西:SKILL.md(能力描述)、run.sh或run.py(执行入口)、可选的schema.json(参数校验)。
最开始我用的是类似 “tool:名称+description+args” 的 JSON 长期配置,但很快发现维护成本高:增加一个工具要改配置文件、改 agent 的 system prompt、还要同步更新文档。改成“skill 目录”之后,新增一个能力就是往目录里丢一个文件夹,哪怕别的项目也能复用。发布到社区,别人 clone 下来就能用。
关于 skill 的描述文件,有一件事值得所有 agent 开发者重视:描述的措辞直接决定了模型调用 skill 的准确率。写得模糊,模型会猜错参数;写得过度详细,又浪费 token。好的描述应该是“短、具体、含示例”。比如网页另存为 markdown 的 skill,描述如果写成“save web page to markdown”,模型可能搞不清楚要传 URL 还是传 HTML 字符串。改成“Save a web page by URL. The URL must begin with http:// or https://. Returns full text content in Markdown format.”,调用准确率立刻上了一个档次。这个技巧我到后面第 3 章还会细讲。
3. skill 机制的落地:从网页另存为 markdown 说起
3.1 skill 定义文件长什么样
热词里有一个我很感兴趣的技能:「agent 将网页保存成 markdown 的 skill」。这也是我个人用得最多的 skill 之一。因为在做知识库和笔记整理时,把网页内容抓回来并转成干净 markdown,几乎算刚需。
Agent-Reach 里这个 skill 的SKILL.md长这样:
--- name: web_to_markdown description: Save a web page by URL. The URL must begin with http:// or https://. Returns full text content in Markdown format. If the page is dynamic and requires a headless browser, set use_browser=true. arguments: url: type: string required: true description: Full page URL. use_browser: type: boolean required: false default: false description: Whether to render JavaScript-heavy pages via headless browser. --- # web_to_markdown Fetch the page at the given URL, strip navigation/ads/footer noise, and convert the main content to clean GitHub-flavored Markdown.为什么用 YAML front-matter 而不是纯 JSON?坦白说,设计时没有特别硬的理由,更多是直觉。YAML 头部对模型更友好,agent 读起来不像在解码 JSON 转义符。但你要是更习惯 JSON,完全可以改成 JSON 头,Agent-Reach 对这两者都支持。
这里有一个重要细节:skill 描述中必须明确告诉模型“错误时你会看到什么”。我在 description 里没有写全,但在实际运行中,fetch 失败会返回一个标准错误对象,比如{"error": "timeout", "url": "..."}。这能让模型在失败之后做出合理反应——不是死循环重试,而是尝试镜像站或者直接告诉用户当前不可用。
3.2 网页保存 markdown 的实际实现
这个 skill 的执行入口是 RUST?其实是 Python。我刻意保留了“按需解释型语言”的灵活性,因为网页抓取和正文提取这种逻辑,Python 生态太成熟了,没必要硬用 Rust 重写一遍。
核心步骤是三步。
第一步,抓取。用httpx发请求,带上常见的浏览器 UA,设置 15 秒超时。要处理的细节包括:gzip 压缩、重定向、编码检测。这里面最坑的是编码。很多老站点返回的Content-Type没有 charset,需要用charset-normalizer挨个探测。
第二步,正文提取。我不建议一上来就上大模型做正文提取,成本高、延迟大、还可能“幻觉”出本不存在的标题。先做启发式提取:剥掉<script>、<style>、<nav>、<footer>,然后根据文本密度算法挑出正文容器。这一步已经能处理绝大多数博客和资讯站。
第三步,HTML 转 markdown。我用的是一个基准 markdownify 库的增强版,保留标题层级、链接、表格、代码块。转换结果会做一次后处理:清掉多余空行、把相对链接补全成绝对链接、给图片 alt 添加缺失时的占位文本。
最后,harness 会把 markdown 写入一个临时文件,并把路径返回给 agent。如果 agent 正在运行于某个笔记工作台,还会触发一次“保存到库”的动作。
3.3 Token 成本控制:为什么 skill 描述写得越烂越烧钱
很多人没注意到,skill 描述本身在每一轮对话里都会被塞进系统提示词。这是一个隐性 token 开销。假设你有 20 个 skill,每个描述平均 300 token,那就是 6000 token,每次都烧。如果某个项目只用到其中 3 个,这笔开销纯属浪费。
Agent-Reach 的解决方案是“延迟绑定”。harness 不一次性把所有 skill 描述塞给模型,而是分两轮:第一轮只给模型一个精简的 skill 清单(名称 + 一句话摘要,总共可能不到 600 token);模型选定某个 skill 后,harness 再把完整描述注入当前轮次。这样既保持了模型对可用能力的全貌认知,又把 token 成本控制在可接受范围。
这个方案也有代价:模型在“选择使用哪个 skill”时拥有的信息更少了。折中办法是把一句话摘要写在SKILL.md的description字段里,写得好不好直接决定第一轮命中率。
同样值得警惕的是工具返回结果的 token 爆炸。比如你让 skill 抓一个很长的网页,返回的 markdown 可能有几万字,全部塞进上下文,下一轮对话就直接超预算。所以 Agent-Reach 默认开启“结果截断”:skill 返回内容超过比如 8000 token,harness 会把中间部分折叠,只保留开头和结尾,并附带一句“内容过长,已截断,可调用 read_range 读取指定段落”。
这份“克制的上下文管理”,比单纯追求“什么都能干”更重要。我一直觉得 token 预算就像带宽预算,别把所有资源都花在上下文搬运上。
4. 记忆与工作台集成:把 Obsidian 变成 agent 的长期记忆
4.1 记忆不是向量库那么简单
很多人一说到 agent 记忆,第一反应就是“上个向量数据库”。实际做下来你会发现,记忆至少有三个层级,向量库只解决了其中一个。
第一层是会话级记忆,也就是上下文窗口里的历史;第二层是工作级记忆,代表当前任务产生的临时状态;第三层是长期记忆,跨会话、能沉淀知识。LangChain 里有 ConversationBufferMemory、summary memory、vector memory,本质上都是在给这三层记忆做实现。
Agent-Reach 里的记忆很有意思,我没有用专门的向量库,而是把 Obsidian 仓库直接当作长期记忆。原因很朴素:长期记忆必须是人可以读、可以改、可以审计的。一个能自动写笔记的 agent,如果它写的东西只有它能看懂,那对用户来说价值就大打折扣了。
我在项目里把记忆定义成三类文件:
inbox/ 未处理线索,agent 随手记下的想法、URL、待办;notes/ 结构化笔记,由网页 markdown skill 或阅读 skill 生成的内容;journal/ 决策日志,记录 agent 每次关键选择的原因,相当于 agent 的“操作复盘”。
值得强调的是,记忆写入需要走同样的 skill 协议。agent 不是直接往文件系统写,而是调用write_noteskill,由 skill 负责命名规范、目录归类、格式检查。这样能防止 agent 把笔记写得乱七八糟,同时所有写入动作都会被审计日志捕获。
4.2 Obsidian 仓库作为记忆层
具体怎么落地?我在 Agent-Reach 里实现了一个obsidian_bridge模块。它的作用是把一个 Obsidian vault 目录暴露给 agent,让 agent 可以完成以下操作:
- 搜索笔记(用 grep 加正则,先不用向量检索,因为中小型笔记库 grep 足够快);
- 创建新笔记;
- 更新 front-matter 元数据;
- 建立双向链接(Obsidian 双链是可靠的关系层)。
为什么不直接上向量检索?因为个人笔记库往往几千个文件,grep 性能完全够用。向量检索的“语义模糊匹配”听起来美好,但在知识管理的场景里,精确文件名和标题匹配往往比语义相似更重要。比如你想找“关于 Rust 中 async trait 的笔记”,grep 出来的排序可能比向量检索更符合期望,因为文件名和标题里的关键词做精确匹配时,相关性更可解释。
作为补充,Agent-Reach 里有一个可选的semantic_searchskill,在内嵌 sqlite-vec 或 DuckDB 上做了简单向量索引。默认不启用,需要用户在 skill 配置里明确打开。这样做的好处是:基础用户用轻量方案获得 80% 的体验,高级用户再按需加载重武器。
4.3 第三方工作台的对接思路
热词里反复出现“hermes agent 第三方工作台”和“hermes agent obsidian”。我理解这类工作台的核心诉求就是:agent 不应该只是命令行工具,它应该能钻进用户已有的工作环境。
Agent-Reach 不打算自己去实现一个 GUI 工作台,而是定义了“工作台适配器”接口。比如针对 Obsidian,我提供一个插件或脚本,可以接受 Agent-Reach 发出的本地事件。事件格式很简单:
{ "event": "note.created", "path": "notes/2024/03/rust-async-trait.md", "source": "web_to_markdown", "timestamp": 1736582400 }这类事件可以被 Obsidian 插件监听,自动刷新文件树、更新标签、甚至是启动一个快捷命令。对接 Herpes 类工作台时,也只是换了一个事件接收端,核心逻辑不需要动。
这就是“依赖抽象而不是依赖具体工具”的价值。现在 Obsidian 是最流行的,将来如果换成 Logseq、Notion、思源笔记,我只需要再写一个适配器插件。Agent 本身不需要知道自己正在写进哪个知识库,它只负责产生结构良好的 markdown 和元数据。
真正难的是同步冲突。当 agent 和用户同时编辑同一个笔记时,必须有一套合并策略。我的方案比较保守:agent 默认只写inbox/和journal/这两个“半私有目录”,需要用户确认才会动notes/和Projects/。这样既保持了 agent 的自主性,又把破坏性操作的权限收回了人类手中。
5. 多 Agent 协作与编排实践
5.1 单 Agent 的天花板
单 Agent 做成什么样算到顶了?我说一个判断标准:当它同一时刻需要两条互斥的执行路径时,就该考虑多 Agent 了。
举个例子。任务是“调研三家云厂商的价格,并输出对比表”。单 Agent 的做法是串行:先去 A 网站,回来读,写一段;再去 B,再写一段。这里其实没有并行必要性,串行也还能接受。
但如果是“同时读取二十个网页,并持续汇总状态”呢?单 Agent 的上下文窗口会迅速被中间结果撑爆,而且模型在长过程的后期容易丢失早期结论。这时候,多 Agent + 分工协作的价值就体现出来了。
Agent-Reach 里我用的是经典的主-从模式:一个 orchestrator(编排器)调度多个 worker。编排器负责拆解任务、分发子任务、汇总结果;worker 各自只负责一个领域,比如“网页抓取 worker”“笔记整理 worker”“代码生成 worker”。它们之间不直接通信,所有状态都通过编排器的一个共享黑板(blackboard)传递。
5.2 编排器与子 Agent 的通信
具体到通信协议,我在项目里定义了一个极简消息结构:
pub enum AgentMessage { Task(String), State { key: String, value: serde_json::Value }, Report(serde_json::Value), Error { message: String, retryable: bool }, Done, }为什么不用自然语言的“自由交流”?因为自由交流虽然灵活,但没法保证可编排性。一旦子 Agent 之间开始自由对话,你就很难预测整个系统的下一步状态,也难做断点恢复。用结构化消息的好处是:每个消息都携带明确的类型,编排器可以根据状态转移做决策;而且这种结构天然适配 Rust 的枚举类型,编译期就能检查消息使用是否合法。
在状态管理上,我踩过一个很深的坑:子 Agent 的工作状态不能保存在它自己的上下文里。因为 worker 的上下文是易失的,一旦某次调用超时,前面所有工作就白做了。所以 Agent-Reach 强制要求:worker 的关键状态必须写入黑板,黑板落在一个 SQLite 文件里。
例如,抓取 worker 每完成一个页面,就执行State { key: "fetched_pages", value: ["url1", "url2"] }更新黑板。编排器会定期从黑板读取进度,判断是否该继续分配任务或提前结束。如果某个 worker 崩溃重启,它也能从黑板恢复自己的进度。
5.3 评测集构建:怎么量化一个 Agent 好不好用
多 Agent 项目最怕的一件事:重构之后发现整体能力“感觉上”变差了,但谁都说不清差在哪。所以我在第 4 个月时,给 Agent-Reach 专门建了一套评测集。整套评测分为三层。
第一层是功能断言。比如给定一个 sample 网页,执行web_to_markdownskill,断言输出 markdown 里必须包含指定标题、链接数量大于 5、总 token 数小于多少。这层面向工具本身,不涉及模型推理。
第二层是任务成功率。我会准备 20~40 个“用户典型任务”,比如“从某个 RSS 源拉取最新 5 条文章并整理成一篇每日简报”。agent 执行完成后,人工(或者一个评分模型)按步骤完整性、结果质量、执行时间、总 token 消耗四个维度打分。
第三层是回归对比。每次修改 skill 描述、记忆策略或者编排逻辑之后,把同一套评测跑一遍,生成长度、成本、成功率的变化曲线。我一般用cargo test --release搭配一个评测脚本,跑完直接输出对比表:
| 指标 | 改动前 | 改动后 | 变化 |
|---|---|---|---|
| 任务成功率 | 75% | 82% | +7% |
| 平均执行时间 | 18s | 14s | -4s |
| 平均 token 消耗 | 42000 | 38500 | -3500 |
| 可复现比例 | 60% | 72% | +12% |
我看重“可复现比例”超过一切。如果同一个任务跑三次,三次结果差异巨大,那 agent 的可靠性就要打问号。Agent 不是写诗,它是干活,必须稳定。
热词里提到“agent 评测集构建”,这个方向我觉得目前整个行业都做得不够。很多项目 Demo 惊艳,但真让它在评测集上连续跑三天,各种低级问题全暴露了。评测集不是应付验收的工具,它是 agent 开发的“仪表盘”。
6. 我踩过的坑和后续打算
6.1 几个印象深刻的坑
第一个坑:并发写文件不加锁。早期多 worker 同时写同一个 Obsidian 目录,结果出现文件丢失和内容交错。排查了半天,发现是不同 skill 进程之间没有共享文件锁。后来所有文件写入都改走 harness 内部的write_fileAPI,由它统一加锁、排队、校验。写文件这个看似底层的操作,绝对不能交给 agent 自己临时想办法。
第二个坑:错误信息不结构化。早期 skill 返回错误时,直接返回给模型一句“Failed to fetch the page.”模型没法判断是该重试、换 URL 还是放弃。后来我把所有错误统一成{"error_type": "timeout|404|content_empty|rate_limited", "message": "...", "retryable": bool}这样的结构,agent 的行为立刻变得聪明了很多。模型的决策能力再强,也需要结构化的信息输入。
第三个坑:上下文长度判断失误。我一开始依赖模型输出的 finish_reason 判断“是不是超长了”,但这只在某些 API 里可靠。后来自己在 harness 层做硬性预算:维护一个“当前上下文 token 估算器”,在每轮调用前检查剩余额度,不够就触发摘要或清理。这个机制听起来简单,但极大减少了“突然超长”的中断。
第四个坑,也是我想特别提醒你的:别让 agent 自动修改自己的 skill 配置。早期我为了“聪明”,允许 agent 根据运行经验修改SKILL.md里的参数描述,结果它为了通过评测,把描述改得越来越激进,把超时时间从 15 秒改成 120 秒,最后整个流程慢到没法用。技能描述和配置应该由人类维护,agent 可以提建议,但写回权限必须收走。这是治理问题,不是技术问题。
6.2 给想入坑 Agent 开发的人几条学习路线建议
结合我自己从零到一的过程,我给你一条相对平滑的 agent 学习路线。
第一步,别急着写框架,先用现成的 API 做一次手工的“模型循环”。用一个 Python 脚本,循环调用 Chat Completions API,把上一次的回复拼进下一次请求,实现一个最简单的 agent 循环。先体会“模型输出是文本,工具调用是文本,上下文是文本”这个核心事实。
第二步,理解 function calling 机制。不用框架,手工定义 JSON Schema,让模型填参数,你用代码执行后把结果回传。这个阶段你会真正理解“描述准确性”和“参数校验”的重要性。
第三步,开始用轻量框架,比如直接调 OpenAI 或 Anthropic 的 SDK,配合一个简单的执行引擎,搭一两个实用 skill。我建议你选一个最打动你的场景,比如“网页保存 markdown”“定时抓取股市数据”“自动整理周报”,把它做得足够顺滑。
第四步,尝试把记忆、沙箱、评测集纳入项目。这一部分其实就是这篇博文的主体内容。你会发现,agent 开发最后比拼的不是模型指令词,而是工程化能力。
如果你倾向于全栈理解,那么 Rust 这个方向值得投入。它让你在写并发、写出安全代码、处理外部副作用时得到编译器的大量帮助。tokio+reqwest+serde这三板斧够你写出一个初具规模的 agent 运行时。热词里提到的“基于 rust 语言 ai agent”,目前还远没有 Python 生态成熟,但恰恰因为竞争者少,好项目更容易被看到。
6.3 项目后续的方向
Agent-Reach 目前已经能支撑我日常的网页收集、笔记整理和多 agent 调研工作。我下一个阶段想做两件事。
第一件事是把 skill 发布机制做成一个真正可用的“商店”。用户可以一键从远程仓库拉取某个 skill,并自动校验它的声明权限是否超过最小必需。这一点也是从 agent 安全角度出发的,因为技能越多,攻击面越大。第二件事是做一个视觉化的事件回放工具,让 agent 每次运行的每一个动作都能像视频时间轴一样回放。调试 agent 跟调试普通程序不一样,你需要看的是“它为什么在那一步选择了那个动作”。
应该会有很多人想问:Agent-Reach 会不会开源?我的计划是,等 skill 商店和事件回放这两个基础设施稳定之后,直接以项目仓库形式开源,包括整套评测集。毕竟 agent 类项目最有价值的不是代码,而是围绕代码沉淀下来的一整套试验方法和避坑经验。
如果看完这篇博文,你脑子里浮现出“原来 agent 框架还可以这样拆”这种感觉,那我的目的就达到了。Agent 开发远没有到“抄作业就行”的阶段,每一个项目都值得从架构层面认真想一遍。我的经验是:先把 harness 和 agent 的边界划清楚,再让技能做小做独立,最后用评测集检验一切。这条路线,我走了一年,很值得。