
每个用Postman的团队多多少少都攒下一座API金矿几百条接口请求、一整套环境变量、带好的header和鉴权、甚至写好的测试断言。但我一度觉得这些资产只能在Postman里用手工导出、手工贴curl、手工给AI描述接口换个工具就全归零。直到我仔细研究了OpenAI Codex的Skill机制才意识到完全可以把Postman里的API能力直接变成Codex的“插件”让智能体像老同事一样自己查集合、自己发请求、自己分析响应。这篇分享不是概念介绍而是我自己搭过一遍之后的完整落地记录包括方案选型、目录结构、脚本写法、SKILL.md怎么写以及我踩过的一些坑。适合API测试工程师、后端开发、以及所有想让AI Agent真正“上手”操作API的朋友。我会尽量把“为什么这么做”也讲清楚不只是给你抄代码。1. 为什么是“Postman集合Codex Skill”这个组合1.1 三种常规接法的天花板我先说说不推荐的做法免得你绕弯路。第一种是“手把手教Agent”模式。每次写提示词时把curl命令、header、鉴权流程一股脑贴进去让Codex照着写。这个方法我试过当时觉得真方便但用了几天就撑不住了——提示词越写越长Token消耗直线上升而且接口一旦变更这段提示词就成了过期信息下次又要重新贴。更麻烦的是每个会话都要重新教一遍没有积累性。第二种是“把Postman导出的Collection JSON直接丢给Codex”。Collection JSON是v2.1格式里面除了请求方法、URL之外还混着大量测试脚本、事件回调、变量定义、描述信息。Codex确实能读但它分不清你要的是“描述这个接口”还是“帮我真实调用这个接口”经常会在几十行的脚本片段里迷失重点。你问它登录接口的路径它可能翻出三层item嵌套然后猜一个URL给你。第三种是“让Agent去啃接口文档”。我见过一些团队会把Swagger/OpenAPI文档放在某个内部Wiki里指望Agent自己去找。问题是文档维护常常滞后格式也不统一有的写OpenAPI 2.0有的写Markdown有的干脆只有Postman集合。Agent解析这些异构信息要花很多精力可靠性很一般。这些方法不是说不能用而是维护成本高、复用性差、换项目就要重来。我们需要的是把API资产沉淀成可被按需加载的能力单元而不是每次重新描述。1.2 Skill形态的优势按需加载、动态同步、可复用Codex里的Skill本质上就是“给智能体的一份可触发的能力说明书”。这个形态刚好能解决上面三个问题。按需加载系统只会根据用户提问把匹配描述的那个Skill完整读入上下文平时完全不占用对话空间。这比把全部接口信息写进系统提示词聪明得多——就像书架上放一本厚手册需要用哪本拿哪本而不是把整个书架都搬上桌。动态同步Skill目录里可以放脚本。我做了两个一个负责调用Postman Collection API拉取最新集合JSON一个负责把集合转换成OpenAPI契约。每次Agent需要的时候先跑脚本再出结果拿到的永远是Postman里最新的接口定义。也就是说团队在Postman里改一个参数Agent下一次就能感知到。可复用可分发Skill就是一个普通目录可以放Git仓库团队成员clone就能用。不同项目对应不同Skill互不干扰删除也只是一条命令。1.3 先判断你的项目适合做这件事吗在做全套之前建议先自我评估一下不是所有场景都值得。值得做的信号很明确你经常需要把Postman里的接口细节交给AI让它帮你写调用代码、排查接口返回你们团队有维护得很整洁的Postman工作区你希望Agent能“真实调用”接口而不是只停留在生成代码片段。不适合的场景也要说清楚如果API还在高频变动中连Postman集合都懒得每天更新那Skill里存的永远是过时信息反而误导Agent如果全是生产环境高权限接口直接给AI调用风险很大如果你只是零散调用一两个接口手工贴curl确实更快别折腾这套架构。2. 摸清Codex Skill的运行机制再动手不迟2.1 Skill是怎么被“自动加载”的很多人以为Skill是装了就能用的插件其实它的加载机制更像“请求时路由”。Codex CLI在启动时扫描~/.codex/skills/目录每个子目录里的SKILL.md顶部有一个YAML格式的frontmatter里面包含name和description两个核心字段。系统把description当作索引存进一个语义检索表。当你提问时Codex根据你的自然语言意图去匹配这个索引匹配命中后才会把SKILL.md的正文完整读进上下文。这里有个容易被忽略的点description写得好不好直接决定这个Skill会不会被触发。我一开始写得太抽象只写了一句“提供API操作能力”结果Codex压根不加载我还在那怀疑是路径不对。2.2 写好SKILL.md的description等于给Agent一个精准的路标description至少要覆盖三个维度。第一是触发场景什么情况下该用这个技能例如“当用户要求查询Postman集合中的接口定义”第二是具体能力技能能做什么比如“读取集合、转换OpenAPI、发送真实请求”第三是边界什么情况下不该用比如“不处理数据库操作”。正文部分同样有讲究。我见过有人把SKILL.md写成一篇很长的知识文档堆了一堆HTTP状态码解释Agent看了半天不知道该干什么。正确写法是让它像操作手册一样有明确步骤第一步做什么第二步做什么。我给Agent写的核心指令就是“按步骤执行先拉取集合再转契约再找接口最后发请求”。脚本能做的事绝不要让它用自然语言去猜。2.3 给Skill铺数据为什么OpenAPI要排在Collection前面Postman Collection和OpenAPI描述的是同一个东西但结构逻辑完全不同。我做个类比Collection像是“带演示的测试用例集”里面有怎么点按钮、怎么填参数、怎么断言响应它关注的是执行过程和测试逻辑。OpenAPI是“接口契约”关注的是路径、参数、请求体、响应结构。Codex做推理时读OpenAPI的效率远高于读Collection——因为OpenAPI把“什么是接口的合法调用方式”写得清清楚楚Agent不需要从一堆脚本里挑出有用的信息。所以我的Skill里同时保留两份数据一份原始的Collection JSON作为“字典”兜底一份转换后的OpenAPI文档作为“主力参考”。SKILL.md正文负责说明怎么用这两份数据。3. 从Postman到Codex Skill完整落地实操3.1 前置依赖与必要的环境变量开始动手前先确认环境。我当前使用的组合是最新版Codex CLI、Node.js 18后面转OpenAPI的脚本用到、系统装了jq和curl。Postman侧需要一个API Key用来通过Postman Collection API拉取集合数据。获取API Key的位置在Postman账号的Settings里找到API Keys一栏生成一把只读Key就够了没必要给写权限。我会把它存到环境变量里而不是写死在Skill目录中export POSTMAN_API_KEY你的只读Key export POSTMAN_COLLECTION_ID你的Collection UID这里说明一下Collection UID从哪找在Postman网页端打开某个集合浏览器地址栏里那一长串数字ID就是UID。也可以用下面的命令列出来curl -s -H X-Api-Key: $POSTMAN_API_KEY https://api.getpostman.com/collections | jq .collections[] | {id, name, uid}3.2 第一步用Collection API拉取最新集合Postman集合每次手通过界面导出挺烦的我直接写脚本拉取。Collection API返回的JSON外面套了一层collection对象需要先用jq剥掉外壳。curl -s -H X-Api-Key: ${POSTMAN_API_KEY:?} \ https://api.getpostman.com/collections/${POSTMAN_COLLECTION_ID:?} \ | jq .collection references/collection.json拿到之后先看一眼内容确认里面能搜到请求路径jq -r .item[] | .name references/collection.json这一步看起来很基础但很关键。我建议一有空就手动跑一次这个命令确认集合JSON是完整的。我遇到过API返回成功但内容被截断的情况那次的问题就出在Collection里有个请求的响应示例过大接口侧做了截断。3.3 第二步转换出OpenAPI契约文件转换这一层我提供两个方案按你的偏好选。方案A是直接用社区工具postman-to-openapi一条命令搞定npx postman-to-openapi references/collection.json -o references/openapi.yaml这个工具对v2.1格式解析得比较完整但遇到包含复杂raw body模板的请求偶尔会报错。它会在输出目录自动生成一个openapi.yaml你直接打开检查一下paths数量就行。方案B是写个几十行的转换脚本手动生成OpenAPI 3.0 JSON。我倾向于方案B可控性更强而且转换逻辑本身可以交给Codex生成——我第一次就是让Codex根据我的需求写的这个脚本效果意外地好。核心逻辑是把Collection里的每个item映射成OpenAPI里的一个pathmethodconst fs require(fs); const collection JSON.parse(fs.readFileSync(references/collection.json, utf8)); const paths {}; function walk(items) { for (const item of items) { if (item.item) { walk(item.item); } else if (item.request) { const req item.request; const url typeof req.url string ? req.url : req.url.raw; const method req.method.toLowerCase(); const [pathPart] url.split(?); paths[pathPart] ?? {}; paths[pathPart][method] { operationId: item.name, description: req.description || item.name, parameters: (req.query || []).map(p ({ name: p.key, in: query, schema: { type: string } })) }; } } } walk(collection.item); const openapi { openapi: 3.0.3, info: { title: collection.info.name, version: collection.info.version || 1.0.0 }, paths }; fs.writeFileSync(references/openapi.yaml, JSON.stringify(openapi, null, 2), utf8);这个脚本牺牲了请求体的结构化描述但对我们日常给Agent做索引参考已经足够了。转换完之后同样检查一下jq .paths | keys references/openapi.yaml看到一组路径列表就说明转换成功。3.4 第三步搭建Skill目录并编写SKILL.md目录结构我建议这样组织~/.codex/skills/postman-api/ ├── SKILL.md ├── scripts/ │ ├── fetch-collection.sh │ ├── to-openapi.sh │ └── call-api.sh └── references/ ├── collection.json ├── collection-variables.json └── openapi.yamlreferences里放数据文件scripts里放可执行脚本SKILL.md是入口。SKILL.md我写过好几版最终还是确认了一个原则正文只写流程和约定不写具体的接口列表。接口列表会变写在正文里只会让Agent被迫重读过期信息。下面是精简后的示例--- name: postman-api-skill description: 使用Postman集合中的接口定义来查询和调用API。当用户提到Postman集合、调用某个接口、查一下接口怎么请求、按集合里的方式发请求等意图时触发。 --- # Postman API Skill 这个技能帮助你使用用户的Postman Collection完成API查询和调用。 ## 使用步骤 1. 先运行 scripts/fetch-collection.sh 获取最新集合 2. 再运行 scripts/to-openapi.sh 把集合转换成OpenAPI文档 3. 根据用户问题从 references/openapi.yaml 或 references/collection.json 中找到对应path和method 4. 如果用户需要真实调用运行 scripts/call-api.sh 发送请求 5. 解析响应输出简洁结论。 ## 调用约定 - 不要把密钥直接写入代码或输出通过环境变量注入 - 如果请求失败并返回401/403提醒用户更新Token - 如果集合中存在 {{variable}} 占位符先到 references/collection-variables.json 中查找替换 - 不要编造集合中不存在的接口务必以实际读取到的数据为准。3.5 第四步同步脚本与端到端验证三个脚本里fetch-collection.sh的逻辑前面已经给了我补上另外两个。to-openapi.sh本质上是调上面的Node转换脚本或者调npx命令#!/usr/bin/env bash set -euo pipefail cd $(dirname $0)/.. # 方案A npx postman-to-openapi references/collection.json -o references/openapi.yaml # 如果npx失败走方案B node scripts/convert-to-openapi.jscall-api.sh则是真正发请求的脚本参数依次是HTTP方法、URL、以及任意curl参数#!/usr/bin/env bash set -euo pipefail method$1 url$2 shift 2 token${POSTMAN_ENV_TOKEN:-} curl -sS -X $method $url -H Authorization: Bearer $token $这里的POSTMAN_ENV_TOKEN建议从Postman环境变量中提取设置到你本机的环境里不要写死进Skill目录。端到端验证很简单。先手动跑一遍同步cd ~/.codex/skills/postman-api bash scripts/fetch-collection.sh bash scripts/to-openapi.sh接着开一个Codex会话问它“请用postman-api这个skill帮我查一下用户列表接口的请求方式”。如果Skill正常加载它会先读取SKILL.md然后自己去跑脚本、查文档、回答你。我第一次看到它自己把整个流程跑通的时候确实有点兴奋。4. 运行效果实测Agent怎么用这个Skill干活4.1 一次真实的Codex会话演示我把当时跑通的交互记录整理了一下大概是这样的风格你请查一下用户列表接口帮我真实调用一次并返回前5条数据。 Codex 我先同步Postman集合。 bash scripts/fetch-collection.sh bash scripts/to-openapi.sh 从openapi.yaml里找到了 GET /api/users。 读取集合中的环境变量模板替换为当前配置。 bash scripts/call-api.sh GET https://api.example.com/api/users?page1size5 返回200响应体前5条数据如下 1. id101, name张三 2. id102, name李四 ...注意这里有个细节Agent不是从我给的提示词里找到的接口地址而是自己从Skill的数据文件里查出来的。也就是说如果Postman集合里这个接口已经改了路径它拿到的就是新路径。4.2 确认Skill真的被命中两个硬核验证方法有个问题我建议你认真验证一下Agent到底是靠Skill干活还是靠它自己训练数据里已有的通用知识碰巧答对的两个方法可以验证。方法一故意改Postman集合里某个接口的路径加一个不常见的版本号比如把/api/users改成/api/v2/users。重新同步一次然后问Agent这个接口的路径是什么。如果它回答/api/v2/users说明Skill的同步链路是通的如果它还在说/api/users那就要检查它是不是根本没走Skill。方法二临时把SKILL.md里description改成完全无关的一句话比如“这个技能用于查询天气”。再问同样的API问题如果Agent彻底抓瞎说明它确实依赖Skill路由如果它还是能答上来说明它在用通用知识硬撑。这个方法我试过能很干净地验证Skill的作用。4.3 性能、权限和安全方面的三个提醒第一是Token消耗。Skill只有在命中之后才会加载正文这个设计很省Token。但要注意references里的openapi.yaml如果特别巨大Agent还是会被喂一大坨数据。建议定期清理那些从不出现在日常问题里的老接口让契约文件保持精简。第二是密钥安全。千万不要在SKILL.md里写任何真实密钥也不要放在collection.json里。Postman环境变量里的token虽然是测试环境的但泄露出去依然有风险。我建议你给Agent调用用的API Key做成“只读限流”模式避免突发事件导致生产故障。第三是团队协作。我习惯把整个Skill目录塞进Git仓库用.gitignore把references下的collection.json和openapi.yaml排除掉因为它们是生成的、不是源文件。真正的源文件是Postman集合本身Skill只是它的投影。5. 踩坑实录我替你先趟一遍这些雷5.1 “CC switch local proxy failed”这类网络报错我在一次升级Codex之后遇到过一行报错内容大概类似cc switch local proxy failed while handling codex endpoint /responses。当时第一反应是配置坏了后来排查下来是本地一个转发配置和新版Codex的responses处理流程不兼容Codex在切换内部执行环境时没找对本地配置。处理办法分三步第一步检查~/.codex/config.toml里有没有残留的自定义本地转发相关字段有就把相关行注释掉第二步删除Codex的临时缓存目录重新启动第三步升级到最新版CLI。这个报错本身不影响代码生成质量但会导致整个会话卡死遇到建议优先处理。5.2 Skill一次都没被触发先查这五处我刚开始搭建时Skill怎么都不生效。排查下来发现是frontmatter里description写得不行后来改成上面那种“包含触发词具体场景”的形式才正常。如果你也遇到完全不触发的情况按这张清单逐项查目录位置必须是~/.codex/skills/skill-name/SKILL.md虽然大小写一般不影响但保持全小写最稳妥frontmatter开头的---必须存在name和description字段不能拼错尤其是“description”打成了“desc”这类笔误触发词覆盖description里最好包含人们平时口语里会说的词比如“查接口”“调用一下”“请求方式”Codex版本老版本不支持Skills机制务必更新到较新版本多Skill冲突如果同一个description写了相似的词Codex可能路由到另一个Skill把description改得更独特一些。5.3 集合里的{{}}占位符最容易被忽略的坑Postman里几乎所有URL都是{{baseUrl}}/api/users这种带占位符的写法脚本拉下来的集合JSON里全是变量名。要命的是Agent不知道{{baseUrl}}等于什么直接发请求肯定会失败。我的解决办法是从Postman环境的导出JSON里提取一份变量映射存到references/collection-variables.jsoncurl -s -H X-Api-Key: ${POSTMAN_API_KEY:?} \ https://api.getpostman.com/environments/${POSTMAN_ENV_ID:?} \ | jq {values: .environment.values} references/collection-variables.json然后在SKILL.md里写清楚遇到{{...}}先去这个文件里查映射查不到再问用户。这个小约定救了我很多次否则每次都要在对话里手动告诉Agent baseUrl是多少。5.4 Token过期401刷屏Postman环境变量里的token是有时效性的特别是OAuth2类型的Access Token一般一两个小时就失效。Agent拿着过期token去请求回回来一堆401它会一脸无辜地说“接口返回401了”然后等你做决定。我的对策是在call-api.sh里加一层状态码判断遇到401/403就自动提示“当前Token可能已过期请到Postman环境里刷新后重新设置POSTMAN_ENV_TOKEN”。这个提示比让Agent盲目分析失败请求要高效得多因为问题不在接口逻辑而在鉴权凭证。5.5 响应体过大导致输出截断调用一个列表接口返回可能是个几百KB的JSONAgent的上下文窗口再大也经不住反复塞大段数据。我踩过一次坑Agent为了“分析全部数据”把整个响应体打印了出来然后对话直接卡死了。处理策略是在call-api.sh里限制最大响应体或者用jq只提取需要的字段。比如只取前3条bash scripts/call-api.sh GET $url | jq .data[:3]同时建议在SKILL.md里写清楚响应体超过一定大小先截取前N条进行分析不要一次性全量读取。5.6 问题速查表症状可能原因解决方法Skill完全不触发description太宽泛/无触发词重写description覆盖常见口语表达拉取集合失败API Key无权限或UID错误用/collections列一下确认UID转换OpenAPI报错Collection里有复杂raw body改用自写脚本手动转换URL全是{{}}环境变量未提取生成collection-variables.json并写进SKILL.md返回401/403Token过期call-api.sh捕获状态码并提示更新响应被截断响应体过大用jq截取前N条限制输出大小最后分享一个我现在的习惯每次新建项目我都会顺手把Postman集合整理干净然后跑一遍这个Skill的同步脚本整个过程三分钟都不到。这件事给我最大的改变不是省下了“贴curl”那点时间而是让AI真正变成了团队里那个可以随时上手调接口的“同事”——它不需要你反复交接API上下文只需要自己翻开Postman这本工作手册。如果你手上正好有一份维护得不错的集合建议今晚就试一下。