0%

RAG(Retrieval-Augmented Generation)

流程:

Word Embeddings/Sentence Embeddings

  • 信息检索(Retrieval): 8-10. 给定一个查询,系统首先从一个大型文档库中检索出与查询相关的文档或段落。
    这一步通常使用嵌入技术和相似度计算来完成。
  • 生成(Generation): 13- 15. 生成模型(如GPT-3、T5等)接收检索到的信息作为额外的上下文,并根据这些信息生成更准确、相关的响应。

流程

解决的问题:

1.LLM 数据更新问题

2.数据安全问题

3.幻觉

局限:

1:无法处理隐含关系(推理).A的所在部门销售

2:全局推理缺陷

GraphRAG(仍有缺陷)

应用

VS SFT

对比微调
4

Ollama:

Ollama是一个开源的大模型管理工具,它提供了丰富的功能,包括模型的训练、部署、监控等。 通过Ollama,你可以轻松地管理本地的大模型,提高模型的训练速度和部署效率。

  • 此外,Ollama还支持多种机器学习框架,如TensorFlow、PyTorch等,使得你可以根据自己的需求选择合适的框架进行模型的训练.同时提供模型仓库

Hugging Face

Hugging Face Hub 是一个协作平台,其中托管了大量的用于机器学习的开源模型和数据集,你可以将其视为 ML 的 Github。该 hub 让你可以轻松地找到、学习开源社区中有用的 ML 资产并与之交互,从而促进共享和协作

GGUF(GPT-Generated Unified Format) 大模型文件标准格式之一

AnytingLLM

LangChain

LangChain 的核心是一个开发环境,通过使用抽象方法简化 LLM 应用程序的编程:将一个或多个复杂流程表示为封装所有组成步骤的命名组件

LlamaIndex

Dify

对比

Agent

语法

1.some test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

let a = {o: "091"}
a['8'] = "90"
a[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
Object.getPrototypeOf(a).a = 898
let b = Object.create(a)
Object.getPrototypeOf(b).a = 666
let car = new Car("ma","mo","ye")
//Object.getOwnPropertyNames(Object.getPrototypeOf(a))
console.log(Object.getOwnPropertyNames(Object.getPrototypeOf(car)));

function showProps(obj, objName) {
var result = "";
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
result += objName + "." + i + " = " + obj[i] + "\n";
}
}
return result;
}

function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
}

function forProps(obj) {
let object = obj;
let resullt = ""
do {
object = Object.getPrototypeOf(object);
resullt += object +"\n"
} while (object);
return resullt

}

function* fibonacci() {
let a = 0, b = 1;
while (true) {
yield b;
[a, b] = [b, a + b];
}
}
  1. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function a() {
    }

    function B() {
    this.b = "12"
    }

    class C {
    e() {
    }
    }

    let d = {}
    console.log(B.__proto__ === Object.getPrototypeOf(B))
    // new B().__proto__ === Object.getPrototypeOf(new B())
    // B.prototype === Object.getPrototypeOf(new B())
    // B.prototype["constructor"] === B
    // Object.getPrototypeOf(new B())["constructor"] === B
    // B.__proto__ === Object.getPrototypeOf(B)
    // B.__proto__ != B.prototype // Object.getPrototypeOf(B) 为 function (){ [native code] } , 而 Object.getPrototypeOf(new B()) === B.prototype 为 {constructor:B}
    // 以上同样规则 使用a 与 C .只是C.prototype 为 {constructor:C,e:(){}},多了C的成员函数的变量。如果想让B与C达到一样,只需B.prototype.e = function (){}即可
    ````
    2.`...`eg:

拦截器

执行过程类似Okhttp的责任链Filter.doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

@WebFilter("/fi/d")
class MyFilter : Filter {
override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
println("------->before ${this.javaClass.name}")//3
chain.doFilter(request, response)//必须放行,否则会卡在此处
println("------->after ${this.javaClass.name}")//4
}
}

@WebFilter("/*")
class AllFilter : Filter {
override fun doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
println("------->before ${this.javaClass.name}") //1
request.getRequestDispatcher("/fi/d").forward(request, response) //a
//(response as HttpServletResponse).sendRedirect("${request.servletContext}/fi/d") //b

println("------->after ${this.javaClass.name}") //2
}
}
1:无a+无b 请求/fi/d 执行顺序为 1->3-> servlet代码->4->2
2:有a 请求任何路径含(/fi/d) 执行顺序为 1->servlet代码->2,即forword直接跳过后面所有Filter ,直接到servlet
3:有b 请求任何路径含(/fi/d) 都会出错,也就是filter中不能redirect
拦截器中不能进行sendRedirect操作
4:范围都一致时,按拦截器类名字母排序

拦截器类型

以下顺序越来越精确,拦截链则是越精确越后拦截,其它都相同情况下则拦截顺按拦截器类名字母排序
1:指定资源匹配。例如”/index.jsp”
2:目录匹配。例如”/servlet/
3:后缀名匹配,例如”
.jsp”
4:通配符,拦截所有web资源。”/*”

  • 我们设置的Cookie浏览器会分path,只有同一path返回的cookie,下一次访问同path时(请求转发也算),浏览器请求头才会带上对应path.
    可以手动设置Cookie.path = xxx eg:req.contextPath来指定path,浏览器默认根据要访问的url依次匹配最接近的1级,2级path的cookie并带上
  • Cookie的值只能是String无法想session一样是object,且无法为中文,需要放中文时需要URLEncode
  • Cookie的有效期Cookie.maxAge = 1000 // 秒为单位
  • JSP中可以通过${cookie.key.value} key为cookie对应的key获取Cookie

Session

Session作用域,浏览器重启或者新session后则刷新,原理是利用Cookie,带了个JSESSIONID=BE09C25AA4F9F1CBDC6B5641F59DBA36, 同一对话
该session id值会一致,java web服务器根据id获取对应session,提供session作用域.
浏览器会自动管理session对应的cookie键值对,会话结束或者浏览器关闭时不进行存储,保证下次新会话不带上。

销毁

2种方式销毁
1:过期,可以配置过期时间
web.xml中配置

1
2
3
4

<session-config>
<session-timeout>100</session-timeout><!--单位为分钟-->
</session-config>

没有配置默认30分钟,在tomcat的web.xml中配置
2:主动销毁调用Session.invalidate()方法

JSP(Java Server Pages)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<%@ page import="org.example.mybatis.pojo.User" %><%--
Created by IntelliJ IDEA.
User: wupeixin
Date: 2023/3/19
Time: 8:02 PM
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<%!User user = new User(1, "userName1", "pa2");%> <%--! 此标签内容会放到——jspservice方法之外,即不会影响展示可以专门定义function 或者变量--%>

<body>
<%=user.getPassword()%> <%--内容直接放到out.print()中,作为out.print()参数,也就是会直接在response的流中直接显示--%>
$END$
<% System.out.println("Use Java in JSP" + user.getUserName());%> <%--内容直接放到_jspService方法之中,也就是和标签组成response body返回内容--%>
</body>
</html>

EL(Expression Language)表达式

语法${变量名}
会依次从 page(当前页面有效)->request(当前请求有效)->session(当前会话有效)->application(当前应用有效) 寻找直到寻找到为止

JSTL(Tomcat 10使用不知该使用哪个依赖库及url)

1:引入依赖库
2:在 JSP 页面上引入 JSTL 标签库 如<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<c:if test="${flag == 1}">

</c:if>
<c:if test="${flag == 2}">

</c:if>

<c:forEach items="${brands}" var="brand">
<tr align="center">
<td>${brand.id}</td>
<td>${brand.brandName}</td>
<td>${brand.companyName}</td>
<td>${brand.description}</td>
</tr>
</c:forEach>

<c:forEach begin="0" end="10" step="1" var="i">
${i}
</c:forEach>

获取请求参数

get 或 post请求&&Content-Type 为application/x-www-form-urlencoded :
可以通过HttpServletRequest.getParameterHttpServletRequest.parameterMap来获取URL中字段参数

post请求body参数只能通过HttpServletRequest.readerHttpServletRequest.inputStream获取

中文乱码问题

1.HttpServletRequest.getParameterHttpServletRequest.parameterMap获取URL中字段参数中文乱码问题
原因是浏览器默认用UTF-8进行URL encode,而tomcat
默认用ISO-8859-1解码后放入parameterMap。解决方案:String(req.getParameter("xxx").getBytes("ISO-8859-1"),"UTF-8")
Tomcat 8后默认以UTF-8解码,故无此问题

请求转发

请求转发(forward)
一种在服务器内部的资源跳转方式,1次请求 req.getRequestDispatcher("/本服务内要挑战的路径").forward(req, resp)

重定向

请求2次
方式1:

1
2
resp.setStatus(302)
resp.setHeader("location", "重定向地址")

方式2:

1
resp.sendRedirect("重定向地址")

response

1
2
3
4
5
6
7
8
9
10
11
12
13
resp.contentType = "text/html;charset=utf-8" //告诉客户端响应字符集,如果用字节流返回文字,也要设置
resp.writer.write("测试响应") //使用字符流

//字节流返回文件 ,也可以用common-io:common-io:2.6 这个库的IOUtils.copy(fileInput,resp.outputStream)替代
val fileInput = FileInputStream("本机文件路径")
val bytes = ByteArray(1024)
var len = 0
do {
len = fileInput.read(bytes)
if (len != -1) {
resp.outputStream.write(bytes, 0, len)
}
} while (len != -1)

安装

Debian

  • 前提准备
  • Java环境安装
    Tomcat 需java环境,运行
    1
    2
    3
    sudo apt update #升级apt
    sudo apt install default-jdk #sudo apt install default-jdk

  • 新增tomcat用户及用户组
    以root运行Tomcat,具有安全风险。我们将创建普通用户运行Tomcat
    1
    2
    sudo groupadd tomcat #增加tomcat用户组
    sudo useradd -s /bin/false -g tomcat -d /opt/tomcat tomcat # 创建一个新 tomcat用户。我们将使该用户成为该tomcat组的成员,它有/opt/tomcat的主目录(我们将安装Tomcat)和 /bin/false的shell(因此没有人可以登录该帐户)

下载

tomcat官网找到合适版本点击,获取对应tar.gz链接
将其下载到/tmp(这是一个很好的下载短暂项目的目录,)目录下

1
2
3
wget https://dlcdn.apache.org/tomcat/tomcat-10/v${VERSION}/bin/apache-tomcat-${VERSION}.tar.gz -P /tmp # 下载对应tomcat到tmp目录下
sudo mkdir /opt/tomcat # 在opt下创建tomcat目录
sudo tar xzvf /tmp/apache-tomcat-${VERSION}.tar.gz -C /opt/tomcat --strip-components=1 # 将下载的tar.gz解压到opt的tomcat目录下,--strip-components=1,代表删除压缩文件根目录,直接将其子孙文件按层级提取到/opt/tomcat下

更新权限

设置的tomcat用户需要能够访问Tomcat安装

1
2
3
4
5
sudo chgrp -R tomcat /opt/tomcat # 在整个安装目录中授予tomcat组权限
cd /opt/tomcat
sudo chmod -R g+r conf #为tomcat组提供对当前目录下conf目录及其所有内容的读访问权限
sudo chmod g+x conf # 执行对当前目录下conf目录本身的访问
sudo chown -R tomcat webapps/ work/ temp/ logs/ # tomcat用户成为webapps,work,temp,和logs目录的所有者

创建一个systemd服务文件来管理Tomcat进程

我们希望能够将Tomcat作为服务运行,因此我们将设置systemd服务文件。 Tomcat需要知道Java的安装位置。此路径通常称为“JAVA_HOME”
sudo update-java-alternatives -l,将会得出如
java-1.11.0-openjdk-amd64 1111 /usr/lib/jvm/java-1.11.0-openjdk-amd64
有了这条信息,我们就可以创建systemd服务文件了。在/etc/systemd/system目录中键入以下内容以打开一个名为tomcat.service的文件:
sudo nano /etc/systemd/system/tomcat.service
将以下内容粘贴到您的服务文件中。替换对应JAVA_HOME, 如有必要可进行其他属性替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[Unit]
Description=Apache Tomcat Web Application Container
After=network.target

[Service]
Type=forking

Environment=JAVA_HOME=/usr/lib/jvm/java-1.11.0-openjdk-amd64
Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid
Environment=CATALINA_HOME=/opt/tomcat
Environment=CATALINA_BASE=/opt/tomcat
Environment='CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC'
Environment='JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom'

ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh

User=tomcat
Group=tomcat
UMask=0007
RestartSec=10
Restart=always

[Install]
WantedBy=multi-user.target

完成后,保存并关闭文件(按下Ctrl+X),然后根据提示输入Y确认,最后按下Enter键退出编辑器.

1
2
3
4
5
6
sudo systemctl daemon-reload #重新加载systemd守护程序,以便它知道我们的服务文件
sudo systemctl start tomcat #启动Tomcat服务
sudo systemctl status tomcat #仔细检查它是否正常启动:... Active: active (running) since...
sudo ufw allow 8080 #允许防火墙打开8080端口
打开 http://server_domain_or_IP:8080 看是否能看到tomcat主页,如果可以则
sudo systemctl enable tomcat # 配置tomcat自启动

配置

  • 如果是Windows,默认是GBk编码,在控制台上日志会有些乱码,需修改tomcat输出日志为GBK编码。
    在comcat安装目录下conf目录下logging.propertisjava.util.logging.ConsloeHandler.encoding = GBK
  • 默认端口为8080可在conf/server<Connector port="8080"/>中修改

servlet

tomcat 9及后面servlet包 引用问题

Servlet从3.0版本后开始支持使用注解配置,3.0版本前只支持XML配置文件的配置方式

1
2
3
4
5
6
7
8
9
10

<servlet>
<servlet-name>Myservlet</servlet-name>
<servlet-class>org.example.servlet.Myservlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>Myservlet</servlet-name>
<url-pattern>/ms</url-pattern>
</servlet-mapping>

urlPatterns匹配规则

精确路径>目录路径(“/xx/*“)>扩展路径(“*.do”)>任意匹配(“/“,”/*“)
扩展匹配前不能再有/

/和/*区别:
当我们的项目中的Servlet配置了“/”,会覆盖掉tomcat中的DefaultServlet,当其他的url-pattern都匹配不上时都会走这个Servlet
当我们的项目中配置了“/*“,意味着匹配任意访问路径
而实际请求时差别就是调用http://localhost:8080/项目名称/ 时,该servlet是否会调用。只是替换默认的则不会,匹配任意的则会。
任意匹配路径都会直接屏蔽静态资源直接访问

Mybatis入门
不使用代理时:
1.config.xml文件可随意放,可在resources文件下再创建文件。SqlSessionFactoryBuilder加载时路径传相对resources根目录。
2.config.xml文件中配置的mapper文件位置<mapper resource="xxx/xxx"/>可以随意放,路径相对于resources根目录下,而不是相对config.xml文件位置
3.mapper.xml文件中的命名空间(namespace=”user”)随便定义,如简单定义为数据库名即可
4.使用sqlSession.selectxxx或updatexxx等("${3中mapper文件中定义namespace}.${mapper文件中sql语句的id}")来查询

使用Mapper代理

MyBatis 配置中标签存在一定顺序,可以利用别名标签给pojo类统一省略包名,别名大小写忽略如

1
2
3
4
5

<typeAlias>
<package name="xxxx.pojo路径"/>
</typeAlias>

MyBatis标签顺序

mapper标签细节

占位符,特殊字符及parameterType省略

特殊字符如 <在xml文件 mapper标签中会被认为是标签的开始,所以在mapper标签sql中需转义(html encode)或cddata注释(
特殊字符较多时用cddata较少时用转义)如:

1
2
1 ... where xxx &lt; 10
2 ... where xxx <![CDATA[<]]>

mapper标签细节

多条件查询参数格式

  1. 不封装每个参数前加@Param注解
  2. 封装成对象
  3. 分装成Map
1
2
3
4
5
6
7
8
9
10
11
//不封装直接传
fun selectMultiParams(@Param("userName") name: String, @Param("password") password: String): List<User>

//多参数传参, 封装成User对象
fun selectMultiParams(user: User): List<User>

//多参数传参, 使用Map
fun selectMultiParams(map: Map<String, *>): List<User>

//mapper.xml
SELECT * FROM tb_use WHERE username like #{ userName } and password like #{ password }
多条件查询优化

1.以上多条件查询时,可能存在后面参数password
不传参问题,那整个SQL就会变为SELECT * FROM tb_use WHERE username like #{userName} and password like ,查询就会出错,
可以用标签优化为

1
2
3
4
5
6
7
SELECT * FROM tb_use WHERE
<if test="userName!=null and userName!='' ">
username like #{userName}
</if>
<if test="password!=null and password!=''">
and password like #{password}
</if>

2.此时如果出现第一个参数username不传仍然有问题,此时可以将所有条件都加上and开头然后
2.1 以一个恒等式 eg: where 1=1 <if test="userName!=null and userName!='' "> and username like #{userName}</if> 来避免
2.2 使用Mybatis的<where>标签实现2.1功能
<where> 1=1 <if test="userName!=null and userName!='' "> and username like #{userName}</if> <if>...</if></where>

动态单条件查询

choose (when,otherwise)选择类似switch

1
2
3
4
5
6
7
8
9
10
11
12
13
14

<select id="selectChooseParams" resultType="user">
SELECT *
FROM tb_use
where
<choose>
<when test="userName!=null and userName!='' ">
username like #{userName} <!--可以加and,<where>标签会动态去除-->
</when>
<when test="password!=null and password!=''">
password like #{password}
</when>
</choose>
</select>

同理以上语句当所有条件都不成立时会变成SELECT * FROM tb_use where,会出问题,解决方案

  1. 利用添加恒等式,让sql完成eg: <when text="..">...</when> <otherwise>1=1</otherwise>
  2. 利用标签

标签小结

1.动态删除sql中and。当sql中第一个标签语句含and时,会动态删除。但做不到动态添加and,如第2个标签缺and,不会自动添加
2.动态删除where,当标签内所有条件都不成立时,不会给语句添加where,使sql出问题.

insert值

  • 默认情况下Mybatis开始事务,故增删改时
    1.要么在创建session时factory.openSession(true)设置默认自动提交
    or
    2.在每次操作后session.commit
  • 可在插入后返回指定列数据
    <insert id="add" useGeneratedKeys="true" keyProperty="自动生成主键名">

update

可以通过标签避免,sql语法后的,问题eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<update id="update">
UPDATE tb_use
<set>
<if test="userName!=null and userName!=''">
username = #{userName},
</if>
<if test="password!=null and password!=''">
password = #{password}
</if>
<if test="age>0">
age = #{age}
</if>
</set>
WHERE id = #{id}
</update>

delete

1
fun deleteSome(@Param("ids") ids:List<Int>)
1
2
3
4
5
6
7
8
<delete id="deleteSome">
DELETE FROM tb_use WHERE id in
<!-- ids需要在接口中通过@Param("ids")手动指定,
否者collection参数类型,mybatis有自己定义key的规则,如list的key就是list,数组的key是array,而不是参数名-->
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>

注解生成sql

eg:

1
2
3
@Delete("delete from tb_use where id=#{id}")
fun delete(id: Int): Int
//这样就不用在对应的mapper文件中增加标签

ResultMap

用于映射实体类字段名与列名关系,如果2者一样则可不映射,如果不一样默认以实体类定义字段顺序映射,可通过ResultMap设定映射关系

1
2
3
4
5
6
7
8
9
10
<mapper>
mapper xml文件中定义resultMap
...
<resultMap id="userResultMap" type="user">
<result column="second_name" property="sN"/>
<result column="age_str" property="agString"/>
</resultMap>
...
</mapper>

1: 如果SQL是写在接口的注解中,则同时使用@ResultMap("${userResultMap //mapper文件定义的resultMap id}")
2: 如果SQL是通过mapper xml标签写的,则在对应标签中eg: <select id="selectAll" resultType="user" resultMap="userResultMap">

动态SQL

常用命令

1
2
3
4
5
6
7
8
9
10
# 打包:
mvn package
# 编译:
mvn compile
# 清空:清除编译后目录,默认是target目录)
mvn clean
# 运行测试:
mvn test
# 安装jar包到本地仓库中:
mvn install

IDEA集成

IDEA更改Maven默认Home及setting
创建Maven项目
导入依赖
依赖范围
POM 文件中 alt+insert快捷键,选择dependence选项,方便关键字快捷搜索所需库

Scope

  • 默认是compile类型,不写或特殊指定即是默认
  • 运行环境类型的依赖,基本都是provided ,仅用于编译通过及查看源码,不用打进包里,实际的类在环境中已经有。

API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

import java.sql.DriverManager

//1.注册驱动(Mysql5 之后可以不写,利用jar的META-INF/services/java.sql.Driver文件驱动类)
Class.forName("com.mysql.jdbc.Driver")//该类static块调用 DriverManager.resisterDriver方法
/**2 获取连接 如果是本机且端口为3306则可url和port部分省略,为 jdbc:mysql:///${databsename}?参数键值对(eg:useSSL=true).
* 此时不能显式设置useSSL=false,否则会出异常,因为账号密码连接就是ssl连接,默认为true
* useServerPrepStmts=true,则开启sql预编译功能
* **/

val connect = DriverManager.getConnection("jdbc:mysql://${url:port}/${databsename}[?参数键值对1&参数键值对2..]","root","password")

/**
* Connection.setAutoCommit() 对应sql: set @@autocommit;
* Connection.commit() 对应sql: commit;
* Connection.rollback() 对应sql: rollback;
* createStatement() 普通执行sql对象
* prepareStatement(sql) 预编译SQL的执行sql对象:防止SQL注入
* prepareCall(sql) 执行存储过程的对象
* **/
//3.创建执行sql对象并执行
val prepareStatement = connect.prepareStatement("sql 带问好号的语句")
val result = prepareStatement.apply{
setXXX(1,xxx)
}.executeQuery() //executeUpdate() 更新操作可用于DDL或DML,DQL的结果是ResultSet需要close释放
//4.处理结果
while (result.next()){
println("${result.getString(1)}")//getXXX 均支持列index 或 列名2种方式
}
//5.释放资源
result.close()
prepareStatement.close()
connect.close()


连接远程报错问题

如果连接远端 Mysql报 - Host ‘xxx.xx.x.x‘ is not allowed to connect to this MySQL server,这是数据库操作权限问题,可以通过

1
2
3
4
mysql -u root -proot 
mysql> use mysql;
mysql> update user set host = '%' where user = 'root';
mysql> flush privileges;