接口测试在项目里经常是“会执行、难设计、更难归因”。用 Postman 手工点接口并不难难的是把一组接口、环境变量和断言组合成可重复的测试资产而 AI Agent 的出现开始把“人告诉 Postman 怎么测”变成“Agent 读取 Postman 资产自己排测试计划并解释失败原因”。下面这套实现以 Postman Collection 和 Newman 为主线结合一个 Python 编写的 Agent 骨架完成“读取接口清单 - 生成测试计划 - 注入断言 - Newman 执行 - 汇总失败 - 生成修复建议”的最小闭环。读完可以直接在现有 Postman 资产上改造也适合作为接口测试智能化的第一个落地模板。适合已经用过 Postman 的测试开发、后端开发或测试平台工程师。如果你还停留在“用 Postman 手动点一遍接口、看返回是否 200”的阶段这套思路会帮你把精力从重复劳动转移到测试设计和问题归因上。1. 为什么接口测试需要引入 AI Agent 来驱动1.1 接口测试的重复性工作远超想象接口测试表面上是在“请求接口”实际工作中消耗时间的却是另一批事情准备测试数据、梳理接口之间的依赖、判断用哪些参数组合、决定断言应该校验状态码还是业务字段、接口失败后还要区分是环境问题、数据问题还是代码 bug。在常见团队里一次中等规模的接口回归真正执行请求的时间只占一小部分。大量时间被下面几件事消耗从接口文档或 Postman Collection 里确认请求地址、请求方法、请求头和请求体。为不同场景准备不同的环境变量比如 baseUrl、token、orderId。手写 pm.test 断言判断状态码、响应字段、响应时间。回归失败后打开 Postman 和日志系统逐个接口确认失败原因。这些工作非常适合交给程序自动化但“自动化”并不等于“智能”。普通的自动化脚本只能按照固定规则执行无法根据接口返回灵活调整用例也无法在失败时解释最可能的原因。AI Agent 补上的正是“理解上下文、制定计划、观察结果、给出判断”这一层。1.2 AI Agent 在接口测试链路中的真实位置AI Agent 不是一个神奇的黑盒而是一个能根据目标拆解任务、调用外部工具、观察结果并调整下一步动作的程序。放到接口测试场景里它至少承担四个职责解析 Postman Collection把接口清单转换成模型可以理解的文本或结构化数据。制定测试计划决定哪些接口需要覆盖成功路径、参数缺失、非法参数、权限不足等场景。生成可执行的测试断言也就是 Postman 的 pm.test 脚本片段。分析 Newman 的执行结果给出失败原因和修复建议。这里要注意Agent 并不能替代 Newman 去发请求。请求的执行仍然交给 Postman/Newman 这套成熟链路Agent 做的是“生成规则、解读结果”。这种分工很重要因为生成规则和解读结果恰恰是 LLM 擅长、传统脚本不擅长的部分而发请求、维护 cookie、处理重定向、生成 HTML 报告则是专业工具更可靠的部分。1.3 这套方案的整体工作链路整套流程可以概括成一条闭环链路从 Postman 导出 Collection 和 Environment保存成 JSON 文件。Python 脚本解析 Collection提取接口名称、方法、URL、请求体等信息。调用 LLM 接口把接口清单和测试要求发送给 Agent。Agent 返回一份结构化测试计划包含每个用例要校验的断言。Python 脚本把这些断言写入一个临时 Collection交给 Newman 执行。Newman 运行结束后生成 JSON 报告。Python 脚本汇总报告再交给 Agent 分析失败原因。Agent 输出可执行的修复建议人工确认后修改接口或测试数据。这条链路没有引入新的测试框架也没有替代 Postman 的资产体系而是把 Postman 已有的 Collection、Environment、Newman 执行能力变成 Agent 可以调用的工具。因此团队里已经存在的 Postman 资产不会浪费。2. 准备环境Postman、Newman 与 Agent 程序的依赖关系2.1 先确认现有 Postman 资产Collection、Environment、ExamplePostman 里最有价值的三类资产是 Collection、Environment 和 Example。Collection一组接口的集合可以包含文件夹嵌套、请求定义、前置脚本、测试脚本。Environment一组键值对用于描述不同环境下的变量比如baseUrl、token、orderId。Example某个请求的示例响应通常用于文档化也可以作为 Agent 生成断言的参考。本文的落地方式不要求从零创建接口而是建议你先把团队里已有接口整理成 Collection。如果没有现成 Collection可以先新建一个最小集合包含两三个最常回归的接口比如用户登录、创建订单、查询订单。后续所有实验都围绕这几个接口展开成本低也容易验证效果。2.2 安装 Newman 和 Python 依赖Newman 是 Postman 官方提供的命令行工具可以用 Node.js 的 npm 安装。Newman 可以脱离 Postman 图形界面运行 Collection非常适合接入脚本和 CI/CD。先确认 Node.js 环境node -v npm -v然后全局安装 Newmannpm install -g newman newman --version如果公司网络环境限制全局安装也可以把 Newman 作为项目级依赖npm init -y npm install -D newmanAgent 程序使用 Python 编写建议 Python 3.10 及以上版本。创建虚拟环境并安装依赖python -m venv .venv source .venv/bin/activate # Windows 下使用 .venv\Scripts\activate pip install requests pyyaml python-dotenv这里requests用于调用 LLM 接口python-dotenv用于读取本地环境变量文件pyyaml用于后续解析 YAML 格式的配置或 CI 文件。如果只是跑通最小闭环requests和python-dotenv是必须的pyyaml可以按需安装。2.3 环境变量与密钥管理Agent 调用 LLM 需要一个 API Key。不要把密钥直接写死在代码里也不要提交到 Git 仓库。推荐的做法是用环境变量管理或者在项目根目录放一个.env文件并加入.gitignore。需要准备的环境变量如下变量名用途示例值LLM_API_KEY调用大模型服务的密钥sk-xxxxLLM_BASE_URLLLM 服务地址兼容 OpenAI Chat Completions 协议https://api.openai.com/v1LLM_MODEL模型名称gpt-4o-miniPOSTMAN_API_KEY可选用于通过 Postman API 拉取云端 CollectionPMAT-xxxx在本地运行时可以这样设置export LLM_API_KEYsk-xxx export LLM_BASE_URLhttps://api.openai.com/v1 export LLM_MODELgpt-4o-mini如果使用.env文件from dotenv import load_dotenv load_dotenv()不同团队的模型服务协议可能不同。本文示例以 OpenAI 兼容的/chat/completions接口为例实际项目换成自建模型网关时只需要调整LLMClient的请求地址和请求体结构。2.4 学习环境与生产环境的差异建议先把这套流程跑在本地学习环境再考虑生产接入。两者的关注点完全不同。维度学习环境生产环境接口数据本地 Mock 或测试环境接口可能是生产只读接口或预发接口测试数据手工构造允许随机生成需要稳定、可清理、不会污染业务数据LLM 调用允许反复试错需要考虑成本、超时、熔断、日志脱敏权限本机执行需要 CI 权限、密钥管理、审计断言质量人工肉眼确认必须有人工 review 和版本管理生产环境不建议直接把 Agent 生成的断言全量应用到正式回归用例。先让 Agent 生成建议人工确认后再固化是更稳妥的过渡方式。3. 让 Agent 能读懂 Postman Collection3.1 Collection 导出的 JSON 结构怎么看Postman 导出 Collection 后得到一个 JSON 文件。以 v2.1 版本为例最小结构大致如下{ info: { name: 订单服务接口集, schema: https://schema.getpostman.com/json/collection/v2.1.0/collection.json }, item: [ { name: 创建订单, request: { method: POST, url: { raw: https://api.example.com/orders, host: [api.example.com], path: [orders] }, header: [ { key: Content-Type, value: application/json } ], body: { mode: raw, raw: {\userId\: 1, \amount\: 99.9} } } }, { name: 查询订单, request: { method: GET, url: { raw: https://api.example.com/orders/{{orderId}} } } } ] }这里有几个关键点info保存 Collection 名称和 schema 版本。不同版本字段略有差异建议统一使用 v2.1 导出。item是接口数组。如果接口有分组item会嵌套出现。request里包含 method、url、header、body 等信息。URL 里的{{orderId}}是 Postman 变量真正执行时需要 Environment 文件提供值。Agent 要做的第一件事就是从item中递归提取所有request节点而不是只取第一层。3.2 用 Python 解析 Collection 并提取接口元信息先写一个解析函数支持文件夹嵌套。重点是递归遍历itemimport json from pathlib import Path def load_collection(collection_path: str) - dict: return json.loads(Path(collection_path).read_text(encodingutf-8)) def flatten_items(items, parent_name): results [] for item in items: name f{parent_name} / {item.get(name, )}.strip( /) if request in item: results.append({ name: name, request: item[request], original_item: item }) if item in item: results.extend(flatten_items(item[item], name)) return results if __name__ __main__: collection load_collection(order_service.postman_collection.json) requests_spec flatten_items(collection.get(item, [])) for req in requests_spec: method req[request].get(method, GET) url_raw req[request].get(url, {}).get(raw, ) print(method, url_raw, -, req[name])original_item是后续向临时 Collection 注入断言时要用的原始节点引用。解析阶段先把它保存下来可以避免重复查找。运行后控制台会输出类似结果POST https://api.example.com/orders - 创建订单 GET https://api.example.com/orders/{{orderId}} - 查询订单如果打印结果为空说明 Collection 的item字段不是标准路径需要检查导出的 schema 版本。3.3 把接口信息转成 Agent 可以理解的上下文LLM 不直接理解 JSON 数组里的所有字段也不适合把整个 Collection 原样塞进 Prompt。建议把接口信息整理成结构化文本让模型快速抓住重点。def build_context(requests_spec): lines [] for idx, item in enumerate(requests_spec): req item[request] method req.get(method, GET) url req.get(url, {}).get(raw, ) name item[name] lines.append(f{idx}. [{method}] {url} # {name}) body req.get(body) or {} raw body.get(raw, ) if raw: lines.append(f body: {raw[:200]}) headers req.get(header, []) if headers: header_text , .join( f{h.get(key)}{h.get(value)} for h in headers[:5] ) lines.append(f headers: {header_text}) return \n.join(lines)这样生成的上下文大概长这样0. [POST] https://api.example.com/orders # 创建订单 body: {userId: 1, amount: 99.9} headers: Content-Typeapplication/json 1. [GET] https://api.example.com/orders/{{orderId}} # 查询订单这里的{{orderId}}仍然是占位符。真正的值会由 Newman 执行时从 Environment 文件注入Agent 只需要知道这里存在一个变量即可。3.4 这一步容易踩的三个坑第一只遍历第一层item漏掉文件夹里的接口。Postman Collection 经常按模块分文件夹解析时必须递归。如果只读第一层Agent 看到的接口清单会不全。第二没有处理 Postman 变量。Collection 里大量出现{{baseUrl}}、{{token}}、{{orderId}}如果直接把占位符发给 AgentAgent 会误以为接口地址不完整。正确做法是执行时通过 Newman 的-e参数传入 Environment 文件让变量在真实请求阶段替换。第三盲目相信 LLM 返回的 JSON。大模型偶尔会返回 Markdown 代码块、解释性文字或多余字段。解析时要做兼容处理先剥离代码块标记再尝试json.loads解析失败时要记录原始返回方便排查。4. 编写 Agent 的核心逻辑从生成用例到执行计划的闭环4.1 设计一个面向接口测试的 Agent 提示词Agent 的行为主要受系统提示词控制。面向接口测试的提示词要解决两件事一是让模型明白自己的角色和输出格式二是约束模型不要瞎编业务预期。一个可用的系统提示词如下你是一个接口测试专家。你会收到一个 Postman Collection 中待测接口的清单。 请生成一份 Newman 可以执行的测试计划。 要求 1. 输出 JSON 数组不要输出多余文字。 2. 每个元素包含 requestIndex、caseName、assertions。 3. requestIndex 对应接口清单中的编号。 4. assertions 是 Postman 的 pm.test 脚本片段。 5. 优先覆盖成功路径、参数缺失、非法参数、状态码和关键业务字段。 6. 没有明确预期时只校验状态码和响应结构不要猜测具体业务含义。用户消息则把接口上下文和本次测试目标拼接在一起user_prompt f 本次测试目标对订单服务接口做冒烟回归。 接口清单 {context} 请生成测试计划 JSON。 这里的关键是“不要猜测具体业务含义”。订单接口是否必须返回orderId、创建失败时返回什么业务码这些信息 Agent 并不知道。它只能基于接口名和请求体做合理推断。明确这一条可以避免断言过度。4.2 实现一个最小 LLMClient 和 JSON 解析器以 OpenAI 兼容的 Chat Completions 接口为例写一个最小客户端import os import requests class LLMClient: def __init__(self): self.api_key os.environ[LLM_API_KEY] self.base_url os.environ.get(LLM_BASE_URL, https://api.openai.com/v1) self.model os.environ.get(LLM_MODEL, gpt-4o-mini) def chat(self, system: str, user: str) - str: resp requests.post( f{self.base_url}/chat/completions, headers{Authorization: fBearer {self.api_key}}, json{ model: self.model, messages: [ {role: system, content: system}, {role: user, content: user}, ], temperature: 0.2, }, timeout60, ) resp.raise_for_status() return resp.json()[choices][0][message][content]如果团队使用自建的大模型网关只需要修改base_url和请求体字段不需要改 Agent 的整体设计。LLM 返回的内容不一定是干净 JSON需要做一层兼容解析import json def parse_llm_json(text: str): text text.strip() if text.startswith(): text text.strip() if text.startswith(json): text text[4:].strip() return json.loads(text)这里兼容了最常见的 Markdown 代码块包裹情况。如果 LLM 输出中包含大量解释文字建议在 Prompt 中强调“只输出 JSON”并在解析失败时记录原始文本而不是直接抛异常后丢弃。4.3 把测试计划注入 Collection再交给 Newman 执行Agent 返回的测试计划大致长这样[ { requestIndex: 0, caseName: 创建订单-成功路径, assertions: [ pm.test(\状态码为200\, function () { pm.response.to.have.status(200); });, pm.test(\订单号存在\, function () { const data pm.response.json(); pm.expect(data.orderId).to.not.be.empty; }); ] } ]Python 脚本需要把这个测试计划合并到一个临时 Collection 中。合并方式是给对应请求节点添加event字段写入pm.test脚本import copy def add_assertions_to_collection(collection, test_plan): new_collection copy.deepcopy(collection) items flatten_items(new_collection.get(item, [])) for case in test_plan: idx case.get(requestIndex) if not (0 idx len(items)): continue original_item items[idx][original_item] script_lines [] for assertion in case.get(assertions, []): script_lines.extend(assertion.splitlines()) event { listen: test, script: { type: text/javascript, exec: script_lines } } original_item.setdefault(event, []).append(event) return new_collection注入完成后可以把临时 Collection 写入文件with open(tmp_collection.json, w, encodingutf-8) as f: json.dump(temp_collection, f, ensure_asciiFalse, indent2)然后调用 Newman 执行import subprocess def run_newman(collection_file, environment_fileNone, output_filenewman_result.json): cmd [ newman, run, collection_file, --reporters, json, --reporter-json-export, output_file, ] if environment_file: cmd [-e, environment_file] result subprocess.run(cmd, capture_outputTrue, textTrue) return result.returncode, output_file这里要注意Newman 执行失败时进程退出码非 0但这时候仍然有 JSON 报告文件。后续分析脚本不要因为returncode ! 0就直接终止否则会丢掉最关键的失败信息。4.4 把执行结果反馈给 Agent 做失败分析Newman 的 JSON 报告通常包含run.stats和run.failures。先写一个摘要函数def summarize_newman_report(report_path): with open(report_path, encodingutf-8) as f: report json.load(f) run report.get(run, {}) stats run.get(stats, {}) failures run.get(failures, []) lines [ ftotalRequests: {stats.get(requests, {}).get(total, 0)}, ffailedRequests: {stats.get(requests, {}).get(failed, 0)}, ftotalAssertions: {stats.get(assertions, {}).get(total, 0)}, ffailedAssertions: {stats.get(assertions, {}).get(failed, 0)}, ] for failure in failures[:20]: lines.append( fFAIL at {failure.get(at, )}: f{failure.get(error, {}).get(test, )} ) return \n.join(lines)不同版本的 Newman 报告字段可能略有差异。落地前先用一个已知失败用例验证stats和failures的路径是否正确。拿到摘要后再调用一次 LLM让 Agent 做归因分析analysis_system_prompt 你正在分析一次接口测试的 Newman 执行结果。 请根据摘要区分四类失败原因 1. 接口代码 bug。 2. 测试数据问题。 3. 断言过严或断言写错。 4. 环境变量或依赖服务问题。 请给出最可能的原因和可执行的修复建议。 analysis_result llm.chat(analysis_system_prompt, summary) print(analysis_result)这一轮不重新解析接口也不重新生成用例而是专门做“结果解读”。把生成和解读拆成两个独立环节能让每个 Prompt 更短、更聚焦也更容易排查问题。5. 把 Agent、Postman 和 Newman 串成一条可复用流水线5.1 项目结构建议最小可复用项目可以按照这个目录组织agent-postman-test/ ├── main.py ├── llm_client.py ├── collection_parser.py ├── test_runner.py ├── analyzer.py ├── requirements.txt ├── collections/ │ ├── order_service.postman_collection.json │ └── order_service.postman_environment.json └── logs/各文件职责如下main.py编排主流程把解析、生成、执行、分析串起来。llm_client.py封装 LLM 调用。collection_parser.py解析 Collection、构建上下文、注入断言。test_runner.py封装 Newman 执行和报告摘要。analyzer.py封装失败分析 Prompt 和结果输出。requirements.txt记录 Python 依赖。项目规模不需要大关键是把“读资产、生成用例、执行、归因”四个环节解耦方便单独验证和替换。5.2 主流程编排脚本main.py的核心逻辑可以简化成下面的样子import json from dotenv import load_dotenv from collection_parser import ( load_collection, flatten_items, build_context, add_assertions_to_collection, ) from llm_client import LLMClient from test_runner import run_newman, summarize_newman_report from analyzer import build_analysis def main(collection_path, environment_path): load_dotenv() collection load_collection(collection_path) requests_spec flatten_items(collection.get(item, [])) context build_context(requests_spec) llm LLMClient() system_prompt 你是一个接口测试专家。你会收到一个 Postman Collection 中待测接口的清单。 请生成一份 Newman 可以执行的测试计划。 要求输出 JSON 数组不要输出多余文字。 每个元素包含 requestIndex、caseName、assertions。 assertions 是 Postman 的 pm.test 脚本片段。 user_prompt f本次测试目标对核心接口做冒烟回归。\n接口清单\n{context}\n请生成测试计划 JSON。 raw_plan llm