你好,我是邢云阳。
上一节课,我们留了一个小尾巴,也就是在 Agent 插件中,如何实现 JSON Mode 输出呢?本节课,我们先来解决掉这个小尾巴。
JSON Mode
在[第 21 讲]中,我带你开发JSON Mode小插件时,详细讲解了JSON Mode的工作原理。其核心是通过prompt指示大模型按照指定的JSON Schema格式化输出结果。由于本插件的JSON Schema支持自定义,因此我对之前的JSON Mode prompt进行了调整,修改后的形式如下:
1 | Given the Json Schema: %s, please help me convert the following content to a pure json: %s |
- 第一个%s用于填充用户自定义的JSON Schema内容;
- 第二个%s用于填充需要格式化的原始数据。
在完成核心逻辑后,代码的实现就变得顺理成章了。具体流程如下:
- 在获取到“Final Answer”时,首先判断是否开启了JSON输出设置。
- 如果开启了JSON格式化功能,就先将结果按照指定的JSON Schema进行格式化;
- 如果未开启,就直接返回结果,继续后续的Body替换操作。
JSON 格式化的核心代码如下:
1 | func jsonFormat(llmClient wrapper.HttpClient, llmInfo LLMInfo, jsonSchema map[string]interface{}, assistantMessage Message, actionInput string, headers [][2]string, streamMode bool, rawResponse Response, log wrapper.Log) string { |
在代码实现中,我们首先拼接好了包含JSON Schema和待格式化数据的prompt模板,随后通过HTTP请求调用大模型,成功获取了JSON格式化后的结果。至此,上节课遗留的“小尾巴”问题就圆满解决了。
此外,我想补充一点关于编译命令的注意事项。之前我们使用的编译命令是:
1 | tinygo build -o main.wasm -scheduler=none -target=wasi -gc=custom -tags='custommalloc nottinygc_finalizer' ./main.go |
这条命令仅适用于插件根目录下只有一个main.go文件的情况。如果根目录下还存在其他Go文件(例如config.go),那么该命令会报错。为了解决这个问题,我们需要将./main.go替换为.,表示编译当前目录下的所有Go文件。完整的命令如下:
1 | tinygo build -o agent.wasm -scheduler=none -target=wasi -gc=custom |
测试
部署 ginTools 服务
接下来,我们将使用前面章节中介绍的ginTools工具来测试本插件的效果。首先,简单回顾一下ginTools的功能:它是一个基于gin框架和client-go库开发的服务器,主要用于与Kubernetes集群进行交互。ginTools提供了以下几个核心路由:
1 | GET /:resource 获取指定资源列表 |
为了将ginTools工具以Pod形式部署到Higress所在的Kubernetes集群中,我们需要解决一个关键问题:ginTools如何在容器内操作容器外部的K8s资源?
在之前讲解client-go时,我曾简要提到过一种方法,即使用 InCluster 模式。这种模式允许运行在K8s集群中的Pod通过集群内部的认证机制访问外部的K8s资源。下面,我们来详细说明具体操作步骤。
首先,我们需要创建一个K8s服务账户(ServiceAccount,简称sa),作为ginTools访问K8s资源的凭证。该服务账户的权限决定了ginTools能够操作哪些K8s资源。
为了给服务账户赋予权限,通常使用Role/RoleBinding或ClusterRole/ClusterRoleBinding:
- Role/RoleBinding:作用域限定在某个命名空间内。
- ClusterRole/ClusterRoleBinding:作用域覆盖整个集群。
由于ginTools可能需要操作集群级别的资源,我们选择使用ClusterRole/ClusterRoleBinding来为服务账户赋权。以下是具体的YAML配置:
1 | apiVersion: v1 |
在本测试中,我们仅对Pod、Service以及Pod的日志(logs)和事件(events)进行操作测试,其他资源暂不涉及。因此,在ClusterRole的resources字段中,我们只配置了 YAML 文件中 resources 所对应的几种类型。同时,我们为这些资源设置了增(create)、删(delete)、查(get)以及列表(list)四种操作权限。
接下来是 ginTools 的部署 YAML:
1 |
|
整个 YAML 很简单,唯一需要注意的就是 serviceAccountName 字段,这里要填刚刚创建的 sa 的名称。部署完成后,可以在 Higress 控制台的服务列表页面查看到该服务。

暴露 ginTools 服务
目前,我们已经接近在插件中访问ginTools服务的目标,但还差最后一步。由于Kubernetes(K8s)集群中的服务数量可能非常多,如果所有服务都能被插件访问,会导致以下问题:
- xds推送时的计算开销增加:大量服务信息需要被计算和推送,影响性能。
- 内存开销增加:过多的指标和服务信息会占用大量内存。
为了解决这些问题,Higress在设计上默认只允许插件访问与路由关联的服务。如果需要放开这一限制,有以下两种方式:
方式一:修改Helm安装参数
在安装Higress时,可以通过修改Helm的global.onlyPushRouteCluster参数为false,从而允许插件访问所有K8s服务。具体命令如下:
1 | helm install higress ./higress-chart \ |
这种方式虽然简单,但可能会带来额外的计算和内存开销,因此需要根据实际需求谨慎使用。
方式二:使用 DNS 域名暴露服务
我们可以通过 DNS 域名的方式将K8s服务暴露出来。该方式还是通过在 Higress 控制台的服务来源页面配置。如下图所示,服务端口需要填写服务的 service 暴露出的 pod,域名列表填写服务地址,这些信息在上文中的服务列表中都可以查到。

由于ginTools在部署时采用的是ClusterIP方式的服务暴露,这种方式只能在Kubernetes集群内部访问。为了在外部(例如浏览器)测试配置的DNS域名方式是否生效,我们需要为ginTools添加一个路由规则,将其暴露到外部网络。


配置完成后,在浏览器输入 URL:
1 | http://<你的网关IP>/pods/logs?podname=<你的ginTools pod名称> |
得到下图效果,说明服务是可用的。

我们用肉眼看一下日志的最后一行,提示 watch pod 失败,这是由于上文在配置 sa 权限时,我们故意没有配置 watch 权限导致的。接下来就用该服务作为 Agent 的工具,让 agent 来分析一下这个日志。
配置与测试 Agent
Agent 的配置主要包含 API 和 LLM 两个部分,我先写一个示例,然后再讲解参数的含义:
1 | apis: |
在 apis 部分,配置外部工具。此处可以配置多个服务商的工具,例如可以同时配置高德地图 + 心知天气的 API Tools。在这里我们就先配置本地的 ginTools 工具。在OpenAPI 文档中,url 即为服务的 service 地址。在 apiProvider 部分,由于是本地服务,没有 APIKey,因此没有如下关于 apiKey 的配置:
1 | apiKey: |
llm 部分就是 Agent 从第二轮对话开始所使用的大模型的服务商信息,按自己的实际情况填写即可,但是建议使用推理能力强的模型,否则可能幻觉会比较严重。
配置完成后,我们用 apifox 软件做一下测试:

我让 Agent 帮我分析一下 gintools pod 的日志。得到的返回为:

可以看到 deepseek 模型给出了正确的分析和排查方向。接下来,我们补充给 sa 补充上 watch 权限后,再来测一个列出资源列表的用例。
补充完 watch 权限的 YAML如下:
1 |
|
需要重新执行以下 kubectl apply。配置完成后,我们来进行测试:

结果如下:

得到了预期的结果。
最后,我们测一下 JSON Mode 的效果,首先不自定义 JSON Schema。在 agent 配置中新增如下配置:
1 | apis: |
开始测试:

测试结果:

看起来是得到了一坨 JSON,我们让大模型给我们格式化一下,看得更清楚一点:


可以看到,效果非常惊艳,大模型是建立在读懂了 ginTools 返回的内容的基础上,才自动设计了 Schema,并做了 JSON 格式化。自定义 JSON Schema 的方式就留给你当作课后思考题自行测试吧。
总结
在本节课中,我们首先回顾并解答了上节课的思考题,探讨了JSON Mode代码在AI Agent插件中的实现方法。接着,我们以第二章和第三章中使用的ginTools工具为例,详细介绍了将Kubernetes服务暴露给插件的两种方式。经过比较,我们最终选择了DNS方式,将ginTools服务配置为Agent Tool,并进行了实际测试。测试结果令人满意,完全符合我们的预期目标。
通过本节课的学习,相信你对AI微服务的特点有了更加直观和清晰的理解。让我们再次总结一下这些特点:
- 网关具备AI Agent能力:能够自主调用后端API,实现智能化服务。
- 前端访问方式的革新:不再需要直接调用各种API,而是通过自然语言的形式进行交互。
- 后端输出的自然语言化:通过JSON Mode规范格式,使输出更加结构化和易于理解。
你可以通过测试更好地理解这几个特点。
思考题
在课上,我们测试了让大模型自动 JSON 格式化的效果,感兴趣的话你可以测试一下自定义 JSON Schema 又是什么效果。
欢迎你在留言区分享你的测试效果,我们一起来讨论。如果你觉得这节课的内容对你有帮助的话,也欢迎你分享给其他朋友,我们下节课再见!