Higress AI 意图识别插件(ai-intent):让 LLM 为请求打标签,驱动下游模型与缓存选择
2026/9/16 15:13:36 网站建设 项目流程

Higress AI 意图识别插件(ai-intent):让 LLM 为请求打标签,驱动下游模型与缓存选择

【免费下载链接】higress🤖 AI Gateway | AI Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/hi/higress

导读

ai-intent 是 Higress AI 网关中基于 LLM(大语言模型)的意图识别 Wasm 插件:它在请求转发前调用一次大模型,将用户问题归类到预设场景类别(如“金融|电商|法律”),并把识别结果写入intent_category属性,供 ai-proxy、ai-cache 等后续插件按意图选择不同大模型或缓存策略。读完本文,你将掌握该插件的运行机制、完整配置项与默认值、前置依赖(内部路由 + 固定地址服务),以及如何通过源码与测试验证它的行为,从而在自己的 AI 网关场景中落地“按意图分流”的能力。

插件功能概述

根据插件文档与源码注释,ai-intent 的核心职责是:智能判断用户请求与某个领域或 Agent 的功能契合度,从而提升不同模型的应用效果和用户体验。它在请求体阶段提取用户提问,构造提示词(prompt)并同步调用一次大模型,将返回结果与预设类别比对后,把命中的类别写入 proxy-wasm 的 Property(属性)intent_category中。

该插件位于plugins/wasm-go/extensions/ai-intent/目录,当前版本号为2.0.2(见 VERSION),插件名称为ai-intent,模块路径为github.com/alibaba/higress/plugins/wasm-go/extensions/ai-intent(见 go.mod)。

运行属性:执行阶段与优先级

属性
插件执行阶段默认阶段(Default Phase)
插件执行优先级700(文档标注)

需要说明的是,main.go 中的注解声明为@Phase AUTHN@Priority 1000,文档标注的执行优先级为700,实际部署时的优先级以 WasmPlugin CRD 中配置的priority字段为准。无论取哪个值,关键约束是:ai-intent 的优先级必须高于 ai-proxy 等后续消费意图的插件,这样它才能在请求转发给上游大模型之前完成意图识别并写入 Property。

前置准备:四条关键前提

在启用 ai-intent 之前,需要按文档说明完成以下四项前置配置(这是文档中反复强调、最容易踩坑的部分):

  1. 优先级高于后续插件:ai-intent 的优先级高于 ai-proxy 等“后续使用意图”的插件。后续插件可以通过proxywasm.GetProperty([]string{"intent_category"})获取意图类别,并据此为不同缓存库或不同大模型做选择。
  2. 新建一条供插件访问大模型的路由:例如路由以/intent作为前缀,服务选择大模型服务,并为该路由开启 ai-proxy 插件。
  3. 新建一个固定地址服务(如intent-service:服务指向127.0.0.1:80(即网关自身实例 + 端口),ai-intent 内部需要通过该服务发起调用以访问上述新增路由,服务名对应配置项llm.proxyServiceName;也可以新建 DNS 类型服务,使插件直接访问其他大模型服务。
  4. 访问白名单:如果使用固定地址服务调用网关自身,需要把127.0.0.1加入网关的访问白名单,否则内部回环调用会被拦截。

这一设计使得插件通过“自己调用自己的大模型路由”完成一次额外的 LLM 分类请求,对用户请求透明,不影响最终的业务转发。

配置参数详解

配置采用 YAML 结构,分为scene(场景)与llm(大模型代理)两个区块。以下参数表完整覆盖了文档定义,并补充了从 main.go 的parseConfig中确认的默认值与解析行为:

名称数据类型填写要求默认值描述
scene.categorystring必填-预设场景类别,以\|分割,如金融\|电商\|法律\|Higress;为空时插件启动报错
scene.promptstring非必填见下方默认提示词LLM 请求的 prompt 模板,包含%s占位符
llm.proxyServiceNamestring必填-新建的 Higress 服务,指向大模型(取 Higress 中的 FQDN 值);为空时插件启动报错
llm.proxyUrlstring必填-大模型路由请求地址全路径,可以是网关自身地址或任意 OpenAI 协议大模型地址,例如http://127.0.0.1:80/intent/compatible-mode/v1/chat/completions;为空时插件启动报错
llm.proxyDomainstring非必填proxyUrl解析获取大模型服务的域名
llm.proxyPortstring/number非必填proxyUrl解析获取大模型服务端口号
llm.proxyApiKeystring非必填-使用外部大模型服务时需配置对应大模型的 API_KEY
llm.proxyModelstring非必填qwen-long大模型类型
llm.proxyTimeoutnumber非必填10000调用大模型的超时时间,单位 ms

默认提示词模板(中文,源码常量DefaultPrompt,见 main.go):

你是一个智能类别识别助手,负责根据用户提出的问题和预设的类别,确定问题属于哪个预设的类别,并给出相应的类别。用户提出的问题为:'%s',预设的类别为'%s',直接返回一种具体类别,如果没有找到就返回'NotFound'。

从源码可以确认的默认值细节:

  • proxyDomainproxyPort的自动解析:当未配置llm.proxyDomain时,从proxyUrl中解析Hostname();当未配置llm.proxyPort(或解析结果<= 0)时,从proxyUrl解析端口;若 URL 未显式携带端口,则按协议取默认值——HTTP 为80、HTTPS 为443
  • proxyTimeout默认 10000ms:配置值<= 0时回退到defaultTimeout = 10 * 1000(ms)。
  • proxyModel默认qwen-long:未配置时使用该模型名。
  • keyFrom(内部默认值):插件从请求 Body 提取用户问题时默认使用 GJSON Pathmessages.@reverse.0.content(即 messages 数组中最后一条 user 消息的 content);解析 LLM 响应时默认使用choices.0.message.content

完整配置示例

以下示例来自文档并可直接套用(注意proxyTimeout在文档示例中写为字符串"10000",源码按数字解析,两者均可被兼容处理):

scene: category: "金融|电商|法律|Higress" prompt: "你是一个智能类别识别助手,负责根据用户提出的问题和预设的类别,确定问题属于哪个预设的类别,并给出相应的类别。用户提出的问题为:'%s',预设的类别为'%s',直接返回一种具体类别,如果没有找到就返回'NotFound'。" llm: proxyServiceName: "intent-service.static" proxyUrl: "http://127.0.0.1:80/intent/compatible-mode/v1/chat/completions" proxyDomain: "127.0.0.1" proxyPort: "80" proxyModel: "qwen-long" proxyApiKey: "" proxyTimeout: "10000"

对应的 WasmPlugin 资源声明可参照仓库中的示例结构(如 samples/wasmplugin/default-config.yaml),将上述内容放入spec.defaultConfig,并通过url指定 ai-intent 插件的 OCI 镜像地址(如oci://higress-registry.cn-hangzhou.cr.aliyuncs.com/plugins/ai-intent:2.0.2),通过matchRulesmatchAll声明生效范围。

工作原理:源码级解析

1. 配置解析阶段(parseConfig)

main.go 中的parseConfig负责初始化插件:

  • scene 初始化scene.category为空直接返回scene.category must not by empty错误;随后用strings.Split(category, "|")将类别拆分为数组CategoryArr,用于后续比对。
  • prompt 初始化scene.prompt为空时使用内置DefaultPrompt
  • llm 代理初始化llm.proxyServiceNamellm.proxyUrl为必填,缺失直接报错;通过url.Parse解析出请求路径ProxyPath,并完成proxyDomain/proxyPort的兜底逻辑(如上文所述),最终用wrapper.NewClusterClient(wrapper.FQDNCluster{FQDN: ProxyServiceName, Port: ProxyPort, Host: ProxyDomain})构建基于 FQDN 集群的 HTTP 客户端。

一个值得注意的安全细节:测试 main_test.go 中的TestParseConfigDoesNotLogProxyAPIKey专门验证了parseConfig不会把proxyApiKey、自定义 prompt 以及 URL 中内嵌的用户名密码(user:password@)写入日志,防止敏感信息泄漏。

2. 请求体处理阶段(onHttpRequestBody)

意图识别的核心逻辑发生在 onHttpRequestBody:

  1. 提取用户问题:用 GJSON 按keyFrom.requestBody(默认messages.@reverse.0.content)从请求 Body 中提取原始问题,并经zhToUnicode处理 Unicode 转义。
  2. 拼接 prompt:用fmt.Sprintf(prompt, 问题, 预设类别)完成两个%s占位符替换,即“用户问题”和“预设类别集合”。
  3. 构造 LLM 请求generateProxyRequest组装 OpenAI 协议请求体{"model": ..., "messages": [{"role": "user", "content": prompt}]},并携带Content-Type: application/jsonAuthorization: Bearer <proxyApiKey>头(见 main.go)。
  4. 同步等待识别结果:通过ProxyClient.Post异步发起调用,超时时间取proxyTimeout;期间请求处理返回types.ActionPause暂停请求,调用结束后通过proxywasm.ResumeHttpRequest()恢复。
  5. 类别校验与写入 Property:仅当 LLM 返回statusCode == 200且解析出choices[0].message.content时,遍历CategoryArr进行比对。判定条件有两条:返回的 category 与预设类别完全一致,或返回的 category包含该预设类别(同时跳过空白类别)。命中后调用proxywasm.SetProperty([]string{"intent_category"}, ...)写入意图类别(见 main.go)。
  6. 未命中处理:若 LLM 返回NotFound或响应异常(非 200、无 choices),则不会写入任何 Property,请求照常放行——这也意味着后续插件拿不到intent_category时会走默认分支。

3. 与其他阶段的关系

  • 请求头阶段onHttpRequestHeaders仅执行ctx.DisableReroute()并返回HeaderStopIteration,用于禁用重路由,避免与后续路由逻辑冲突。
  • 响应头 / 响应体 / 流式响应阶段均为透传(ActionContinue/ 原样返回 chunk),意图识别只影响请求阶段,不修改业务响应。

行为验证:测试用例解读

main_test.go 覆盖了配置解析、请求处理、配置校验与边界场景四类测试,可作为理解插件行为的最佳参考:

  • 配置解析:验证“基本配置、自定义 prompt、最小配置(仅 category + proxyServiceName + proxyUrl)、HTTPS 配置”四类配置均能正常启动(OnPluginStartStatusOK)。
  • 请求体处理:构造“今天股市怎么样?”(应识别为“金融”)与“这个商品什么时候发货?”(应识别为“电商”)的请求,模拟 LLM 返回对应类别后,断言host.GetProperty([]string{"intent_category"})的值分别为金融电商;而“今天天气怎么样?”模拟返回NotFound时,断言GetProperty返回错误(即未设置 Property)。这三个用例直观验证了识别与校验逻辑。
  • 配置校验:分别缺少scene.categoryllm.proxyServiceNamellm.proxyUrl时,插件启动状态均非 OK,与parseConfig中的必填校验一一对应。
  • 边界情况:无效 JSON 请求体(返回NotFound时不写 Property)、LLM 服务返回 503 错误(非 200 不写 Property),验证了插件在异常路径下不会误写意图。

与下游插件联动:基于意图的路由与缓存选择

ai-intent 的价值最终体现在联动上。文档明确说明:后续插件(如 ai-proxy、ai-cache 等)可以通过proxywasm.GetProperty([]string{"intent_category"})读取意图类别,据此为不同缓存库或不同大模型做选择。

实现层面,intent_categoryproxywasm.SetProperty写入(见 main.go),任何运行在同一 Wasm 过滤器链、优先级更低的插件都可以通过proxywasm.GetProperty读取该键。仓库中 wasm-rust/example/ai-intent/src/lib.rs 也展示了 Rust 侧对intent_category属性的消费示例,说明这一属性协议是跨语言 SDK 统一的约定。

典型的联动场景是:意图识别 → 意图分发。例如“金融”类问题路由到金融领域专用模型并启用对应缓存,“电商”类问题走电商 Agent,未命中类别(无intent_category)则回落到通用模型。这样既提升了分类准确率,也避免了所有流量都打到昂贵的大模型上,这正是文档所称“提升不同模型的应用效果和用户体验”的落地方式。

总结

ai-intent 通过“一次额外的 LLM 调用 + Property 写入”实现了细粒度的请求意图分类,是 Higress AI 网关中构建多模型路由、意图感知缓存等高级能力的基础插件。实践要点可归纳为:正确配置前置路由与固定地址服务(含 127.0.0.1 白名单)、保证插件优先级高于下游消费插件、按需定制scene.promptscene.category。如需深入实现细节,可继续阅读 main.go 与 main_test.go,或参考 Rust 版实现 plugins/wasm-rust/example/ai-intent/src/lib.rs。

【免费下载链接】higress🤖 AI Gateway | AI Native API Gateway项目地址: https://gitcode.com/GitHub_Trending/hi/higress

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询