Spring AI Agent Skills实战教程:从零构建文章摘要机器人  

让AI帮你读文章!Spring AI技能配置全记录  

Agent Skills规范让AI智能体能调用本地定义的能力。本文用Spring AI实战,创建文章摘要技能并集成到聊天机器人,全程命令行和配置,感受智能体如何按技能说明书自动执行脚本完成任务。

什么是Agent Skills

说到Agent Skills,你可能会想到钢铁侠的贾维斯。贾维斯能控制各种设备,是因为那些设备都给它留了接口。Agent Skills干的就是类似的事情,只不过它是给AI大模型准备的标准化本地能力接口规范。

本质上,一个技能就是一个文件夹。这个文件夹里面必须有一个叫SKILL.md的文件,这个文件相当于技能说明书。说明书最前面是YAML格式的frontmatter,写着技能的名字和描述,后面跟着一大段自然语言写的操作步骤,告诉AI该怎么使用这个技能。除了说明书,文件夹里还可以放Python脚本、Bash脚本或者其他资源文件,技能需要什么就放什么。

当用户给AI发消息时,AI会先看所有可用技能的描述,判断有没有跟用户请求匹配的。如果找到了合适的,AI就把技能文件夹里的文件加载到上下文里,然后照着说明书的步骤一步步执行。如果没找到匹配的技能,AI就用自己的通用能力正常回答,不调用任何技能。整个过程对用户来说是透明的,你根本感觉不到AI在后面翻说明书、找工具、跑脚本。

项目依赖配置

要玩Agent Skills,得先把项目的依赖搞定。Spring AI从2.0版本开始支持这个特性,所以版本号要选对。这里用OpenAI的模型做演示,但理论上只要支持Agent Skills规范的大模型都可以。

打开你的pom.xml文件,把下面这两个依赖加进去。第一个是Spring AI提供的OpenAI启动器,用来跟大模型对话。第二个是Spring AI社区提供的工具包,它负责把技能能力挂载到聊天模型上。

xml

    org.springframework.ai
    spring-ai-starter-model-openai
    2.0.0


    org.springaicommunity
    spring-ai-agent-utils
    0.10.0

依赖加完别急着启动,还差一步。你得在application.yaml配置文件里把OpenAI的API密钥和模型名称写上。密钥建议用环境变量传,别硬编码在配置文件里,不然代码传仓库就泄露出去了。

yaml
spring:
  ai:
    openai:
      api-key: ${OPENAI_API_KEY}
      chat:
        options:
          model: gpt-5.5

这里指定了gpt-5.5模型,你也可以换成其他支持Agent Skills的模型。配置完这两项,Spring AI会自动创建一个ChatModel类型的Bean,后面跟模型聊天就全靠它了。

自定义摘要技能

好,现在来做一个真正的技能。这个技能的功能是:给AI一个文章URL,它能抓取内容并输出摘要。我们要让AI变成你的私人文章速读助手。

第一步,在项目的根目录下创建文件夹.openai/skills。这个路径是固定的,Spring AI的工具会默认扫描这个位置。然后在这个文件夹里再创建一个子文件夹article-summarizer,这个子文件夹的名字就是技能的名字。

在article-summarizer文件夹里创建SKILL.md文件,内容如下:

``markdown



name: article-summarizer
description: Summarizes articles into concise digests. Useful when user asks to summarize or get key points from an article.


# Article Summarizer
Instructions
When summarizing an article:
1. If given a URL: Run
uv run scripts/fetch_article.py to retrieve the content.
2. Once content is available, extract the main thesis, few key points, and conclusion.
3. Structure the output as a TL;DR, key points, and a bottom line.

最上面的frontmatter写了技能名称和描述,描述特别关键,AI就是靠它来判断该不该用这个技能。下面的Instructions部分是操作指南,AI会逐条照着做。这里第一条指令说,如果用户给了URL,就用uv命令运行fetch_article.py脚本,把URL传进去。第二条说拿到内容后提取核心论点、几个关键点和结论。第三条说输出格式要分成TL;DR、Key Points和Bottom Line三部分。

接着创建scripts文件夹,在里面放fetch_article.py脚本。为了演示方便,我们不真的去请求网络,而是直接打印一篇预设的文章内容。

python
ARTICLE = """
...硬编码的文章内容,这里省略实际文本
"""
print(ARTICLE)

注意,我们的脚本用Python写的,但你完全可以用Bash、JavaScript或者任何你喜欢的语言。只要确保运行环境提前装好了,AI执行命令时能找到对应的解释器就行。

构建聊天机器人

配置都搞定了,现在开始写代码。Spring AI里面,跟大模型聊天主要靠ChatClient这个类,它是整个聊天的入口。

我们需要写一个配置类,把ChatClient的Bean定义好。这里要注册三个工具:SkillsTool负责告诉AI技能目录在哪里,FileSystemTools让AI能读写文件系统,ShellTools让AI能执行shell命令。

java
@Bean
ChatClient chatClient(ChatModel chatModel) {
    String skillsRootDirectory = ".openai/skills";
    return ChatClient
      .builder(chatModel)
      .defaultTools(
        SkillsTool.builder()
          .addSkillsDirectory(skillsRootDirectory)
          .build(),
        FileSystemTools.builder()
          .allowedDirectory(skillsRootDirectory)
          .build(),
        ShellTools.builder()
          .build()
      ).build();
}

FileSystemTools我们设置了allowedDirectory,限制它只能操作技能目录,防止AI乱翻电脑里其他文件。ShellTools是直接在本机执行命令的,没有沙箱隔离,所以一定要小心,只让AI执行你审核过的脚本。生产环境最好把应用容器化,限制文件系统访问范围。

然后写一个Controller,暴露一个POST接口给前端调用。

java
@PostMapping("/chat")
ResponseEntity chat(@RequestBody ChatbotRequest chatbotRequest) {
    String answer = chatClient
      .prompt()
      .user(chatbotRequest.question)
      .call()
      .content();
    return ResponseEntity.ok(new ChatbotResponse(answer));
}
record ChatbotRequest(String question) {}
record ChatbotResponse(String answer) {}

这个接口很简单,收到用户问题就传给chatClient,拿到模型回复再返回给前端。整个流程看起来就像普通的聊天接口,但背后已经暗藏了技能调用的玄机。

测试运行效果

一切就绪,启动Spring Boot应用,然后打开终端用HTTPie工具发个请求测试一下。为了让测试更有说服力,我们故意传一个不存在的文章URL,看AI会不会中招。

bash
http POST :8080/chat question="Can you summarize the following article: XXX"
``

服务端收到请求后,AI开始工作。它先看所有技能描述,发现article-summarizer的描述跟"summarize article"匹配,于是决定调用这个技能。接着它打开SKILL.md文件,看到第一条指令是运行fetch_article.py脚本。于是ShellTools出马,执行了uv run scripts/fetch_article.py https://...命令。脚本并不关心URL是什么,直接打印了硬编码的文章内容。AI拿到标准输出内容后,继续看说明书第二条和第三条,开始提取核心论点、关键点和结论,最后按照TL;DR、Key Points、Bottom Line的格式组织回复。

最终返回的JSON响应里,answer字段就是AI整理好的结构化摘要。我们故意给了不存在的URL,但AI老老实实总结了我们预设的文章,这说明它压根没去请求那个URL,完全按照技能脚本的逻辑在执行。

技能执行流程拆解

刚才的测试背后其实发生了一系列动作,咱们来拆解一下。整个过程分成发现、加载、执行、输出四个阶段,每个阶段都环环相扣。

发现阶段,AI把用户问题"Can you summarize the following article"跟所有技能的description做匹配。article-summarizer的描述里正好有"summarize"和"article"关键词,匹配成功。

加载阶段,AI通过FileSystemTools读取了article-summarizer文件夹里的SKILL.md文件,把整个文件内容加载到上下文窗口中。

执行阶段,AI解析SKILL.md里的Instructions,识别出第一步是要运行Python脚本。于是它通过ShellTools执行了uv run命令,脚本跑完后输出了文章内容,AI把这个输出保存在内存里。

输出阶段,AI继续按照Instructions的第二和第三步处理,从文章内容里提取出TL;DR、Key Points和Bottom Line,最后把整理好的摘要作为最终回答返回给用户。

整个过程AI就像一个有工牌的新员工,拿到用户需求后先翻岗位手册,找到对应的操作流程,然后按照流程一步步执行,最后把结果汇报给用户。

技能目录结构规范

刚才我们只创建了一个技能,但实际项目中可能有很多个技能。Agent Skills规范的目录结构设计得挺巧妙,支持多技能共存。

根目录.openai/skills下面,每个子文件夹代表一个独立的技能。每个技能文件夹必须包含SKILL.md文件,其他文件是可选的。

如果你的技能需要跑脚本,建议建一个scripts子文件夹统一存放。如果需要配置文件或者模板文件,也可以建configs或templates之类的文件夹,没有强制规定。

每个SKILL.md文件的结构是固定的:最上面是YAML frontmatter,用三个短横线包裹,里面定义name和description。然后是一级标题写技能名称,二级标题写Instructions,下面跟着自然语言的操作步骤。

这种结构的好处是AI可以快速扫描所有技能的description做匹配,而不需要读取整个文件。等匹配上了再加载完整内容,省流量省时间。

安全注意事项

ShellTools直接执行shell命令,这玩意儿跟双刃剑一样。如果技能脚本里写了rm -rf /,那AI执行起来可不会跟你客气。所以安全方面一定要上心。

第一,只让AI访问你明确授权的目录。FileSystemTools的allowedDirectory方法就是干这个的,把技能目录锁死,AI读写文件只能在这个范围内。

第二,技能脚本必须经过人工审核。别从网上下载不明来源的技能文件夹直接放进项目里,鬼知道里面藏着什么命令。

第三,生产环境建议容器化部署。把应用装进Docker容器,限制文件系统访问和网络访问,就算AI执行了危险命令,影响范围也局限在容器内部。

第四,谨慎对待需要网络请求的技能。如果技能脚本里用了requests.get()或者curl,AI可能会去访问内网地址或者恶意网站,这个风险也得评估。

技能描述撰写技巧

技能描述是AI决定调不调用技能的唯一依据,写得好不好直接影响调用准确率。这里分享几个实战技巧。

描述要包含用户可能用到的自然语言触发词。比如我们的描述里写了"Summarizes articles into concise digests. Useful when user asks to summarize or get key points from an article.",当用户说"帮我总结这篇文章"或者"提取几个关键点"时,AI就能精准匹配。

描述不要写得太长。AI在匹配阶段只会扫描description字段,这个字段应该简洁明了,信息密度高。具体操作步骤放到Instructions部分去写。

描述里可以适当放几个同义词变体。比如"summarize"可以换成"condense"、"digest"、"extract key points",覆盖更多用户表述方式。

如果你有多个技能,描述之间的区分度要高。不要两个技能都写"处理文本",一个写"翻译英文到中文",另一个写"生成文章摘要",让AI能清晰区分。

多技能协同场景

虽然我们只演示了单技能调用,但Agent Skills支持多个技能同时存在,AI甚至可以在一次对话中依次调用多个技能。

比如你可以定义三个技能:fetch_article负责抓取文章内容,translate_to_chinese负责把英文翻译成中文,summarize负责生成摘要。用户问"把这篇英文文章摘要用中文发给我",AI就会先调fetch_article拿到内容,再调summarize生成英文摘要,最后调translate_to_chinese翻译成中文。

这种组合拳能力让Agent Skills的应用场景非常广泛。你可以把日常工作中反复用到的操作都封装成技能,让AI当你的自动化助理。写周报、整理会议纪要、生成代码注释、检查配置文件格式,只要能写成自然语言指令加脚本的组合,都能变成技能。

技能调试心得

实战开发中,技能写好了不一定能一次跑通,这里分享几个调试经验。

如果AI不调用你的技能,先检查description是不是写得太模糊,或者用户问题里的关键词跟description匹配不上。你可以故意在用户问题里重复description里的原词,测试是不是匹配问题。

如果技能被调用了但执行结果不对,检查SKILL.md里的Instructions是不是写得太笼统。AI理解自然语言有时候会跑偏,Instructions要尽量具体,步骤编号清晰,能给出输入输出示例最好。

如果Python脚本报错,AI会把错误信息返回在最终回答里。你可以把错误信息拿过来,检查脚本语法、依赖包、文件路径是否正确。记住AI执行命令时的当前工作目录是项目根目录,不是技能文件夹所在目录,所以脚本里的相对路径要小心写。

如果AI不按Instructions要求的格式输出,可以在Instructions最后加一句"Output must strictly follow this format"并给出示例模板。AI对格式约束的理解能力取决于模型本身,GPT-5.5系列通常表现不错。

总结

Agent Skills在Spring AI中提供了一种轻量级方式向AI暴露本地能力,无需搭建MCP服务器。通过SKILL.md定义技能说明,配合脚本执行,AI能自动完成文章摘要等任务。