天池大赛Higress插件官方demo详细部署+调试

天池大赛Higress插件官方demo详细部署+调试

契机

使用Higress AI网关优化AI调用成本。就是基于向量召回相似问题的缓存,降低LLM API调用成本。就是开发一个网关插件做QA缓存嘛。前文已经成功复现了hello-world插件,这次结合官方提供的AI-Cache插件自己动手改改,再写点注释放到天池大赛去跑跑分,环境搭建起来确实有很多要注意的地方,所以记录下来。

前期准备

文档中所有变量都是${your_qwen_token}这种形式,需要你自己替换

#docker仓库准备,不多赘述,以后docker login的时候需要这个页面设置的访问凭证
#这个是调试插件CI/CD的关键
https://cr.console.aliyun.com/cn-hangzhou/instance/repositories

#申请千问token
[https://help.aliyun.com/zh/dashscope/opening-service](https://help.aliyun.com/zh/dashscope/opening-service)
#保存变量${your_qwen_token}

#上传文件到千问,文件下载位置见下图
#地址:https://tianchi.aliyun.com/competition/entrance/532192/informatio
#下载下来,解压缩得到doc.md
curl --location --request POST 'https://dashscope.aliyuncs.com/compatible-mode/v1/files' \
  --header 'Authorization: ${your_qwen_token}' \
  --form 'file=@./doc.md' \
  --form 'purpose=file-extract'
#得到结果如下
{"id":"${your_file_id}","object":"file","bytes":79439,"created_at":1719468299,"filename":"doc.md","purpose":"file-extract","status":"processed"}
#保存变量${your_file_id}

在这里插入图片描述

本地搭建调试

docker运行higress

#本地新建docker-compose.yml如下
#我们只需要网关即可,不需要其他的httpbin容器

version: '3.9'
services:
  higress:
	  #这个镜像包含redis,并且包含了ai-proxy插件
    image: registry.cn-hangzhou.aliyuncs.com/ztygw/aio-redis:1.4.0-rc.1
    environment:
	    #开启日志输出
      - GATEWAY_COMPONENT_LOG_LEVEL=misc:error,wasm:debug
    ports:
      #管理页面端口
      - "8080:8080/tcp"
	    #llm端口
      - "8001:8001/tcp"
      #redis端口
      - "6379:6379/tcp"
    restart: always
    

#直接启动起来
docker compose up

higress管理页面配置

此时容器运行起来了,访问http://localhost:8001,进入higress管理页面,密码随便

创建服务来源

首先创建官方文档中的DNS类型的服务,域名是 dashscope.aliyuncs.com,端口是443

在这里插入图片描述

然后创建一个redis固定地址服务来源,服务地址写127.0.0.1:6379,名称直接写redis

在这里插入图片描述

最后你的服务来源应该如下
在这里插入图片描述

路由配置

创建一条前缀匹配/的路由,转发给上面创建的服务,并附加注解:

higress.io/backend-protocol: HTTPS

higress.io/proxy-ssl-name: dashscope.aliyuncs.com

higress.io/proxy-ssl-server-name: on

就按照下图填写就完了

在这里插入图片描述

配置AI代理插件

这里要把插件打开,并且把 y o u r q w e n t o k e n , {your_qwen_token}, yourqwentoken{your_file_id}填写上去

在这里插入图片描述

LLM访问验证

上面配置好了,此时你的llm就可以使用了

#测试访问
#注意这里是8080端口
curl 'http://localhost:8080/api/openai/v1/chat/completions' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'Content-Type: application/json' \
  --data-raw '{"model":"qwen-long","frequency_penalty":0,"max_tokens":800,"stream":false,"messages":[{"role":"user","content":"higress项目主仓库的github地址是什么"}],"presence_penalty":0,"temperature":0.7,"top_p":0.95}'

#如果返回如下格式说明成功
{
    "id": "from-cache",
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "Higress项目的GitHub主仓库地址为: https://github.com/higress-group/higress-group.github.io"
            },
            "finish_reason": "stop"
        }
    ],
    "model": "gpt-4o",
    "object": "chat.completion",
    "usage": {
        "prompt_tokens": 0,
        "completion_tokens": 0,
        "total_tokens": 0
    }
}

官方demo添加

加点日志

上面我们已经把项目拷贝下来了,找到官方ai-cache的demo的parseConfig方法,在这里加点日志,等下我们去观察日志插件是否生效

在这里插入图片描述

func parseConfig(json gjson.Result, c *PluginConfig, log wrapper.Log) error {
	log.Info("开始读取配置...")

	// 读取redis的基本配置
	c.RedisInfo.ServiceName = json.Get("redis.serviceName").String()
	if c.RedisInfo.ServiceName == "" {
		log.Error("Redis 服务名不能为空")
		return errors.New("redis service name must not be empty")
	}
	log.Infof("Redis 服务名: %s", c.RedisInfo.ServiceName)

	c.RedisInfo.ServicePort = int(json.Get("redis.servicePort").Int())
	if c.RedisInfo.ServicePort == 0 {
		if strings.HasSuffix(c.RedisInfo.ServiceName, ".static") {
			// use default logic port which is 80 for static service
			c.RedisInfo.ServicePort = 80
		} else {
			c.RedisInfo.ServicePort = 6379
		}
	}
	log.Infof("Redis 服务端口: %d", c.RedisInfo.ServicePort)

	c.RedisInfo.Username = json.Get("redis.username").String()
	log.Infof("Redis 用户名: %s", c.RedisInfo.Username)

	c.RedisInfo.Password = json.Get("redis.password").String()
	log.Info("Redis 密码已读取")

	c.RedisInfo.Timeout = int(json.Get("redis.timeout").Int())
	if c.RedisInfo.Timeout == 0 {
		c.RedisInfo.Timeout = 1000
	}
	log.Infof("Redis 超时时间: %d ms", c.RedisInfo.Timeout)

	c.CacheKeyFrom.RequestBody = json.Get("cacheKeyFrom.requestBody").String()
	if c.CacheKeyFrom.RequestBody == "" {
		c.CacheKeyFrom.RequestBody = "messages.@reverse.0.content"
	}
	log.Infof("Cache Key From RequestBody: %s", c.CacheKeyFrom.RequestBody)

	c.CacheValueFrom.ResponseBody = json.Get("cacheValueFrom.responseBody").String()
	if c.CacheValueFrom.ResponseBody == "" {
		c.CacheValueFrom.ResponseBody = "choices.0.message.content"
	}
	log.Infof("Cache Value From ResponseBody: %s", c.CacheValueFrom.ResponseBody)

	c.CacheStreamValueFrom.ResponseBody = json.Get("cacheStreamValueFrom.responseBody").String()
	if c.CacheStreamValueFrom.ResponseBody == "" {
		c.CacheStreamValueFrom.ResponseBody = "choices.0.delta.content"
	}
	log.Infof("Cache Stream Value From ResponseBody: %s", c.CacheStreamValueFrom.ResponseBody)

	c.ReturnResponseTemplate = json.Get("returnResponseTemplate").String()
	if c.ReturnResponseTemplate == "" {
		c.ReturnResponseTemplate = `{"id":"from-cache","choices":[{"index":0,"message":{"role":"assistant","content":"%s"},"finish_reason":"stop"}],"model":"gpt-4o","object":"chat.completion","usage":{"prompt_tokens":0,"completion_tokens":0,"total_tokens":0}}`
	}
	log.Info("Return Response Template 已读取")

	c.ReturnStreamResponseTemplate = json.Get("returnStreamResponseTemplate").String()
	if c.ReturnStreamResponseTemplate == "" {
		c.ReturnStreamResponseTemplate = `data:{"id":"from-cache","choices":[{"index":0,"delta":{"role":"assistant","content":"%s"},"finish_reason":"stop"}],"model":"gpt-4o","object":"chat.completion","usage":{"prompt_tokens":0,"completion_tokens":0,"total_tokens":0}}` + "\n\ndata:[DONE]\n\n"
	}
	log.Info("Return Stream Response Template 已读取")

	c.CacheKeyPrefix = json.Get("cacheKeyPrefix").String()
	if c.CacheKeyPrefix == "" {
		c.CacheKeyPrefix = DefaultCacheKeyPrefix
	}
	log.Infof("Cache Key Prefix: %s", c.CacheKeyPrefix)

	c.redisClient = wrapper.NewRedisClusterClient(wrapper.FQDNCluster{
		FQDN: c.RedisInfo.ServiceName,
		Port: int64(c.RedisInfo.ServicePort),
	})
	log.Info("Redis 客户端实例已创建")

	err := c.redisClient.Init(c.RedisInfo.Username, c.RedisInfo.Password, int64(c.RedisInfo.Timeout))
	if err != nil {
		log.Errorf("Redis 客户端初始化失败: %v", err)
		return err
	}
	log.Info("Redis 客户端初始化成功")

	log.Info("配置初始化成功")
	return nil
}
还有一个问题onHttpRequestHeaders函数
最后有一个*return types.HeaderStopIteration
最好先改成return types.ActionContinue

我不太懂HeaderStopIteration含义,之前卡住的时候我改成ActionContinue就好了*

打包插件+push

#进入ai-cache的目录
cd ~/higress/plugins/wasm-go/extensions/ai-cache

#用tinygo打包
tinygo build -o main.wasm -scheduler=none -target=wasi -gc=custom -tags="custommalloc nottinygc_finalizer" ./

#需要看看本地有main.wasm生成没有
#作者验证过,macos+arm打包不了

#当前目录新建一个DockerFile
vim DockerFile
#写入
FROM scratch
COPY main.wasm plugin.wasm

#登陆阿里云docker
docker login --username=${your_docker_username} registry.cn-hangzhou.aliyuncs.com
#输入密码${your_docker_psw}

#开始build,注意我这里版本是1.0.0
docker build -t registry.cn-hangzhou.aliyuncs.com/${your_docker_namespace}/${your_docker_repository}:1.0.0 -f Dockerfile .

#推送到远程docker
docker push registry.cn-hangzhou.aliyuncs.com/${your_docker_namespace}/${your_docker_repository}:1.0.0

#此时得到你的插件地址了
registry.cn-hangzhou.aliyuncs.com/${your_docker_namespace}/${your_docker_repository}:1.0.0

添加ai-cache插件

继续访问higress管理页面http://localhost:8001,新增插件

插件名称:ai-cache

镜像地址:上面你推送过去的地址,这个的ocl://前缀可以不填写,他是自己加上的

执行阶段:认证阶段

优先级:99

~现在插件没有启动,还要其他配置

在这里插入图片描述

访问日志查看

#进入higress容器内部,比如我本地CONTAINER ID = ac11f4f3588a
docker exec -it ${your_container_id} bash

#查看日志
#由于我们之前配置了环境变量GATEWAY_COMPONENT_LOG_LEVEL=misc:error,wasm:debug
tail -f /var/log/higress/gateway.log

配置+启动插件

这里要先复制,再开启,配置如下

在这里插入图片描述

cacheKeyFrom:
  requestBody: "messages.@reverse.0.content"
cacheStreamValueFrom:
  responseBody: "choices.0.delta.content"
cacheValueFrom:
  responseBody: "choices.0.message.content"
redis:
  serviceName: "redis.static"
  timeout: 2000
returnResponseTemplate: |
  {"id":"from-cache","choices":[{"index":0,"message":{"role":"assistant","content":"%s"},"finish_reason":"stop"}],"model":"gpt-4o","object":"chat.completion","usage":{"prompt_tokens":0,"completion_tokens":0,"total_tokens":0}}
returnStreamResponseTemplate: |-
  data:{"id":"from-cache","choices":[{"index":0,"delta":{"role":"assistant","content":"%s"},"finish_reason":"stop"}],"model":"gpt-4o","object":"chat.completion","usage":{"prompt_tokens":0,"completion_tokens":0,"total_tokens":0}}
  data:[DONE]

此时看看刚才我们开启的日志,出现以下字样说明没问题了

在这里插入图片描述

验证ai-cache

#测试访问
#注意这里是8080端口
curl 'http://localhost:8080/api/openai/v1/chat/completions' \
  -H 'Accept: application/json, text/event-stream' \
  -H 'Content-Type: application/json' \
  --data-raw '{"model":"qwen-long","frequency_penalty":0,"max_tokens":800,"stream":false,"messages":[{"role":"user","content":"higress项目主仓库的github地址是什么"}],"presence_penalty":0,"temperature":0.7,"top_p":0.95}'

#连续两次访问,如果间隔很短,就说明生效了

#我们之前把redis映射出来了,可以用redis客户端上去看看key,这里就不多赘述了

迭代升级

后续去higress管理页面,修改ai-cache的镜像地址就行
所以每次代码更新,需要打包代码,打包镜像,推送到docker仓库,修改插件镜像地址

写到最后

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/754065.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

私域流量的深度解析与电商应用

一、私域流量的核心价值 在当今数字化时代,流量成为了企业发展的重要资源。与公域流量相比,私域流量以其独有的私有性和可复用性,为企业提供了与用户建立深度联系的机会。私域流量不仅有助于企业精准触达目标用户,还能通过数据分…

Docker中修改TiDB数据库密码(类似mysql)

1.Docker容器运行TiDB pingcap/tidb:last 2.登陆容器系统: 3.在容器中安装mysql客户端: 4.空密码登陆TiDB 5.修改TiDB密码并退出 6.使用修改后的密码登陆验证:

vue3中若v-model绑定的响应字段出现三级,该如何实现rules验证规则

比如以下内容: 配置的rules内容 const rulesref({title:[{required:true,message:"请输入标题",trigger:"blur"},{max:50,message:"最大不能超过256个字",trigger:"blur"}],Category:[{required:true,message:"请选择…

网络问题排障专题-数据分析

目录 一、各协议数据包介绍 1、Ping、DNS数据包介绍(单包一来一回) Ping DNS 2、TCP数据包 在正常情况下,TCP连接确实是从三次握手开始的。三次握手是建立TCP连接的过程,它的目的是确保双方都能够正常通信。 为啥要四次挥手…

阿里云常用的操作

阿里云常见的产品和服务 容器服务 可以查看容器日志、监控容器cpu和内存, 日志服务 SLS 可以查看所有服务的日志, Web应用防火墙 WAF 可以查看 QPS. 阿里云查看集群: 点击 “产品和服务” 中的 容器服务,可以查看 集群列表&…

树莓派Pico

树莓派Pico是树莓派基金会推出的一款基于RP2040微控制器的微型计算机板,它是专为需要高性能微控制器的应用场景设计的,特别适合于需要实时控制、低功耗和小型化解决方案的项目。以下是树莓派Pico的详细介绍: ### 核心特点: - **基…

一看就会的Jmeter分布式压测实战技巧详解

一、什么是jmeter分布式压测? jmeter分布式压测:指将需要模拟的大量并发用户数分发到多台压力机,使jmeter拥有更大的负载量,满足真实业务场景(高并发场景)。可以理解为通过一个Jmeter控制台来远程控制多个…

云计算:重塑数字时代的基石

目录 一、引言 二、云计算的定义与特点 三、云计算的发展历程 四、云计算的应用场景 五、云计算面临的挑战 六、云计算的未来发展趋势 七、结语 一、引言 随着信息技术的飞速发展,云计算已经逐渐渗透到我们生活的方方面面。从个人用户的在线存储、在线办公&…

从零开始:Spring Boot 中使用 Drools 规则引擎的完整指南

规则引擎作用 规则引擎主要用于将业务逻辑从应用程序代码中分离出来,提高系统的灵活性和可维护性。规则引擎通过预定义的规则来处理输入数据并做出相应的决策,从而实现业务逻辑的自动化和动态调整。 例如 门店信息校验:美团点评在门店信息…

遥感数据并行运算(satellite remote sensing data parallell processing)

文章内容仅用于自己知识学习和分享,如有侵权,还请联系并删除 :) 之前不太会用,单纯想记录一下,后面或许还会用到 1. 教程 [1] Pleasingly Parallel Programming: link 1.1 处理器,核和线程 …

使用容器部署redis_设置配置文件映射到本地_设置存储数据映射到本地_并开发java应用_连接redis---分布式云原生部署架构搭建011

可以看到java应用的部署过程,首先我们要准备一个java应用,并且我们,用docker,安装一个redis 首先我们去start.spring.io 去生成一个简单的web项目,然后用idea打开 选择以后下载 放在这里,然后我们去安装redis 在公共仓库中找到redis . 可以看到它里面介绍说把数据放到了/dat…

Ansys Zemax|在设计抬头显示器(HUD)时需要使用哪些工具?

附件下载 联系工作人员获取附件 汽车抬头显示器或汽车平视显示器,也被称为HUD,是在汽车中显示数据的透明显示器,不需要用户低头就能看到他们需要的重要资讯。这个名字的由来是由于该技术能够让飞行员在头部“向上”并向前看的情况下查看信息…

第五节:如何使用其他注解方式从IOC中获取bean(自学Spring boot 3.x的第一天)

大家好,我是网创有方,上节我们实践了通过Bean方式声明Bean配置。咱们这节通过Component和ComponentScan方式实现一个同样功能。这节实现的效果是从IOC中加载Bean对象,并且将Bean的属性打印到控制台。 第一步:创建pojo实体类studen…

人工智能AI风口已开:如何赋予UI设计与视频剪辑新生命

随着科技的浪潮不断向前推进,人工智能(AI)正以惊人的速度重塑着我们的世界,特别是在创意产业的核心领域——UI设计与视频剪辑中,AI正逐步成为驱动行业创新与变革的关键力量。在这个AI技术全面开花的新时代,…

搭建企业内网pypi镜像库,让python在内网也能像互联网一样安装pip库

目录 知识点实验1.服务器安装python2.新建一个目录/mirror/pip,用于存储pypi文件,作为仓库目录3.下载python中的所需包放至仓库文件夹/mirror/pip3.1. 新建requirement.py脚本(将清华pypi镜像库文件列表粘贴到requirement.txt文件中&#xff…

Hadoop版本演变、分布式集群搭建

Hadoop版本演变历史 Hadoop发行版非常的多,有华为发行版、Intel发行版、Cloudera Hadoop(CDH)、Hortonworks Hadoop(HDP),这些发行版都是基于Apache Hadoop衍生出来的。 目前Hadoop经历了三个大的版本。 hadoop1.x:HDFSMapReduce hadoop2.x…

mtu 1500 qdisc noop state DOWN group default qlen 1000问题的解决

问题描述 1、打开虚拟机终端,root身份启动ens网卡(一般情况下还是会直接报错 ifup ens33 2、停止网卡设置disable再启动 systemctl stop NetworkManager 不报错即可 systemctl disable NetworkManagerservice network restart出现了绿色的OK啦&#…

流水线作业模拟程序

目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 namespace 流水线作业模拟 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private int Count 0;private bool IsStop false;private void uiLight1_Click(object sender, EventArgs e…

某麦网自动刷新抢票脚本——手机端(高级版)

某麦网自动刷新抢票脚本——电脑端 小白操作-抵制黄牛–需要更好用更高级关注获取 如何用Python自动抢大麦网演出票? 在数字化时代,购票已经成为我们生活的一部分,无论是音乐会、话剧、体育赛事还是各种展览,抢票几乎成了一项“…

[每周一更]-(第103期):GIT初始化子模块

文章目录 初始化和更新所有子模块分步骤操作1. 克隆包含子模块的仓库2. 初始化子模块3. 更新子模块 查看子模块状态提交子模块的更改处理子模块路径错误的问题 该问题的缘由是因为:在写某些代码的时候,仓库中有些文件夹,只提交了文件夹名称到…