【第 8 篇:数据接口管理——从模拟到真实与企业级接口治理】
第 8 篇:数据接口管理——从模拟到真实与企业级接口治理
系列记录:《从零搭建企业级 LLM 应用》,这是第 8 篇
上一篇:API 调用 Agent——外部系统打通与结果解析
一、三大核心能力
1.1 能力一:Swagger URL 导入——一键接入整个服务的接口
这是整个改造最重要的入口能力。
两阶段探测 + 选择性导入
用户的 Swagger 系统并非标准 OpenAPI 结构——不是每个服务一个独立的 Swagger JSON 端点,而是所有服务挂在一个基础 URL 下。为此设计了两阶段探测:
阶段一:服务发现 输入:http://192.168.1.160:18889/ 后端 → 探测自定义 API 文档端点 → 解析返回的服务列表 输出:基础信息管理、报警管理、设备管理、隐患治理、工单系统...(N 个服务可选) 阶段二:标签选择 用户选择某个服务 → 后端查询该服务下的所有标签 输出:人员统计、参数管理、数据信息...(若干标签可选) UI 提供"全选 / 取消全选"按钮为什么不是"一键全量导入"
讨论过两种方案:
- 方案 A:输入一个基础 URL,自动全量导入所有服务的所有接口。简单粗暴,但用户根本没有办法预览要导入的内容,也不知道哪些需要、哪些不需要。
- 方案 B:服务 → 标签 → 接口,逐层展开,用户自主勾选要导入的部分。
最终选择了方案 B,原因很简单:企业接口文档动辄上百个接口,用户通常只需要其中 5-10 个核心接口。全量导入会让 api_agent 的list_interfaces返回几十页内容,LLM 在语义匹配时会淹没在噪音中。
自定义 API 文档端点兼容
标准 Swagger 探测路径(/v3/api-docs、/v2/api-docs、/swagger.json)对企业的私有化 Swagger 系统无效——他们的 API 文档通过自定义端点暴露。
所以discover_swagger_services()在标准路径失败后,会自动尝试自定义路径。这是面向企业环境的必要兼容。
从前端还是后端导入
用户的核心问题是:“一个普通企业员工,如果不写代码,怎么把接口接入系统?”
答案是:前端可视化操作 + 后端执行。管理员在interface_config.html页面输入 Swagger 基础 URL 和服务名称 → 前端调/api/admin/interfaces/discover-services→ 后端探测 → 返回服务列表 → 用户选择 → 前端调/api/admin/interfaces/import-tags→ 后端拉取选中的标签并保存为 JSON 文件 → 返回结果。
整条链路没有命令行、没有配置文件,全程在网页上完成。这就是"企业员工也能用"的接口接入体验。
1.2 能力二:前端接口测试——在页面上直接调接口看结果
blog_07 的 api_agent 可以直接调接口,但那是 Agent 内部调用的链路——用户看不到真实的请求和返回,只能看到 Agent 整理后的中文回答。对于管理员配置接口时的验证需求来说,这不够直接。
所以在interface_config.html的接口详情面板中增加了一套接口测试功能:
接口详情页 ├── 参数列表(从 OpenAPI spec 自动提取) │ ├── 参数名、类型、是否必填、描述 │ ├── 默认值(从 spec 填入) │ └── 可编辑输入框(用户修改参数值测试) ├── 认证信息展示(Bearer Token / API Key / Basic Auth) ├── 【发送测试请求】按钮 └── 返回结果区 ├── HTTP 状态码 ├── 响应时间 └── 格式化的 JSON 响应几个细节
必填字段校验:用户最初发现 GET 方法的必填字段不填也能测试成功,以为是从 Swagger “继承"了自动校验。这其实是个常见的误解——OpenAPI 规范只是"说明书”,不是"执行引擎"。Swagger UI 之所以会自动校验,是因为它自己的 JavaScript 代码读了required: true后在前端拦截了提交。自己的系统需要显式实现这套校验逻辑。所以在发送请求前加了前端参数校验,必填字段为空时直接阻断并标红提示。
滚动条修复:接口详情页内容多的时候,右侧没有滚动条导致内容被截断。给#detail-view容器加了overflow-y: auto,与返回结果区域的滚动体验保持一致。
后端代理测试请求:前端的测试请求不是直接从前端发的——受 CORS 限制,实际走的是后端/api/admin/interfaces/test代理,后端收到后转发到目标服务器,然后把响应原样返回给前端。这样做的好处是认证信息(如果接口需要 Token)可以安全地存于后端,不会暴露在浏览器控制台。
1.3 能力三:接口权限管理——用户可以看哪些接口
上一篇里所有用户都能访问所有接口。但在企业场景中,不同部门、不同角色的员工应该只能看到自己业务相关的接口。
权限粒度:到单个接口级别
不是按"服务"分权限,而是按单个接口分。管理员可以为每个用户勾选/取消勾选具体哪些接口可以访问。
权限管理面板 ├── 选择用户 ├── 显示所有已接入的接口(按服务 → 标签分组) │ ├── ☑ 基础信息管理 > 人员统计 > GET 导出Excel │ ├── ☑ 基础信息管理 > 人员统计 > POST 汇总列表 │ ├── ☐ 基础信息管理 > 参数管理 > GET 列表 │ └── ... ├── 【保存权限】 └── 全选 / 取消全选 按钮设计决策
| 决策 | 说明 |
|---|---|
| 默认权限空白 | 新创建的用户默认不能访问任何接口,需要管理员逐一授权。安全优先。 |
| 仅管理员可操作 | 普通用户看不到接口配置和权限管理入口,所有接口管理功能均为 admin-only。 |
| 权限即时生效 | 保存后立即生效,api_agent 的list_interfaces工具会根据当前用户权限过滤返回结果。 |
二、一个绕不开的架构问题:JSON 文件存的是"数据"还是"说明书"
注:data_interface/目录下存放的 JSON 文件不是"数据",是OpenAPI 规范文件——接口的"说明书"。
类比: data_interface/用户中心/员工管理.json ≈ 一本工具说明书 真正的接口数据 ≈ 工具本身 说明书告诉你: - 这个接口叫什么、做什么用 - 需要传什么参数(名字、类型、是否必填) - 返回什么格式的数据 - 调用地址是什么 真正的数据是从服务器上实时获取的——每次 Agent 调用 api_agent, 它读"说明书"知道怎么拼 URL 和参数,然后向服务器发 HTTP 请求拿回数据。 本地的json接口说明书只占几 KB,真正的数据体量可以无限大。回到部署场景:
- 本地开发:
data_interface/下的 JSON 文件是"导入"操作生成的,应该加入.gitignore,不提交到 GitHub。 - 服务器部署:管理员通过前端 Swagger URL 导入功能,把需要接入的服务导入到服务器的
data_interface/目录。不需要从本地拷贝,不需要走 GitHub。 - 新成员拉代码:拉下来的代码不包含
data_interface/的任何 JSON,但包含完整的导入工具。启动后在网页上填 Swagger URL 即可一键导入所需接口。
三、文件组织:用目录结构表达业务含义
data_interface/的组织结构经过几次迭代:
data_interface/ ├── 信息管理/ │ ├── 人员统计.json # 一个标签 = 一个文件 │ ├── 参数管理.json │ └── XXX.json ├── 数据管理/ │ ├── 数据信息.json │ └── 数据规则.json └── ... 好处: - 服务 → 目录,标签 → 文件,一眼看清 - list_interfaces 按服务+标签分组展示,LLM 做语义匹配更精准 - 删除、修改单个标签的接口不影响同服务的其他标签四、数据库存储方案的取舍
讨论过是否将接口配置全部存入数据库(而非文件系统)。
选择文件系统 + 数据库索引的混合方案,原因:
| 存储内容 | 存储位置 | 理由 |
|---|---|---|
| OpenAPI 规范 JSON(完整文件) | 文件系统data_interface/ | 单个文件 10-50KB,文件系统更适合大文本存储;方便直接查看/备份/迁移 |
| 接口元数据索引(服务名、标签名、路径、方法) | SQLitedata_interfaces表 | 快速查询和过滤;支撑权限管理 |
| 用户接口权限 | SQLiteuser_interface_access表 | 关系型查询天然适合权限匹配 |
这个方案兼顾了性能和可维护性。未来如果接入的接口上了千,也只需要在数据库索引上加缓存,文件层的改动不大。
五、补充:命令行导入脚本
虽然日常使用走前端可视化操作,但仍保留了一个命令行工具scripts/import_swagger_specs.py,用于:
- 批量导入:一次性将所有服务的接口全量下载为 OpenAPI JSON 并写入
data_interface/ - 初始化环境:在新服务器上快速批量导入,省去在前端逐个操作
- 自动化流程:可在 CI/CD 中集成,当外部系统接口变更时自动更新
用法:python scripts/import_swagger_specs.py http://XXX.XXX.X.XXX:XXXXX/
上一篇搭好的 api_agent 解决的是"能不能调"的问题,本篇解决的是"怎么接入、怎么管理、谁能调"的问题。
