跳到主要内容
Agent / RAG / MCP / Skill 通用工程解法与技术选型 | 极客日志
编程语言 AI 大前端 java
Agent / RAG / MCP / Skill 通用工程解法与技术选型 综述由AI生成 解析了 AI 领域的核心概念 Agent、RAG、MCP 和 Skill,指出它们本质是补充大模型在知识、实时性和执行能力上的短板。文章通过记忆管理、检索增强生成、工具调用及标准化协议等工程实践,提供了通用的技术选型方法和落地检查清单,帮助开发者避免被术语误导,构建可控、可观测的 AI 系统。
RefactorPro 发布于 2026/4/5 更新于 2026/5/22 28 浏览Agent / RAG / MCP / Skill 通用工程解法与技术选型
刷到'Skill、MCP、RAG、Agent'这些词时,第一反应大概率是:我是不是又落后了?
换个研发负责人的视角看:绝大多数新名词,都在做同一件事——把'模型只会生成字'的能力,包装成'能完成任务的系统'。名字可以很潮,但工程本质永远逃不出:
数据(Context)
检索(Search)
工具(Tool)
编排(Workflow)
约束(Schema)
下面用一套'通杀新概念'的方法,把这些词拆到你能复用、能落地。
摘要(先看结论)
RAG、Agent、MCP、Skill 本质都在补 LLM 的短板:缺知识、缺实时、缺手脚。
选型只问三件事:补什么短板?确定性来自哪里?风险与成本在哪里?
不要把名词当'黑科技'。把它们当成可拆分、可替换的系统零件,你就不会被词牵着走。
0)一句话定义(方便记忆)
术语 一句话 你真正要做的工程事 RAG 先检索,再把命中的材料喂给模型 做好召回/排序/切片/去重/防注入与评估闭环 Agent 带工具的循环控制器:计划→调用→观察→再计划 设计循环、停止条件、失败回退与可观测性 Function Calling(工具调用)与结构化输出 LLM 世界的'接口契约' 用 schema 把输入输出钉死,避免解析失败与字段乱填 MCP 工具生态对接的标准化插头 把'接工具'变成可复用连接层,同时补齐权限与审计 Skill 可复用的提示词/流程片段(有时带工具) 做版本化、评估、依赖声明与适用范围说明
0.1)放到开发环境中:这些词分别对应什么?
如果你平时主要用代码助手来读代码、改代码、跑命令,可以把上面这些概念直接'落到日常动作'里理解:
概念 在开发工具中你看到的样子 最小可复现案例(示意) Context / Memory 你发给模型的 messages + 你补充的规则/状态/资料 把「问题 + 相关文件片段 + 当前改动目标」拼到一次请求里 RAG 先找材料,再回答 先在仓库里搜(代码/文档),把命中的片段喂给模型再生成结论 Function Calling(工具调用) 模型不直接'写答案',而是先触发一次可执行动作 先让模型去搜代码/读文件/跑测试(工具),再基于结果输出最终答案 Agent 多轮循环:计划→执行→观察→再计划 修一个线上 bug:先定位→改动→跑测试→失败再定位→直到通过 MCP 把外部系统'接进来'给模型用 拉飞书文档/设计稿/组件库文档作为上下文或工具输出 Skill 一套可复用的'工作流提示词 + 约束 + 自检清单' 做一个'仓库问答带引用'的 Skill,让新人按固定格式提问与验收
1)先把地基钉死:大模型到底会什么、不会什么?
大语言模型(LLM/LM)的核心能力可以粗暴理解为:在给定上下文里生成下一段最可能的文本。这很强,但也天然有三大短板:
不知道你公司的私有信息(除非你把信息塞进上下文)
不知道今天刚发生的事(训练数据是历史的)
没有手脚(不会自己去查系统、发消息、改表格)
Prompt / Context / Memory:怎么把更多信息塞进上下文
Function Calling / 工具调用:怎么让模型可靠地'动手'
实战示例:把'三短板'翻译成三个具体动作 把'短板'翻译成开发环境中你每天会做的动作,会更直观:
缺私有知识(不知道你公司/你仓库)→ 先把材料找出来再问:在仓库里搜到关键文件与片段(相当于 RAG 的 retrieve),再让模型基于这些片段解释或改代码。
缺实时(不知道今天发生了什么)→ 让模型先拿到新信息再回答:例如先抓取公告/最新文档/线上日志摘要(来自你的系统/网页/平台),再回填给模型。
缺手脚(不会动手)→ 把'动手'变成工具:跑测试、执行脚本、生成补丁、读写文件,都要让模型通过'可执行动作'完成,而不是只靠嘴说。
1.1)记忆:短期记忆是'上下文管理',长期记忆才是'可持久化的库' 很多人说'给大模型加记忆',容易误会成'模型自己会记住'。工程上更准确的说法是:LLM 每次调用只看你当次发给它的上下文,所谓'记忆'通常由你的应用侧负责存储与回填。
短期记忆(Short-term):存在于上下文窗口内,本质是'把最近对话/状态/工具结果拼回去'。特点是即时、便宜、但会被 token 预算挤掉。
长期记忆(Long-term):存在于上下文窗口之外,本质是'把历史沉淀到外部存储,再按需检索回填'。特点是可持久、可治理、但必须做检索、去噪与权限隔离。
两类记忆最容易踩坑的点:短期记忆不是'存',而是'选哪些发给模型';长期记忆不是'全存',而是'存什么、怎么取、怎么删'。
1.1.1 短期记忆怎么做:对话历史 + 状态压缩 + token 预算
对话历史(messages):你在服务端保存历史消息,每次请求挑一部分塞回去。
运行时状态(state):当前任务进度、已选选项、已完成步骤、用户当前页等(不要让模型'回忆',要让它'看到')。
工具结果(tool results):检索命中片段、数据库查询结果、接口返回等。
压缩摘要(summary):当历史太长时,用摘要把关键事实与决策压缩成更短的片段。
messages (last N) + state (snapshot) + tool_results (recent) + summary (if needed) -> assemble_context (token_budget)
1.1.2 长期记忆怎么做:存储、检索、回填三件事 长期记忆不是'把所有聊天记录都存起来',而是把可复用的东西沉淀成可治理资产。常见的长期记忆形态:
用户画像/偏好(Profile):语言偏好、输出格式、常用项目、权限范围(结构化字段优先)。
事实记忆(Facts):确认过的事实(例如'项目代号、接口地址、约定字段'),必须可追溯来源。
经验记忆(Episodic):历史交互的关键片段(例如'上次排查过的错误、最终结论是什么'),适合用向量检索按相似度召回。
结构化记忆:SQL/NoSQL/KV(便于更新、删除、按用户隔离、做审计)。
语义记忆:向量库(embedding)+ 元数据(用户/租户/权限标签/时间戳/来源)。
回填到模型时,永远走'检索后注入',不要走'全量塞回':
user_query -> retrieve_memories (user_scope, topK) -> dedupe + sanitize -> inject_into_context
1.1.3 记忆怎么'传给模型':本质就是上下文注入 无论短期还是长期,最终都要走到同一件事:把你选中的记忆片段拼到 prompt 里发给模型。可以用一个更直观的拼装示意:
system (规则/角色) + tools (schemas) + user (question) + retrieved_docs (RAG) + retrieved_memories (long-term) + session_state (short-term) -> LLM
实战示例:一次多轮排障时,短期/长期记忆分别放什么?(Android) 场景:Android 新同学在开发工具里排查一个'Gradle 单测只在 CI 失败、本地 Android Studio 跑是绿的'的问题。你希望模型每一轮都能稳定'接着上一步继续',而不是反复问同样的问题。
{ "task" : "Fix CI-only Android unit test failure" , "context" : { "build" : "gradlew testDebugUnitTest" , "ci_os" : "Linux runner" , "local_os" : "macOS" , "jdk" : "17" , "timezone" : "CI=UTC, local=Asia/Shanghai" } , "hypotheses" : [ "时区/Locale 不一致导致日期格式化/解析差异" , "Robolectric/Android SDK 版本差异导致行为不同" , "协程/线程调度导致偶发竞态(本地复现概率低)" , "测试依赖文件路径/编码(Windows 路径、大小写、换行符)在 CI 不同" ] , "confirmed_facts" : [ "失败用例:com.example.app.LoginViewModelTest#whenTokenExpired_shouldLogout" , "只在 CI 的 Linux runner 失败,本地 macOS 通过" , "失败栈里出现了 Date/Time 或 Locale 相关的关键调用" ] , "next_action" : "定位失败用例中对时间/Locale/线程调度的依赖点,并固定可控输入(Clock/Locale/Dispatcher)" }
把它拼到'本轮请求的上下文'里,模型就会把它当成当前状态继续推进;它不是'记住',而是'看见'。
长期记忆(跨天/跨人可复用的结论)建议只沉淀'可复用且可追溯'的东西,例如把下面内容写入团队知识库/故障库:
结论:某类 Android 单测在 CI 默认时区/Locale 为 UTC/en-US,需固定时区/Locale 或注入 Clock
证据:链接到具体失败日志与对应代码行
修复模板:给出统一的测试基建写法(例如注入 Clock、固定 Locale、对协程使用可控 Dispatcher)
下次再遇到类似问题,你在开发工具里提问时做的事情其实是'先检索历史故障库(长期记忆召回)→ 再把命中的结论片段回填到上下文',然后模型才能复用经验,而不是从头猜。
1.1.4 记忆的工程边界:不要把'风险'一起存进去
权限隔离:长期记忆必须按用户/租户隔离,检索时强制带 scope 过滤。
防注入:记忆片段也可能携带恶意指令,回填前同样需要 sanitize。
可删除/可审计:涉隐私与合规场景必须支持删除(TTL/硬删)与访问审计。
防'幻觉写入':模型生成的'新事实'不要直接进长期记忆,必须要么可验证(工具查证),要么人工/规则确认后再写入。
2)RAG:别神化,它就是'先检索再喂给模型' RAG(Retrieval-Augmented Generation)说白了就是:模型自己'不一定知道',那就先去资料库找证据,再把证据连同问题一起喂给模型,让它基于材料回答。
检索质量:召回是否全、排序是否准(向量检索/混合检索/重排)
上下文拼装:片段怎么截、怎么去重、怎么防注入
评估闭环:命中率、引用覆盖率、事实一致性(否则就是'看起来更像对了')
query -> retrieve (topK) -> rerank -> chunk + dedupe + sanitize -> assemble_context (token_budget) -> model_answer (with_citations)
retrieve(topK):召回。用 query 去知识库/索引里'捞'出候选片段,topK 表示先取前 K 个候选(K 越大召回越全,但噪声与成本也更高)。
rerank:重排。对召回的候选再做一轮更精细的相关性排序(通常更慢但更准),把真正最相关的片段提到最前面,供后续拼装上下文使用。
chunk:把命中的长文档切成'可用片段'。通常按段落/标题/滑窗切分,并控制片段长度,避免一段太长塞爆上下文或一段太短丢语义。
dedupe:去重。把高度相似/重复的片段合并或丢弃,避免浪费 token、降低模型被重复信息'带偏'的概率。
sanitize:净化/消毒。对片段做安全与质量处理,比如去掉无关噪声、过滤潜在 prompt injection(例如'忽略以上指令')、做最小必要的转义与白名单化。
assemble_context(token_budget):在 token 预算内拼上下文。要做取舍与排序:保留最高相关片段、补齐必要元信息(来源/时间/权限),并防止引用超长导致后续步骤被截断。
model_answer(with_citations):让模型回答,并要求带引用。引用至少要能定位到'来自哪份材料的哪段',否则评估闭环做不起来。
实战示例:把'仓库'当知识库做一次最小 RAG(Android 视角,带引用) 场景:Android 新同学问'登录态为什么会丢?token 是在哪写入/读取的?失败会怎么处理?'
先搜(retrieve):搜 token、interceptor、auth、DataStore/SharedPreferences、refresh
再读(chunk):只读和问题相关的几个关键文件片段(不要把整个目录都塞给模型)
再去重/净化(dedupe + sanitize):去掉重复片段,过滤无关噪声与潜在注入内容
最后回答并引用(with_citations):每个关键结论都能回放到'某个文件的某段'
示意输出(路径/行号为示意,重点是格式与验收方式):
{"answer":"登录态通常丢在两类问题:token 持久化没写成功/被覆盖,或网络层刷新失败但上层没做降级处理。先从 token 的写入点、读取点、以及 401/refresh 流程三处排查。" ,"citations" :[{"path ":"app/src/main/java/com/example/auth/TokenStore.kt (示意)" ,"lines" :"1-120" },{"path ":"app/src/main/java/com/example/network/AuthInterceptor.kt (示意)" ,"lines" :"1-160" },{"path ":"app/src/main/java/com/example/network/RefreshTokenUseCase.kt (示意)" ,"lines" :"1-200" }]}
这里的'引用'不是装饰:你拿着引用范围回到代码里核对,就能判断结论是不是'代码里真的这么实现的',也能快速定位该改哪。
3)Agent:别把它当'机器人',它更像'带工具的循环控制器' 很多人理解 Agent 以为是'有自主意识的机器人'。工程上更准确的说法是:
Agent = 模型 + 工具(Tools) + 循环(Loop) + 停止条件(Stop Condition)
确定性优先 → Workflow(可控、可测、可回滚)
探索性/开放问题 → Agent(更灵活,但要更强的治理)
Goal -> Plan -> Act (tool call) -> Observe (tool result) -> Update memory/context -> Stop? else loop
停止条件:什么时候算完成?什么时候必须停?
失败策略:工具超时/权限不足/返回异常怎么办?
可观测性:每一步到底干了什么?成本与耗时在哪?
实战示例:用'循环控制器'修一个 bug(并且能停得住) 场景:新同学接到一个需求:'某个页面偶发崩溃,堆栈提示空指针,修完需要跑完测试再交付。'
把它按 Agent 循环落地,通常长这样(示意日志):
Goal: Fix NPE crash in FooViewModel 1) Plan: - 定位 NPE 触发路径 - 找到谁在传 null /谁没做校验 - 修复 + 补回归用例 2) Act (tool call): - 搜索崩溃堆栈里的符号/函数名 3) Observe (tool result): - 命中 3 处调用点,其中 1 处来自异步回调 4) Update memory/context: - 记录已确认事实:null 来自网络字段缺失 - 更新下一步动作:给解析层加默认值/给 ViewModel 加 guard 5) Act: - 修改代码并补测试 - 运行测试 6) Stop condition: - 单测通过 + 关键路径有回归覆盖 + 变更范围可解释 - 否则回到第 1 ) 继续循环
'能停得住'的关键不在模型聪明,而在你把停止条件写清楚:验收标准是什么、必须满足哪些客观信号(测试通过/引用齐全/风险可控)。没有停止条件,Agent 很容易变成'越修越多、越跑越远'。
4)Function Calling(工具调用)与结构化输出:它们不是'黑科技',是'契约' 模型要调用工具,最大的问题不是'能不能调用',而是'输出能不能被机器稳定解析'。
一句话:这是'前后端接口协议'在 LLM 世界的再发明。它解决的是工程确定性——不然你会天天在解析失败、字段缺失、枚举乱填里痛苦。
下面是一个最小示例(schema 约束工具入参),核心点是:让模型只能在你允许的结构里填值。
{ "name" : "search_docs" , "description" : "Search internal docs and return relevant snippets" , "parameters" : { "type" : "object" , "properties" : { "query" : { "type" : "string" } , "top_k" : { "type" : "integer" , "minimum" : 1 , "maximum" : 20 } } , "required" : [ "query" ] } }
如果你完全看不懂,上面这个 JSON 可以先按'工具说明书'来理解:它不是让你直接调用工具的参数,而是让模型知道'有哪些工具可以用、每个工具要填哪些字段、字段有什么约束'。
name:工具名。模型在决定要用工具时,会产出'我要调用 name=search_docs'这样的结构化意图。
description:工具用途说明。给模型做选择依据:什么时候该用它。
parameters:工具入参的 JSON Schema(核心)。
type: object:表示入参整体是一个对象(类似函数的参数对象)。
properties:这个对象里允许出现哪些字段。
query:字符串。你要搜什么。
top_k:整数,且限定范围 1–20。你允许模型最多取多少条候选,避免模型乱填一个特别大的数导致成本爆炸。
required:必填字段列表。这里要求必须提供 query,top_k 不填也可以(你的程序可以给默认值)。
它和 Function Calling 的关系可以一句话讲清:
Function Calling 是'模型怎么把调用意图变成机器可执行的结构化数据'的机制。
上面这个 JSON(schema)就是 Function Calling 需要的'契约':你把工具的名字与入参约束定义好,模型就按这个契约产出可解析的调用参数。
你把 tools (=schemas) 交给模型 -> 模型产出:call search_docs ({query: "..." , top_k: 5 }) -> 你的程序校验参数是否符合 schema -> 你的程序真实执行搜索 -> 把搜索结果回传给模型继续生成最终答案
实战示例:把'工具调用'当成强类型接口(先校验再执行) 在实际开发体验里,你会频繁看到'模型先触发一个工具动作(搜代码/读文件/跑命令)→ 再基于结果回答'。这件事之所以稳定,是因为它不是'让模型随便输出一段文字再让你猜',而是:
输入:用 schema 约束字段(防止字段缺失、枚举乱填、topK 过大导致成本爆炸)
过程:宿主程序做校验与执行(模型不直接碰你的数据库/命令行)
输出:用输出 schema 或固定格式要求'答案 + 引用/证据',便于验收与回放
typeSearchDocsArgs={ query:string; top_k?:number};functionvalidateSearchDocsArgs (args:any):asserts args is SearchDocsArgs {if (!args ||typeof args.query !=="string"|| args.query.length ===0 ){thrownewError ("invalid args: query is required");}if (args.top_k !==undefined&&(typeof args.top_k !=="number"|| args.top_k <1 || args.top_k >20 )){thrownewError ("invalid args: top_k must be 1 ..20 ");}}asyncfunctionhandleToolCall (name:string, rawArgs:unknown){if (name !=="search_docs")thrownewError ("unknown tool");const args = rawArgs asany;validateSearchDocsArgs (args);returnawaitrealSearch (args.query, args.top_k ??5 );}
新人理解到这里,就能把'Function Calling'当成一次'后端接口调用':模型负责产出结构化请求,你的程序负责校验与执行,最后再把结果回传给模型生成最终答案。
你问'这玩意是谁传给 LLM 的,还是 LLM 自带的?'——答案是两部分:
schema 不是 LLM 自带的知识,也不是模型训练时'天然就知道你有哪些工具'。它是你(应用开发者)在调用模型 API 时,通过 tools/functions 之类的参数显式传给模型的。
Function Calling 是模型/接口提供的能力:模型能在你提供的 tools 列表里做选择,并按 schema 生成结构化的调用参数;但'工具清单与约束'永远来自你的应用侧配置。
LLM 自带:生成文本、在候选工具里做选择、按 schema 填字段(尽量)。
你要提供:有哪些工具、每个工具的入参/约束、工具实际怎么执行(真实 HTTP/DB/脚本调用)、鉴权与审计。
如果你还要求输出也必须严格符合结构(例如必须给出引用段落与置信信息),那就是把'结构化输出'进一步拉满:
{ "type" : "object" , "properties" : { "answer" : { "type" : "string" } , "citations" : { "type" : "array" , "items" : { "type" : "object" , "properties" : { "doc_id" : { "type" : "string" } , "start" : { "type" : "integer" } , "end" : { "type" : "integer" } } , "required" : [ "doc_id" , "start" , "end" ] } } , "required" : [ "answer" , "citations" ] }
这段 schema 描述的不是'工具入参',而是'你希望模型最终返回的答案长什么样'(输出契约):
type: object:输出整体是一个对象。
properties:允许的输出字段。
answer:字符串,模型给出的最终答案正文。
citations:数组,每一项代表一条引用(证据)。
items.type: object:每条引用是一个对象。
doc_id:字符串,用来标识证据来自哪份文档/哪条数据源(例如 URL、文档主键、文件路径、知识库条目 ID)。
start/end:整数,用来定位证据在原文中的范围(可以是字符偏移、chunk 序号、段落号等;关键是你要选一种'可回放'的口径并坚持)。
required:每条引用至少要带 doc_id/start/end,避免模型只给'泛泛而谈的引用'。
required: ["answer","citations"]:要求必须同时返回答案与引用,否则就视为不合格输出。
目标:用户问'Android 发版前必须跑哪些检查/Gradle task?给出处。' 输入(应用 -> LLM)包含三块: 1 ) 用户问题(messages) 2 ) 工具契约:search_docs 的入参 schema (tools/functions) 3 ) 输出契约:要求最终必须返回 { answer, citations} (输出 schema / response schema )
第一步:模型决定先调用工具(Function Calling 的产物,结构化调用参数)
{ "tool_name" : "search_docs" , "arguments" : { "query" : "Android 发版 SOP 提测 检查 gradle task lint test" , "top_k" : 5 } }
第二步:你的程序执行工具,把结果回传给模型(tool result)
{ "tool_name" : "search_docs" , "result" : [ { "doc_id" : "android-release-sop-2026" , "text" : "提测前必跑:./gradlew testDebugUnitTest 与 ./gradlew lint...(略)" , "start" : 1200 , "end" : 1268 } ] }
第三步:模型输出最终答案(必须满足上面的输出 schema)
{ "answer" : "发版/提测前需要跑的检查是:./gradlew testDebugUnitTest 与 ./gradlew lint...(根据 SOP 条款整理)" , "citations" : [ { "doc_id" : "android-release-sop-2026" , "start" : 1200 , "end" : 1268 } ] }
把它和上一段'工具入参 schema'对照起来,你会发现:
工具入参 schema:约束的是'模型调用工具时怎么填参数'(call 的 arguments)。
输出 schema:约束的是'模型给用户最终回答的结构'(final answer JSON)。
5)MCP:它解决的是'工具生态对接的标准化',不是取代 Function Calling MCP(Model Context Protocol)是一个开放协议,用来把 LLM 应用与外部数据源/工具用统一方式连接起来。
你可以把它理解成:'Agent/IDE/Chat 应用(客户端)'对接'工具/数据(服务器)'的标准插头。有了插头,生态就能扩张得更快。
Function Calling:模型 ↔ 你的程序之间的'工具调用格式/契约'
MCP:你的程序 ↔ 外部工具服务之间的'连接与交互规范'
很多系统会两者同时用:模型用 Function Calling 产出结构化调用参数,你的程序再通过 MCP 去连各种工具服务。
同样重要的一句提醒:工具一旦'连通',风险也会被放大。研发负责人的视角必须补齐:权限边界、最小授权、审计与沙箱,否则'能干活'会变成'能闯祸'。
实战示例:用 MCP 拉飞书 SOP 文档,做'带出处'的问答 场景:团队把'Android 发版/提测 SOP'放在飞书文档里,新同学想问'提测前必须跑哪些检查、失败怎么处理',并且要求每个结论都能给出处。
用户问题 -> MCP:拉取飞书文档内容(拿到原文) -> RAG:把文档切片 + 检索命中段落 -> 输出:答案 + 引用(文档ID/段落范围)
示意(把'拉文档'这一步当成 MCP 工具调用):
{ "tool_name" : "mcp_mcp-component-doc_get-feishu-content" , "arguments" : { "documentLink" : "https://your-feishu-doc-link" } }
把它展开成'端到端三步',新人更容易理解'谁在调用谁、数据怎么流':
Step 1 ) 模型触发 MCP 工具:拉飞书文档(拿原文) Step 2 ) 宿主执行工具:返回文档内容片段(可能很长,后续要切片/检索) Step 3 ) 模型输出最终答案:结论 + 引用(指向文档的段落/范围)
示意(第 2 步的 tool result,形状因平台而异,这里只强调'你拿到了原文'):
{"tool_name" :"mcp_mcp-component-doc_get-feishu-content" ,"result" :{"title" :"Android 发版 SOP" ,"content_markdown" :"## 提测前检查\n ...\n ## 灰度与回滚\n ..." }}
拿到文档内容后,再做检索与引用输出(和前面的 RAG/输出 schema 完全同一套方法),新人就能理解:MCP 不神秘,它只是把'外部内容/工具'接进来,让你有材料可喂、有动作可做。
实战示例:用 MCP 把设计稿变成代码(把'资料'换成'设计源') 场景:产品给了 Figma 链接,希望快速生成一版可落地的 UI 骨架。
在实际应用中你可以把它理解为:MCP 负责把设计稿数据拉进来,然后你再让模型做'解释/改造/对齐规范'的工作。
{ "tool_name" : "mcp_mcp-component-doc_get-figma-to-code" , "arguments" : { "figma_url" : "https://www.figma.com/file/xxxxxx" } }
文档/设计稿属于数据源:要做权限隔离与审计,不要让'能拉到的都能问到'
生成代码属于可执行产物:要有 review、lint、测试与回滚路径
6)Skill:多数产品里它就是'可复用提示词/流程片段',别被神化 'Skill'在不同产品里定义不一,但落到工程实现,经常就是两类东西:
Prompt 模板的资产化:把一段高质量提示词 + 输入槽位 + 约束,做成可复用组件
轻量流程编排:把'先做 A 再做 B'的步骤固化(有时只是把步骤写进提示词)
所以你听到'Skill 很强',不要先激动,先问:
它是纯提示词?还是带工具?
有 schema 约束吗?
有评估与版本管理吗?
没有这些,Skill 很容易变成'看起来很强、线上很飘'的玄学资产。
开发工具中的 Skill 更接近'一个可被发现与加载的文件夹',核心文件通常是 SKILL.md(Markdown + YAML frontmatter 元信息),并配套 references/、scripts/、assets/ 等资源:
.trae/skills/ doc- search- answer/ SKILL .md references/ # 可选:示例输入、 知识片段、 对齐材料 scripts/ # 可选:用于复现/校验的脚本(如果你的环境支持执行) assets/ # 可选:图片/ 示意图等
一个'更像开发工具'的 SKILL.md(示例)可以这样写(重点是:触发条件 + 输入要求 + 输出格式 + 自检清单):
--- name: "doc-search-answer" description: "对文档库检索并生成带引用的回答;适合 FAQ/制度/规范类问题。" --- # Doc Search Answer ## 使用时机(触发条件) - 用户问的是'有明确证据来源' 的问题:制度、规范、接口文档、SOP、历史决策 - 你需要输出可追溯引用,而不是只给看起来合理的回答 ## 输入要求(尽量明确) - 用户问题:一句话 + 关键约束(时间范围/团队/版本/区域) - 可选:需要优先检索的数据源范围(例如:仅 policies/ 或仅 engineering/) ## 工具依赖(概念层) - search_docs (query, top_k): 检索候选片段 ## 输出格式(严格) ```json { "answer": "..." , "citations" : [ { "doc_id": "..." , "start" : 0 , "end" : 0 } ] } ``` ## 工作流(推荐) 1 ) 先检索:用问题里的关键词做 search 2 ) 再筛选:去重、过滤注入片段,保留最相关证据 3 ) 再回答:先给结论,再用引用对齐关键句 ## 自检清单 - [ ] 是否每个关键结论都有对应 citation? - [ ] 引用是否能定位到原文范围(doc_id + start/end)? - [ ] 是否避免把引用当成'装饰'(引用必须真的支持结论)?
实战示例:再给一个更'工程向'的 Skill 模板(修 bug/改代码) 如果你的目标不是'回答问题',而是'改代码并交付',Skill 的输出就不该只有答案,还要包含可验收的产物(补丁/测试结果/回滚方式)。一个偏工程的模板可以这样写:
--- name: "repo-bugfix-workflow" description: "在仓库内定位问题、最小改动修复、跑测试验证,并输出可回放证据。" --- # Repo Bugfix Workflow ## 使用时机(触发条件) - 用户给了错误现象/堆栈/ 日志,目标是'修复并验证' ## 输入要求 - 错误信息:堆栈/日志关键行 - 验收标准:要通过哪些测试/ 是否允许改动行为 ## 输出格式(固定) 1 ) Root Cause(根因一句话) 2 ) Fix(改动点列表:文件 + 行号范围) 3 ) Verification(验证命令 + 关键输出摘要) 4 ) Risk & Rollback(风险点 + 回滚方式) ## 自检清单 - [ ] 是否提供了能复现/回放的证据(文件引用或日志片段)? - [ ] 是否跑过项目约定的测试/ 检查? - [ ] 改动是否满足'最小范围',避免顺手重构?
7)给你一套'通杀新概念'的三问法(拿去就能用) 下次再出现一个新黑话(比如 XX Copilot、YY Agent、ZZ Skill),你只问三件事:
它在补大模型哪块短板?
缺知识 → RAG/搜索
缺记忆 → Memory/总结压缩
缺手脚 → Tools/MCP/插件
它的确定性来自哪里?
schema/结构化输出?
workflow 编排?
还是'相信模型会乖'?
它的风险与成本在哪里?
权限/数据泄露/注入
token 成本与延迟
线上可观测与回滚
实战示例:用'三问法'选对打法(新人不容易走偏) 场景:新同学说'我想搞个 Agent,把问题都自动解决'。这时候用三问法能快速把需求落到工程选型:
它在补什么短板?
只是'读懂仓库/解释代码' → 缺知识:优先做 RAG(先搜再读再答),不需要 Agent 循环
需要'改代码并验证' → 缺手脚:需要工具调用(跑测试/改文件),是否需要 Agent 取决于任务是否开放探索
它的确定性来自哪里?
有明确验收(测试必须通过/输出必须带引用)→ 用 schema + 固定输出格式 + workflow 步骤约束
没有明确验收('帮我优化一下体验')→ 才更像 Agent 的探索型任务,但必须加停止条件与预算上限
它的风险与成本在哪里?
读权限/写权限边界是否清晰?是否会把敏感内容回显?
会不会跑错命令/改错文件?是否能回滚?
token 与延迟是否可接受?是否需要缓存与摘要?
8)一张图讲清全家桶(研发视角) 用户问题 ↓ (可选) RAG/搜索:取资料 ↓ 上下文拼装(Context/Memory) ↓ LLM 推理(生成/决策) ↓ (可选) 工具调用:Function Calling(工具调用) ↓ (可选) 连接工具生态:MCP / 插件 ↓ 执行结果 → 回写上下文 → 继续循环(Agent)或结束(Workflow)
8.1)开发工具版'全家桶'一眼看懂(把概念映射到实际动作) 你在开发工具输入需求 ↓ (可选)加载 Skill:选择一套固定工作流 /输出格式 ↓ (可选)RAG:在仓库/ 文档里搜索 + 读取关键片段 ↓ 上下文拼装:把规则 + 资料片段 + 当前状态拼进一次请求 ↓ 模型决策:生成方案 / 选择下一步动作 ↓ (可选)工具调用:读文件 / 跑命令 / 生成补丁 ↓ (可选)MCP:对接飞书 /设计稿/ 组件库等外部数据源 ↓ 验证与交付:测试通过 + 引用可回放 + 风险可控
9)趋势判断:未来一定是'降门槛',而不是'叠名词'
更多能力被打包成默认能力(不用你配一堆参数)
更强的治理与安全成为标配(权限、审计、沙箱、评估)
Workflow 与 Agent 会长期共存:核心链路要稳,边缘探索要灵活
10)落地检查清单(快速自查) 这一段只做一件事:在你准备'真的把它用到研发流程里'之前,用 1 分钟把方向校准好,避免把系统做成'能演示但不好用、能生成但不能上线'。
我到底要解决什么问题?
知识类(看不懂代码/制度/文档)→ 先做 RAG(先搜再读再答)
执行类(改代码/跑测试/发版)→ 需要工具调用 + 验证闭环
我交付的'证据'是什么?
知识类:答案 + 可回放引用(文件/段落/行号范围)
执行类:补丁 + 验证结果(测试/检查输出摘要)
我怎么保证它不会乱来?
结构:schema / 固定输出格式
流程:workflow 步骤 + 停止条件(什么时候必须停)
权限:最小授权 + 审计 + 沙箱(能读什么、能写什么、能跑什么)
我怎么上线后兜底?
评估:命中率/引用覆盖/事实一致/成本与延迟(至少有一组回归问题)
回滚:禁用工具、只读模式、回滚提交
10.1)放到实际项目中怎么验收(新人交付不翻车) 把一次开发工具里的交付,验收成'像正常研发交付一样':
读得懂:结论是否能回放到证据?
必须有引用:文件路径/段落/行号范围(不接受'我觉得是这样')
改得对:改动是否最小且可解释?
清楚说明:改了哪几个文件、为什么改、影响面是什么(Android 侧尤其要写清楚是否影响主线程/启动/序列化)
跑得过:是否真的验证过?
至少提供:执行了哪些命令(例如 ./gradlew test / ./gradlew lint),以及关键输出摘要(通过/失败点)
不越权:是否守住数据与权限边界?
不回显敏感信息、不把内部链接/凭证贴进答案;需要访问外部系统时必须走授权工具链
能回退:是否有明确回滚方式?
出问题如何快速降级到只读/禁用工具,或回滚到某次提交
结尾:别怕黑话,你要盯的是'系统补短板的方式' 你不需要追着每个新名词跑。记住开头那五个零件(Context/Search/Tool/Workflow/Schema),再用三问法校准:它补什么短板?确定性来自哪里?代价和风险在哪里?
回答完这三个问题,Skill/MCP/RAG/Agent 就会从'玄学名词'变成'可控组件':能被验收、能回滚、能迭代。
相关免费在线工具 RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online