资讯动态

Agent技能系统设计:告别重复调提示词的工程实践

发布时间:2026/10/16 0:52:59 来源:尧图企业网站定制
做Agent项目最让人头大的不是模型不够聪明而是同一个问题隔三差五就要重新调一遍提示词。我们内部管一套组件叫agent-skills最初就是为了治这个毛病把一类任务的完整经验——触发条件、执行步骤、判断规则、样例输出、辅助脚本——打包成一个独立技能文件让Agent在遇到对应场景时自动加载。这套思路跑了大半年从日志分析到报表生成都用上了今天把整个设计、实操和踩坑过程完整拆一遍希望能帮正在做Agent的同学少走几趟弯路。1. 为什么通用Prompt不够还需要一套技能系统1.1 从一次失败的Agent对话说起说起来挺哭笑不得。有段时间我们让Agent帮运营同学清洗Excel里的客户数据任务本身不复杂去重、统一日期格式、补全缺失值。真正跑起来才发现每次都得跟Agent重新交代一遍规则。“请你只保留日期最新的一行”“不要动id列”“日期格式统一成YYYY-MM-DD”……一条条指令往对话框里塞有时候一轮对话能来回拉扯七八次。更离谱的是同一套规则换一批数据又要重新讲一遍。我刚开始也以为是模型能力不行后来仔细复盘发现根本不是。问题出在我们把“一次性指令”和“可复用能力”混为一谈了。每次对话里的临时指令只活在当前上下文窗口里一旦对话变长、内容变杂前面说的规则很容易被遗忘。今天交代明天就丢今天能用明天可能就不能用了这就是“时灵时不灵”的根源。后来我们开始试着把这类任务收敛成一套技能体系命名为agent-skills。这个思路的出发点很简单凡是流程稳定、规则明确、重复出现的事情就不该让Agent每次从零“理解”一遍而应该让它像人一样打开一个工具包就能开工。1.2 技能与Prompt的本质区别是什么很多人第一次听到“Agent技能”时会以为它就是一个更长的Prompt。这个理解方向是对的但深度远远不够。对比来看一次性的Prompt是“临时指令”它依靠对话上下文中临时塞入的规则技能是独立文件像给Agent装了一个插件。技能包里包含元信息、触发条件、执行步骤、参数定义、示例和辅助脚本它有生命周期开发、测试、发布、升级。常规Prompt很难做测试和回归技能可以单独建一套测试集每次改动都跑一遍回归。常规Prompt在长对话中容易漂移技能则通过主动加载机制让关键规则重新注入上下文保证稳定发挥。如果你做Agent时总觉得“换个人用就失灵”大概率就是缺少这层结构。稳定性不是靠把提示词写得更长得到的而是靠一套能被单独验证、单独管理的模块化能力堆出来的。1.3 什么样的任务才适合做成技能不是所有事都该技能化。我的判断标准是三条任务结构化程度高输入输出边界清晰执行逻辑相对稳定不需要每次都大幅度跟随对话走向变化出现频率足够高值得投入成本去沉淀。典型的例子包括日志分析、代码评审、数据脱敏、标准化报告生成、特定格式的文档转换。这些都是“有章可循”的任务。反过来一次性探索任务、高度依赖实时审美判断的创作类任务、需要跨多个用户系统做连续实时操作的工作流就不太适合硬塞进技能体系。硬做只会得到一份冗长但谁也不遵守的操作手册。技能系统的意义是把“可标准化的判断”沉淀下来剩下的不确定性继续留给模型和用户交互去处理。2. 拆解一份技能文件到底长什么样2.1 元信息与触发条件的设计一份技能文件通常由一个Markdown主文件加上若干辅助资源组成。最上方是元信息区一般用YAML写包含name、description、when_to_use、when_not_to_use、version等字段。这里最容易被忽略的是description它写给谁看不是人是模型。它是技能被检索和激活的索引。好的description必须具体什么场景下调用、什么时候绝对不要调用。我们早期写的description都是“分析日志并生成摘要”这种人类能懂但模型分不清楚的话结果用户问一句“为什么系统报错了”技能就被触发开始读日志。其实用户只是想要一句人话解释根本不需要跑完整分析流程。后来我们给每个技能都加了when_not_to_use字段情况才好转。元信息部分还有一点值得注意技能name不要起得太诗意。名字是给模型识别用的也是给日志排查用的应尽量语义化一眼能看出职责范围。2.2 工作流的定义步骤、决策点、回退策略技能正文的核心是工作流。写它的时候最忌讳散文式描述。应该写成“带决策分支的分步指令”每一步都要明确做什么、依据什么判断、出了异常怎么办。以日志分析技能为例工作流大概是这样的确认输入数据来源判断是文件路径还是日志文本检查日志时间范围确定是否完整按错误级别分类对ERROR级别内容做聚合按错误码和出现次数排序输出Top异常生成结构化摘要包含时间范围、异常类型、疑似模块最后判断是否满足输出条件不满足则提示用户补充信息。每一步都配一个回退策略。日志为空时怎么办、数据量太大时是否先采样、解析失败时要不要放弃并汇报这些在技能里都要写清楚。只写“正常路径”不写“异常路径”是技能质量差的最大原因。2.3 参数Schema与示例输入的必要性为了让Agent稳定调用能力技能应该定义参数Schema。我这边用JSON Schema字段类型、是否必填一目了然。不要嫌它啰嗦它同时约束了用户侧的信息收集技能启动前需要哪些信息模型可以主动询问用户去补齐而不是凭感觉猜。Schema之外我要求每个技能至少包含两个示例一个成功案例一个失败案例。成功案例展示“输入什么、按什么步骤处理、最终输出什么”失败案例教模型判断“什么时候应该拒绝执行”。这两个案例就是模型对齐行为标准的锚点。有一次我们因为缺少失败案例技能在用户没有给出日志文件路径时竟然开始编造日志内容。加上失败的示例之后它学会了礼貌地要求用户提供数据。2.4 技能清单与依赖管理一个技能不只有一份文档往往还带着一个Python脚本、几个模板文件、一份样例数据。主文件在技能根目录辅助资源和依赖都要在清单里声明方便Agent加载时动态读取也方便统一环境安装依赖。依赖管理这块一定要从一开始就做。我们在前中期完全没管后来换了台机器跑出的结果不一致排查了大半天才发现是脚本依赖库版本不同。技能是“可复现的执行单元”如果连依赖都不能锁死复现就无从谈起。3. 从零开发一个日志分析技能完整实操过程3.1 需求确认与能力边界定义用一个我实际做过的例子来走完整流程。当时我们内部有个监控系统每天产生大量业务日志运维同学希望Agent能自动生成“异常摘要”。需求听起来很简单输入日志文件输出问题清单。正式开发前我先花了不少时间确认边界输入文本格式的日志文件或用户直接粘贴的日志片段输出结构化摘要包含时间范围、异常类型、次数、疑似模块不做不负责修复问题、不读数据库、不处理流式日志。这个边界看起来保守实际帮了大忙。因为“不做什么”写清楚了后续遇到模糊需求时Agent知道要拒绝而不是硬闯。边界就是Agent的护栏比任何提示词都有效。3.2 编写技能主文件技能根目录建好之后先创建主文件。这是整个技能的核心结构是YAML元信息加Markdown工作流。贴一个精简版本--- name: log-anomaly-summarizer description: 分析应用日志并生成异常摘要仅当用户提供日志文件路径或日志文本时使用。 when_to_use: 用户要求分析日志、定位异常、汇总报错信息时 when_not_to_use: 用户只是询问系统状态并未要求解析日志内容时 version: 0.1.0 --- # 日志异常摘要技能 ## 目标 从输入日志中提取异常信息输出统一格式的结构化摘要。 ## 执行步骤 1. 确认输入读取用户提供的日志路径。路径无效时提示用户重新提供。 2. 检查数据判断日志时间范围若为空则直接返回“无数据”。 3. 按级别分类将日志行按 ERROR / WARN / INFO 分类。 4. 聚合分析对 ERROR 行按错误码聚合按次数降序取前 10 类。 5. 生成摘要 - 日志时间范围 - 主要异常类型与出现次数 - 疑似影响的模块 - 建议排查方向 6. 只输出摘要不输出日志全文。主文件里不要塞太多行业背景知识那些会占用模型的注意力。规则写清楚、步骤写紧凑比什么都重要。3.3 辅助脚本与参数解析日志解析有一些高频操作比如时间范围提取、按错误码聚合、去掉重复堆栈。这些不适合让模型去“思考”应该写成脚本。规则确定的事情交给代码模型只负责理解和解释结果这样准确率会高很多。下面是一个简化版的核心脚本import re from collections import Counter from datetime import datetime LOG_PATTERN re.compile( r^(?Ptime\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}) r.*?\b(?PlevelERROR|WARN|INFO)\b r.*?\b(?Pcode[A-Z]\d{3,})\b ) def parse_logs(text: str): rows [] for line in text.splitlines(): m LOG_PATTERN.search(line.strip()) if m: rows.append(m.groupdict()) else: rows.append({ time: unknown, level: UNKNOWN, code: PARSE_FAILED, }) return rows def summarize(rows): time_values [r[time] for r in rows if r[time] ! unknown] start min(time_values) if time_values else None end max(time_values) if time_values else None counter Counter(r[code] for r in rows if r[level] ERROR) top_errors counter.most_common(10) return { start: start, end: end, total_lines: len(rows), top_errors: top_errors, }脚本写完后在主文件里说明“解析工作交给log_parser.py模型负责读取结果并整理摘要”。这样模型不会被正则逻辑绕晕解析结果也更稳定。脚本里的正则规则可以按实际日志格式调整。3.4 测试用例与挂载调用技能开发完不是直接上线要先过一遍测试。我准备的用例包括正常日志样本包含ERROR、WARN、INFO结构完整空日志验证“无数据”分支超大日志比如上百MB验证是否需要采样提示格式异常行比如没有时间戳的行验证解析失败的处理用户只问“系统状态”但没给日志验证“不触发”逻辑。全部通过后把技能注册到Agent的路由配置里。本质上是告诉Agent遇到这类场景时把技能文件内容加载进上下文。注册完成后要做一轮端到端验证分别验证应该触发和不应该触发的情况。我强烈建议把这个验证清单固化下来不然技能更新后很容易悄悄退化。4. 测试、评估与调优怎么衡量技能质量4.1 构建测试集与回归基线有了技能之后最需要建立的是“它到底行不行”的判断标准。我从真实日志里抽了六十多条样本覆盖不同业务模块、不同错误码组合人工整理出标准摘要。这份测试集就是技能的“考卷”。之后无论改格式还是改流程都要跑一遍回归测试。跑的时候不是只看“有没有输出”而是看输出和标注结果的吻合程度。比如错误码聚合是否一致、排序是否合理、有没有遗漏关键信息。回归测试这件事撑起了整个技能体系的稳定性。有了它子后面改技能才敢下手因为能随时知道改坏了没有。4.2 关键指标设计我一般用四个维度来观察技能表现这套指标表也一直在用指标统计口径合格参考线任务完成率成功产出结果数 / 技能调用次数≥ 90%人工修正率人工介入纠错次数 / 任务数≤ 15%Token成本单个任务平均消耗量相对初始值有下降端到端耗时从调用到产出结果的平均秒数在可接受范围“人工修正率”是最容易被忽略的指标。自动跑通100次不代表100次都符合用户预期。我会让使用方在结果有误时顺手点一个“修正”这个数据比任何测试都真实。4.3 三个真实调优案例第一个案例是输出格式漂移。最开始技能有时候输出表格有时候输出列表同一任务两种格式下游解析脚本就崩了。解决方式是在步骤里明确加上一句“输出必须使用Markdown表格不得使用其他形式”。格式约束在技能层面写死效果立竿见影。第二个案例是触发过宽。前面提到过技能在用户不是要分析日志时也触发。补上when_not_to_use并增加反向描述后误触发率从百分之三十几降到百分之五以内。第三个案例是示例不足导致步骤遗漏。最初版本只有成功案例模型遇到模糊请求时选择自己“脑补”。补上失败案例后它学会先向用户确认需求而不是拿幻觉来填坑。还有一个容易被坑的地方只看一个测试集就发布。第一次我们跑一轮测试觉得不错直接上线结果数据分布一变就不行了。后来规定至少两个不同来源的样本集都通过才算合格这才把“过拟合测试集”的问题压下来。5. 版本管理、共享与跨项目复用5.1 技能仓库的目录结构技能不是写完就丢的单个文件它是一种需要持续维护的资产。我们采用集中仓库管理每个技能一个独立文件夹skills/ log-anomaly-summarizer/ SKILL.md scripts/log_parser.py tests/sample_logs/ tests/expected_outputs/ CHANGELOG.md这种方式的好处是不同项目组都能各自挂载技能不会互相干扰技能改动有了痕迹出了问题还能回溯。如果一个Agent平台只有一套技能那它只是“个人的小工具”有了共享仓库才能变成团队的公共能力。5.2 版本迁移与兼容策略技能也做语义化版本。我们把规则写得很简单修改描述文字、补充示例等不影响输出的增加修订号改变输出字段结构、关键步骤顺序的升级次版本号破坏性变更比如删除字段、改变输入格式升主版本号。有一次我们把某技能输出字段重命名了觉得是小改动只改了代码没通知下游。结果消费该输出的解析模块一连好几天都在报错排查半天才找到原因。从那以后凡是结构性变更必须提前发布变更通知确认所有使用方都完成迁移才可以下线旧版本。技能和普通代码一样破坏性变更要极其谨慎。5.3 团队协作与评审机制技能开发不是一个人写文档的事。我们给每个技能指定一个owner负责定义目标和使用边界。所有改动都要走review重点看三件事边界是否清晰、步骤是否真的可操作、有没有把个人偏好写成通用规则。早期有一个技能是A同学做的他把自己对某种日志格式的偏好写进了通用步骤换个团队用就水土不服。评审会通过讨论把这类“隐形假设”挖出来逐个标记为可选或可配置。技能的通用性不是一步到位的是靠持续评审慢慢磨出来的。6. 踩坑复盘最常见也最容易被忽略的五个问题6.1 提示词太长核心约束反而失效技能文档不是越详细越好。我们早期往主文件里塞了大量背景说明结果模型处理任务时真正关键的步骤淹没在冗长叙述里。解决办法是让关键规则尽量靠前使用短句背景知识全部挪到附录模型需要时再读取。稳定性的核心不是“信息量大”而是“关键信息密度高”。6.2 多个技能之间的误触发与竞争技能数量多了以后会出现一个更隐蔽的问题多个技能的description写得不清不楚模型在边界场景里来回选错。两个技能都声称自己负责日志分析模型就没法判断。我们的处理方式是在每个技能的when_not_to_use里互相声明边界比如“本技能不负责数据库操作如需数据库分析请调用另一个技能”。这就像团队里的职责说明书把边界写到明面上冲突自然就少了。6.3 过度形式化把轻量设计做成重框架有一段时间我们想把所有技能都套进统一的编排框架什么状态机、跨技能工作流、复杂事件总线全都上。结果技能没写几个光框架代码就一大堆大家都不敢动。后来删繁就简保留了“主文件辅助脚本测试集”的三层结构。轻量结构的好处是易写、易改、易迁移。技能体系的本质是工具不是给人添堵的制度。6.4 环境差异与模型版本漂移同一条技能在不同环境表现不一致原因通常有两个模型版本更新后触发率漂移或者脚本依赖版本不一致。前者在测试环境里锁住模型版本、把版本号写进测试报告就能定位后者则需要前面说的依赖管理。我现在的习惯是每次模型服务大版本升级全量技能统一回归一遍。看起来费时间但能避免上线后才发现的系统性退化。6.5 安全与权限边界技能可以携带脚本、访问外部资源这就意味着权限边界必须最小化。我们内部要求技能脚本不允许执行任意系统命令避免从日志内容里读入恶意指令再拼进命令执行用户输入可能包含提示注入不能直接作为可执行内容技能日志里不得出现明文密钥、口令等敏感信息。Agent技能做出来是为了让系统更可靠但如果没有安全护栏可靠就会变成危险。权限、审计、敏感信息脱敏这些设计应当在技能框架建设初期就纳入而不是出了问题再补。最后再分享一个我自己的体会技能体系真正跑起来靠的不是某个优雅的设计而是一点点积累。多沉淀一个稳定技能就少一次重复调提示词的痛苦。如果你正准备上手别急着搭大框架挑一个重复频率最高的任务先做成一个技能把它测稳再慢慢向外扩。这套东西不复杂复杂的是坚持维护和持续迭代。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑