Harness 的实践:使用skill search 提高 skill 调用准确度

最近给自己的 Agent 做了一次关键的改造。表面上看,只是新增了一个 Skill Search 工具,但真正改变的,是 Agent 的工作方式。 以前 Skill 的调用非常不稳定。明明已经很明确告诉它"搜索天气"“搜索新闻”,也提供了相应的工具,但它就是不能自动触发。尝试优化提示词、改进 Skill 描述,做了很多尝试,效果都不理想。 后来看到 Claude Code 的源码,里面有一个 Tool Search 机制:每次使用工具之前,先查询一下有没有可用工具。受这个启发,我做了一个 Skill Search 工具,希望在 Agent 触发能力边界时——比如需要搜索网络、写脚本、调用外部命令时——先检查有没有现成 Skill 可以用,而不是从头造轮子。 核心问题 原来的 Skill 调用机制是这样的:把所有 Skill 的名字和描述都塞进系统提示词里,然后告诉模型"如果当前任务适合某个 Skill,就优先使用"。 这个思路一开始是成立的,模型确实"看得到"这些 Skill,也能在某些场景下主动调用。但真正用久了之后,问题就暴露出来了。 只有显式调用才稳定。当直接输入 /web-search 或明确指定某个 Skill 时,没问题——因为这时候不是模型在判断,而是用户替它做了决策。但真实使用中,用户更常见的表达是: “帮我搜一下这个话题” “去网上查一下最近有什么信息” “看看有没有现成工具能做这件事” “帮我处理一下这个文件” 这些输入对人类来说已经足够明确,大家都知道这时候应该优先检查 Skill。但模型不是每次都这么做。很多时候,明明已经有现成 Skill,它还是直接跳过去,自己动手。 根本原因不是 Skill 描述不够好,而是机制本身有问题。 原来的调用流程太长了:模型先看用户输入,再判断是否需要执行任务,再回忆提示词里有没有对应 Skill,再匹配描述,最后才决定要不要调用。只要其中任何一步松掉,它就会进入更省事的路径:自己来做。 随着 Skill 越来越多,问题还会继续恶化。Skill 越多,提示词越长,模型越容易漂移。这些 Skill 只是混在上下文里的动态信息,对模型来说不是强制执行的流程,只是可能参考的背景材料。 改造方案 核心上做了三件事。 1. 从隐式到显式 把 Skill 从"提示词中的隐式能力"变成"运行时中的显式能力"。新增真正的 skill_search,让 Agent 在面对非纯文本任务时,不是默认自己动手,而是先查有没有现成 Skill。 ...

2026-06-12 · 2 min · 424 words

我在真实 Agent 产品里落地 Sandbox 的全过程

我一开始以为,给 Agent 加 Sandbox 这件事并不复杂: 把 bash 套进隔离层 限一下文件系统 限一下网络 再处理一下环境变量 但真把它放进一个真实产品里,问题马上就不是“能不能隔离”,而是: 既要让 Agent 真能干活,又不能让它顺手把宿主机掀了。 这次我在自己的 Agent Runtime 里,先后被两个非常具体的场景逼着重构权限模型: curl 在沙箱里访问网络,一直报错 agent-browser 要打开网页并截图,但它本质上不是普通网络请求,而是宿主浏览器能力 最后我做出来的,不只是一个 Shell Sandbox,而是一整套: bash 执行边界 Host Capability 审批 白名单复用 自动续跑 配置脱敏 多渠道结构化审批 这篇文章,我就完整讲讲这套东西是怎么从真实问题里长出来的。 我在真实 Agent 产品里落地 Sandbox 的全过程 从 curl 报错,到 agent-browser 审批升级,我是怎么把权限、审批、配置安全真正做成产品能力的 如果你最近在做 Agent,而且这个 Agent 不是纯聊天,而是真的会: 调 bash 装依赖 读写文件 连网 调本机工具 打开网页、截图、控制浏览器 那你迟早会遇到一个问题: “让 Agent 能干活”和“让 Agent 不乱来”之间,根本不是加一个开关就能解决的。” 一开始我也以为,所谓 Sandbox,无非就是: 把 bash 套进一个 OS-level sandbox 限文件系统 限网络 再处理一下环境变量 听上去很合理。 但真把它放进一个真实产品里,你很快就会发现: ...

2026-06-12 · 8 min · 1664 words

别让 AI Agent 在你的电脑上裸奔:主流沙箱方案全景解析与 Anthropic Sandbox Runtime 深度拆解

过去一年,Agent 的能力边界被迅速拉高。它不再只是“会聊天的大模型”,而是在越来越多的场景里真正拥有了“手脚”:能写代码、改文件、跑测试、装依赖、发请求,甚至直接操作本地终端。 但问题也恰恰出在这里。 一旦 Agent 可以直接在开发机上执行命令,它就不再只是一个推理系统,而变成了一个半可信执行体:正常情况下它是高效助手,异常情况下它也可能是一个“拿着系统权限的自动脚本”。模型幻觉、Prompt Injection、第三方仓库里的恶意指令、错误的工具调用路径,都会把风险从“回答错了”升级为“真的把你的环境改坏了”。 于是,一个绕不开的问题摆在所有 Agent 产品面前: 怎么让 Agent 真正自动化地干活,同时又不把宿主机暴露在不可控风险里? 这就是 Agent Sandbox 的价值所在。 “系统安全能力的下限,决定了 Agent 自动化能力的上限。” 问题 在没有成熟沙箱之前,最常见的办法是“人工确认”:Agent 每执行一步命令,每改一次文件,都弹窗询问用户要不要继续。 这种做法看起来安全,但实际上只解决了心理安慰,并没有真正解决底层风险。 第一,它会快速演变成严重的中断疲劳。一个稍微复杂一点的重构任务,可能要经历十几次读写文件、数十次 shell 调用、若干次网络请求。每一步都确认,Agent 的自动化价值会被彻底抵消。 第二,它对真实攻击并不可靠。开发者并没有足够的时间在一秒钟内审完一长串 bash 命令,更不可能靠肉眼持续识别被混淆过的脚本、链式调用或隐蔽的外带逻辑。换句话说,弹窗确认本质上是在把安全责任转嫁给用户,而不是在系统层面建立边界。 真正可持续的方案不是“每一步都问你”,而是: 默认把 Agent 放进一个边界明确的运行区域; 边界内自动执行,不打扰用户; 一旦越界,由底层机制直接拦截,而不是事后追责。 这就是现代 Agent 沙箱的核心设计目标:把安全从“交互层提醒”下沉到“执行层约束”。 方案演进 从当前行业实践看,Agent 沙箱大致形成了三条路线。它们并不是谁绝对淘汰谁,而是分别适合不同的产品形态。 1. 容器型沙箱 这一类方案通常基于 Docker 或容器池,把代码执行环境封装进独立容器,再通过 API 或任务调度系统与 Agent 主流程解耦。 它的优势很明显:环境一致性好,依赖管理成熟,易于做多租户调度,也方便把环境变量、文件系统和网络策略统一配置。很多云端 Agent 平台、代码执行服务、Browser + Code 一体化沙箱都属于这一路线。 但它的局限同样明显: 如果你的目标是“让 Agent 直接辅助用户本地开发”,Docker 会显得偏重。你需要处理 volume 映射、UID/GID、路径同步、宿主文件状态与容器视图的一致性,以及本地开发工具链与容器内部环境的错位问题。它更适合“把任务送进一个隔离盒子里执行”,而不天然适合“在用户当前工作区无缝协作”。 2. MicroVM 型沙箱 这一类典型代表是 Firecracker 体系或基于它的代码执行平台。它的优势是隔离强度极高,接近虚拟机级别,天然适合云端多租户场景,也更适合执行不可信代码。 ...

2026-05-11 · 3 min · 607 words

Claude Code 团队经验:学会用 Agent 的眼光看世界

![截屏2026-03-26 23.32.27](截屏2026-03-26 23.32.27.webp) 开发一个智能体(Agent)系统,最难的部分之一,就是怎么给它设计"工具箱"(Action Space)。 Claude 是通过调用工具(Tool Calling)来做事的。但在 Claude API 里,有各种各样的工具构建方式,比如执行 bash 命令、调用 Skills,或者最近新出的代码执行功能。 面对这么多选择,你怎么给 Agent 设计工具?是只给它一个全能工具(比如直接执行代码或 bash),还是给它 50 个工具,覆盖它可能遇到的每一种场景? 为了弄明白这个问题,我喜欢把自己代入模型。想象一下,如果给你一道很难的数学题,你希望手头有什么工具?这其实取决于你自己的能力! 给你一张纸是最低配置,但你只能手算。给你一个计算器会好很多,前提是你得知道怎么按那些高级功能键。最快、最强大的工具是一台电脑,但这要求你必须懂编程,能写代码来解题。 这是一个设计 Agent 时非常有用的思维框架。你给它的工具,必须跟它的能力相匹配。 可是,你怎么知道它有多大能耐呢?答案是:去观察它,去读它的输出,去不断实验。你要学会"用 Agent 的眼光看世界"。 在开发 Claude Code 的过程中,我们一直在观察 Claude。下面是我们学到的一些经验。 改进提问方式与 AskUserQuestion 工具 我们在开发 AskUserQuestion 这个工具时,目标是让 Claude 更擅长向用户提问(这通常被称为激发,elicitation)。 虽然 Claude 本来就能用纯文本问问题,但我们发现,回答这些问题通常很费时间。我们该怎么降低这种摩擦,让用户和 Claude 的沟通更高效呢? 尝试 1:修改 ExitPlanTool 我们最初的想法是,在现有的 ExitPlanTool(退出并输出计划的工具)里加一个参数,让它在输出计划的同时,也输出一组问题。这是最容易实现的方法,但它把 Claude 搞糊涂了。因为我们让它同时做两件事:一边给计划,一边问跟计划相关的问题。如果用户的回答和计划冲突了怎么办?Claude 是不是得再调用一次 ExitPlanTool?显然,这条路走不通。 尝试 2:改变输出格式 接着,我们尝试修改 Claude 的系统提示词,让它输出一种特定格式的 Markdown,用来表示问题。比如,我们可以要求它输出一个列表,括号里写上可选项。然后我们通过解析这个格式,在终端里渲染出一个漂亮的提问界面。 这看起来是个通用的改动,Claude 似乎也能做到,但这并不可靠。Claude 有时会多加几句话,有时会漏掉选项,或者干脆用了别的格式。 尝试 3:推出 AskUserQuestion 工具 ...

2026-03-26 · 1 min · 211 words

5个ADK开发者必须掌握的Agent Skill设计模式

名词解释 ADK: Agent Development Kit(Agent 开发工具包) 最近使用 AI 写代码用到了很多 SKILL,但是每个人写的 SKILL 都不同,没有一个公共的标准或者模式,最近看到Google Cloud 技术团队的一篇文章,很有启发,翻译成中文,大家可以参考一下。 说到SKILL.md,开发者往往过于关注格式——怎么写YAML、怎么组织目录、怎么遵循规范。但现在已经有30多个Agent工具(比如Claude Code、Gemini CLI、Cursor)都采用了相同的布局,格式问题基本上已经解决了。 现在的挑战是内容设计。规范解释了怎么打包一个Skill,但对Skill内部的逻辑结构完全没有指导。比如,一个封装FastAPI约定的Skill,和一个四步文档生成流水线,虽然它们的SKILL.md文件看起来一模一样,但运作方式完全不同。 通过研究整个生态系统中Skill的构建方式——从Anthropic的代码库到Vercel和Google的内部规范——我们发现了五种反复出现的设计模式,可以帮助开发者构建更好的Agent。 作者 @Saboo_Shubham_ 和 @lavinigam 本文将介绍每种模式,并附带可用的ADK代码示例: Tool Wrapper:让你的Agent瞬间成为任何库的专家 Generator:从可复用模板生成结构化文档 Reviewer:按严重程度对代码进行清单式评分 Inversion:Agent在行动前先采访你 Pipeline:通过检查点强制执行严格的多步工作流 模式1:Tool Wrapper Tool Wrapper让你的Agent按需获取特定库的上下文。你不是把API约定硬编码到系统提示词里,而是把它们打包成一个Skill。你的Agent只在真正用到该技术时才加载这些上下文。 这是最简单的实现模式。SKILL.md文件监听用户提示词中的特定库关键词,动态加载references/目录下的内部文档,并将这些规则视为绝对真理。这正是你将团队内部编码规范或特定框架最佳实践直接分发到开发者工作流中的机制。 下面是一个Tool Wrapper示例,教Agent如何编写FastAPI代码。注意指令如何明确要求Agent只在开始审查或编写代码时才加载conventions.md文件: # skills/api-expert/SKILL.md --- name: api-expert description: FastAPI开发最佳实践和规范。在构建、审查或调试FastAPI应用、REST API或Pydantic模型时使用。 metadata: pattern: tool-wrapper domain: fastapi --- 你是FastAPI开发专家。将这些约定应用到用户的代码或问题中。 ## 核心约定 加载'references/conventions.md'获取完整的FastAPI最佳实践列表。 ## 审查代码时 1. 加载约定参考文件 2. 将用户代码与每个约定进行比对 3. 对每个违反项,引用具体规则并建议修复方案 ## 编写代码时 1. 加载约定参考文件 2. 严格遵循每个约定 3. 为所有函数签名添加类型注解 4. 对依赖注入使用Annotated风格 模式2:Generator Tool Wrapper是应用知识,而Generator则强制产生一致的输出。如果你苦于Agent每次运行都生成不同的文档结构,Generator通过填空式流程解决了这个问题。 ...

2026-03-19 · 2 min · 261 words

Claude Code 开发者的一些使用建议(中文版)

Claude Code 开发者的一些使用建议 作者:Boris(Claude Code 的创造者) 译者:Claude 日期:2026年3月17日 我是 Boris,Claude Code 的创造者。我想快速分享一些来自 Claude Code 团队的使用建议。团队使用 Claude 的方式和我个人使用的方式不太一样。记住:使用 Claude Code 没有唯一正确的方式——每个人的配置都不同。你应该多尝试,找到适合自己的方法! 1. 多任务并行处理 同时启动 3-5 个 git worktree,每个运行独立的 Claude 会话。这是最大的生产力提升点,也是团队的首要建议。就我个人而言,我使用多个 git checkout,但大多数 Claude Code 团队更喜欢 worktree——这正是 @amorriscode 在 Claude Desktop 应用中内置支持 worktree 的原因! 有些人还会给 worktree 命名,并设置 shell 别名(za, zb, zc),这样一键就能在它们之间切换。还有人专门设置一个"分析" worktree,只用于读取日志和运行 BigQuery。 参考:https://code.claude.com/docs/en/common-workflows#run-parallel-claude-code-sessions-with-git-worktrees 2. 复杂任务先从 plan 模式开始 把精力投入到计划中,让 Claude 一次性完成实现。 有人会让一个 Claude 写计划,然后启动第二个 Claude 以高级工程师的身份审查它。 另一个人说,一旦事情开始偏离轨道,就切换回 plan 模式重新规划。不要硬撑下去。他们还明确告诉 Claude 在验证步骤时进入 plan 模式,而不仅仅是在构建时。 ...

2026-03-19 · 2 min · 241 words

Agent Tool Call:从“对话”到“执行”的工程实践

在使用大模型的过程中,你肯定发现目前的大语言模型(LLM)在逻辑推理、代码编写和文本生成方面表现优异。但是,它们都有一个共同的局限:无法直接干预外部世界。 如果你要求模型“查询订单状态”或“发送一封邮件”,它通常会回复:“对不起,我无法访问您的数据库。”这是因为模型本质上只是一个预测下一个 Token 的概率模型,并没有直接访问系统资源的权限。 Tool Call(工具调用,也称 Function Calling)的出现,正是为了给模型安装上“手脚”,让它能够通过结构化的方式与外部系统交互。 ## 一、 核心概念:决策与执行分离 ![截屏2026-03-09 22.39.50](截屏2026-03-09 22.39.50.png) 理解 Tool Call 的关键在于:模型本身并不执行代码,它只负责决策。 我们可以将其理解为“指挥官”与“执行官”的关系: 模型(决策者):负责判断“当前需要调用哪个工具”、“需要传入什么参数”。 程序(执行者):负责运行真实的后端逻辑,如数据库查询、发送邮件、鉴权、限流等。 这种“决策与执行分离”的架构,确保了系统的安全性。模型产生的只是一个 JSON 格式的调用指令,真正的执行权限始终掌握在开发者手中,而不是交给模型。 二、 通用工作流 无论是查询数据(读操作)还是执行动作(写操作),在工程上通常遵循以下五个步骤: 定义工具:开发者向模型描述可选工具的功能(建议使用动词命名,如 get_order_status)及其参数规格(使用 JSON Schema)。 发送上下文:将用户问题与工具清单一并发送给模型。 模型决策:模型判断当前问题是否需要工具。如果需要,它会返回一个结构化的响应,包含工具名、参数及唯一标识符 call_id。 本地执行:程序解析参数,调用真实的 API 或数据库,并获取结果。 生成回答:程序将执行结果回传给模型,模型结合结果生成最终的自然语言回复。 三、 Tool Call Schema 详解 Schema 是模型与程序之间的“契约”。定义得越严谨,模型调用的准确率就越高。 1. 结构示例 { "type": "function", "function": { "name": "get_order_status", "description": "根据订单号查询订单状态与物流信息", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "description": "订单号,例如 1001" } }, "required": ["order_id"], "additionalProperties": false }, "strict": true } } 2. 字段含义与最佳实践 字段 说明 最佳实践 name 工具的唯一标识符 使用动词式命名,如 get_order_status description 工具的用途说明 越详细越好:说明适用场景、限制条件及返回格式 parameters 参数定义 每个参数都应包含 type 和 description required 必填参数名数组 明确模型必须提供的字段 additionalProperties 额外参数 设为 false,防止模型生成多余参数 strict 严格模式 设为 true,强制模型输出符合 Schema 的 JSON 3. 一个“好”的描述长什么样 差的描述: ...

2026-03-09 · 2 min · 375 words

如何实现一个极简的 Agent

![如何实现一个极简的 Agent-cover](如何实现一个极简的 Agent-cover.webp) 如何从 0 实现一个极简 Agent 这两年大家一提 Agent,脑子里很容易浮现出一个“会思考、会规划、会调用工具、还会自我修复”的高级智能体。听起来很玄,但如果把那些花哨概念都剥掉,一个能跑起来的极简 Agent,其实没有那么复杂。 说到底,它就两件事: 一个持续运行的 while 循环。 一套精心设计的上下文工程。 大模型本身既没有状态,也没有手脚。它只负责在当前上下文里做判断:这轮该说话,还是该调用某个工具;如果调用工具,工具名是什么,参数应该怎么填。真正读文件、执行命令、写入内容、保存记忆、控制权限的,都是你写的程序。 所以 Agent 的核心从来不是“让模型像人一样思考”,而是:如何把合适的信息在合适的时机交给模型,再把模型的决策稳稳地落到执行环境里。 这篇文章就结合我手头这套玩具代码,从 0 到 1 拆一下:如何把一个看起来很复杂的 Agent,拆成几个可以逐步实现的小能力。 先讲结论:Agent 的最小闭环是什么? ![如何实现一个极简的 Agent-loop](如何实现一个极简的 Agent-loop.webp) 一个最小 Agent,至少要有下面这条闭环: 用户提出任务 -> 模型判断是否需要工具 -> 程序执行工具 -> 把执行结果回填给模型 -> 模型继续决策 -> 直到模型不再调用工具,输出最终答案 这个流程也可以写成更工程化一点的五步: 定义工具,并用 JSON Schema 描述参数约束。 把用户消息、系统提示词、工具清单一起发给模型。 模型返回普通文本,或者返回 tool_call。 程序解析 tool_call,在本地执行真实工具。 将工具结果作为 tool 消息带回模型,进入下一轮。 只要这条链打通,一个最简 Agent 就已经成立了。 为什么说本质是 while 循环? 因为 Agent 和普通聊天机器人的根本区别,不在于“更聪明”,而在于“能继续行动”。 普通聊天模型通常是一次请求、一次回复,停在那里。Agent 则是在程序外面再包一层循环,让它可以不断经历: Think -> Act -> Observe -> Think 这在代码里其实非常朴素。simple-agent.py 里就是典型的双层循环: ...

2026-03-06 · 5 min · 934 words