首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

Mahout聚类算法学习之Canopy算法的分析与实现

3.1 Canopy算法 3.1.1 Canopy算法简介 Canopy算法的主要思想是把聚类分为两个阶段:阶段一,通过使用一个简单、快捷的距离计算方法把数据分为可重叠的子集,称为“canopy”;阶段二,通过使用一个精准、严密的距离计算方法来计算出现在阶段一中同一个canopy的所有数据向量的距离。这种方式和之前的聚类方式不同的地方在于使用了两种距离计算方式,同时因为只计算了重叠部分的数据向量,所以达到了减少计算量的目的。 具体来说,阶段一,使用一个简单距离计算方法来产生具有一定数量的可重叠的子集。canopy就是一个样本数据集的子集,子集中的样本数据是通过一个粗糙的距离计算方法来计算样本数据向量和canopy的中心向量的距离,设定一个距离阈值,当计算的距离小于这个阈值的时候,就把样本数据向量归为此canopy。这里要说明的是,每个样本数据向量有可能存在于多个canopy里面,但是每个样本数据向量至少要包含于一个canopy中。canopy的创建基于不存在于同一个canopy中的样本数据向量彼此很不相似,不能被分为同一个类的这样的观点考虑的。由于距离计算方式是粗糙的,因此不能够保证性能(计算精确度)。但是通过允许存在可叠加的canopy和设定一个较大的距离阈值,在某些情况下可以保证该算法的性能。 图3-1是一个canopy的例子,其中包含5个数据中心向量。 图3-1中数据向量用同样灰度值表示的属于同一个聚类。聚类中心向量A被随机选出,然后以A数据向量创建一个canopy,这个canopy包括所有在其外圈(实线圈)的数据向量,而内圈(虚线)中的数据向量则不再作为中心向量的候选名单。 那么针对一个具体的canopy应该如何创建呢?下面介绍创建一个普通的canopy算法的步骤。 1)原始数据集合List按照一定的规则进行排序(这个规则是任意的,但是一旦确定就不再更改),初始距离阈值为T1、T2,且T1 > T2(T1、T2的设定可以根据用户的需要,或者使用交叉验证获得)。 2)在List中随机挑选一个数据向量A,使用一个粗糙距离计算方式计算A与List中其他样本数据向量之间的距离d。 3)根据第2步中的距离d,把d小于T1的样本数据向量划到一个canopy中,同时把d小于T2的样本数据向量从候选中心向量名单(这里可以理解为就是List)中移除。 4)重复第2、3步,直到候选中心向量名单为空,即List为空,算法结束。 图3-2为创建canopy算法的流程图。 阶段二,可以在阶段一的基础上应用传统聚类算法,比如贪婪凝聚聚类算法、K均值聚类算法,当然,这些算法使用的距离计算方式是精准的距离计算方式。但是因为只计算了同一个canopy中的数据向量之间的距离,而没有计算不在同一个canopy的数据向量之间的距离,所以假设它们之间的距离为无穷大。例如,若所有的数据都简单归入同一个canopy,那么阶段二的聚类就会退化成传统的具有高计算量的聚类算法了。但是,如果canopy不是那么大,且它们之间的重叠不是很多,那么代价很大的距离计算就会减少,同时用于分类的大量计算也可以省去。进一步来说,如果把Canopy算法加入到传统的聚类算法中,那么算法既可以保证性能,即精确度,又可以增加计算效率,即减少计算时间。 Canopy算法的优势在于可以通过第一阶段的粗糙距离计算方法把数据划入不同的可重叠的子集中,然后只计算在同一个重叠子集中的样本数据向量来减少对于需要距离计算的样本数量。 3.1.2 Mahout中Canopy算法实现原理 在Mahout中,Canopy算法用于文本的分类。实现Canopy算法包含三个MR,即三个Job,可以描述为下面4个步骤。 1)Job1:将输入数据处理为Canopy算法可以使用的输入格式。 2)Job2:每个mapper针对自己的输入执行Canopy聚类,输出每个canopy的中心向量。 3)Job2:每个reducer接收mapper的中心向量,并加以整合以计算最后的canopy的中心向量。 4)Job3:根据Job2的中心向量来对原始数据进行分类。 其中,Job1和Job3属于基础操作,这里不再进行详细分析,而主要对Job2的数据流程加以简要分析,即只对Canopy算法的原理进行分析。 首先来看图3-3,可以根据这个图来理解Job2的map/reduce过程。 图3-3中的输入数据可以产生两个mapper和一个reducer。每个mapper处理其相应的数据,在这里处理的意思是使用Canopy算法来对所有的数据进行遍历,得到canopy。具体如下:首先随机取出一个样本向量作为一个canopy的中心向量,然后遍历样本数据向量集,若样本数据向量和随机样本向量的距离小于T1,则把该样本数据向量归入此canopy中,若距离小于T2,则把该样本数据从原始样本数据向量集中去除,直到整个样本数据向量集为空为止,输出所有的canopy的中心向量。reducer调用Reduce过程处理Map过程的输出,即整合所有Map过程产生的canopy的中心向量,生成新的canopy的中心向量,即最终的结果。 3.1.3 Mahout的Canopy算法实战 1.输入数据 从 http://archive.ics.uci.edu/m1/databases/synthetic_control/synthetic_control.data.html 下载数据,这里使用的数据同样是第2章中提到的控制图数据,包含600个样本数据,每个样本数据有60个属性列,这些数据可以分为六类。我们首先上传该文本数据到HDFS,使用如下命令: $HADOOP_HOME/bin/hadoopfs–copyFromLocal/home/mahout/mahout_data/synthetic_control.datainput/synthetic_control.data 这里只针对Job2的任务进行实战:Job2的输入要求使用的数据是序列化的,同时要求输入数据要按照一定的格式,因此,编写代码清单3-1对原始数据进行处理。 代码清单 3-1 原始数据处理代码 packagemahout.fansy.utils.transform; importjava.io.IOException; importorg.apache.hadoop.conf.Configuration; importorg.apache.hadoop.fs.Path; importorg.apache.hadoop.io.LongWritable; importorg.apache.hadoop.io.Text; importorg.apache.hadoop.mapreduce.Job; importorg.apache.hadoop.mapreduce.Mapper; importorg.apache.hadoop.mapreduce.Reducer; importorg.apache.hadoop.mapreduce.lib.input.FileInputFormat; importorg.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat; importorg.apache.hadoop.util.ToolRunner; importorg.apache.mahout.common.AbstractJob; importorg.apache.mahout.math.RandomAccessSparseVector; importorg.apache.mahout.math.Vector; importorg.apache.mahout.math.VectorWritable; /** ??*transformtextdatatovectorWritabledata ??*@authorfansy ??* ??*/ publicclassText2VectorWritableextendsAbstractJob{ publicstaticvoidmain(String[]args)throwsException{ ToolRunner.run(newConfiguration(),newText2VectorWritable(),args); } @Override publicintrun(String[]arg0)throwsException{ addInputOption(); addOutputOption(); if(parseArguments(arg0)==null){ return-1; } Path input = getInputPath (); Path output = getOutputPath (); Configuration conf = getConf (); //setjobinformation ?Job job = new Job(conf,"text2vectorWritableCopywithinput:"+input.getName()); job.setOutputFormatClass(SequenceFileOutputFormat.class); job.setMapperClass(Text2VectorWritableMapper.class); job.setMapOutputKeyClass(LongWritable.class); job.setMapOutputValueClass(VectorWritable.class); job.setReducerClass(Text2VectorWritableReducer.class); job.setOutputKeyClass(LongWritable.class); job.setOutputValueClass(VectorWritable.class); job.setJarByClass(Text2VectorWritable.class); FileInputFormat.addInputPath(job,input); SequenceFileOutputFormat.setOutputPath(job,output); if(!job.waitForCompletion(true)){//waitforthejobisdone thrownewInterruptedException("CanopyJobfailedprocessing"+input); } return0; } /** ??*Mapper:mainprocedure ??*@authorfansy ??* ??*/ publicstaticclassText2VectorWritableMapperextendsMapper < LongWritable ,Text,LongWritable,VectorWritable > { publicvoidmap(LongWritablekey,Textvalue,Contextcontext)throws IOException,InterruptedException{ ??String[] str = value .toString().split("\\s{1,}"); //splitdatauseoneormoreblanker ???Vector vector = new RandomAccessSparseVector(str.length); ???for(int i = 0 ;i < str.length ;i++){ ???vector.set(i,Double.parseDouble(str[i])); ???} ???VectorWritable va = new VectorWritable(vector); ???context.write(key,va); } } /** ??*Reducer:donothingbutoutput ??*@authorfansy ??* ??*/ publicstaticclassText2VectorWritableReducerextendsReducer < LongWritable , VectorWritable,LongWritable,VectorWritable > { publicvoidreduce(LongWritablekey,Iterable < VectorWritable > values,Con-textcontext)throwsIOException,InterruptedException{ ???for(VectorWritablev:values){ ?context.write(key,v); ???} } } } 把上面的代码编译打包成ClusteringUtils.jar并放入/home/mahout/mahout_jar目录下,然后在Hadoop根目录下运行下面的命令: $HADOOP_HOME/bin/hadoopjar/home/mahout/mathout_jar/ClusteringUtils.jar mahou·t.fansy.utils.transform.Text2VectorWritable–iinput/synthetic_control.data–o input/transform 命令运行成功后可以在文件监控系统查看转换后的输入数据,如图3-5所示。 由图3-5方框中的内容可以看出,数据已经被转换为VectorWritable的序列文件了。经过上面的步骤,输入数据的准备工作就完成了。 提示在Hadoop中运行编译打包好的jar程序,可能会报下面的错误: Exceptioninthread"main"java.lang.NoClassDefFoundError: org/apache/mahout/common/AbstractJob 这时需要把Mahout根目录下的相应的jar包复制到Hadoop根目录下的lib文件夹下,同时重启Hadoop即可。 2.运行 进入Mahout的根目录下,运行下面的命令: $MAHOUT_HOME/bin/mahoutcanopy--inputinput/transform/part-r-00000--outputoutput/canopy--distanceMeasureorg.apache.mahout.common.distance.EuclideanDistanceMeasure--t180--t255--t380--t455--clustering 其中输入文件使用的是转换后的序列文件;距离计算方式使用的是欧式距离;T1和T3设置为80,T2和T4设置为55;--clustering选项表示最后对原始数据进行分类。 可以看到其输出类名为ClusterWritable,编写下面的代码清单 3-2。 代码清单3-2 转换canopy聚类中心向量代码 packagemahout.fansy.utils; importjava.io.IOException; importorg.apache.hadoop.conf.Configuration; importorg.apache.hadoop.io.Text; importorg.apache.hadoop.mapreduce.Job; importorg.apache.hadoop.mapreduce.Mapper; importorg.apache.hadoop.mapreduce.lib.input.FileInputFormat; importorg.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat; importorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat; importorg.apache.hadoop.util.ToolRunner; importorg.apache.mahout.clustering.iterator.ClusterWritable; importorg.apache.mahout.common.AbstractJob; importorg.slf4j.Logger; importorg.slf4j.LoggerFactory; /** ??*readclustercenters ??*@authorfansy ??*/ publicclassReadClusterWritableextendsAbstractJob{ publicstaticvoidmain(String[]args)throwsException{ ToolRunner.run(newConfiguration(),newReadClusterWritable(),args); } @Override publicintrun(String[]args)throwsException{ addInputOption(); addOutputOption(); if(parseArguments(args)==null){ return-1; ?} Jobjob=newJob(getConf(),getInputPath().toString()); job.setInputFormatClass(SequenceFileInputFormat.class); job.setMapperClass(RM.class); job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(Text.class); job.setNumReduceTasks(0); job.setJarByClass(ReadClusterWritable.class); FileInputFormat.addInputPath(job,getInputPath()); FileOutputFormat.setOutputPath(job,getOutputPath()); ???if(!job.waitForCompletion(true)){ thrownewInterruptedException("CanopyJobfailedprocessing"+getInputPath()); } ?return0; } publicstaticclassRMextendsMapper<Text,ClusterWritable,Text,Text>{ privateLoggerlog=LoggerFactory.getLogger(RM.class); ???publicvoidmap(Textkey,ClusterWritablevalue,Contextcontext)throws IOException,InterruptedException{ Stringstr=value.getValue().getCenter().asFormatString(); //System.out.println("center****************:"+str); ?log.info("center*****************************:"+str);//setloginformation context.write(key,newText(str)); } } } 把上面的代码编译打包放入/home/mahout/mahout_jar目录下,运行下面的命令: $HADOOP_HOME/bin/hadoopjar/home/mahout/mahout_jar/ClusteringUtils.jarmahout.fansy.utils.ReadClusterWritable-ioutput/canopy/clusters-0-final/part-r-00000-ooutput/canopy-output

优秀的个人博客,低调大师

hadoop学习第二天之伪分布模式安装(下)

继续伪分布安装 7.安装JDK 使用winscp将hadoop和jdk复制到linux目录下 a)打开Winscp输入虚拟机的ip,用户,密码,保存密码后点击登录 左边windows,右边linux。在左边找到要复制的文件(hadoop1.1.2.tar.gz,JDK-xx-xx.bin),直接拖到linux系统下的/usr下的local中. b)解压hadoop-1.1.2.tar.gz #tar –xzvf hadoop-1.1.2.tar.gz c)在linux中二进制文件一般是以bin结尾,但仍然需要执行权限才能执行 #chmod 755 jdk-6u24-linux-i586.bin 解压jdk #./ jdk-6u24-linux-i586.bin d)配置环境变量才能使得jdk生效, #vim /etc/profile 修改前先备份一份 #cp /etc/profile /etc/profile.bak 在开头的空白行添加 export JAVA_HOME=/usr/local/jdk export PATH=$JAVA_HOME/bin:$PATH 就类似于windows下的jdk配置环境变 量 e)重命名hadoop和jdk的文件夹,使得容易使用 #mv hadoop-1.1.2.tar.gz hadoop #mv jdk-6u24-linux-i586.bin jdk f)使得环境变量生效 #source /etc/profile g)验证java版本 #java -version 8.安装hadoop a)因为在在第七步已经解压并且重命名了hadoop,直接切换到hadoop目录 bin下存放的是hadoop的可执行文件 conf下放的是配置文件 lib目录下放的是hadoop依赖的jar包 src目录是存放hadoop源代码的位置 docs存放的是hadoop的文档 b)为了执行hadoop命令方便,将hadoop的bin目录添加到环境变量文件中 #vim /etc/profile exportHADOOP_HOME=/usr/local/hadoop export PATH=$HADOOP_HOME/bin:$JAVA_HOME/bin:$PATH c)使环境变量生效 #source /etc/profile d)修改hadoop的配置文件 进入conf目录 hadoop#cd conf 主要修改的配置文件有四个 hadoop-env.sh \core-site.xml\mapred-site.xml\hdfs-site.xml hadoop-env.sh中将第九行的#去掉,成为 #exportJAVA_HOME=/usr/loal/jdk/ 修改core-site.xml配置文件内容如下,hadoop1是我设置的主机名 修改hdfs-site.xml配置文件内容如下 修改mapred-site.xml配置文件内容如下: hadoop1修改为自己的主机名 e)启动hadoop前的文件系统格式化 # hadoop namenode -format f)启动hadoop #start-all.sh 启动与hadoop有关的所有进程 g)查看hadoop是否正常启动,使用jps命令可以查看java进程 如何看到这五个java进程代表hadoop启动成功 JobTracker、TaskTracker、DataNode、SecondaryNameNode、NameNode 启动时最有可能造成NameNode启动不成功的可能原因 (1). 没有格式化 (2). 环境变量设置错误 (3).ip和hostname绑定失败 h) 验证hadoop是否正在运行 浏览器地址栏中:http://hadoop1:50070 (hadoop1需要在windows或linux的host文件中绑定)显示正常网页表示NameNode正在运行 http://hadoop1:50030的链接,显示正常表示mapreduce正在运行

优秀的个人博客,低调大师

Docker学习笔记之一,搭建一个JAVA Tomcat运行环境

前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序,并通过配置文件可以轻松实现应用程序的自动化安装、部署和升级,非常方便。因为使用了容器,所以可以很方便的把生产环境和开发环境分开,互不影响,这是 docker 最普遍的一个玩法。更多的玩法还有大规模 web 应用、数据库部署、持续部署、集群、测试环境、面向服务的云计算、虚拟桌面 VDI 等等。 主观的印象:Docker 使用 Go 语言编写,用 cgroup 实现资源隔离,容器技术采用 LXC. 提供了能够独立运行Unix进程的轻量级虚拟化解决方案。它提供了一种在安全、可重复的环境中自动部署软件的方式。LXC命令有些复杂,若感兴趣,这里有一篇我以前写的基于LXC,(<ahref="http: www.blogjava.="" net="" yongboy="" archive="" 2012="" 06="" 23="" 381346.html"="">从无到有,搭建一个简单版的JAVA PAAS云平台),可以提前复习一下。 有关实现原理、相关理论、运用场景等,会在本系列后面书写,这里先来一个浅尝辄止,完全手动,基于Docker搭建一个Tomcat运行环境。先出来一个像模像样Demo,可以见到效果,可能会让我们走的更远一些。 环境 本文所有环境,VMware WorkStation上运行ubuntu-13.10-server-amd64,注意是64位系统,理论上其它虚拟机也是完全可行的。 安装Docker Docker 0.7版本需要linux内核 3.8支持,同时需要AUFS文件系统。 # 检查一下AUFS是否已安装 sudo apt-get update sudo apt-get install linux-image-extra-`uname -r` # 添加Docker repository key sudo sh -c "wget -qO- https://get.docker.io/gpg | apt-key add -" # 添加Docker repository,并安装Docker sudo sh -c "echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list"sudo apt-get update sudo apt-get install lxc-docker # 检查Docker是否已安装成功 sudo docker version # 终端输出 Client version: 0.7.1 Go version (client): go1.2 Git commit (client): 88df052 Server version: 0.7.1 Git commit (server): 88df052 Go version (server): go1.2 Last stable version: 0.7.1 去除掉sudo 在Ubuntu下,在执行Docker时,每次都要输入sudo,同时输入密码,很累人的,这里微调一下,把当前用户执行权限添加到相应的docker用户组里面。 # 添加一个新的docker用户组 sudo groupadd docker # 添加当前用户到docker用户组里,注意这里的yongboy为ubuntu server登录用户名 sudo gpasswd -a yongboy docker # 重启Docker后台监护进程 sudo service docker restart # 重启之后,尝试一下,是否生效 docker version #若还未生效,则系统重启,则生效 sudo reboot 安装一个Docker运行实例-ubuntu虚拟机 Docker安装完毕,后台进程也自动启动了,可以安装虚拟机实例(这里直接拿官方演示使用的learn/tutorial镜像为例): docker pull learn/tutorial 安装完成之后,看看效果 docker run learn/tutorial /bin/echo hello world 交互式进入新安装的虚拟机中 docker run -i -t learn/tutorial /bin/bash 会看到: root@51774a81beb3:/# 说明已经进入交互式环境。 安装SSH终端服务器,便于我们外部使用SSH客户端登陆访问 apt-get update apt-get install openssh-server which sshd /usr/sbin/sshd mkdir /var/run/sshd passwd #输入用户密码,我这里设置为123456,便于SSH客户端登陆使用 exit #退出 获取到刚才操作的实例容器ID #docker ps -l CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 51774a81beb3 learn/tutorial:latest /bin/bash 3 minutes ago Exit 0 thirsty_pasteur 可以看到当前操作的容器ID为:51774a81beb3。注意了,一旦进行所有操作,都需要提交保存,便于SSH登陆使用: docker commit 51774a81beb3 learn/tutorial 以后台进程方式长期运行此镜像实例: docker run -d -p 22 -p 80:8080 learn/tutorial /usr/sbin/sshd -D ubuntu容器内运行着的SSH Server占用22端口,-p 22进行指定。-p 80:8080指的是,我们ubuntu将会以8080端口运行tomcat,但对外(容器外)映射的端口为80。 这时,查看一下,是否成功运行。 #docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 871769a4f5ea learn/tutorial:latest /usr/sbin/sshd -D About a minute ago Up About a minute 0.0.0.0:49154->22/tcp, 0.0.0.0:80->8080/tcp focused_poincare 注意这里的分配随机的SSH连接端口号为49154: ssh root@127.0.0.1 -p 49154 输入可以口令,是不是可以进入了?你一旦控制了SSH,剩下的事情就很简单了,安装JDK,安装tomcat等,随你所愿了。以下为安装脚本: # 在ubuntu 12.04上安装oracle jdk 7 apt-get install python-software-properties add-apt-repository ppa:webupd8team/java apt-get update apt-get install -y wget apt-get install oracle-java7-installer java -version # 下载tomcat 7.0.47 wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-7/v7.0.47/bin/apache-tomcat-7.0.47.tar.gz # 解压,运行 tar xvf apache-tomcat-7.0.47.tar.gz cd apache-tomcat-7.0.47 bin/startup.sh 默认情况下,tomcat会占用8080端口,刚才在启动镜像实例的时候,指定了 -p 80:8080,ubuntu镜像实例/容器,开放8080端口,映射到宿主机端口就是80。知道宿主机IP地址,那就可以自由访问了。在宿主机上,通过curl测试一下即可: curl http://192.168.190.131 当然,你也可以使用浏览器访问啦。 真实情况,可能不会让tomcat直接对外开放80端口,一般都会位于nginx/apache或者防火墙的后面,上面仅为演示。 小结 在Docker帮助下搭建一个Tomcat运行时环境,总体很简单,让我们看到了PAAS的身影。不错,使用Docker作为PAAS底层服务,本身就不复杂。 下面有时间,会谈一谈如何使用脚本文件构建一个镜像实例,同时会谈一谈Docker的实现原理和机制等。

优秀的个人博客,低调大师

Solon AI 开发学习 6 - chat - 两种 http 流式输入输出

http 流式输出(主要是指文本流式输出),需要使用响应式接口和支持流输出的 mime 声明。常见的有两种文本流式输出: 1、输出 sse(Server Sent Event) 输出的格式:以 sse 消息块为单位,以"空行"为识别间隔。 示例代码: import org.noear.solon.annotation.Mapping; import org.noear.solon.annotation.Produces; import org.noear.solon.core.util.MimeType; import org.noear.solon.web.sse.SseEvent; import reactor.core.publisher.Flux; import java.io.IOException; @Produces(MimeType.TEXT_EVENT_STREAM_UTF8_VALUE) @Mapping("case1") public Flux<SseEvent> case1(String prompt) throws IOException { return Flux.from(chatModel.prompt(prompt).stream()) .filter(resp -> resp.hasContent()) .map(resp -> new SseEvent().data(resp.getContent())); } 输出效果如下(sse 消息块有多个属性,data 为必选,其它为可选): data:{"role":"ASSISTANT","content":"xxx"} data:{"role":"ASSISTANT","content":"yyy"} 2、输出 ndjosn(Newline-Delimited JSON) 输出的格式:以 json 消息块为单位,以"换行符"为识别间隔。 import org.noear.solon.ai.chat.message.AssistantMessage; import org.noear.solon.annotation.Mapping; import org.noear.solon.annotation.Produces; import org.noear.solon.core.util.MimeType; import reactor.core.publisher.Flux; import java.io.IOException; @Produces(MimeType.APPLICATION_X_NDJSON_UTF8_VALUE) @Mapping("case2") public Flux<AssistantMessage> case2(String prompt) throws IOException { return Flux.from(chatModel.prompt(prompt).stream()) .map(resp -> resp.getMessage()); } 输出效果如下: {"role":"ASSISTANT","content":"xxx"} {"role":"ASSISTANT","content":"yyy"} 3、获取 上面讲的是作为 server 以流式输出。solon-net-httputils 则提供了,作为客户端接收流式获取(或接收)的能力: 使用 HttpUtils 获取文本行流(比如 ndjosn) Publisher<String> publisher = HttpUtils.http("http://localhost:8080/stream") .execAsLineStream("GET"); 使用 HttpUtils 获取 ServerSentEvnet (简称:sse)文本流 Publisher<ServerSentEvent> publisher = HttpUtils.http("http://localhost:8080/sse") .execAsSseStream("GET");

优秀的个人博客,低调大师

Solon AI 开发学习 4 - chat - 模型实例的构建和简单调用

聊天模型接口(ChatModel)支持: 同步调用(call),一次性返回结果 支流式调用(stream,基于 reactivestreams 规范)。通过sse或x-ndjson流式返回结果。 Tool Call(或 Function Call) 与本地数据互动(需要 llm 支持) 提示语多消息输入输出(记忆体) 带图片消息 与 solon-flow 结合使用 1、聊天模型的构建 配置方式构建 solon.ai.chat: demo: apiUrl: "http://127.0.0.1:11434/api/chat" # 使用完整地址(而不是 api_base) provider: "ollama" # 使用 ollama 服务时,需要配置 provider model: "llama3.2" headers: x-demo: "demo1" 代码: import org.noear.solon.ai.chat.ChatConfig; import org.noear.solon.ai.chat.ChatModel; import org.noear.solon.annotation.Bean; import org.noear.solon.annotation.Configuration; import org.noear.solon.annotation.Inject; @Configuration public class DemoConfig { @Bean public ChatModel build(@Inject("${solon.ai.chat.demo}") ChatConfig config) { return ChatModel.of(config).build(); } } 手动方式构建 @Configuration public class DemoConfig { @Bean public ChatModel build() { return ChatModel.of("http://127.0.0.1:11434/api/chat") //使用完整地址(而不是 api_base) .provider("ollama") .model("llama3.2") .headerSet("x-demo", "demo1") .defaultOptionAdd("stream_options", Utils.asMap("include_usage", true)) .build(); } } 2、同步调用(call) public void case1() throws IOException { ChatResponse resp = chatModel.prompt("hello").call(); //打印消息 log.info("{}", resp.getMessage()); } 3、异步流式或响应式调用(stream) 流式返回为org.reactivestreams.Publisher(reactivestreams 规范) public void case2() throws IOException { Publisher<ChatResponse> publisher = chatModel.prompt(ChatMessage.ofUser("hello")).stream(); //return publisher; //使用 solon-web-rx 时可直接返回;或者对接 solon-web-sse 或 websocket publisher.subscribe(new SimpleSubscriber<ChatResponse>() .doOnNext(resp -> { log.info("{}", resp.getMessage()); }).doOnComplete(() -> { log.debug("::完成!"); }).doOnError(err -> { log.error("{}", err); })); } 可以直接订阅消费(如上)。也可对接各种流行的响应式框架,比如 mutiny、rxjava 或 reactor: @Produces(MimeType.TEXT_EVENT_STREAM_UTF8_VALUE) @Mapping("case2") public Flux<SseEvent> case2(String prompt) throws IOException { return Flux.from(chatModel.prompt(prompt).stream()) .map(resp -> resp.getMessage()) .map(msg -> new SseEvent().data(msg.getContent())) .doOnError(err->{ log.error("{}", err); }); } 4、模型日志 内部默认会打印 llm 请求与响应的日志,分别以ai-request:和ai-response:开头。日志级别为:DEBUG。

优秀的个人博客,低调大师

酷瓜云课堂(内网版)v1.2.1 发布,内部学习培训系统

优化索引管理工具 优化章节等页面UI 管理员初始99999积分 修正workerman中onMessage问题 method="post" -> method="POST" 修正非免费课程试听问题 优化layer窗口中的表单跳转 优化倒计时 系统介绍 酷瓜云课堂内网版,采用C扩展框架Phalcon开发,使用本地基础服务,无营销相关功能,主要适用于公司、集团、机关、学校等内部网络环境使用。 友情提示: 演示系统配置低,带宽有限,切莫压测 课程数据来源于网络(无实质内容) 管理后台已禁止数据提交,私密配置已过滤 系统演示: 前台演示 后台演示 演示账号:100015@163.com / 123456 (前后台通用) 项目组件 后台框架:phalcon 3.4 前端框架:layui 2.9 全文检索:xunsearch 1.4 基础依赖:php7.3, mysql5.7, redis5.0 项目文档 运行环境搭建 系统服务配置 客户终端配置 产品试用 申请地址:点击申请

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册