智能体技能为智能体提供完成任务所需的可复用指令和配套文件。您可以在 Responses API Shell 工具中使用这些技能,也可以将其放入 Agents API 沙盒中供智能体使用。
下文的上传、附加和版本管理说明适用于 Responses API Shell 工具。Agents API 会话会从其沙盒内的目录中发现技能。
Responses API 支持两种技能执行形式:本地执行和
基于容器的托管执行。要在您自己的计算机上运行代码,请使用
Shell 工具的本地执行模式。
技能是一个文件目录,其中包含 SKILL.md 清单文件(前置元数据 + 指令)。技能提供模块化指令,您可以用它们将流程和规范编写成可复用的指令,涵盖公司风格指南、多步骤工作流等内容。上传的技能采用带版本的文件包。
技能兼容开放的 Agent Skills 标准。
1
2
3
4
5
6---
name: basic-math
description: Add or multiply numbers.
---
Use this skill when you need a quick sum or product of numbers.
在发现技能时,模型会看到技能的名称和描述。编写描述时,请说明技能的用途以及适用时机。例如,与“协助处理法律工作”相比,“使用备选条款审查供应商协议并标注修订”能为模型提供更有用的上下文。
将主要指令放在 SKILL.md 中,并根据需要添加指向配套文件的链接:
review-pr/
├── SKILL.md
├── references/
│ └── review-guidelines.md
├── scripts/
│ └── check-changes.sh
└── assets/
└── review-template.md
使用 references/ 存放背景资料,使用 scripts/ 存放可重复执行的操作脚本,使用 assets/ 存放可复用的模板。
您可以通过多部分表单数据上传目录,也可以上传仅包含一个顶层文件夹的 .zip 文件。
上传多个 files[] 部分。每个部分都包含同一个顶层文件夹内的路径。
1
2
3
4curl -X POST 'https://api.openai.com/v1/skills' \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-F 'files[]=@./basic_math/SKILL.md;filename=basic_math/SKILL.md;type=text/markdown' \
-F 'files[]=@./basic_math/calculate.py;filename=basic_math/calculate.py;type=text/plain'
将顶层文件夹压缩为 zip 文件,然后上传该文件。
1
2
3curl -X POST 'https://api.openai.com/v1/skills' \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-F 'files=@./basic_math.zip;type=application/zip'
要在托管式 Shell 环境中挂载技能,请在调用 Shell 工具时通过 tools[].environment.skills 附加技能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19curl -L 'https://api.openai.com/v1/responses' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-6-astra",
"tools": [
{
"type": "shell",
"environment": {
"type": "container_auto",
"skills": [
{ "type": "skill_reference", "skill_id": "<skill_id>" },
{ "type": "skill_reference", "skill_id": "<skill_id>", "version": 2 }
]
}
}
],
"input": "Use the skills to add 144 and 377, then compute triangle area with base 9 height 13."
}'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
tools: [
{
type: "shell",
environment: {
type: "container_auto",
skills: [
{ type: "skill_reference", skill_id: "<skill_id>" },
{ type: "skill_reference", skill_id: "<skill_id>", version: "2" },
],
},
},
],
input:
"Use the skills to add 144 and 377, then compute triangle area with base 9 height 13.",
});
console.log(response.output_text);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22response = client.responses.create(
model="gpt-6-astra",
tools=[
{
"type": "shell",
"environment": {
"type": "container_auto",
"skills": [
{"type": "skill_reference", "skill_id": "<skill_id>"},
{
"type": "skill_reference",
"skill_id": "<skill_id>",
"version": 2,
},
],
},
}
],
input="Use the skills to add 144 and 377, then compute triangle area with base 9 height 13.",
)
print(response.output_text)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{
Environment: responses.FunctionShellToolEnvironmentUnionParam{OfContainerAuto: &responses.ContainerAutoParam{
Skills: []responses.ContainerAutoSkillUnionParam{
{OfSkillReference: &responses.SkillReferenceParam{SkillID: "<skill_id>"}},
{OfSkillReference: &responses.SkillReferenceParam{SkillID: "<skill_id>", Version: openai.String("2")}},
},
}},
}}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Tools: []responses.ToolUnionParam{tool},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Use the skills to add 144 and 377, then compute triangle area with base 9 height 13.")},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.ResponseCreateParams;
import java.util.List;
import java.util.Map;
String skillId = "<skill_id>";
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input(
"Use the skills to add 144 and 377, then compute a triangle area with base 9 and height 13.")
.putAdditionalBodyProperty(
"tools",
JsonValue.from(
List.of(
Map.of(
"type",
"shell",
"environment",
Map.of(
"type",
"container_auto",
"skills",
List.of(
Map.of("type", "skill_reference", "skill_id", skillId),
Map.of(
"type", "skill_reference",
"skill_id", skillId,
"version", "2")))))))
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "Use the skills to add 144 and 377, then compute a triangle area with base 9 and height 13.",
tools: [
{
type: :shell,
environment: {
type: :container_auto,
skills: [
{
type: :skill_reference,
skill_id: "<skill_id>"
},
{
type: :skill_reference,
skill_id: "<skill_id>",
version: "2"
}
]
}
}
]
)
puts(response.output_text)
挂载技能后,模型可以自行决定何时使用它。如果您希望行为更确定,可以在适当时明确指示模型“使用 <skill name> 技能”。
技能也适用于本地 Shell 模式,但本地 Shell 和托管式 Shell 接受的技能附件格式不同。
- 托管式 Shell 支持已上传的
skill_reference 附件,包括精选技能和明确指定的版本。
- 本地 Shell 不支持
skill_reference 附件。请改为在您控制的运行时中,通过本地文件路径提供技能文件。
有关本地 Shell 执行的详细信息,请参阅 Shell 指南。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22curl -L 'https://api.openai.com/v1/responses' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-6-astra",
"tools": [
{
"type": "shell",
"environment": {
"type": "local",
"skills": [
{
"name": "csv-insights",
"description": "Summarize CSV files and produce a markdown report.",
"path": "<path-to-skill-folder>"
}
]
}
}
],
"input": "Use the csv-insights skill and run locally to summarize today\'s CSV reports in this repo."
}'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26import OpenAI from "openai";
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-6-astra",
tools: [
{
type: "shell",
environment: {
type: "local",
skills: [
{
name: "csv-insights",
description: "Summarize CSV files and produce a markdown report.",
path: "<path-to-skill-folder>",
},
],
},
},
],
input:
"Use the csv-insights skill and run locally to summarize today's CSV reports in this repo.",
});
console.log(response.output_text);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21response = client.responses.create(
model="gpt-6-astra",
tools=[
{
"type": "shell",
"environment": {
"type": "local",
"skills": [
{
"name": "csv-insights",
"description": "Summarize CSV files and produce a markdown report.",
"path": "<path-to-skill-folder>",
}
],
},
}
],
input="Use the csv-insights skill and run locally to summarize today's CSV reports in this repo.",
)
print(response.output_text)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31package main
import (
"context"
"fmt"
"github.com/openai/openai-go/v3"
"github.com/openai/openai-go/v3/responses"
)
func main() {
client := openai.NewClient()
tool := responses.ToolUnionParam{OfShell: &responses.FunctionShellToolParam{
Environment: responses.FunctionShellToolEnvironmentUnionParam{OfLocal: &responses.LocalEnvironmentParam{
Skills: []responses.LocalSkillParam{{
Name: "csv-insights",
Description: "Summarize CSV files and produce a markdown report.",
Path: "<path-to-skill-folder>",
}},
}},
}}
response, err := client.Responses.New(context.Background(), responses.ResponseNewParams{
Model: "gpt-6-astra",
Tools: []responses.ToolUnionParam{tool},
Input: responses.ResponseNewParamsInputUnion{OfString: openai.String("Use the csv-insights skill and run locally to summarize today's CSV reports in this repo.")},
})
if err != nil {
panic(err)
}
fmt.Println(response.OutputText())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.core.JsonValue;
import com.openai.models.responses.ResponseCreateParams;
import java.util.List;
import java.util.Map;
String skillPath = "<path-to-skill-folder>";
ResponseCreateParams params =
ResponseCreateParams.builder()
.model("gpt-6-astra")
.input("Use the csv-insights skill to summarize today's CSV reports.")
.putAdditionalBodyProperty(
"tools",
JsonValue.from(
List.of(
Map.of(
"type",
"shell",
"environment",
Map.of(
"type",
"local",
"skills",
List.of(
Map.of(
"name", "csv-insights",
"description",
"Summarize CSV files and produce a Markdown report.",
"path", skillPath)))))))
.build();
client.responses().create(params).output().stream()
.flatMap(item -> item.message().stream())
.flatMap(message -> message.content().stream())
.flatMap(content -> content.outputText().stream())
.forEach(text -> System.out.println(text.text()));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24require "openai"
client = OpenAI::Client.new
response = client.responses.create(
model: "gpt-6-astra",
input: "Use the csv-insights skill to summarize today's CSV reports.",
tools: [
{
type: :shell,
environment: {
type: :local,
skills: [
{
name: "csv-insights",
description: "Summarize CSV files and produce a Markdown report.",
path: "<path-to-skill-folder>"
}
]
}
}
]
)
puts(response.output_text)
要在 Agents API 中使用技能,请将技能目录放入沙盒,并在创建会话时将其父目录注册到 environment.capability_directories 中。这些父目录称为 能力目录。执行框架使用这些目录来发现技能;这种配置方式不使用托管式 Shell 的 skill_reference 附加格式。
例如,在沙盒中放入一个合同审查技能和一个 Pull Request 审查技能:
/workspace/capabilities/
├── legal/
│ └── contract-redline/
│ ├── SKILL.md
│ └── references/
│ └── fallback-clauses.md
└── engineering/
└── review-pr/
├── SKILL.md
└── references/
└── review-guidelines.md
在创建会话的请求中使用以下环境配置:
12345678910{
"environment": {
"type": "self_hosted",
"workspace_directory": "/workspace",
"capability_directories": [
"/workspace/capabilities/legal",
"/workspace/capabilities/engineering"
]
}
}
能力目录须满足以下要求:
- 路径必须指向沙盒内的目录。
- 路径必须是绝对路径且互不重复,并且不能包含
. 或 .. 路径段。
- 一个会话最多可以注册 32 个能力目录。
- 目录必须已存在于环境中。
沙盒可用后,执行框架会在这些目录中搜索 SKILL.md 文件,并将发现的每个技能的名称和描述添加到上下文中。模型可以选择相关技能,并读取其完整指令和配套文件。
有关会话设置,请参阅智能体配置;有关执行环境,请参阅连接沙盒。在向智能体提供技能之前,请审查技能及其配套文件,并遵循沙盒安全指南。
对于 Responses API Shell 工具,平台会将每个可用技能的 name、description 和 path 添加到用户提示上下文中,让模型知道该技能的存在。
模型根据这些元数据决定是否调用技能。如果模型调用某个技能,就会通过 path 从 SKILL.md 中读取完整的 Markdown 指令。
技能指令属于用户提示输入(而非系统提示输入),因此其处理优先级与用户提供的其他指令相同。要明确控制技能的使用,您仍可以指示模型“使用 <skill name> 技能”。
- 匹配
SKILL.md 文件时不区分大小写。
- 一个技能包中必须有且只能有一个
skill.md/SKILL.md 文件。
- 技能前置元数据的验证遵循 Agent Skills 规范。
- 上传的 zip 文件大小上限为
50 MB。
- 每个技能版本最多可包含
500 个文件。
- 未压缩文件的大小上限为
25 MB。
检查与 Responses API 配合使用的每个技能至关重要。技能
会带来安全风险,例如由提示注入引发的数据外泄。
使用此工具前,请仔细阅读下方的风险与安全
部分。
- 未提供版本时,使用
default_version。
latest_version 指向最新上传的版本。
skill_reference.version 接受整数或 "latest"。
1
2
3curl -X POST 'https://api.openai.com/v1/skills/<skill_id>/versions' \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-F 'files=@./geometry.zip;type=application/zip'
1
2
3
4curl -X POST 'https://api.openai.com/v1/skills/<skill_id>' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{"default_version": 2}'
- 您无法删除默认版本;请先将其他版本设为默认版本。
- 删除最后一个剩余版本时,也会删除该技能。
- 删除技能时,会级联删除其所有版本。
OpenAI 维护了一组第一方技能,您可以通过 ID(例如 openai-spreadsheets)引用这些技能。
{ "type": "skill_reference", "skill_id": "openai-spreadsheets", "version": "latest" }
如果您不想创建托管技能,可以在环境的 skills 数组中内联一个经 base64 编码的 zip 文件包。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20INLINE_ZIP=$(base64 -i ./basic_math.zip)
curl -L 'https://api.openai.com/v1/containers' \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"name": "inline-skill-container",
"skills": [
{
"type": "inline",
"name": "basic_math",
"description": "Add or multiply numbers.",
"source": {
"type": "base64",
"media_type": "application/zip",
"data": "'"$INLINE_ZIP"'"
}
}
]
}'
检查与 Responses API 配合使用的每项技能非常重要。技能会带来安全风险,例如提示注入导致的数据外泄。
如果技能需要配合网络访问使用,请仔细阅读网络访问的风险与安全章节。
技能内容可能影响规划、工具使用和命令执行。在开发者完成验证之前,应将任何技能都视为可能不可信的输入并加以审查。
在产品设计中,应避免让消费端最终用户从开放的技能目录中自由浏览、选择或附加任意技能。这会显著增加以下风险:
- 通过恶意 SKILL.md 指令进行提示注入和绕过策略限制。
- 未经审查的自动化触发数据外泄或破坏性操作。
技能应由开发者检查并集成,然后仅通过范围受限的产品功能提供给最终用户。具体做法包括:
- 将技能映射到特定的产品工作流或使用场景。
- 防止最终用户自行选择任意技能。
- 写入操作或影响重大的操作必须获得明确审批并通过策略检查后才能执行。
对于能够执行写入操作或影响重大操作的工作流,要求在执行前获得明确审批。
Responses API 支持两种技能执行形式:本地执行和基于容器的托管执行。托管技能遵循与托管式 Shell 相同的容器生命周期:容器处于活跃状态时,挂载的技能和容器文件会一直可用;容器过期或被删除时,这些内容也会被丢弃。如果您希望执行过程完全在自己管理的基础设施上进行,请使用本地 Shell 模式。有关 Agents API 沙盒,请参阅沙盒生命周期。进一步了解我们的数据控制。