1. agent-skills 到底是什么:先搞清楚我们要解决的问题
这两年只要聊到 Agent,几乎绕不开一个词:agent-skills。很多人第一次听到它,第一反应是“这不就是给 Agent 写几个函数吗”?如果你也这么想,那大概率在项目做到一半的时候,就会发现事情没那么简单。
我自己的体会是,agent-skills 本质上是一套让大模型驱动的智能体能够稳定调用外部能力的方法论和工程体系。它不仅仅是写几个工具函数那么简单,而是涵盖了技能的定义、注册、检索、调用、容错、观测和扩展这一整条链路。换句话说,你今天写了一个“查天气”的函数,这只能算一个 API;只有当这个函数能被模型在合适的场景下自动发现、正确调用、并在出错时优雅降级,它才配叫一个 skill。
这个领域之所以突然变得重要,和 Agent 自身的发展阶段密切相关。早期大家用 LangChain 之类的框架链式调用模型,每次任务都是写死的工作流,模型几乎没有自主决策空间。后来大家发现,大模型本身的推理能力已经足够强,为什么不把任务拆解和工具选择的权力交还给模型呢?于是基于 ReAct 模式、函数调用(Function Calling)的 Agent 开始流行。但问题也随之而来:当 Agent 的技能数量从几个增长到几十个、上百个时,靠系统提示词(System Prompt)硬塞列表已经完全不现实了。技能如何组织、如何被模型准确选中、如何避免技能之间的互相干扰,成了真正卡脖子的技术难点。
这篇文章我就以“agent-skills”作为主题,分享一下我在实际项目里做技能注册中心、技能编排和调用链路的完整经验。不追求教科书式的全面讲解,重点放在那些真正能落地、能上生产环境的细节上。如果你正在做自己的 Agent 应用,或者准备把现有的框架改造成技能驱动架构,这篇文章应该能帮你少踩不少坑。
2. 先定架构:agent-skills 应该长什么样子
2.1 从“函数列表”到“技能库”的思维转变
如果只是应付一两个 demo 性质的 Agent,你完全可以在 system prompt 里把所有工具的描述列出来,让模型慢慢选。但生产环境完全是另一回事。我在项目里处理过最多的场景,是技能目录膨胀之后引起的意图混淆和检索失效。模型面对 50 个以上描述相似的技能时,选择准确率会明显下降,而且你很难通过微调 prompt 来彻底解决。
所以第一步要转变的,是把它当成一个独立的“技能库”来设计,而不是散落在代码里的函数集合。一个完整的 agent-skills 体系,在我的实践里通常由四个层次组成:
- 技能注册中心(Skill Registry):统一登记所有可用技能的元数据、版本、依赖和权限要求。
- 技能执行引擎(Skill Executor):负责实际调用技能对应的实现代码,管理入参校验、超时和结果返回。
- 技能发现与路由(Skill Discovery):根据用户请求和对话上下文,选择合适的技能组合,并规划调用顺序。
- 技能观测与治理(Skill Observability):记录每次调用的输入、输出、耗时、失败原因,为后续优化提供数据支撑。
这套分层设计的好处,是让每个组件可以独立演进。比如注册中心的格式调整,不会影响到执行引擎的代码;新的技能上线,只需要在注册中心里登记,不需要改动 Agent 的核心逻辑。很多团队上来就把工具调用逻辑和业务代码耦合在一起,短期内看着省事,到后期加一个技能要改三个模块,维护成本直接起飞。
2.2 为什么技能注册中心是整个体系的枢纽
在整套 agent-skills 架构里,我最看重的其实是技能注册中心。它有点像一个项目的接口文档中心,但比文档要求更高:它既要让人类开发者能看懂,也要让模型能精确地理解每个技能的功能边界。
注册中心存储的信息,通常包括技能 ID、名称、描述、参数 Schema、返回值 Schema、依赖资源、权限标签、版本号等。其中“描述”这一项是最容易被低估的。很多开发者写技能描述时特别随意,就一句“这是一个天气查询接口”,结果模型在调用时经常判断失误。真正高质量的技能描述,应该像一个优秀的同事给你交代任务一样:不仅说明这个技能是做什么的,还要说清楚它适合什么场景、不适合什么场景、特殊参数怎么传、常见的坑有哪些。
我举个例子。一个订单查询技能,简单的描述可能是:
查询订单信息但我推荐写成这样:
当用户询问特定订单的状态、物流、金额等信息时使用。 需要提供订单号;如果用户没有提供订单号,err_prompt 会引导用户补充。 如果用户询问的是批量订单统计,请使用“订单报表生成”技能,而不是本技能。这个差异在生产环境里是决定性的。前者让模型靠猜,后者把决策依据摆得明明白白。我把这类“路由指引”叫技能的上下文胶水,能显著提高模型在多技能场景下的选择准确率。
3. 构建技能注册中心:从数据模型到核心 API
3.1 技能注册中心的元数据模型设计
在动手写注册中心之前,先定义清楚技能元数据的数据结构。下面是我在项目里用得比较顺手的一套 JSON 结构,兼顾了机器可读和人工可维护性。
{ "skill_id": "order_query", "name": "订单查询", "version": "2.3.0", "description": "当用户询问特定订单明细、物流状态时使用。需要订单号,支持电商与线下门店订单查询。", "tags": ["order", "query", "ecommerce"], "author": "platform-team", "owner_department": "交易中台", "permission": "user.auth.required", "visibility": "public", "parameters": { "type": "object", "properties": { "order_id": { "type": "string", "description": "用户提供的订单号,通常为数字字符串", "required": true }, "detail_level": { "type": "string", "enum": ["basic", "logistics", "payment"], "default": "basic", "description": "查询详细程度,默认 basic" } } }, "return_schema": { "type": "object", "properties": { "order_status": { "type": "string" }, "logistics_trace": { "type": "array" } } }, "timeout_ms": 3000, "idempotent": true, "rate_limit": { "window_sec": 60, "max_calls": 120 }, "changelog": ["2025-01-10: 新增物流轨迹查询支持"] }有几个字段值得单独说一下。
首先是visibility,它决定了这个技能对哪些 Agent 可见。在大型组织里,有些技能可能是内部运营专用的,有些技能需要用户授权后才能调用。如果不设置这个字段,后续做技能权限管理时就会非常痛苦。
其次是idempotent,这个字段表示技能是否可以安全地重复调用。对 Agent 来说,模型很可能会因为超时重试而重复提交同一个指令。如果技能本身不是幂等的,比如“创建工单”“转账付款”,那一旦模型自动重试,就会产生重复操作,后果很严重。设置了这个字段之后,执行引擎可以针对非幂等技能做额外的二次确认,或者生成幂等键来去重。
3.2 注册中心的读写 API 设计
注册中心本质上是一个元数据存储服务,我把它的核心 API 设计成下面这样,涵盖了技能的增删改查、上下线和版本管理。
# 伪代码:注册中心核心接口 from typing import Optional from dataclasses import dataclass @dataclass class SkillRepository: storage: dict # 实际生产环境建议用 Redis/PostgreSQL 持久化 def register(self, skill_meta: dict) -> str: """ 注册新技能,返回 skill_id。 如果 skill_id 已存在,则执行覆盖并记录版本变更。 """ skill_id = skill_meta["skill_id"] skill_meta["version"] = skill_meta.get("version", "1.0.0") skill_meta["created_at"] = skill_meta.get("created_at", now()) self.storage[skill_id] = skill_meta return skill_id def get(self, skill_id: str) -> Optional[dict]: return self.storage.get(skill_id) def delete(self, skill_id: str) -> bool: # 删除前建议检查是否有 Agent 正在引用 return self.storage.pop(skill_id, None) is not None def list_skills(self, tags: Optional[list] = None, visibility: str = "public") -> list[dict]: """ 返回技能列表,按 tag 过滤。 路由模块会调用这个接口做技能候选集筛选。 """ result = [] for meta in self.storage.values(): if meta["visibility"] not in ("public", visibility): continue if tags and not set(tags).intersection(set(meta["tags"])): continue result.append(meta) return result在实现注册中心时,我强烈建议把“读”和“写”分开。写入操作走管理后台或 CI/CD 流水线,频率很低;读取操作是在 Agent 每次决策时都要发生的高频操作。所以注册中心的元数据建议在服务启动时加载到本地缓存,配合 Redis 做跨节点一致性。每次技能变更后,通过版本号或者更新时间戳让缓存失效,这一步能显著降低 Agent 决策链路的延迟。
3.3 技能描述的 Prompt 工程化处理
刚才提到了描述质量很重要,那具体怎么把描述写成模型能理解的样子?这里有一个技巧:用测试对话来反向检验描述质量。
我通常会在写完一个技能描述后,构造 10 到 20 条典型的用户请求,然后让模型只根据描述来决定是否调用这个技能。如果某些请求被错误地路由到了别的技能,说明描述存在歧义,需要调整。这个过程听起来简单,但非常有效。很多时候,你觉得一个描述已经写得很明白了,但模型就是选了另一个技能,原因往往是另一个技能的描述里包含了更高频的关键词。这时候不是怪模型笨,而是要对描述做差异化设计,在自己的技能描述里明确写上“如果你只是想 XX,不要用我”。
另一个小技巧是给技能描述加“反向示例”,也就是明确说明哪些情况不该调用当前技能。这个在真实场景里比正向描述更能提高路由准确率。模型在二选一的场景下,最怕就是两个技能描述既包含正向匹配词,又缺少排他性信息。加一句“本技能无法处理 XX 类需求,请使用 YY 技能”往往能解决大半问题。
4. 技能执行引擎:打通从意图到落地的最后一公里
4.1 设计技能装饰器:把普通函数变成“可被模型调用”的技能
注册中心解决的是“技能如何被描述和组织”的问题,执行引擎解决的是“技能如何被稳定地跑起来”的问题。在实际编码里,我倾向于用 Python 装饰器的方式,把已有业务函数快速包装成标准技能。
下面是一个简化版的技能装饰器实现:
import inspect import functools from typing import Callable, Any, get_type_hints def skill( skill_id: str, description: str, tags: list[str] | None = None, timeout_ms: int = 3000, idempotent: bool = True, permission: str = "user.auth.required", ): """ 将普通函数包装为一个标准 Agent Skill。 用法示例: @skill( "order_query", "查询订单信息,需要订单号" ) def query_order(order_id: str) -> dict: return {"status": "delivered"} """ def decorator(func: Callable) -> Callable: # 自动从函数签名中提取参数 Schema hints = get_type_hints(func) signature = inspect.signature(func) properties = {} required = [] for param_name, param in signature.parameters.items(): if param_name in ("self", "cls", "kwargs", "args"): continue properties[param_name] = { "type": _map_type(hints.get(param_name, str)), "description": f"参数 {param_name}", } if param.default is inspect.Parameter.empty: required.append(param_name) # 为函数挂载技能元数据 func.__skill_meta__ = { "skill_id": skill_id, "name": description.split("。")[0] if description else func.__name__, "description": description, "tags": tags or [], "parameters": { "type": "object", "properties": properties, "required": required, }, "timeout_ms": timeout_ms, "idempotent": idempotent, "permission": permission, "handler": func, } @functools.wraps(func) def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper return decorator这段代码的核心价值在于,它把“函数签名”自动映射成了模型的参数 Schema,省去手写 JSON Schema 的繁琐工作。你只需要在函数上面加一行装饰器,就能把一个普通函数升级为具备完整元数据的技能。这对团队的协作体验提升非常明显——后端同事不需要理解模型推理细节,只需要学会用装饰器,就能把内部接口包装成 Agent 可调用的技能。
4.2 参数的严格校验与自动补全
在实际调用中,我发现模型传参经常出现两类问题。一类是类型传错,比如文档说order_id应该是字符串,但模型可能传了一个数组。另一类是缺少必要参数,模型在对话中没拿到信息就直接调用了技能。
为了解决这两个问题,我在执行引擎里实现了三层参数处理逻辑。
第一层是基础类型校验,检查参数类型是否匹配,如果类型不匹配但能安全转换,就自动做转换。第二层是语义补全,从对话上下文中提取缺失的必填参数信息,比如用户上一轮说了订单号,这轮只说了“帮我查一下”,技能引擎应该能从记忆里自动填上订单号。第三层是拒绝执行,当必填参数确实缺失且上下文无法补全时,返回一个固定格式的“缺参请求”给 Agent 的规划模块,让它继续向用户提问,而不是强行用空参数把技能跑一遍然后拿个错误结果。
开放问答场景里语气很重要,但技能层返回值一定要统一结构化。我的做法是:每个技能返回固定格式的{ "success": bool, "data": dict, "error": dict | None }。这样下游的 Agent 规划模块拿到结果之后,不需要再做一层格式解析,可以直接拼进上下文继续推理。
4.3 技能调用的超时、重试与熔断
生产环境里,一个 Agent 往往需要按顺序调用多个技能才能完成一个任务。如果其中一个技能依赖的下游服务变慢,整个 Agent 的响应时间都会被拖垮。所以技能的治理规则不能不提前设计。
我设置了三个层级的保护:超时、重试、熔断。
- 超时:每个技能在注册中心里定义了
timeout_ms,执行引擎用异步任务包裹,超时直接丢弃结果并返回错误。 - 重试:只有
idempotent = true的技能才允许自动重试。非幂等技能重试逻辑必须由上层业务人工确认。 - 熔断:连续失败超过阈值(比如 5 次)后,该技能自动进入“冷却”状态,Agent 在路由阶段就会跳过它,而不是反复调用失败接口。
熔断这个点尤其要提醒。有些开发者觉得 Agent 会自己判断错误并换个方案,但实际情况是,如果技能列表里仍然存在一个已故障的技能,模型很可能会在下一次规划时继续选它。把故障技能从路由候选里隐去,比在调用后报错要优雅得多。
5. 技能调用决策:让模型在正确的时间选到正确的技能
5.1 先粗筛后精排:技能发现不能全靠模型
当技能数量超过一定量级后,直接把所有技能 Schema 塞给模型,不仅 token 消耗大,而且模型在超大候选集里选错概率急剧上升。我在项目里采用的是“粗筛 + 精排”两阶段路由。
第一步粗筛,是基于关键词和标签的检索。将用户当前请求和对话历史做一次轻量的实体识别和高频词提取,然后和技能标签做匹配,挑出 10 到 15 个候选技能。这一步不需要太高的准确率,只要保证真正的目标技能不会被过滤掉就行。
第二步精排,是把候选技能的描述和参数 Schema 拼进 prompt,让模型从候选里挑出最合适的 1 到 3 个技能。由于候选数量少,token 压力小,模型的决策精度也能大幅度提高。
下面是一个粗筛函数的示意代码:
import re def coarse_filter(user_input: str, all_skills: list[dict], top_k: int = 12) -> list[dict]: """ 基于简单规则从全量技能中筛选出候选技能。 这里用关键词匹配做示例,实际生产可以考虑接入向量检索。 """ # 抽取用户输入中的名词短语,简化处理只提取中文或英文单词 entities = set(re.findall(r"[\u4e00-\u9fa5]{2,}|[a-zA-Z]{3,}", user_input.lower())) scored = [] for skill_meta in all_skills: score = 0 # 对技能描述和标签做关键词匹配 text_pool = (skill_meta.get("description", "") + " " + " ".join(skill_meta.get("tags", []))).lower() for ent in entities: if ent in text_pool: score += 1 if score > 0: scored.append((score, skill_meta)) scored.sort(key=lambda x: x[0], reverse=True) return [meta for _, meta in scored[:top_k]]这个方案在中小规模技能库(几十个技能)下表现稳定。如果技能库膨胀到几百个甚至上千个,我会把粗筛这层替换为向量检索,配合标题嵌入和描述嵌入混合打分。但不建议一开始就上向量化,因为维护向量索引的成本并不低,尤其是技能描述经常变化的时候。
5.2 系统提示词与技能描述在上下文中的排布
在精排阶段,系统提示词的结构也颇有讲究。我的经验是,不要罗列所有技能,而是按“任务类目”分组。把候选技能按业务域组织,比如订单域、物流域、售后域,然后告诉模型“如果你需要查询订单,以下技能可供选择”。分组能极大降低模型的认知负担,它不再需要在一长串平铺的列表里做区分,而是先想清楚自己需要哪类能力,再进入对应的组里选技能。
还有一个经常被忽视的细节:把对话历史中的关键信息以摘要形式叠加到技能选择 prompt 上。举个例子,用户第一句话是“我想查一下昨天买的东西到哪了”,模型在后续决策时,如果只能看到最新的那轮请求“地址是什么”,就很容易困惑。如果能在技能选择阶段附加一句“用户之前提到要查询订单物流”,模型的决策质量完全不同。
5.3 避免技能幻觉:让模型学会说“我不需要技能”
很多 Agent 框架从一开始就引导模型“能调就调”,导致模型把很多简单的问题也包装成技能调用。比如用户就问了句“你们几点下班”,如果技能列表里刚好有个“客服工作时间查询”,模型可能也会调一下。这在 demo 阶段显得很聪明,但在生产环境里,无谓的调用既增加延迟,也增加下游系统的负载。
在提示词里,我会刻意强调“不是每个问题都需要调用技能”。同时给路由模块增加一个自动决策分支:当技能候选粗筛阶段的最高分低于某个阈值,或者用户请求中的实体与任何技能描述完全不匹配时,直接跳过技能调用,把原始问题交给模型用常识回答即可。
6. 技能观测与质量治理:上线之后才是真正的开始
6.1 技能调用日志应该记录哪些维度
技能上线只是第一步,真正决定长期体验的是数据反馈闭环。我给每个技能增加了一套标准的调用日志 JSON,核心字段包括:
- 用户请求原文
- 路由决策结果(选了哪些技能,各技能置信度排序)
- 技能入参和出参的快照
- 调用耗时、失败原因
- 模型对结果的二次判断(判断技能结果是否成功解决了用户问题)
这些日志有三大用途。第一,离线分析路由准确率,定位哪些技能的描述需要优化。第二,及时发现技能本身的性能问题,比如某个技能调用量暴增,可能是路由压倒了某个不该覆盖的意图。第三,为后续做基于强化学习的路由优化积累数据,虽然这在多数项目里是远期目标,但先把数据收集起来总没有坏处。
6.2 技能回放与回归测试:让每一次改动都可追溯
技能描述或代码改动,最怕的就是“这次改完,别的地方出问题”。我在实践里建立了一个小型的技能回放测试集:把过去一段时间真实的用户请求按技能分组保存下来,每次技能版本升级后,在离线环境里对这些请求做一次批量路由和调用测试,对比新旧版本的输出差异。
如果新版本在某些样本上路由到了不同的技能,或者调用结果与预期不符,系统会高亮提示人工检查。这个东西本质上就是一套为 Agent 技能准备的回归测试系统,实现成本并不高,但能在关键时刻救你一命。我有一次优化了一个技能的描述,离线回放立刻发现有两成原本能正确路由的请求跑偏了,当时如果直接发上线,一定会收到一堆用户投诉。
这个经验,换成传统软件开发其实很自然——没有测试谁敢直接改核心模块?但到了 Agent 技能这里,很多团队反而偷懒了。因为技能的行为有概率性,所以更要做回归验证,不能只靠“我觉得描述优化了应该没问题”。
6.3 技能废弃与灰度下线的流程
技能也会老化。业务方变更了内部接口,某个技能长时间无人调用,或者被新技能完全取代,这些场景都需要有下线的流程。我见过最粗暴的做法是直接从注册中心删除。但这样很危险,历史会话里有些还是旧技能在跑,删除后这些会话会直接报错。
合理的做法是给技能增加生命周期状态:active→deprecated→disabled。deprecated状态下技能仍可使用,但注册中心会在它的描述里标注“即将下线,请转向使用 XX 技能”;新会话的路由层会降低对它的选择优先级;已经发出但还没完成的调用可以正常跑完。观察一段时间,确认没有新增流量后,再把它改为disabled。这套流程虽然简单,但在协作团队里能避免很多不必要的线上事故。
7. 工具链选型:在框架、低代码平台与你自己的代码之间做选择
7.1 开源框架 vs 自研组件
现在做 agent-skills 并不需要一切从零开始,市面上已经有相当多成熟的方案可以借力。我自己常见的几种选择组合如下表:
| 需求层次 | 可选方案 | 我的选择建议 |
|---|---|---|
| Agent 对话与编排 | LangChain、LlamaIndex、Dify、Coze | 技术团队以代码开发为主,用 LangChain/LlamaIndex 更灵活;业务团队想快速产出,用 Dify/Coze |
| 函数调用能力 | OpenAI Tool Calling、Anthropic Tool Use、各类开源模型 Function Calling | 不必绑定大厂,模型自带的结构化输出支持可能更稳定 |
| 技能注册与治理 | 自研轻量注册中心 | 通用框架自带的工具注册机制偏简单,生产级治理建议自研 |
| 观测与追踪 | LangSmith、Langfuse、自研日志系统 | 优先用现成的可观测平台,重点看对技能调用的追踪支持 |
并不是说这些开源框架不好,而是在技能治理这块,它们的抽象层次普遍还比较薄。比如 LangChain 的@tool装饰器确实能快速定义一个工具,但它对技能版本、权限、熔断、观测这些生产级问题的管理能力很有限。我的建议是,可以拿框架的 agent runner 做执行骨架,但技能注册和治理这一层需要自己攒,尤其是当你不止做一个 Agent,而是要支撑多个 Agent 共享技能库的时候。
7.2 自定义技能库时,要不要上 MCP
MCP(Model Context Protocol)是近期比较受关注的一个协议,它本质上定义了大模型应用与外部工具/数据源之间的标准化接口。如果你想做一套开放的技能生态,让不同团队甚至第三方开发者都能往你的 Agent 里贡献技能,那 MCP 是值得考虑的规范。它最大的优势是把“技能提供方”和“技能消费方”解耦,一个服务如果实现了 MCP,可以做数据库查询技能,也可以做文件分析技能。
但要说清楚,MCP 不是银弹。如果你的 Agent 完全在单一技术栈内部闭环,业务方都是自己的后端同学,直接走内部 RPC 反而比引入 MCP 多一跳网络开销和协议转换。我的建议是:内部技能不必强行 MCP,开放生态才值得引入 MCP。很多人听到新协议就往上冲,结果只是为了在内部服务之间调一个查库存的接口,属实没必要。
8. 常见问题与排查技巧实录
8.1 模型总是选错技能,该怎么办
这是我来被问得最多的一个问题。排查这类问题的标准步骤是:
- 先看路由日志,确认粗筛阶段目标技能是否进入了候选集。如果没有,问题出在粗筛规则(关键词或向量召回)上。
- 如果进入了候选集但模型没选它,说明精排 prompt 里技能描述区分度不够。这时候优先做描述差异化,增加排他性说明。
- 如果描述看起来已经很清晰,再检查候选技能列表的排列顺序。有些模型对列表靠前的技能有明显的选择偏好,需要把和目标意图最接近的技能放在靠前位置。
- 最后才是考虑微调或更换模型。绝大多数选错问题在数据和 prompt 层就能解决,不值得一上来就上大模型微调。
8.2 技能调用超时导致对话中断
技能超时不一定会导致整个 Agent 崩溃,但如果没有合理的错误处理,用户会体验到“机器人突然不说话了”。我在执行引擎里设计了超时返回“该技能暂时不可用”的结构化错误,并让规划模块感知到这个错误后,自动向用户解释并给出备选方案。
如果这个技能是只读查询,比较简单;如果是写操作,还要注意超时后的状态不确定性。比如一个接口实际上写入成功了,但响应超时被标记为失败,Agent 端如果再提示用户“操作失败,请重试”,用户一重试就产生了两条相同记录。这个场景建议在业务接口设计里补充幂等键支持。
8.3 技能数量膨胀后,系统提示词的 token 压力过大
当全量技能数据太大时,有几个缓解方案。最优先的是做技能分组,按部门和场景拆分成多个技能子域,在 Agent 启动时只挂载当前场景相关的技能子域。其次是做描述压缩,把长描述改成简洁的说明和几个高质量示例词,让模型更容易理解。最后才是上向量检索和动态召回,这个方案虽然先进,但对基础设施的要求也更高。
在压缩技能描述时,有一点需要特别注意:不要为了省 token 把参数 Schema 里的枚举值说明删掉。模型如果不知道某个参数可以填哪些选项,很容易编造出非法值。参数说明可以有技巧地压缩,比如“type: string, enum: [basic, logistics, payment]”只保留枚举项,不加多余解释,已经能帮助模型做出稳定选择。
9. 最后一个经验:把 agent-skills 当成产品来做,而不是技术亮点
说回整个 agent-skills 的落地。我个人最大的体会是,这个体系能不能跑起来,技术不是瓶颈,组织协同才是。技能不是一次性交付的静态代码,而是需要持续更新的活资产。一次成功的 agent-skills 落地,背后至少需要三种角色的配合:业务方负责定义技能边界和验收标准,开发负责把已有接口改造为标准技能,算法或 Agent 工程师负责路由和提示词的持续调优。
如果你是在一个比较小的团队里单打独斗,那么至少要把自己拆成这三个角色来思考。做注册中心时,站在平台工程师的角度;写技能描述时,站在业务运营的角度;调路由准确率时,站在算法工程师的角度。这种“人格分裂”式的思考方式,确实能帮你少走很多弯路。
最后分享一个小技巧:我每次新增一个技能之前,会强制自己先写三条“用户可能会问但我不应该用这个技能回复”的请求,然后把它放到技能描述的反向提示里。这个习惯坚持下来之后,技能路由准确率提升得非常明显。大家不妨也试试,不一定一步到位,但至少可以先挑一个技能权重高的场景去跑通整套链路,然后再逐步扩展。