news 2026/10/14 9:37:40

Agent Skills 技能体系设计实战:从零构建可维护、可测试的智能体

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Agent Skills 技能体系设计实战:从零构建可维护、可测试的智能体

最近几周我一直在折腾一个叫agent-skills的项目,准确说不是某个开源仓库,而是我自己的一套 Agent 技能体系建设思路。折腾完之后最大的感受是:很多人把 Agent 开发想得太玄,其实真正决定它好用不好用的,往往不是底层大模型有多强,而是你给它的“技能”有没有设计好。

早先我写 Agent 的时候,习惯把所有指令、工具、流程全塞进一段 prompt 里,结果只有两种:要么它只会做我给你表演过的那几个动作,换个场景就废;要么它自由发挥,跑偏了你还不知道在哪偏的。后来我把整条链路上能拆出来的能力全部“技能化”——也就是封装成一个个带描述、带输入输出约定、带容错策略的独立模块,Agent 只负责调度,技能只负责执行。这套重构之后,项目的可维护性、可测试性、可扩展性提升了一个量级。

这篇文我打算把从零设计一套 agent-skills 体系的完整过程写下来。包括 Skills 到底是什么、接口怎么定、文件怎么组织、代码怎么落地,还有我在实际项目中踩过的坑和排查方法。适合正在做 Agent 应用开发、想把自己那堆“函数 + prompt”升级成正式技能体系的开发者参考。如果你只是写 demo 玩,可能体会不深,但一旦你要维护一个复杂的多智能体系统,这套东西迟早用得上。

1. Skills 到底在解决什么问题

1.1 一个 Skill 的本质

先说我的理解:Skill 不是“把功能函数再包一层”的概念,而是把一个 Agent 应该具备的能力,封装成一个自包含的执行单元。这个单元里至少要有四样东西:

  • 元信息:这个技能是干什么的、什么时候该用、什么时候不该用。
  • 入口约定:接收什么参数、输出什么结构。
  • 执行逻辑:具体怎么做,可能调一个外部 API,也可能组合多个步骤。
  • 异常与边界处理:失败了怎么办、超时怎么办、数据格式不对怎么办。

打个比方:如果把 Agent 比作一个餐厅后厨,那 Skills 就是后厨里一个个熟练掌握的菜品技能。厨师(Agent)不需要知道“糖醋排骨”的每一克调料的配比细节,它只需要知道这道菜的名字、口感方向、大概需要哪些备料,然后喊一声“做糖醋排骨”,后厨就把活儿干完了。干完端上桌,还能告诉你“今天的排骨偏瘦,建议下次换五花”。

这个类比里最关键的一点是:Agent 不关心技能的内部实现,但它必须能从外部准确判断该不该点这个技能。这就决定了 Skills 体系设计的核心工作,其实都集中在“元信息”和“接口约定”上,而不是内部逻辑。

1.2 为什么碎片化能力会让 Agent 变“傻”

我见过很多半成品项目,代码结构大概是这样的:一个大模型调接口、一个 2000 行的工具函数文件、一个写满规则和例子的 prompt。这种“三座大山”架构在 demo 阶段完全没问题,但一旦任务变复杂,问题立刻暴露。

第一个问题是Agent 不知道自己“会什么”。你把一堆函数堆给它,它只知道函数名和短描述,遇到一个需要综合判断的任务,它根本不知道应该把哪几个能力组合起来。比如你要做“把上周的所有销售周报整理成一份分析 PPT”,这背后可能需要数据查询、摘要提取、图表生成、幻灯片排版四个能力。如果你没有把这些能力显式地声明成“技能”,大模型大概率只会用第一直觉选其中一个函数,然后硬编出一份非常粗糙的结果。

第二个问题是技能内部一多,prompt 上下文就炸。我在一个项目里曾经把所有工具的说明全塞进 system prompt,当时有 40 多个工具,描述加起来超过 8000 token。结果发现模型越来越“犹豫”,每个工具它都看过,但每个都不敢用,更可怕的是核心任务的上下文被压缩了。把技能独立出来后,prompt 里只有当前任务需要的技能描述,上下文干净很多,决策速度也上来了。

第三个问题,也是要命的:无法测试、无法排查。所有逻辑都写在 prompt 里的时候,你根本没法给单步逻辑写单测。我把技能抽出来之后,每个技能都可以单独跑、单独测、单独加日志,哪里挂了查哪里。这一步改造带来的收益,很快就在一次第三方 API 连续报错的问题排查中体现出来——我只看技能执行日志就定位到了是哪一步的参数填充错了,而不是对着大模型的返回内容猜。

1.3 Skills 与工具集、插件、Workflow 的区别

这里想特意说一下几个概念的边界,因为很多人在设计时把混在一起。

概念侧重点例子
工具(Tool)原子能力,无状态,不关心调用时机发送 HTTP 请求、读文件、计算 MD5
技能(Skill)原子能力 + 意图判断 + 执行流程 + 容错,自带边界从网页抽取正文并生成摘要、根据数据自动画图表
工作流(Workflow)多个技能按固定顺序编排,有向无环图先查数据,再生成图表,最后套 PPT 模板
插件(Plugin)通常是第三方生态里的功能包,粒度可大可小一个能接入某电商平台数据的能力包

在 agent-skills 的体系里,我认为 Skill 是承上启下的核心单元:它向上可以被 Workflow 编排,向下可以调用多个 Tool。我甚至会把一个复杂 Skill 的内部实现再拆成几个内部子技能,这样每个子技能都有独立的描述和失败策略,组合起来却像一次“业务操作”。

2. 设计一套 Skills 体系:地基怎么打

2.1 目录结构与文件组织

设计 Skills 体系第一件事,就是确定代码组织方式。我这里分享一个在模拟项目 X 里反复调整后稳定的目录结构:

skills/ common/ toolkit_http/ skill.yaml __init__.py text_utils/ skill.yaml __init__.py content/ webpage_summarizer/ skill.yaml __init__.py requirements.txt document_parser/ skill.yaml __init__.py report_generator/ skill.yaml __init__.py data/ sql_queryer/ skill.yaml __init__.py chart_renderer/ skill.yaml __init__.py

每个技能目录里,skill.yaml是元信息文件,__init__.py暴露执行入口,requirements.txt声明依赖。目录分类按照能力域分:common放通用能力,content放内容处理,data放数据能力。这样 Agent 在做意图路由的时候,可以只浏览分类目录,缩小技能匹配范围,而不是在所有技能里全量搜索。

这套结构看起来简单,但它的价值是把“技能元数据”和“技能实现”彻底解耦。Agent 加载技能时,先读skill.yaml,通过元信息判断该不该用;真要调用时,才去 import 具体实现。这样加载阶段非常轻量,几十个技能的扫描时间基本可以忽略。

2.2 接口规范:输入输出、异常处理

技能接口是整个体系里最容易改来改去、也是越改越乱的部分。我的经验是尽早定死,情愿一开始多思考,也绝不在写了 20 个技能之后再统一重构。

接口规范分两层:

第一层是技能的入口定义。标准做法是每个技能暴露一个统一方法,比如:

def execute(context: SkillContext, params: dict) -> SkillResult: ...
  • context里带着共享状态、调用链信息、全局配置。
  • params是本次调用的具体参数。
  • SkillResult是标准化返回,至少包含 status(成功/失败/部分成功)、data、message、trace_id、消耗指标。

第二层是参数定义。我不建议只靠params字典传参,会导致技能内部到处params.get("xxx", default),丑且难维护。更好的做法是让每个 skill 声明自己的输入参数结构,然后在执行入口做一次参数校验,校验失败直接返回结构化的错误,而不是让技能内部代码去处理脏数据。

关于异常处理,我习惯强制每个技能捕获所有可能的外部异常,并返回统一的SkillResult(status="failed", message="..."),同时把异常堆栈写入日志。为什么这么做?因为在 Agent 链路上,技能失败是常态,Agent 需要根据失败原因决定重试、换策略还是直接放弃。如果技能抛一个没有任何结构化信息的异常,Agent 只能一脸茫然地瞎猜,容易原地打转。

2.3 元数据声明:Agent 靠什么“看见”技能

skill.yaml是技能的门面,Agent 对大模型侧的“技能可见性”完全依赖它。一个合格的元信息文件,至少应该包含这些字段:

  • name:技能名,全局唯一,尽量用全局视野来命名,别太口语化。
  • description:一段面向大模型的自然语言描述,回答“这个技能做什么、什么场景用、什么场景禁用”。
  • parameters:入参结构,包含每个参数的类型、必填性、说明。
  • tags:分类标签,辅助路由。
  • timeout:执行超时时间。
  • permissions:权限声明,比如是否需要网络、是否需要文件写入。
  • allowed_tools:技能内部允许调用的工具白名单。

我当时在description上踩过坑,早期写得特别简短,比如“生成图片的 URL”,模型经常在不需要图片的时候调用它。后来我按“正向 + 反向 + 边界”三个维度重写描述:先说适合什么,再说不适合什么,最后说必须满足什么条件才可以用。例如:

description: | 用于从远程 URL 抓取网页正文并生成中文摘要。 适用场景:用户提供链接,要求总结文章内容。 不适用场景:用户没有给链接、需要搜索资料、或要求英文摘要。 边界条件:仅支持静态 HTML 页面;需要联网;抓取超时上限 5 秒。

这样模型判断时就会非常明确,误调用率下降特别明显。

2.4 命名规范与分类策略

命名这件事看起来是个小事,但实际影响很大。因为技能名会出现两种地方:一是代码 import 路径,二是大模型在“思考过程”里看到的文本。命名一旦不规范,模型就经常出现幻觉技能名——它可能参考几个相似技能的名字,组合出一个根本不存在的新名字。

我的命名规范是三元组:域_动作_对象。比如:

  • data_query_sales_orders:数据域,查询销售订单。
  • content_summarize_webpage:内容域,摘要网页。
  • doc_generate_ppt_from_markdown:文档域,从 Markdown 生成 PPT。

这个命名风格的好处是天然支持“按前缀做意图聚类”。我给 Agent 的调度层写过一个匹配逻辑:先从用户指令里抽出的关键词映射到域,再映射到动作,最后锁定对象,这样匹配速度比全量语义检索快得多,而且可解释。

分类策略上,我建议分类不要超过两层。我见过有项目把技能分成“数据处理-文本处理-中文文本处理-繁体中文处理”这种四级目录,结果模型根本分不清该用哪一级,调度准确率反而不如平铺结构。保持目录浅、描述精准,比追求分类严谨更实际。

2.5 版本与依赖管理

技能一定会迭代。今天一个技能还只支持表格数据,明天你给它加了图表能力,如果版本管理不好,就会出大乱子——工作流里调的是旧版本,测试环境调的是新版本,生产环境是含 bug 的上一版本。

我目前在项目里采用两套机制:

  1. 技能级版本号:每次修改skill.yaml或实现文件,就更新version字段。调度层在日志里记录“哪个版本被执行”,线上问题一复查就知道是哪个版本引起的。
  2. 依赖锁定:每个技能目录里的requirements.txt明确锁版本。特别注意:技能之间也可能互相依赖,这种依赖关系我会在skill.yaml里用depends_on声明。加载器会做依赖拓扑排序,先加载依赖技能,再加载当前技能,避免import时缺东西。

3. 从零实现一个 Skill:实操全流程

3.1 场景规划:先画边界再写代码

直接撸代码是大忌。我现在的流程是:先选择一个有语义闭环的场景,给这个技能画边界。

我用“网页内容归纳”作为示例场景。需求是用户丢一个 URL,Agent 抓取页面、去噪、提取正文、生成 200 字以内的中文摘要,并返回来源链接。

边界画下来是这样:

  • 输入:url、目标语言(默认中文)、最大摘要字数(默认 200)。
  • 输出:结构化结果,包含 title、content_preview、summary、source_url、fetch_status。
  • 不做的事:不做情绪分析、不做关键词抽取、不处理需要登录的页面。
  • 失败条件:URL 非法、页面非 HTML、抓取超时、正文为空。

这些边界定义完整后,我才开始建目录、写skill.yaml。

3.2 核心代码落地:一个内容归纳技能

目录建好后,实现核心逻辑。这里我贴一个简化版本,重点不是实现本身,而是展示“技能内部按层级组织”的思路:

# skills/content/webpage_summarizer/__init__.py import time from html.parser import HTMLParser from urllib.request import Request, urlopen class SkillError(Exception): pass def _validate(params: dict) -> dict: url = params.get("url", "") if not url.startswith(("http://", "https://")): raise SkillError(f"invalid url: {url}") lang = params.get("lang", "zh") max_len = int(params.get("max_len", 200)) return {"url": url, "lang": lang, "max_len": max_len} def _fetch_html(url: str) -> str: request = Request(url, headers={"User-Agent": "agent-skills/1.0"}) with urlopen(request, timeout=5) as response: content_type = response.headers.get("Content-Type", "") if "text/html" not in content_type: raise SkillError(f"not a html page: {content_type}") return response.read().decode("utf-8", errors="ignore") class _TextExtractor(HTMLParser): def __init__(self): super().__init__() self._text = [] self._skip = 0 def handle_starttag(self, tag, attrs): if tag in ("script", "style"): self._skip += 1 def handle_endtag(self, tag): if tag in ("script", "style") and self._skip > 0: self._skip -= 1 def handle_data(self, data): if self._skip == 0: self._text.append(data.strip()) def get_text(self): return "\n".join(t for t in self._text if t) def _summarize(text: str, lang: str, max_len: int) -> str: # 实际项目里这里会调用大模型做摘要,这里简化为截取前 max_len 字符 if lang == "zh": return text[:max_len] return text[:max_len] def execute(context, params: dict) -> dict: start = time.time() try: clean = _validate(params) html = _fetch_html(clean["url"]) parser = _TextExtractor() parser.feed(html) text = parser.get_text() if not text: raise SkillError("empty page text") summary = _summarize(text, clean["lang"], clean["max_len"]) return { "status": "success", "data": { "title": parser.get_title() or "", "summary": summary, "source_url": clean["url"], "fetch_ms": int((time.time() - start) * 1000), }, "message": "", "trace_id": context.get("trace_id", ""), } except SkillError as exc: return { "status": "failed", "data": {}, "message": str(exc), "trace_id": context.get("trace_id", ""), }

这个实现里值得注意的几点:

  • _validate是独立函数,所有参数在入口就洗干净,后面代码不需要再半路判断参数。
  • _fetch_html带了超时和 content-type 检查,这两个检查是我在实际项目里被坑之后加的——很多 URL 返回的是重定向页或纯 JSON,不带检查的话技能会拿到一堆垃圾内容。
  • 异常处理在技能内部完成,绝对不裸抛异常给上层调度器。上层只需要看status == "success"还是"failed",不用关心技能内部怎么失败的。

3.3 注册与动态加载机制

光有实现还不够,关键是要让 Agent 能“看到”并“加载”这些技能。我实现过一个很轻量的加载器,思路是:

  • 启动时扫描skills/目录,读取所有skill.yaml,构建一个技能索引字典。
  • 只有等到实际调用时,才去importlib动态导入对应技能模块。
  • 每次导入之后把模块缓存起来,避免重复导入的耗时和内存开销。

加载器的核心逻辑大致是这样:

import importlib import yaml from pathlib import Path class SkillRegistry: def __init__(self, root: str): self.root = Path(root) self.index = {} self._modules = {} def scan(self): for skill_file in self.root.rglob("skill.yaml"): with open(skill_file, "r", encoding="utf-8") as fp: meta = yaml.safe_load(fp) skill_name = meta["name"] pkg_path = skill_file.parent.as_posix().replace("/", ".") self.index[skill_name] = { "meta": meta, "module": f"{pkg_path}.__init__", } def get(self, skill_name: str): if skill_name not in self._modules: entry = self.index.get(skill_name) if not entry: raise KeyError(skill_name) self._modules[skill_name] = importlib.import_module(entry["module"]) return self._modules[skill_name]

动态加载的意义不只是省资源,更重要的是允许热更新。改了一个技能的实现,只要重启加载器扫描一遍,不需要把整个 Agent 进程重启。我自己在迭代的时候经常用这个机制,改完一个技能跑一下单测,马上就能在联调环境里看到效果,效率非常高。

3.4 测试与调试技巧

每个技能都要有独立的测试入口。我强烈建议,就算项目再急,也要给每个技能写至少 3 条用例:正常路径、边界参数、异常路径。

拿网页摘要这个技能来说,测试用例大概是:

def test_summarize_success(): result = skill.execute({"trace_id": "t1"}, {"url": "https://example.com"}) assert result["status"] == "success" assert result["data"]["summary"] def test_summarize_invalid_url(): result = skill.execute({"trace_id": "t2"}, {"url": "ftp://invalid"}) assert result["status"] == "failed" assert "invalid url" in result["message"] def test_summarize_empty_page(): result = skill.execute({"trace_id": "t3"}, {"url": "https://example.com/empty"}) assert result["status"] == "failed" assert "empty page" in result["message"]

调试时有一个小技巧:在技能执行日志里加上trace_id,把“技能入参、返回结果、耗时”三样东西打出来。这个 trace_id 从 Agent 任务开始就一路透传,排查问题的时候,拿着一个任务 ID,能串出整条技能调用链。这一步基础设施看着不起眼,但等技能数量过二十个、任务链路超过五跳的时候,没有它就等于摸黑干活。

4. 常见问题与排查技巧实录

4.1 技能“抢活”导致任务漂移

实际运营过一个读数据、画图的 Agent 以后,你会发现一个很魔幻的情况:用户说“统计这个月的销量趋势”,本来应该走data_query_sales_orders+chart_renderer两个技能,结果模型突然调用了content_summarize_webpage,然后开始胡编一个网页摘要。

这个问题的根因一般是两个技能的 description 边界重叠,比如data_query_sales_orders里写了“支持将结果生成表格”,chart_renderer里也写了“可以根据数据生成表格”,模型就迷糊了。

我的排查方法:把技能索引里的 description 全部导出,人工按场景分组,看哪几个技能对同一个场景都有“适得其反”的描述,然后做三件事——收敛一个主入口、把其他技能描述改成“仅限 xxx 场景”、在元数据里加上conflict_with字段主动提示调度层。用这个方法,我把某次调度准确率从 76% 拉到了 91%,代价只是改了十几个描述文本。

4.2 上下文爆炸与技能描述侵占

Agent 会把“当前有哪些可用技能”的描述都攒在上下文里,技能一多起来,光描述就有几千 token。更糟的是,有些技能内部还要把大段工具文档也塞进上下文,结果用户的实际数据反而没地方放了。

我在这块的经验是三层隔离:

  • 全局只放索引:prompt 里只放技能名 + 一句话描述,完整 description 在意图路由命中后再注入。
  • 子技能描述按需注入:当一个技能内部需要模型判断调用哪个子技能时,才加载子技能的 description。
  • 硬性上下文预算:给每个技能调用后的返回数据设 token 上限,超出就截断或者落盘引用。

这套机制做完之后,任务上下文稳定在 4000 token 以内,大模型的指令遵循度明显回升。

4.3 外部工具调用失败与重试策略

技能内部去调第三方接口,失败是常态。常见的有:超时、限流、接口返回格式变更、认证过期。

我整理了一套重试规则,直接写在技能内部:

  • 网络超时类错误:做 2 次重试,退避时间 0.5 秒 + 1 秒。
  • 限流类错误(HTTP 429):退避 5 秒后重试 1 次,仍失败就放弃并返回限流提示。
  • 接口格式错误的:不重试,直接失败。因为重试同样会失败,浪费时间和 token。
  • 认证过期:顺手刷新 token,然后重试一次,这是很多项目最容易漏掉的一类场景。

这里有个很容易踩的坑:重试会把不太稳定的外部接口成功概率提高,但也导致了“技能整体耗时翻倍”。所以重试必须同时携带一个总超时上限,比如整个技能最多 15 秒,超过后无论重试多少次都直接返回失败。否则一个宕机的第三方接口能把整个 Agent 任务拖死,这是线上事故级别的坑。

4.4 安全边界与权限控制

技能体系一旦搭起来,安全隐患会被放大。因为每个技能都相当于一个可以被模型按需调用的“遥控器”,不加权限控制,等于把大门钥匙交给了模型。

我的安全控制经验是:

  • 每个技能在skill.yaml里声明所需权限,比如network: yes/low_timeout、filesystem: read_tmp_only、exec: no。
  • 权限声明不是摆设,调度层会做一次校验。技能要请求网络,但权限声明里没有,直接拒绝调用并记录异常。
  • 涉及文件读取的技能,统一强制让路径落在沙箱目录里面。我在某次排查中发现一个“读取文档预览”的技能竟然能接受任意文件路径,当时吓出一身冷汗,马上加了路径白名单校验。
  • 对于技能内部会执行代码的场景(比如数据科学类技能),额外加一层执行环境隔离,不让它在 Agent 主进程内运行。

4.5 冷启动与性能优化

技能多了之后,冷启动扫描也会成为问题。虽然我只在启动时读 YAML、不 import 模块,但如果技能目录在网络盘上,I/O 也会拖累启动速度。

我的优化方法有三个:

  • 扫描结果缓存为一个索引文件,只有skill.yaml的 mtime 变化时才重建。
  • 技能实现模块使用懒加载,绝不冷启动全量 import。
  • 高频技能可以预热,在启动脚本里主动 import 前 5 个最常用的技能,避免任务首次调用时等待 import 时间。

我实测过一个小项目,30 个技能的冷启动扫描时间从接近 200ms 降到了 20ms 左右,代价就是一份 30 行的索引缓存文件。

5. 进阶:多技能协同与编排

5.1 三种协同模式:串行、并行、条件路由

单一技能再完美,也只是积木。真正体现 agent-skills 设计水平的,是技能之间的协同方式。

我做过的项目里最常见的是三种模式:

  • 串行流水线:A 技能的输出作为 B 技能的输入。比如document_parser解析出 PDF 文本,再交给content_summarize_text生成摘要。这种模式的坑在于:上游给下游传参时,字段名和结构一定要配对,否则下游容易产生类型错乱。
  • 并行分治:一个任务拆成多个互不依赖的子任务,同时跑多个技能。比如分析一份年报,可以同时让三个技能分别处理财务数据、管理层讨论、风险提示。并行时要特别注意共享资源的写冲突,我给每个技能分配独立的结果缓冲区,最后统一聚合。
  • 条件路由:根据第一步的结果决定下一步走哪个分支。这一步最好别让模型自由发挥,而是用一个明确的规则函数去路由。比如摘要技能返回status == "failed"且原因是“页面非 HTML”,那下一个技能应该走search_webpage_text,而不是再重试一次。

5.2 共享状态与跨技能记忆

很多需要多技能协作的任务,中间状态必须能被各个技能看到。比如 Agent 要先确认用户身份,后续所有技能都需要带上用户 ID。这个问题看起来简单,但实现时容易变脏。

我采用的方式是维护一个SkillContext对象,里面是一个可读写的字典,每个技能执行时拿到同一个引用。某技能往context.state["user_id"]写值,后续技能直接从里面读。注意这里面有两条纪律:

  • 只能写自己负责的关键字段。技能 A 不能顺手改掉技能 B 写的字段。
  • 大对象不要存 context,存引用或者落盘路径。我没少吃这个亏,有次在 context 里塞了个 20MB 的 DataFrame,后面每个技能都慢半拍,排查了很久才发现是共享状态导致的内存瓶颈。

5.3 可观测性:让技能调用链路可追踪

技能数量上来后,最让我头疼的其实是“整体不可见”。一个任务在多个技能之间跳来跳去,出问题了很难定位。

后来我给每个技能的执行统一加了三条链路信息:

  • trace_id:任务级唯一 ID,贯穿所有技能调用。
  • span_id:技能级唯一 ID,标识一次具体执行。
  • parent_span_id:记录调用来源,用于构建调用树。

这组信息打到结构化日志里,再配合简单的聚合查询,就能还原出“哪一次任务、按什么顺序、调了哪些技能、各自耗时多少、哪个环节失败”。有一次线上问题排查,我发现一个任务流程明明只需要 4 个技能,实际却调了 8 次,原来是有个技能在失败后被模型反复重试了 4 次。看到调用树之后,我马上去给那个技能的重试策略加了总次数上限,问题当场解决。

最后再分享几个我踩过的坑

技能体系越用越顺的时候,最容易掉以轻心的地方反而是最初级的:依赖管理。我的某个技能从“只做摘要”升级成“摘要 + 主题分类”时,直接改了skill.yaml里的 description,但却忘了更新示例输出,结果模型照着旧的示例结构解析新输出,总是解析失败。自那以后我固定了一条铁律:改技能必改三件套——元信息、示例输出、测试用例,三者必须同步提交。

还有一个建议给刚上手的朋友:不要一开始就追求技能数量多。先把 5 个核心场景打磨成 5 个高质量技能,跑通“技能索引 -> 意图路由 -> 技能执行 -> 结果回填”的完整闭环,再慢慢扩。技能化这件事,质量和边界远比数量重要。我见过太多项目是技能写了几十个,真正被模型稳定调用的只有五六个,其余全是吞 token 的摆设。

这套 agent-skills 的思路我还会继续迭代。下一步我打算把技能的“自评估”机制加进去——让每个技能执行完顺手给自己打个置信度分,这样调度层就能对低置信度的结果做二次校验。开发过程中如果再有值得分享的进展,我再回来补充。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 9:37:26

随机字符串在测试与安全中的技术应用

1. 项目概述"YEWRWREWREWWQEWQ"这个看似随机的字符串组合,实际上可能隐藏着多种潜在的技术应用场景。作为一名长期从事编码与数据处理的技术从业者,我见过不少类似的"无意义"字符串在实际项目中扮演着关键角色。这类字符串通常出现在…

作者头像 李华
网站建设 2026/10/14 9:37:07

让地图成为机器可读的空间服务:对话机器人与地理数据融合实践

lingbot-map这个项目名,拆开就是两件事:lingbot基本是从language bot压出来的,map不用解释,就是地图。合在一起,它指向的是一个把对话交互能力和空间数据能力绑在同一个体系里的项目——机器人能查地图、答方位&#x…

作者头像 李华
网站建设 2026/10/14 9:36:31

知识工作插件化流水线:从设计思路到二次开发实战

1. 这个插件仓库到底在解决什么问题第一次看到knowledge-work-plugins这个仓库名的时候,我下意识以为又是一个把各种零散脚本堆在一起的“杂物间”。点进去翻了两圈才发现,它其实是一套围绕知识工作者日常任务设计的插件集合,核心目标很明确&…

作者头像 李华
网站建设 2026/10/14 9:36:27

CSS 盒模型有什么区别?box-sizing 怎样影响元素宽高?

CSS 盒模型有什么区别?box-sizing 怎样影响元素宽高? CSS 盒模型从里到外是 content、padding、border 和 margin。 默认的 content-box 把 width 和 height 用在内容区上,内边距和边框要另外加。border-box 则让指定的宽高包含内容、内边距…

作者头像 李华
网站建设 2026/10/14 9:36:16

Java策略模式实战:从if-else重构到可扩展设计

1. 策略模式初探:为什么我们需要它? 作为一名在Java领域摸爬滚打多年的开发者,我见过太多因为条件分支泛滥而变得难以维护的代码。还记得刚入行时接手的一个电商项目,运费计算逻辑里嵌套了7层if-else,每次新增用户类型…

作者头像 李华