<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Eric Yang 的博客</title>
    <description>Hi，我是 eric yang，是一个软件工程师，欢迎来到我的博客。</description>
    <image>
      <url>https://gw.alipayobjects.com/zos/k/hj/sLnZnY.jpg</url>
    </image>
    <link>https://ericsky.com</link>
    <atom:link href="https://ericsky.com/feed.xml" rel="self" type="application/rss+xml" />
		
    
    <item>
      <title>Midjourney AI绘画，迪斯尼风格梦幻城堡🏰</title>
      <description>&lt;p&gt;Midjourney 咒语&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;3d render of a floating majestic castle on a cloud, hyper-realistic, dark outerspace, stars. The castle is made of white stone and has tall, pointed towers. It is surrounded by a stars, planets and moons. The castle is lit by luminescent lights. Hyper-detailed, beautifully color-coded, photorealistic, clean focus, depth of field F0,8, dynamic angle, dynamic composition --ar 16:9 --s 1000 --c 10 --q 2 --s 750 --v 5.1 --style raw
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;原始图片的分辨率是1456 × 816，可以用 &lt;a href=&quot;https://github.com/upscayl/upscayl&quot;&gt;upscayl&lt;/a&gt; 进行放大。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/aigc/disney/1.png&quot; alt=&quot;迪斯尼风格梦幻城堡&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/aigc/disney/2.png&quot; alt=&quot;迪斯尼风格梦幻城堡&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/aigc/disney/3.png&quot; alt=&quot;迪斯尼风格梦幻城堡&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/aigc/disney/4.png&quot; alt=&quot;迪斯尼风格梦幻城堡&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/aigc/disney/5.png&quot; alt=&quot;迪斯尼风格梦幻城堡&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/aigc/disney/6.png&quot; alt=&quot;迪斯尼风格梦幻城堡&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/aigc/disney/7.png&quot; alt=&quot;迪斯尼风格梦幻城堡&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/aigc/disney/8.png&quot; alt=&quot;迪斯尼风格梦幻城堡&quot; /&gt;&lt;/p&gt;
</description>
      <pubDate>2024-05-13</pubDate>
      <link>https://ericsky.com/2024-05-13/midjourney-disney-style-castle.html</link>
      <guid isPermaLink="true">https://ericsky.com/2024-05-13/midjourney-disney-style-castle.html</guid>
    </item>
    
		
    
    <item>
      <title>找工作过程中碰到的一些算法题</title>
      <description>&lt;h2 id=&quot;z公司&quot;&gt;Z公司&lt;/h2&gt;

&lt;h3 id=&quot;机考题1&quot;&gt;机考题1&lt;/h3&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;输入描述：n行时分秒字符串
输出：先按秒升序，再按分升序，再按分升序


* 如下的样例，这购买的时间为  
* 12:30:10  
* 12:15:12  
* 15:20:14  
* 正确的排序结果应该是这样的：  
* 12:30:10  
* 12:15:12  
* 15:20:14  
*  
* 12:30:10  
* 12:15:10  
* 11:20:14  
* 的正确排序结果如下:  
* 12:15:10  
* 12:30:10  
* 11:20:14
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;机考题2&quot;&gt;机考题2&lt;/h3&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;提取给定字符串中的数字：
比如给你c12m23b3n4t56  
提取的数字为:12，23，3，4，56总共5个数字  

示例
输入：
&quot;kur1su alan0233&quot;  
输出： 
[1,233]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;r公司&quot;&gt;R公司&lt;/h2&gt;

&lt;h3 id=&quot;机考1&quot;&gt;机考1&lt;/h3&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;输入描述  
一个ASCII字符串，其中字符没有顺序，字符可以重复。输入字符串的长度&amp;lt;=30。  
 
输出描述  
一个新的字符串，该新字符串中字符在输入字符串中只出现一次，且该新字符串按照ASCII码从小到大的顺序排列。如果输入字符串中字符出现的次数都是大于1，则无需输出。  
 
示例 1  
收起  
 
输入  
e1fghabcd1234efgh  
输出  
1234abcd  
说明  
只出现一次的字符包括’a’,’b’,’c’,’d’,’1’,’2’,’3’,’4’，按照ASCII码升序后组成的新字符串为1234abcd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;机考2&quot;&gt;机考2&lt;/h3&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;解析输入的字符串数组，提取出字符串中的时间戳信息，并且将字符串按照时间戳排序后，输出到控制台。  
 
输入描述  
第1行指定数组的size；  
 
第2行到第n+1行，每行为一个独立的字符串，n为size的值。  
 
每行的字符串由&quot; / - : &quot;和字母、数字组成，时间戳在字符串中的位置不确定，时间戳格式为：2019-01-01T07:30:20，表示2019年1月1日，7点30分20秒。时间为24小时制。  
 
输出描述  
将输入的字符串按照时间戳进行从小到大排序后，输出。符合如下规则：  
 
1、如果时间戳信息相同，按照字符串长度从小到大进行排序；  
 
2、如果长度相同，则按照从首字符开始的ASCII码值比较，从小到大进行排序；  
 
3、如果两个字符串完全一样，则只需要输出一个。  
 
补充说明  
考生不需要考虑时间格式不符合的情况。  
 
示例 1  

输入  
5  
my/2019-01-01T09:00:01  
my/2019-01-01T09:00:01  
abc/2018-12-24T08:00:00/test/you  
1/2018-12-24T08:00:00/test/Test1  
123/2018-12-24T08:00:09/test/me  
输出  
1/2018-12-24T08:00:00/test/Test1  
abc/2018-12-24T08:00:00/test/you  
123/2018-12-24T08:00:09/test/me  
my/2019-01-01T09:00:01  
说明  
每行字符串中如果存在多个时间戳，以第一个为准；时间戳固定为&quot;yyyy-MM-dd&apos;T&apos;HH:mm:ss&quot;的格式
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;h公司&quot;&gt;H公司&lt;/h2&gt;

&lt;h3 id=&quot;机考1-1&quot;&gt;机考1&lt;/h3&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;输入描述：
第一行为N，表示访问历史日志的条数，。  
接下来N行，每一行为一个RESTful API的URL地址，约束地址中仅包含英文字母和连接符/，最大层级为10，每层级字符串最大长度为10。  
最后一行为层级L和要查询的关键字。  
  
输出描述  
输出给定层级上，关键字出现的频次，使用完全匹配方式（大小写敏感）。  
  
e.g.  
输入：  
5  
/hcompany/computing/no/one  
/hcompany/computing  
/hcompany  
/hcompany/cloud/no/one  
/hcompany/wireless/no/one  
2 computing  
  
输出：  
2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;机考2-1&quot;&gt;机考2&lt;/h3&gt;

&lt;p&gt;测试用例只通过了80%。机考，提交代码的时候没有提示哪些测试用例没通过，所以也没法调试具体是代码哪部分逻辑出错。&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;给你一个字符串 s，字符串s首尾相连成一个环形 ，请你在环中找出 &apos;o&apos; 字符出现了偶数次最长子字符串的长度。  
  
输入描述  
输入是一串小写字母组成的字符串  
输出描述  
输出是一个整数  
  
补充说明  
1 &amp;lt;= s.length &amp;lt;= 5 x 10^5  
s 只包含小写英文字母  
  
示例：  
输入  
alolobo  
输出  
6  
说明  
最长子字符串之一是 &quot;alolob&quot;，它包含&apos;o&apos; 2个。  
  
输入  
looxdolx  
输出  
复制  
7  
说明  
最长子字符串是 &quot;oxdolxl&quot;，由于是首尾连接在一起的，所以最后一个 &apos;x&apos; 和开头的 &apos;l&apos;是连接在一起的，此字符串包含 2 个&apos;o&apos; 。  
  
输入  
bcbcbc  
输出  
6  
说明  
这个示例中，字符串 &quot;bcbcbc&quot; 本身就是最长的，因为  &apos;o&apos; 都出现了 0 次。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;机考3&quot;&gt;机考3&lt;/h3&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;孙悟空爱吃蟠桃，有一天趁着蟠桃园守卫不在来偷吃。已知蟠桃园有N颗桃树，每颗树上都有桃子，守卫将在H小时后回来。  
  
孙悟空可以决定他吃蟠桃的速度K（个/小时），每个小时选一颗桃树，并从树上吃掉K个，如果树上的桃子少于K个，则全部吃掉，并且这一小时剩余的时间里不再吃桃。  
  
孙悟空喜欢慢慢吃，但又想在守卫回来前吃完桃子。  
  
请返回孙悟空可以在H小时内吃掉所有桃子的最小速度K（K为整数）。如果以任何速度都吃不完所有桃子，则返回0。  
  
输入描述：  
第一行输入为N个数字，N表示桃树的数量，这N个数字表示每棵桃树上蟠桃的数量。  
第二行输入为一个数字，表示守卫离开的时间H。  
其中数字通过空格分割，N、H为正整数，每棵树上都有蟠桃，且0&amp;lt;N&amp;lt;10000，0&amp;lt;H&amp;lt;10000。  
  
输出描述：  
吃掉所有蟠桃的最小速度K，无解或输入异常时输出0  
  
以下是测试用例：  
 
输入：  
2 3 4 5  
4  
输出：  
5  
  
输入：  
2 3 4 5  
3  
输出：  
0  
  
输入：  
30 11 23 4 20  
6  
输出：  
23

类似题目： https://leetcode-cn.com/problems/koko-eating-bananas/description/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;技术面手撕代码1&quot;&gt;技术面手撕代码1&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/merge-two-sorted-lists/description/&quot;&gt;21. 合并两个有序链表 - 力扣（LeetCode）&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例 1：

输入：l1 = [1,2,4], l2 = [1,3,4]
输出：[1,1,2,3,4,4]
示例 2：

输入：l1 = [], l2 = []
输出：[]
示例 3：

输入：l1 = [], l2 = [0]
输出：[0]
 

提示：

两个链表的节点数目范围是 [0, 50]
-100 &amp;lt;= Node.val &amp;lt;= 100
l1 和 l2 均按 非递减顺序 排列
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;技术面手撕代码2&quot;&gt;技术面手撕代码2&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://leetcode.cn/problems/search-in-rotated-sorted-array/description/&quot;&gt;33. 搜索旋转排序数组 - 力扣（LeetCode）&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;整数数组 nums 按升序排列，数组中的值 互不相同 。

在传递给函数之前，nums 在预先未知的某个下标 k（0 &amp;lt;= k &amp;lt; nums.length）上进行了 旋转，使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]（下标 从 0 开始 计数）。例如， [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ，如果 nums 中存在这个目标值 target ，则返回它的下标，否则返回 -1 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

 

示例 1：

输入：nums = [4,5,6,7,0,1,2], target = 0
输出：4
输入：nums = [4,5,6,7,0,1,2]， target = 0
输出：4
示例 2：

输入：nums = [4,5,6,7,0,1,2], target = 3
输出：-1
示例 3：

输入：nums = [1], target = 0
输出：-1
 

提示：

1 &amp;lt;= nums.length &amp;lt;= 5000
-10^4 &amp;lt;= nums[i] &amp;lt;= 10^4
nums 中的每个值都 独一无二
题目数据保证 nums 在预先未知的某个下标上进行了旋转
-10^4 = target &amp;lt;= 10^4
-104 &amp;lt;= 目标 &amp;lt;= 104
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;代码实现：&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Solution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;findK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;findTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// 从 len - k 的位置开始找&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;findTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;findTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Arrays&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;binarySearch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;findK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;// 从0旋转，还是升序&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;技术面手撕代码3&quot;&gt;技术面手撕代码3&lt;/h3&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;寿司店周年庆，正在举办优惠活动回馈新老客户。寿司转盘上总共有n盘寿司，prices[i]是第i盘寿司的价格，如果客户选择了第i盘寿司，寿司店免费赠送客户下一盘寿司j，前提是prices[j]&amp;lt;prices[i]，如果没有满足条件的j，则不赠送寿司。  
给你一个数组prices，返回一个数组，其中第i个元素存放着客户选择第i盘寿司后得到的寿司的总价格。  
 
1 &amp;lt;= prices.length &amp;lt;= 10^5  
1 &amp;lt;= prices[i] &amp;lt;= 10^3  
 
输入：prices = [8,4,6,2,3]  
输出：[12,6,8,2,5]  
 
输入：prices = [1,2,3,4,5]  
输出：[1,3,4,5,6]  
 
输入：prices = [10,1,1,6]  
输出：[11,1,1,7]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;代码实现：
应该没有什么优化的空间了&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Main&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;};&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;};&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;};&lt;/span&gt;

        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[][]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;samples&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[][]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;};&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;samples&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;p&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;:&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;solution&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;samples&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]);&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;println&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;solution&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;priceI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;

            &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;priceJ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;findPriceJ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;priceI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;priceI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;priceJ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;findPriceJ&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;priceI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;//从i的右边开始找j&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;priceI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;//右侧找不到j，从左侧开始找&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;priceI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;b公司&quot;&gt;B公司&lt;/h2&gt;

&lt;h3 id=&quot;机考题&quot;&gt;机考题&lt;/h3&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;给定一个字符串，统计每个字符的出现次数（不区分大小写），然后将字符按次数降序输出。如果字符的次数相同，则按字符升序输出。

例如：
输入：We Attack at Dawn
输出：atwcdekn
说明：a出现4次数最多，a首先输出；c和d都只出现了一次，但c在d前面，所以现输出c再输出d。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;hf公司&quot;&gt;HF公司&lt;/h2&gt;

&lt;h3 id=&quot;机考2-2&quot;&gt;机考2&lt;/h3&gt;

&lt;h4 id=&quot;题目描述&quot;&gt;题目描述&lt;/h4&gt;

&lt;p&gt;西昂（Theon）是一名能源工程师，他的任务是将石油从基础炼油厂输送到主存储单元，输送过程通过一组管道网络完成。该网络呈树形结构，其中基础炼油厂是树的根，而主存储单元是树的叶子节点。管道通过内部连接站连接到存储单元，并且不同的管道具有不同的传输速率（以“每单位时间输送的石油升数”计）。&lt;/p&gt;

&lt;p&gt;西昂希望计算在任意时刻，该管道网络所能输送的最大石油量。&lt;/p&gt;

&lt;p&gt;请你编写一个算法，帮助西昂计算该管道网络的最大输送能力。&lt;/p&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;输入格式&quot;&gt;输入格式&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;第一行输入一个整数 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;num&lt;/code&gt;，表示网络中的存储站数量（即 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt;）。&lt;/li&gt;
  &lt;li&gt;第二行输入一个整数 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;baseR&lt;/code&gt;，表示网络中基础炼油厂的索引（即 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;S&lt;/code&gt;）。&lt;/li&gt;
  &lt;li&gt;第三行输入两个用空格分隔的整数 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;numCon&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;charCon&lt;/code&gt;：
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;numCon&lt;/code&gt; 代表网络中的连接数量，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;numCon = N - 1&lt;/code&gt;。&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;charCon&lt;/code&gt; 代表每条连接的特征数量，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;charCon = 3&lt;/code&gt;。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;接下来的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt; 行（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M = numCon&lt;/code&gt;）包含 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;P&lt;/code&gt; 个用空格分隔的整数：
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;start&lt;/code&gt;：管道的起始节点。&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;end&lt;/code&gt;：管道的终止节点。&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rate&lt;/code&gt;：该管道的最大输送速率（单位：升/单位时间）。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;输出格式&quot;&gt;输出格式&lt;/h4&gt;

&lt;p&gt;输出一个整数，表示该网络在任意时刻能够输送的最大石油量。&lt;/p&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;约束条件&quot;&gt;约束条件&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;( 3 \leq num \leq 10^5 )&lt;/li&gt;
  &lt;li&gt;( 1 \leq baseR \leq 10^5 )&lt;/li&gt;
  &lt;li&gt;( 1 \leq rate \leq 10^3 )&lt;/li&gt;
  &lt;li&gt;( numCon = num - 1 )&lt;/li&gt;
  &lt;li&gt;( charCon = 3 )&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;示例&quot;&gt;示例&lt;/h4&gt;

&lt;h6 id=&quot;输入&quot;&gt;输入：&lt;/h6&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;6
4
5 3
4 2 10
4 6 20
4 1 30
1 3 50
1 5 80
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;输出&quot;&gt;输出：&lt;/h6&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;60
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;解释&quot;&gt;解释：&lt;/h6&gt;

&lt;p&gt;网络结构如下：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;       4
      / | \
     2  6  1
        |  / 
        3 5  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;石油的输送情况如下：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;通过管道 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(4 -&amp;gt; 2)&lt;/code&gt;，输送 10 升。&lt;/li&gt;
  &lt;li&gt;通过管道 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(4 -&amp;gt; 6)&lt;/code&gt;，输送 20 升。&lt;/li&gt;
  &lt;li&gt;通过管道 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(4 -&amp;gt; 1 -&amp;gt; 3)&lt;/code&gt; 和 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(4 -&amp;gt; 1 -&amp;gt; 5)&lt;/code&gt;，由于 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(4 -&amp;gt; 1)&lt;/code&gt; 的管道最大输送能力为 30 升，因此最多可以输送 30 升。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;综上，网络的最大流量为：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;10 + 20 + 30 = 60
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;hr /&gt;

&lt;p&gt;这道题的本质是 &lt;strong&gt;树的最大流量问题&lt;/strong&gt;，可以使用 &lt;strong&gt;深度优先搜索（DFS）&lt;/strong&gt; 计算子树的流量贡献，最终求出整个网络的最大输送能力。&lt;/p&gt;

&lt;h2 id=&quot;总结&quot;&gt;总结&lt;/h2&gt;
&lt;p&gt;总的来说，主要都是考一些基本的逻辑，没有考我比较头疼的动态规划之类的算法。HF的第2道算法题没做出来。&lt;/p&gt;
</description>
      <pubDate>2024-03-24</pubDate>
      <link>https://ericsky.com/2024-03-24/algorithms-faced-during-the-job-hunt.html</link>
      <guid isPermaLink="true">https://ericsky.com/2024-03-24/algorithms-faced-during-the-job-hunt.html</guid>
    </item>
    
		
    
    <item>
      <title>使用 Spring AI 和 PGVector 构建 RAG 的一个简单示例</title>
      <description>&lt;p&gt;Spring AI 官网介绍：&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Spring AI 项目旨在简化开发集成了人工智能功能的应用程序的流程，力求去除复杂性。

这个项目受到了若干知名 Python 项目的启发，比如 LangChain 和 LlamaIndex，但并不是对它们的直接复制。项目的创始信念是，接下来的生成式 AI 应用将不再仅限于 Python 开发者，它们将遍布各种编程语言之中。

Spring AI 的核心在于提供一套开发 AI 应用的基础抽象。这套抽象有着多种实现方式，让你能够通过极少的代码修改来轻松替换组件。

Spring AI 提供的特性包括：

- 支持所有主流的模型提供方，如 OpenAI、Microsoft、Amazon、Google 及 Huggingface。
- 目前支持的模型类型有 Chat 聊天模型和 Text to Image 文本转图片模型，未来将支持更多类型。
- 为 Chat 和 Embedding 模型提供跨各大 AI 提供商的通用 API。支持同步和流式的 API 选项，并允许深入访问特定模型的功能。
- 将 AI 模型的输出映射到 POJOs 纯数据对象。
- 为所有主流的向量数据库提供商提供支持，包括 Azure Vector Search、Chroma、Milvus、Neo4j、PostgreSQL/PGVector、PineCone、Redis 以及 Weaviate。
- 提供一套跨向量存储提供商通用的 API，其中包括一种类 SQL 的元数据筛选 API，也同样通用。

还包括函数调用、为 AI 模型和向量存储配置的 Spring Boot 自动配置及启动器、以及用于数据工程的 ETL 框架。

这些功能集成允许你实现像是“基于文档的问答”或“与文档互动聊天”这样的常见用例。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;以下是使用用 Spring AI 和 PGVector 构建 RAG 的一个简单示例。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1.pom.xml引入相关依赖, ${spring.ai.version} 目前版本为0.8.0-SNAPSHOT。&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.ai&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-openai-spring-boot-starter&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${spring.ai.version}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.ai&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-pdf-document-reader&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${spring.ai.version}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- Database --&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-jdbc&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.postgresql&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;postgresql&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;scope&amp;gt;&lt;/span&gt;runtime&lt;span class=&quot;nt&quot;&gt;&amp;lt;/scope&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;

        &lt;span class=&quot;nt&quot;&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.ai&lt;span class=&quot;nt&quot;&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-ai-pgvector-store-spring-boot-starter&lt;span class=&quot;nt&quot;&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;version&amp;gt;&lt;/span&gt;${spring.ai.version}&lt;span class=&quot;nt&quot;&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;2.声明相关的Bean&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Configuration&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;AIConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VectorStore&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;vectorStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;JdbcTemplate&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;jdbcTemplate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EmbeddingClient&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;embeddingClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;PgVectorStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jdbcTemplate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;embeddingClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;TokenTextSplitter&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tokenTextSplitter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;TokenTextSplitter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;3.定义两个API，一个API用来上传pdf文件存储到PGVector，一个API用来针对pdf文件的内容向ChatGPT提问.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@RestController&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RAGController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;
                        
            You&apos;re a DOCUMENT assistant.
            Use the information from the DOCUMENTS section to provide accurate answers but act as if you knew this information innately.
            If unsure, simply state that you don&apos;t know.
                    
            DOCUMENTS:
            {documents}
                        
            &quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OpenAiChatClient&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chatClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VectorStore&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vectorStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TokenTextSplitter&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tokenTextSplitter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;


    &lt;span class=&quot;nd&quot;&gt;@Autowired&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;RAGController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OpenAiChatClient&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chatClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VectorStore&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vectorStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TokenTextSplitter&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tokenTextSplitter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;chatClient&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chatClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;vectorStore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vectorStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;tokenTextSplitter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tokenTextSplitter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@GetMapping&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/ai/doc_ask&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;doc_ask&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@RequestParam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultValue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hi&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Document&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listOfSimilarDocuments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vectorStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;similaritySearch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listOfSimilarDocuments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;Document:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getContent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Collectors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;joining&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;lineSeparator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()));&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;Message&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;systemMessage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SystemPromptTemplate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;createMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;documents&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;UserMessage&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userMessage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Prompt&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prompt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Prompt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;systemMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;userMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;ChatResponse&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aiResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chatClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aiResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getResult&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getOutput&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getContent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@PostMapping&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/ai/doc_upload&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;doc_upload&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;MultipartFile&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IOException&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localFile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;convertMultiPartToFile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;PagePdfDocumentReader&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pdfReader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PagePdfDocumentReader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FileSystemResource&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localFile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;TokenTextSplitter&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;textSplitter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TokenTextSplitter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;vectorStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;accept&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;textSplitter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pdfReader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()));&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;result&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;upload done&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;


    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;convertMultiPartToFile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;MultipartFile&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IOException&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;//store upload file to somewhere on server&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;File&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;convFile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getOriginalFilename&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;FileOutputStream&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FileOutputStream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;convFile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;fos&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;convFile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;4.使用Docker启动Postgres &amp;amp; PGVector&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker pull ankane/pgvector

docker run &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; postgres_spring_ai &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 5432:5432 &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;POSTGRES_USER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;postgres &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;postgres ankane/pgvector
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;5.连上数据库，创建向量存储表&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EXTENSION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;EXISTS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EXTENSION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;EXISTS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hstore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EXTENSION&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;EXISTS&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;uuid-ossp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IF&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;EXISTS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector_store&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uuid&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DEFAULT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uuid_generate_v4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;metadata&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;embedding&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1536&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INDEX&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector_store&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;USING&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HNSW&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;embedding&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector_cosine_ops&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;6.运行项目，上传pdf文件，然后就可以针对pdf文件的内容向ChatGPT提问啦。&lt;/p&gt;

&lt;p&gt;上传pdf
&lt;img src=&quot;../images/tech/doc_upload.png&quot; alt=&quot;&quot; /&gt;
GPT通过向量数据库检索文档，总结并给出了准确的答案
&lt;img src=&quot;../images/tech/doc_ask.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;完整代码地址：&lt;a href=&quot;https://github.com/yangchuang/spring_ai_example&quot;&gt;spring_ai_example&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>2024-03-01</pubDate>
      <link>https://ericsky.com/2024-03-01/A-simple-example-of-building-RAG-using-Spring-AI-and-PGVector.html</link>
      <guid isPermaLink="true">https://ericsky.com/2024-03-01/A-simple-example-of-building-RAG-using-Spring-AI-and-PGVector.html</guid>
    </item>
    
		
    
    <item>
      <title>如何构建高可用性系统？[译]</title>
      <description>&lt;p&gt;原文：&lt;a href=&quot;https://blog.bytebytego.com/p/how-do-we-design-for-high-availability&quot;&gt;How do We Design for High Availability?&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;如何构建高可用性系统&quot;&gt;如何构建高可用性系统？&lt;/h1&gt;

&lt;p&gt;在数字存在对商业连续性至关重要的今天，高可用性（HA）已经成为系统设计的关键要素。所谓高可用性，是指系统能够在较长时间内持续不间断地运行。&lt;/p&gt;

&lt;p&gt;本篇文章将带你深入了解高可用性的发展历程、衡量方法、在各式系统中的实施策略，以及为之付出的各种取舍。&lt;/p&gt;

&lt;h2 id=&quot;什么是高可用性&quot;&gt;什么是高可用性？&lt;/h2&gt;

&lt;p&gt;高可用性的理念起源于20世纪60年代和70年代，当时的军用和金融计算系统追求的是高度的可靠性和容错能力。&lt;/p&gt;

&lt;p&gt;进入互联网时代，随着电商、支付、物流、金融等数字应用的迅猛发展，优质的用户体验已成为商业成功的关键。因此，商业系统需要接近100%的在线时间，以避免短暂的故障就丢失大量用户。例如，在一个限时抢购活动中，一分钟的系统停机都有可能导致活动失败，给企业声誉带来巨大损害。&lt;/p&gt;

&lt;p&gt;高可用性的目的是让系统或服务在接近100%的时间内始终处于可用和正常运行状态。虽然高可用性和系统在线时间这两个概念常常混用，但高可用性的含义远不止于对在线时间的度量。&lt;/p&gt;

&lt;h2 id=&quot;我们如何测量高可用性&quot;&gt;我们如何测量高可用性？&lt;/h2&gt;

&lt;p&gt;计算可用性离不开两个核心概念：平均无故障时间（MTBF）和平均修复时间（MTTR）。&lt;/p&gt;

&lt;h3 id=&quot;mtbf-和-mttr&quot;&gt;MTBF 和 MTTR&lt;/h3&gt;

&lt;p&gt;MTBF 是通过将系统的运行时间总和除以该时间段内的故障次数来评估系统可靠性的，一般用小时表示。MTBF 越高，表明系统可靠性越好。&lt;/p&gt;

&lt;p&gt;MTTR 则是修复一个失败的组件或系统并使其重新运行所需的平均时间。它包括诊断、获取备件、实际修复、测试及确认运行等所需时间。MTTR 也通常使用小时来衡量。&lt;/p&gt;

&lt;p&gt;如下图所示，除了 MTBF 和 MTTR，还有两个相关的指标 - 平均诊断时间（MTTD）和平均故障时间（MTTF），而MTTR也可以包括诊断时间。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87444a13-e153-4bdd-afce-b480eafb91a3_1600x834.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;九级标准&quot;&gt;九级标准&lt;/h3&gt;

&lt;p&gt;结合MTBF和MTTR，我们可以计算出系统的可用性，即系统运行时间与总时间和维修时间之和的比例，公式如下：&lt;/p&gt;

&lt;p&gt;可用性 = MTBF /（MTBF + MTTR）&lt;/p&gt;

&lt;p&gt;对于追求高可用性的系统，目的是让MTBF最大化（减少故障次数）和MTTR最小化（快速恢复故障）。这些指标是团队提升系统可靠性和可用性的重要依据。&lt;/p&gt;

&lt;p&gt;如下图所示，我们通常按照“九级”来讨论可用性。比如“3个九”的可用性意味着每天仅有1.44分钟的停机时间，这对手动排错来说是个挑战。“4个九”则意味着每天仅8.6秒的停机，这就需要自动化监控、警报和故障排除。因此，系统设计时要考虑到自动故障检测和回滚计划等要求。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63d5256e-b7c0-4b70-b966-d882e6b776d3_1600x959.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;常见的架构模式&quot;&gt;常见的架构模式&lt;/h2&gt;

&lt;p&gt;想要实现“4个九”或更高级别的可用性，我们需要考虑下面几点：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;系统设计要点
    &lt;ul&gt;
      &lt;li&gt;考虑到失败的冗余设计&lt;/li&gt;
      &lt;li&gt;需要做的取舍&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;系统运维
    &lt;ul&gt;
      &lt;li&gt;变更管理&lt;/li&gt;
      &lt;li&gt;容量管理&lt;/li&gt;
      &lt;li&gt;自动化检测与故障排除&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;下面我们来详细看看系统设计方面的内容。&lt;/p&gt;

&lt;h3 id=&quot;冗余&quot;&gt;冗余&lt;/h3&gt;

&lt;p&gt;优化单一实例的容错性是有限的。通常，通过增加冗余来实现高可用性。当一个实例出现问题时，其他实例可以立刻接手继续工作。&lt;/p&gt;

&lt;p&gt;对于像存储这样需要保持状态的实例，还需要考虑数据复制的策略。&lt;/p&gt;

&lt;p&gt;接下来我们介绍几种包含不同冗余方式的常见架构，及其各自的优缺点。&lt;/p&gt;

&lt;h4 id=&quot;热-冷架构&quot;&gt;热-冷架构&lt;/h4&gt;

&lt;p&gt;在热-冷架构中，有一个主实例负责处理所有的读写请求，外加一个备份实例。客户端只与主实例进行交互，对于备份实例则完全无觉。主实例会持续地同步数据至备份实例。若主实例出现问题，就需要手动介入，将客户端切换至备份实例。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7f92181a-d1c4-4195-a8d8-dffecb0b6181_1529x945.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;这种架构虽然简单，但有不小的弊端。备份实例在大多数时间内处于闲置状态，这就造成了资源的浪费。如果主实例出现故障，最后一次数据同步的时间将决定是否会有数据丢失。在备份实例上恢复服务时，需要手动核对当前状态，以确认哪些数据可能丢失了，这意味着客户端可能需要重新发送遗失的信息，以弥补数据的丢失。&lt;/p&gt;

&lt;h4 id=&quot;热-温模式&quot;&gt;热-温模式&lt;/h4&gt;

&lt;p&gt;热-冷模式中的备份实例没有得到充分使用，导致资源被浪费。热-温模式通过允许客户端从备用实例读取数据来解决这一问题。如果主实例出现故障，客户端还能从下线的备用实例读取数据，虽然性能会稍有下降。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4faf5366-8b4b-4f00-8c38-b8a1f1fe2091_1529x945.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;由于备用实例也参与数据读取，因此主备实例之间保持数据一致性就显得尤为重要。哪怕主实例运作正常，由于读取操作同时对两个实例发起，也可能读到旧的数据。&lt;/p&gt;

&lt;p&gt;相较于热-冷模式，热-温模式更适合于读操作较多的场景，如新闻网站和博客。不过，为了更有效地使用资源，即使系统运行正常，也可能会读到过时的数据。&lt;/p&gt;

&lt;h4 id=&quot;热-热模式&quot;&gt;热-热模式&lt;/h4&gt;

&lt;p&gt;在热-热模式下，两个实例都作为主实例，均可处理读写请求。这种模式带来了极大的灵活性，但同时也意味着需要在两个实例之间进行双向同步。某些需要严格顺序性的数据可能会因此发生冲突。&lt;/p&gt;

&lt;p&gt;比如，假设系统按顺序分配用户ID，Bob可能在实例A得到ID 10，而Alice可能同样在实例B得到ID 10。热-热模式在需要复制的数据量较小时最为有效，常见于涉及临时数据的场景，如用户的会话和活动。对于那些需要严格一致性保障的数据则需要谨慎处理。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb712fd8a-96ae-4dc3-88aa-598fafb49f7c_1529x945.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</description>
      <pubDate>2024-02-21</pubDate>
      <link>https://ericsky.com/2024-02-21/How-do-We-Design-for-High-Availability.html</link>
      <guid isPermaLink="true">https://ericsky.com/2024-02-21/How-do-We-Design-for-High-Availability.html</guid>
    </item>
    
		
    
    <item>
      <title>精通 RAG：打造顶尖企业级 RAG 系统的秘籍[译]</title>
      <description>&lt;p&gt;原文地址: &lt;a href=&quot;https://www.rungalileo.io/blog/mastering-rag-how-to-architect-an-enterprise-rag-system&quot;&gt;Mastering RAG: How To Architect An Enterprise RAG System&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;欢迎继续关注我们的精通 RAG 系列课程！我们一起努力一把，深入企业级 RAG 系统构建的纷繁世界。&lt;/p&gt;

&lt;p&gt;当我们在浩如烟海的互联网上搜索与 RAG 系统相关的信息时，琳琅满目的文章多是介绍基本构建方法，而如何打造一个坚不可摧的企业级解决方案则往往像是一块未解之谜。很多构建者在构建 RAG 系统的过程中，甚至连最关键的决定是什么都没弄清楚…&lt;/p&gt;

&lt;p&gt;不过，本系列博文不仅仅停留在理论上，更是一本指导实践的工具书！我们不仅讨论如何的设置安全保护来确保系统安全，还会探讨查询重写如何提升用户体验，旨在为你提供实用的建议和现实案例解析。无论你是资深开发人员还是技术团队的领头者，我们一起深入挖掘，探索先进企业级 RAG 系统构建的复杂内涵。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.sanity.io/images/tf66morw/production/11ecc7741c440f92eaef444027435a5de6e21743-2152x1356.gif?w=2152&amp;amp;h=1356&amp;amp;auto=format&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;在我们深入探討 RAG 架构之前，让我先介绍一个最新&lt;a href=&quot;https://arxiv.org/abs/2401.05856&quot;&gt;研究&lt;/a&gt;，这项研究调查了构建 RAG 系统时的常见故障点。研究人员分析了三个跨领域的案例研究，找出了七个共有的故障点。&lt;/p&gt;

&lt;h2 id=&quot;构建-rag-系统的挑战&quot;&gt;构建 RAG 系统的挑战&lt;/h2&gt;

&lt;h3 id=&quot;案例研究&quot;&gt;案例研究&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://cdn.sanity.io/images/tf66morw/production/12815f255734d2c01d3c370350c006709b2aca98-2078x454.png?w=2078&amp;amp;h=454&amp;amp;auto=format&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;认知审校系统&quot;&gt;认知审校系统&lt;/h4&gt;

&lt;p&gt;认知审校系统是设计来帮助研究者分析科学文件的 RAG 系统。研究者定义研究问题或目标，并上传相关研究文献集合。接着，系统会根据所陈述目标对所有文档进行排名，以便研究者手动审核。研究者也可以直接向整个文档集提问。&lt;/p&gt;

&lt;h4 id=&quot;ai-辅导系统&quot;&gt;AI 辅导系统&lt;/h4&gt;

&lt;p&gt;AI 辅导系统，让学生能够就学习单元提出问题并得到答案，答案来自学习内容资源。学生还能通过查阅资源列表来验证答案。该系统融合到 Deakin 大学的教学管理系统中，对所有学习材料进行索引，包含 PDF 文件、视频和文字文档。利用 Whisper 深度学习模型，系统在文本块切分前对视频内容进行文字转录。RAG 流程中融入了用于查询概化的重写器，聊天界面还利用先前对话作为每个问题的背景上下文。&lt;/p&gt;

&lt;h4 id=&quot;生物医学问答&quot;&gt;生物医学问答&lt;/h4&gt;

&lt;p&gt;在生物医学问答的案例研究中，研究者使用 BioASQ 数据集建立了一个 RAG 系统，该数据集包含问题、文档链接和答案。这份由生物医学专家准备的数据集包括了特定领域的问答对。问题的答案可以是是/否，也可以是文本摘要、事实点或列表形式的。&lt;/p&gt;

&lt;h3 id=&quot;rag-系统的-7-大故障点&quot;&gt;RAG 系统的 7 大故障点&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.sanity.io/images/tf66morw/production/a50df3df3f7a4fc4b184c8f7cd7a9974c7146f4c-2130x970.png?w=2130&amp;amp;h=970&amp;amp;auto=format&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;通过这些案例研究，研究者找出了在设计 RAG 系统过程中常遇到的七个问题点。&lt;/p&gt;

&lt;h4 id=&quot;缺失内容故障点1&quot;&gt;缺失内容（故障点1）&lt;/h4&gt;

&lt;p&gt;当提出的问题无法根据现有文档回答时，理想情况下，RAG 系统会回应：”很抱歉，我不知道。” 然而，如果问题涉及内容没有明确答案，系统可能误提供答复。&lt;/p&gt;

&lt;h4 id=&quot;错过排名靠前的文档故障点2&quot;&gt;错过排名靠前的文档（故障点2）&lt;/h4&gt;

&lt;p&gt;尽管答案在文档中，系统未能将其排名至足够高的位置以提供给用户。实际操作中，尽管理论上所有文档都会被进行排名并应用于后续步骤，但实际上只有排名前 K 的文档会返回给用户，K 是根据性能选定的数值。&lt;/p&gt;

&lt;h4 id=&quot;脱离上下文---合并策略的局限性故障点3&quot;&gt;脱离上下文 - 合并策略的局限性（故障点3）&lt;/h4&gt;

&lt;p&gt;数据库检索到包含答案的文档，但答案没能成为生成回复的上下文。这通常发生在返回了大量文档，导致在合并过程中相关答案的检索受阻。&lt;/p&gt;

&lt;h4 id=&quot;未提取答案故障点4&quot;&gt;未提取答案（故障点4）&lt;/h4&gt;

&lt;p&gt;答案虽然在上下文中，但模型未能提取正确的信息，这类问题通常由于上下文信息过多干扰或信息矛盾导致。&lt;/p&gt;

&lt;h4 id=&quot;格式错误故障点5&quot;&gt;格式错误（故障点5）&lt;/h4&gt;

&lt;p&gt;当问题要求提取特定格式的信息，比如表格或列表时，模型并未遵循这样的指令。&lt;/p&gt;

&lt;h4 id=&quot;不精确故障点6&quot;&gt;不精确（故障点6）&lt;/h4&gt;

&lt;p&gt;答案虽然包含在回复中，但缺少所需的具体性，或过于具体，未能满足用户的需求。这种情况出现在 RAG 系统设计者对给定问题有预设的答案时，例如教师寻找教学内容时。在这种情况下，应当提供特定的教学内容和答案。不精确也发生在用户不清楚如何准确提问而提出过于笼统的问题时。&lt;/p&gt;

&lt;h4 id=&quot;不完整故障点7&quot;&gt;不完整（故障点7）&lt;/h4&gt;

&lt;p&gt;答案虽然准确，却缺少一些信息，即使这些信息在上下文中已经存在且可提取。例如，“文档 A、B 和 C 涵盖了哪些关键点？”如果将问题分开询问可能会得到更好的解答。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.sanity.io/images/tf66morw/production/ea880ca2ef2f6f5e0ac13172ef234e771677c828-2184x1238.png?w=2184&amp;amp;h=1238&amp;amp;auto=format&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;下方表格罗列的是他们通过解决上述问题中学到的经验教训。&lt;strong&gt;我们在构建我们的企业级 RAG 系统时会铭记这些宝贵的教训。&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;打造企业级-rag-系统的实用指南&quot;&gt;打造企业级 RAG 系统的实用指南&lt;/h2&gt;

&lt;p&gt;在确认了设计 RAG 系统时所遇到的普遍问题后，我们现在来详细讨论每个组件的设计需求和角色，以及它们的构建最佳实践。上文展示的 RAG 系统架构图提供了每个组件使用的背景和方式。&lt;/p&gt;

&lt;h3 id=&quot;用户认证&quot;&gt;用户认证&lt;/h3&gt;

&lt;p&gt;这是系统的出发点 — 我们的首个组件！在用户开始与聊天机器人交互前，我们需要出于多种原因对其进行认证。对企业系统而言，确保安全和个性化服务是必须的条件。&lt;/p&gt;

&lt;h4 id=&quot;访问控制&quot;&gt;访问控制&lt;/h4&gt;

&lt;p&gt;用户认证确保只有授权用户获取系统访问权。它能控制谁能与系统交互以及他们允许执行的操作。&lt;/p&gt;

&lt;h4 id=&quot;数据安全&quot;&gt;数据安全&lt;/h4&gt;

&lt;p&gt;保护敏感数据是至关重要的。用户认证可防止未授权人士获取机密信息，避免数据泄露和未授权操作。&lt;/p&gt;

&lt;h4 id=&quot;用户隐私&quot;&gt;用户隐私&lt;/h4&gt;

&lt;p&gt;认证功能保障用户隐私，确保只有真正的用户能获取他们的个人信息和账户详情。这对于树立用户信任非常关键。&lt;/p&gt;

&lt;h4 id=&quot;法律合规&quot;&gt;法律合规&lt;/h4&gt;

&lt;p&gt;许多法制区域和行业均有规定，要求公司必须实施适当的用户认证措施保护数据和用户隐私。遵循这些规定可避免法律问题和潜在的罚款。&lt;/p&gt;

&lt;h4 id=&quot;责任追踪&quot;&gt;责任追踪&lt;/h4&gt;

&lt;p&gt;用户认证通过将系统内的行动与特定用户账户连接起来，确保责任可追踪。这对于审计和追踪用户行为至关重要，帮助识别和应对任何安全事件或可疑行动。&lt;/p&gt;

&lt;h4 id=&quot;个性化和定制化&quot;&gt;个性化和定制化&lt;/h4&gt;

&lt;p&gt;认证允许系统识别独立用户，使得用户体验能够个性化和定制。这可能包括定制内容、偏好设置等。&lt;/p&gt;

&lt;p&gt;像 &lt;a href=&quot;https://www.youtube.com/watch?v=vqAirwfYgrY&quot;&gt;AWS Cognito&lt;/a&gt; 或 &lt;a href=&quot;https://www.youtube.com/watch?v=vBUk293QSKY&quot;&gt;Firebase Authentication&lt;/a&gt; 这样的服务有助于用户在移动和网络应用程序中轻松添加注册和认证功能。&lt;/p&gt;

&lt;h3 id=&quot;输入安全保护&quot;&gt;输入安全保护&lt;/h3&gt;

&lt;p&gt;我们必须阻止可能造成伤害的用户输入，或包含个人私密信息。最近的研究显示，对 LLM 的&lt;a href=&quot;https://llm-attacks.org/&quot;&gt;系统越权&lt;/a&gt;非常容易发生。这时，输入安全保护就显得特别重要。让我们来看看可能需要采取保护措施的不同场景。&lt;/p&gt;

&lt;h4 id=&quot;匿名处理&quot;&gt;匿名处理&lt;/h4&gt;

&lt;p&gt;输入保护条款可以对个人身份信息（PII）进行匿名处理或删减，如姓名、地址或联系方式。这有助于保护隐私，并防止试图泄露敏感信息的恶意行为。&lt;/p&gt;

&lt;h4 id=&quot;禁止特定字串&quot;&gt;禁止特定字串&lt;/h4&gt;

&lt;p&gt;禁止可能导致 SQL 注入、跨站脚本（XSS）或其他注入攻击的特定字串或模式，可防止系统安全弱点或不当行为的发生。&lt;/p&gt;

&lt;h4 id=&quot;限制话题&quot;&gt;限制话题&lt;/h4&gt;

&lt;p&gt;为了过滤与某些不适宜、冒犯或违反社区准则相关的特定话题，我们需要筛选掉涉及仇恨言论、歧视或露骨内容的讨论和输入。&lt;/p&gt;

&lt;h4 id=&quot;限制代码&quot;&gt;限制代码&lt;/h4&gt;

&lt;p&gt;重要的是要防止可执行代码的注入，这可能危及系统的安全并导致代码注入攻击。&lt;/p&gt;

&lt;h4 id=&quot;限制语言&quot;&gt;限制语言&lt;/h4&gt;

&lt;p&gt;确认输入文本是正确的语言或脚本，以防止潜在的误解或处理错误。&lt;/p&gt;

&lt;h4 id=&quot;检测提示注入&quot;&gt;检测提示注入&lt;/h4&gt;

&lt;p&gt;减轻误导性或有害提示注入的尝试，这些注入可能会操纵系统或以意料之外的方式影响 LLM 的行为。&lt;/p&gt;

&lt;h4 id=&quot;限制令牌数&quot;&gt;限制令牌数&lt;/h4&gt;

&lt;p&gt;对用户输入实施最大令牌或字符上限有助于避免资源消耗过大，防止服务拒绝（DoS）攻击。&lt;/p&gt;

&lt;h4 id=&quot;检测有害内容&quot;&gt;检测有害内容&lt;/h4&gt;

&lt;p&gt;实施有害内容筛选器，识别并阻止包含有害或辱骂性语言的输入。&lt;/p&gt;

&lt;p&gt;为了保护您的 RAG 系统不受这些潜在威胁，您可以利用 Meta 的 &lt;a href=&quot;https://towardsdatascience.com/safeguarding-your-rag-pipelines-a-step-by-step-guide-to-implementing-llama-guard-with-llamaindex-6f80a2e07756&quot;&gt;Llama Guard&lt;/a&gt;，您可以选择自己托管或使用像 &lt;a href=&quot;https://aws.amazon.com/blogs/machine-learning/llama-guard-is-now-available-in-amazon-sagemaker-jumpstart/&quot;&gt;Sagemaker&lt;/a&gt; 这样的托管服务。但是，别指望它能完美检测出有害内容。&lt;/p&gt;

&lt;h3 id=&quot;查询改写器&quot;&gt;查询改写器&lt;/h3&gt;

&lt;p&gt;一旦查询通过了输入安全检查，我们便将其发往查询改写器。用户的查询有时可能含糊不清或需要更多上下文才能更好地理解用户意图。查询改写是一个解决此问题的技巧。它涉及改造用户查询，以提升清晰度、精度和相关性。我们来看看一些最流行的改写技术。&lt;/p&gt;

&lt;h4 id=&quot;基于历史重写&quot;&gt;基于历史重写&lt;/h4&gt;

&lt;p&gt;在这个方法中，系统利用用户的历史查询来理解对话上下文，并使后续的查询更加明确。我们以信用卡查询为例。&lt;/p&gt;

&lt;p&gt;查询历史：&lt;/p&gt;

&lt;p&gt;“你有几张信用卡？”
“白金和金信用卡有年费吗？”
“比较两者的功能。”&lt;/p&gt;

&lt;p&gt;我们需要通过用户的查询历史识别上下文演变，确切把握用户的意图以及查询间的关系，并生成符合不断发展的上下文的查询。&lt;/p&gt;

&lt;p&gt;改写后的查询：”比较白金信用卡和金信用卡的功能。”&lt;/p&gt;

&lt;h4 id=&quot;生成子查询&quot;&gt;生成子查询&lt;/h4&gt;

&lt;p&gt;复杂的查询可能因检索问题而难以回答。简化这个任务的方法是将查询分解成更具体的子查询。这有助于检索用于生成答案所需的正确上下文。LlamaIndex 称之为&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/query_engine/sub_question_query_engine.html&quot;&gt;子问题查询引擎&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;面对像 “比较白金和金信用卡的功能” 这样的查询时，系统会针对原始查询中提到的每种卡片生成子查询。&lt;/p&gt;

&lt;p&gt;改写后的子查询：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;“白金信用卡有哪些功能？”&lt;/li&gt;
  &lt;li&gt;“金信用卡有哪些功能？”&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;创建相似查询&quot;&gt;创建相似查询&lt;/h4&gt;

&lt;p&gt;为了提升检索正确文献的可能性，我们会基于用户的输入生成相似的查询，这样做能够弥补语义或词汇匹配在检索过程中的限制。&lt;/p&gt;

&lt;p&gt;举个例子，当用户询问信用卡特性时，系统会生成相关的查询。这就涉及到运用同义词、相关术语或特定领域的知识，来创造与用户意图相一致的查询。&lt;/p&gt;

&lt;p&gt;例如，用户问：“我想了解白金信用卡”，系统则生成：“告诉我关于白金信用卡的好处。”&lt;/p&gt;

&lt;h3 id=&quot;编码器&quot;&gt;编码器&lt;/h3&gt;

&lt;p&gt;确定了原始查询和改写后的查询，我们会将它们编码成向量（即数字列表）进行检索。&lt;strong&gt;选择一个合适的编码器或许是构建 RAG 系统中最关键的决策。&lt;/strong&gt; 以下是选择文本编码器时需要考虑的因素和原因。&lt;/p&gt;

&lt;h4 id=&quot;利用-mteb-基准测试&quot;&gt;利用 MTEB 基准测试&lt;/h4&gt;

&lt;p&gt;为了综合评估编码器的能力，&lt;a href=&quot;https://huggingface.co/spaces/mteb/leaderboard&quot;&gt;Massive Text Embedding Benchmark&lt;/a&gt;（MTEB）是一个很好的资源。它允许我们基于向量维度、平均检索性能以及模型尺寸来挑选编码器。尽管 MTEB 提供有价值的见解，但由于没有普适的评价标准，并且模型训练数据的细节可能并不透明，我们在解读这些结果时应持谨慎态度。&lt;/p&gt;

&lt;p&gt;MTEB 不仅透露了像 OpenAI、Cohere 和 Voyager 这样的流行嵌入技术的性能，还显示出一些开源模型的性能与它们相差无几。然而，这些结果只提供了一个大概概述，并不能精确反映这些嵌入技术在特定领域中的实际表现。因此，在最终选择前，针对自己的数据集进行彻底评估非常必要，有强调了定制评估方法的重要。&lt;/p&gt;

&lt;h4 id=&quot;自定义评估&quot;&gt;自定义评估&lt;/h4&gt;

&lt;p&gt;编码器可能无法始终提供最优性能，尤其是在处理敏感信息时。因此，在这种情况下，自定义评估方法就显得非常关键。以下是几种进行自定义评估的方法：&lt;/p&gt;

&lt;p&gt;通过标注评估&lt;/p&gt;

&lt;p&gt;生成专用的数据集并进行标注以获得黄金标准。标注完成后，利用检索度量指标比如平均倒数排名（MRR）和归一化折扣累积增益（NDCG），量化地评估不同编码器的性能。&lt;/p&gt;

&lt;p&gt;通过模型评估&lt;/p&gt;

&lt;p&gt;类似于标注方法，紧接着一个数据生成过程，不过是使用大语言模型或交叉编码器进行评估。这样可以在所有编码器中设立一个相对的排名。在这之后对前三的编码器进行人工评估，以获得精确的性能指标。&lt;/p&gt;

&lt;p&gt;通过聚类评估&lt;/p&gt;

&lt;p&gt;采用不同聚类技术，分析在各个程度的 Silhouette 分数下数据聚类的覆盖量，以此指示聚类内向量的相似度。试验不同的算法诸如 HDBSCAN，并调整它们的参数以选出性能最佳的编码器。基于聚类的评估为数据点的分布和分组提供了有价值的洞察，有助于选择与特定度量对齐的编码器。&lt;/p&gt;

&lt;h4 id=&quot;选择文本编码器时要考虑的&quot;&gt;选择文本编码器时要考虑的&lt;/h4&gt;

&lt;p&gt;在选择编码器时，你需要在私有编码器和公共编码器之间做出选择。也许你会倾向于使用私有编码器，因为它们使用起来很方便，但是两者之间有一些特定的权衡需要考虑。这是一个影响系统性能和响应延迟的重要决策。&lt;/p&gt;

&lt;p&gt;查询成本&lt;/p&gt;

&lt;p&gt;为了确保语义搜索的用户体验流畅，需要依赖嵌入式 API 服务的高可用性。OpenAI 和类似的服务提供者提供可靠的 API，省去了托管管理的需要。然而，选择一个开源模型，则需要根据模型大小和延迟需求进行工程上的努力。小型模型（最多110M参数）可以通过CPU实例来托管，而大型模型则可能需要GPU服务以满足延迟需求。&lt;/p&gt;

&lt;p&gt;索引成本&lt;/p&gt;

&lt;p&gt;打造语义搜索功能涉及到文档索引，这会产生一笔不小的成本。由于索引和查询使用同一个编码器，故索引成本与选定的编码器服务紧密相关。为了方便服务重置或重新索引到另一个向量数据库，建议将嵌入式向量分开存储。如果忽略这一点，将需要重新计算已有的嵌入式向量。&lt;/p&gt;

&lt;p&gt;储存成本&lt;/p&gt;

&lt;p&gt;对于索引了数百万向量的应用程序，向量数据库的存储成本是一个重要的考量点。存储成本随向量维度线性增加，而OpenAI的1526维向量带来了最高的存储成本。为了估算储存成本，需要计算文档的平均单位（词组或句子）数量，并据此外推。&lt;/p&gt;

&lt;p&gt;语言支持&lt;/p&gt;

&lt;p&gt;为了支持非英语语言，你可以选择使用多语言编码器或者配合英语编码器的翻译系统。&lt;/p&gt;

&lt;p&gt;搜索延迟&lt;/p&gt;

&lt;p&gt;语义搜索的延迟随着嵌入式向量的维度线性增长。为了降低延迟，更倾向于选择较低维度的向量。&lt;/p&gt;

&lt;p&gt;隐私&lt;/p&gt;

&lt;p&gt;在金融和医疗等敏感领域，严格的数据隐私要求可能会限制使用OpenAI之类的服务。&lt;/p&gt;

&lt;h3 id=&quot;文档摄入&quot;&gt;文档摄入&lt;/h3&gt;

&lt;p&gt;文档摄入系统负责管理数据的处理和持久化。在索引过程中，每个文档被拆分成更小的片段，然后通过嵌入式模型转换成嵌入式向量。最后将原始片段和嵌入式向量一起在数据库中索引。以下为文档摄入系统的组成部分。&lt;/p&gt;

&lt;p&gt;文档解析器&lt;/p&gt;

&lt;p&gt;文档解析器在从各种格式的文档中提取结构化信息方面起着核心作用，特别是在处理不同格式上。这包括诸如解析可能含有图片和表格的 PDF 文档等任务。&lt;/p&gt;

&lt;p&gt;文档格式&lt;/p&gt;

&lt;p&gt;文档解析器必须擅长处理各种文档格式，例如 PDF、Word、Excel 等，确保能够灵活适应不同的文档处理需求。这涉及到识别并处理文档中嵌入的内容，如超链接、多媒体元素或注释，从而提供文档内容的全面展现。&lt;/p&gt;

&lt;p&gt;表格识别&lt;/p&gt;

&lt;p&gt;对文档中的表格进行识别和数据提取至关重要，尤其是在报告或研究论文中，这有助于保持信息结构的完整性。比如，提取与表格相关的元数据（如标题和行列信息）可以加深对文档组织框架的理解。像 &lt;a href=&quot;https://huggingface.co/spaces/nielsr/tatr-demo&quot;&gt;Table Transformer&lt;/a&gt; 这样的模型对于这项任务可能很有帮助。&lt;/p&gt;

&lt;p&gt;图像识别&lt;/p&gt;

&lt;p&gt;对文档内的图像应用光学字符识别（OCR）技术是为了识别和提取文本，使得其可以被索引和后续检索。&lt;/p&gt;

&lt;p&gt;元数据提取&lt;/p&gt;

&lt;p&gt;元数据指的是除主要内容以外的文档相关信息。它包括作者、创建日期、文档类型、关键词等详情。元数据为文档提供了宝贵的上下文信息，并通过考虑元数据属性帮助组织文档，提升搜索结果的相关性。元数据可以通过自然语言处理/光学字符识别流程提取，并作为特殊字段与文档一同被索引。&lt;/p&gt;

&lt;h3 id=&quot;文本块分割器&quot;&gt;文本块分割器&lt;/h3&gt;

&lt;p&gt;你决定如何分割长文本（标记化）会影响嵌入式向量的质量和搜索系统的性能。如果文本块过小，则某些问题无法得到回答；如果文本块过大，则答案会包含不必要的噪声。利用&lt;a href=&quot;https://www.youtube.com/watch?v=qaPMdcCqtWk&quot;&gt;摘要&lt;/a&gt;等技术可以帮助减少噪声、文本大小、编码成本和储存成本。文本块分割是一个重要但常被忽略的话题。它可能需要专业知识，类似于特征工程。例如，在对 Python 代码库进行分块时，可能会使用诸如 def/class 这样的前缀。&lt;/p&gt;

&lt;p&gt;点击这个视频链接可以更深入地了解文本块分割。&lt;/p&gt;

&lt;iframe class=&quot;w-full&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; title=&quot;The 5 Levels Of Text Splitting For Retrieval&quot; width=&quot;640&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/8OJC21T2SL4?enablejsapi=1&amp;amp;origin=https%3A%2F%2Fwww.rungalileo.io&amp;amp;widgetid=1&quot; id=&quot;widget2&quot; data-gtm-yt-inspected-8=&quot;true&quot;&gt;&lt;/iframe&gt;

&lt;h3 id=&quot;索引器&quot;&gt;索引器&lt;/h3&gt;

&lt;p&gt;索引器的任务你可能已经猜到了——它负责建立文档索引，这是一个结构化的数据结构（尝试快速说三遍……）。索引器促进了高效的搜索和检索操作。高效索引非常关键，因为它直接影响文档检索的速度和准确性。它的工作包括将文本块或标记映射到文档集合中对应的位置。索引器在文件检索过程中承担重要任务，包括创建索引和添加、更新或删除文档。&lt;/p&gt;

&lt;p&gt;作为 RAG 系统的关键组件，索引器面临各种挑战，这些挑战可能影响系统的整体效率和性能。&lt;/p&gt;

&lt;h4 id=&quot;可伸缩性问题&quot;&gt;可伸缩性问题&lt;/h4&gt;

&lt;p&gt;随着文档数量的增加，保持高效和快速的索引能力变得越来越具有挑战性。当系统难以处理越来越多的文档时，就可能出现可扩展性问题，导致索引和检索速度变慢。&lt;/p&gt;

&lt;h4 id=&quot;实时索引更新&quot;&gt;实时索引更新&lt;/h4&gt;

&lt;p&gt;实时保持索引的更新可能会遇到挑战，尤其是在文档经常增加、更新或删除的系统中。确保实时 API 和索引机制能够无缝运行且不降低系统性能是一个持续存在的挑战。&lt;/p&gt;

&lt;h4 id=&quot;一致性和原子性&quot;&gt;一致性和原子性&lt;/h4&gt;

&lt;p&gt;在并发的文档更新或改动面前保持一致性和原子性可能相当复杂。即使在同时发生变化的情况下，确保索引更新能保持数据的完整性，这需要精心设计和执行。&lt;/p&gt;

&lt;h4 id=&quot;优化存储空间&quot;&gt;优化存储空间&lt;/h4&gt;

&lt;p&gt;索引大量文档可能导致存储需求巨大。在确保索引保持可访问和响应性的同时，优化存储空间是一个持续的挑战，尤其是在存储成本受关注的情况下。&lt;/p&gt;

&lt;h4 id=&quot;安全性和访问控制&quot;&gt;安全性和访问控制&lt;/h4&gt;

&lt;p&gt;实施合适的安全措施和访问控制以防止未授权的索引改动对系统至关重要。确保只有授权用户或程序才能执行新增、读取、更新和删除操作，这有助于确保文档库的完整性。&lt;/p&gt;

&lt;h4 id=&quot;监控和维护&quot;&gt;监控和维护&lt;/h4&gt;

&lt;p&gt;定期监控索引器的健康状况和性能至关重要。为了确保系统随时间顺畅运行，需要有健全的监控和维护程序来发现问题，如索引失败、资源瓶颈或过期的索引。&lt;/p&gt;

&lt;p&gt;这些都是一些挑战性的但众所周知的软件工程问题，通过遵循良好的软件设计实践可以解决。&lt;/p&gt;

&lt;h3 id=&quot;数据存储&quot;&gt;数据存储&lt;/h3&gt;

&lt;p&gt;由于我们要处理多种数据类型，需要为它们各自提供专门的存储。理解每种存储类型和每个用例的不同考虑因素至关重要。&lt;/p&gt;

&lt;h4 id=&quot;嵌入式向量&quot;&gt;嵌入式向量&lt;/h4&gt;

&lt;p&gt;数据库类型：SQL/NoSQL&lt;/p&gt;

&lt;p&gt;单独存储文档的嵌入式向量可以实现快速重建索引，而无需重新计算整个文档库的嵌入式向量。另外，存储的嵌入式向量还可以作为备份，以确保在系统故障或更新情况下关键信息的保存。&lt;/p&gt;

&lt;h4 id=&quot;文档&quot;&gt;文档&lt;/h4&gt;

&lt;p&gt;数据库类型：NoSQL&lt;/p&gt;

&lt;p&gt;以原始格式存储文档对于持久化非常重要。这种原始格式构成了索引、解析和检索等多个处理阶段的基础，并且为未来系统的增强提供了灵活性，使得原始文档得以保存，并可根据需要重新处理。&lt;/p&gt;

&lt;h4 id=&quot;聊天历史&quot;&gt;聊天历史&lt;/h4&gt;

&lt;p&gt;数据库类型：NoSQL&lt;/p&gt;

&lt;p&gt;存储聊天历史对支持 RAG 系统的对话功能至关重要。聊天历史存储使得系统能够记住用户先前的查询、回复和偏好，便于根据用户的独特背景来调整和定制未来的互动。这些历史数据对于利用研究来改进机器学习系统是非常有价值的。&lt;/p&gt;

&lt;h4 id=&quot;用户反馈&quot;&gt;用户反馈&lt;/h4&gt;

&lt;p&gt;数据库类型：NoSQL/SQL&lt;/p&gt;

&lt;p&gt;用户反馈是通过 RAG 应用内的多种互动机制来系统性地收集的。在大多数大语言模型系统中，用户可以利用点赞/点踩、星级评分和文字反馈提供反馈。这些用户反馈汇集成一个珍贵的信息库，它包裹着用户的体验和感知，为系统的持续改进打下基础。&lt;/p&gt;

&lt;h3 id=&quot;向量数据库&quot;&gt;向量数据库&lt;/h3&gt;

&lt;p&gt;向量数据库是 RAG 强大的语义搜索能力背后的关键检索组件。然而，合适地选择这个组件至关重要，以避免潜在的问题。在选择过程中，需要考虑若干个&lt;a href=&quot;https://vdbs.superlinked.com/&quot;&gt;向量数据库的因素&lt;/a&gt;。现在让我们来讨论其中一些。&lt;/p&gt;

&lt;h4 id=&quot;召回率与响应时间&quot;&gt;召回率与响应时间&lt;/h4&gt;

&lt;p&gt;在向量数据库中，优化召回率（即相关结果的百分比）与优化响应时间（即返回结果所需的时间）之间需要做出权衡。如 &lt;a href=&quot;https://github.com/facebookresearch/faiss/wiki/Faiss-indexes#flat-indexes&quot;&gt;Flat&lt;/a&gt;、&lt;a href=&quot;https://weaviate.io/blog/ann-algorithms-vamana-vs-hnsw&quot;&gt;HNSW&lt;/a&gt;（分层导航小世界）、&lt;a href=&quot;https://www.pinecone.io/learn/series/faiss/product-quantization/&quot;&gt;PQ&lt;/a&gt;（产品量化）、&lt;a href=&quot;https://erikbern.com/2015/09/24/nearest-neighbor-methods-vector-models-part-1&quot;&gt;ANNOY&lt;/a&gt; 和 &lt;a href=&quot;https://zilliz.com/learn/DiskANN-and-the-Vamana-Algorithm&quot;&gt;DiskANN&lt;/a&gt; 等不同的索引之间在速度和召回率上做出了不同的&lt;a href=&quot;https://ann-benchmarks.com/&quot;&gt;折中&lt;/a&gt;。在您的数据和查询中进行基准测试，以便做出明智的选择。&lt;/p&gt;

&lt;h4 id=&quot;成本&quot;&gt;成本&lt;/h4&gt;

&lt;p&gt;云原生的数据库通常根据数据存储和查询量来进行计费。对于数据量大的组织来说，这种模型能够避免基础设施成本。关键点包括，评估数据集的增长、团队的能力、数据敏感性，以及理解托管云解决方案的成本含义。&lt;/p&gt;

&lt;p&gt;另一方面，自行托管为组织提供了更多地控制其基础设施的能力，并可能降低成本。然而，这也伴随着管理和维护基础设施的责任，包括可扩展性、安全性和更新等方面的考虑。&lt;/p&gt;

&lt;h4 id=&quot;插入速度与查询速度&quot;&gt;插入速度与查询速度&lt;/h4&gt;

&lt;p&gt;平衡插入速度与查询速度非常重要。寻找能够处理高插入速度需求的流式使用案例的服务提供商。然而，对大多数组织来说，将查询速度放在优先考虑的位置通常更加相关。评估在高负荷时的向量插入速度和查询延迟，以做出明智的决定。&lt;/p&gt;

&lt;h4 id=&quot;内存索引与磁盘索引存储&quot;&gt;内存索引与磁盘索引存储&lt;/h4&gt;

&lt;p&gt;在内存存储和磁盘存储之间进行选择，涉及到速度与成本的权衡。虽然内存存储提供更高的速度，但有些使用案例又需要存储大于内存容量的向量。像内存映射文件这样的技术允许在不牺牲搜索速度的情况下扩展向量存储。像 DiskANN 中的 Vamana 这样的新索引承诺提供高效的超出内存的索引。&lt;/p&gt;

&lt;h4 id=&quot;全文搜索与混合向量搜索&quot;&gt;全文搜索与混合向量搜索&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.sanity.io/images/tf66morw/production/414c9c8001526d75163bce13b5a367683f1b2b00-2640x608.png?w=2640&amp;amp;h=608&amp;amp;auto=format&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;图片来源：&lt;a href=&quot;https://www.pinecone.io/learn/hybrid-search-intro/&quot;&gt;https://www.pinecone.io/learn/hybrid-search-intro/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;单一的向量搜索可能不适合企业级应用程序。另一方面，混合搜索整合了密集型和稀疏型方法，但需要更多的努力来实施。通常情况下，需要实施密集型向量索引、稀疏型倒排索引和重排序步骤。在 &lt;a href=&quot;https://www.pinecone.io/learn/hybrid-search-intro/&quot;&gt;Pinecone&lt;/a&gt;、&lt;a href=&quot;https://weaviate.io/blog/hybrid-search-fusion-algorithms&quot;&gt;Weaviate&lt;/a&gt; 以及 &lt;a href=&quot;https://www.elastic.co/blog/improving-information-retrieval-elastic-stack-hybrid&quot;&gt;Elasticsearch&lt;/a&gt; 中，可以通过一个称为 alpha 的参数来调整密集型和稀疏型元素间的平衡。&lt;/p&gt;

&lt;h4 id=&quot;过滤&quot;&gt;过滤&lt;/h4&gt;

&lt;p&gt;现实世界中的搜索查询通常涉及对元数据属性的过滤。虽然预过滤搜索看起来是自然的选择，但可能会错过一些相关结果。如果过滤属性只占数据集的一小部分，后过滤搜索可能出现问题。自定义过滤搜索，如 &lt;a href=&quot;https://weaviate.io/developers/weaviate/concepts/prefiltering&quot;&gt;Weaviate&lt;/a&gt; 所提供的，结合了预过滤和有效的语义搜索，并利用倒排索引分片和HNSW索引分片。&lt;/p&gt;

&lt;h3 id=&quot;提高检索效果的技巧&quot;&gt;提高检索效果的技巧&lt;/h3&gt;

&lt;p&gt;最新的研究显示，&lt;a href=&quot;https://arxiv.org/abs/2302.00093&quot;&gt;大语言模型可能会因无关上下文分散注意力&lt;/a&gt;，并且如果上下文量过大（检索到的topK文档数量很多），则可能由于大语言模型的注意力模式&lt;a href=&quot;https://arxiv.org/abs/2307.03172&quot;&gt;错失某些上下文&lt;/a&gt;。因此，利用相关且多样的文档来改善检索效果至关重要。让我们看看一些已经证明有效的提高检索效果的技巧。&lt;/p&gt;

&lt;h4 id=&quot;假设文件嵌入hyde&quot;&gt;假设文件嵌入（HyDE）&lt;/h4&gt;

&lt;p&gt;我们可以利用&lt;a href=&quot;https://arxiv.org/abs/2212.10496&quot;&gt;HyDE&lt;/a&gt;技术解决检索表现不佳的问题，特别是在处理那些可能导致信息难以找到的短小或不匹配的查询时。HyDE采用了一种独特的方法，借助像 GPT 这样的模型创建假设性文档。这些假设性文档捕捉了一些关键模式，但可能包含错误或误导性的细节。然后，一个智能文本编码器将这份假设文档转换为向量嵌入表示。这种嵌入式表示有助于比查询的嵌入式表示更加精准地在文档集合中找到类似的真实文档。&lt;/p&gt;

&lt;p&gt;实验表明，HyDE比其他进阶方法的效果要好，这使其成为提升 RAG 系统性能的有力工具。&lt;/p&gt;

&lt;h4 id=&quot;查询路由&quot;&gt;查询路由&lt;/h4&gt;

&lt;p&gt;当处理多个索引时，查询路由特别有用，它将查询引导到最相关的索引中，从而高效检索。这种方法通过确保每个查询都被正确地引导到合适的索引，优化了信息检索的准确性和速度。&lt;/p&gt;

&lt;p&gt;在企业搜索的背景下，由于数据来自不同的来源，如技术文件、产品文档、任务和代码库，查询路由成为一种强大的工具。比如，如果用户正在寻找与特定产品特性相关的信息，查询路由可以智能地将其引导到包含产品文档的索引，增强搜索结果的精度。&lt;/p&gt;

&lt;h4 id=&quot;重排序器&quot;&gt;重排序器&lt;/h4&gt;

&lt;p&gt;当编码器的检索结果未能提供最佳质量时，可以使用&lt;a href=&quot;https://medium.com/@abul.aala.fareh/different-reranking-techniques-in-llamaindex-6a56ed1f30a3&quot;&gt;重排序器&lt;/a&gt;来增强文档排序效果。在交叉编码器设置中使用像&lt;a href=&quot;https://huggingface.co/BAAI/bge-large-en-v1.5&quot;&gt;BGE-large&lt;/a&gt;这样的开源仅编码器变压器已成为常规实践。近来，像&lt;a href=&quot;https://arxiv.org/abs/2309.15088&quot;&gt;RankVicuna&lt;/a&gt;、&lt;a href=&quot;https://arxiv.org/abs/2304.09542&quot;&gt;RankGPT&lt;/a&gt;和&lt;a href=&quot;https://arxiv.org/abs/2312.02724&quot;&gt;RankZephyr&lt;/a&gt;这样的仅解码器方法进一步提升了重排序器的表现。&lt;/p&gt;

&lt;p&gt;引入重排序器有其优点，它能减少大语言模型的幻想现象，并改善系统在领域外的泛化能力。但也有不足之处，复杂的重排序器会因为计算负担增加而引入延迟，这会影响实时间应用的响应速度。此外，部署先进的重排序器可能会耗费大量资源，需仔细权衡性能提升与资源使用之间的平衡。&lt;/p&gt;

&lt;h4 id=&quot;最大边缘相关性mmr&quot;&gt;最大边缘相关性（MMR）&lt;/h4&gt;

&lt;p&gt;MMR 是一种旨在提高对查询响应中的检索项多样性的方法，以避免冗余。MMR 不仅仅专注于检索最相关的条目，而是力求在相关性和多样性之间找到平衡。它就像在派对上为一个朋友介绍人。起初，它会根据朋友的喜好确定最相配的人。然后，它会寻找一个略有不同的人。这个过程持续进行，直到达到所需的介绍次数。MMR 确保呈现的条目集合更加多样化和相关，最小化了重复性。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.sanity.io/images/tf66morw/production/c0473054513fa046750fbbfc4f08f3ba82624b1f-1282x752.png?w=1282&amp;amp;h=752&amp;amp;auto=format&quot; alt=&quot;原始的MMR&quot; /&gt;
原始的MMR&lt;/p&gt;

&lt;h4 id=&quot;自动裁剪&quot;&gt;自动裁剪&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;https://weaviate.io/developers/weaviate/api/graphql/additional-operators#autocut&quot;&gt;Weaviate&lt;/a&gt; 的自动裁剪功能限制了返回搜索结果的数量，它通过探测分数相近的对象群组实现。它通过分析搜索结果的分数来工作，并识别这些值之间的显著变化，这可能表明结果从高相关性过渡到较低相关性。&lt;/p&gt;

&lt;p&gt;例如，考虑一个返回以下距离值的搜索：
[0.1899, 0.1901, 0.191, 0.21, 0.215, 0.23]。&lt;/p&gt;

&lt;p&gt;自动裁剪将返回以下结果：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;autocut: 1: [0.1899, 0.1901, 0.191]&lt;/li&gt;
  &lt;li&gt;autocut: 2: [0.1899, 0.1901, 0.191, 0.21, 0.215]&lt;/li&gt;
  &lt;li&gt;autocut: 3: [0.1899, 0.1901, 0.191, 0.21, 0.215, 0.23]&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;递归检索&quot;&gt;递归检索&lt;/h4&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.sanity.io/images/tf66morw/production/6377b36750c946ae2ba7c75ec47fca036324a1ec-2054x800.png?w=2054&amp;amp;h=800&amp;amp;auto=format&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;图片来源：&lt;a href=&quot;https://youtu.be/TRjq7t2Ms5I?si=D0z5sHKW4SMqMgSG&amp;amp;t=742&quot;&gt;https://youtu.be/TRjq7t2Ms5I?si=D0z5sHKW4SMqMgSG&amp;amp;t=742&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/query_engine/pdf_tables/recursive_retriever.html&quot;&gt;递归检索&lt;/a&gt;也被称为从小到大的检索技术，在检索时嵌入较小的文本块，并返回用于语言模型合成的更大的父级上下文。较小的文本块有助于提高检索的准确性，同时更大的块为语言模型提供了更丰富的上下文信息。这一连贯的过程通过首先关注更小、信息更密集的单位来优化检索的准确性，然后有效地将它们与它们更广泛的背景父块连接起来进行合成。&lt;/p&gt;

&lt;h4 id=&quot;窗口句子检索&quot;&gt;窗口句子检索&lt;/h4&gt;

&lt;p&gt;检索过程会获取单句并返回围绕该特定句子的文本窗口。&lt;a href=&quot;https://docs.llamaindex.ai/en/latest/examples/node_postprocessor/MetadataReplacementDemo.html&quot;&gt;窗口句子检索&lt;/a&gt;确保获得的信息不仅准确，而且与上下文相关，提供了关于主要句子的全面信息。&lt;/p&gt;

&lt;h3 id=&quot;生成器&quot;&gt;生成器&lt;/h3&gt;

&lt;p&gt;在我们讨论完所有的检索组件之后，让我们来讨论一下生成器。在自托管推断部署和私有API服务之间需要进行慎重的考虑和权衡。这本身就是一个相当大的话题，为了不让你感到不知所措，我将简要介绍一下。&lt;/p&gt;

&lt;h4 id=&quot;api-的关键考虑&quot;&gt;API 的关键考虑&lt;/h4&gt;

&lt;p&gt;在评估大语言模型的 API 服务器时，我们必须优先考虑确保无缝整合和强大性能的功能。一个设计得当的 API 应该能像使用普通发射器一样方便地启动流行的大语言模型，并且还要处理好生产环境准备、安全性以及&lt;a href=&quot;https://www.rungalileo.io/blog/5-techniques-for-detecting-llm-hallucinations&quot;&gt;幻象检测&lt;/a&gt;等关键问题。比如，&lt;a href=&quot;https://github.com/huggingface/text-generation-inference&quot;&gt;HuggingFace 的 TGI 服务器&lt;/a&gt; 就体现了一整套这些原则的功能。让我们来了解一下大语言模型服务器需要的一些最受欢迎的功能。&lt;/p&gt;

&lt;p&gt;性能&lt;/p&gt;

&lt;p&gt;一个高效的 API 必须以性能为首要任务，以满足不同用户的需求。张量并行作为一项特殊功能，它通过在多个GPU上进行更快的推理处理，提高了整体加工速度。此外，连续批量处理传入请求确保了总吞吐量的提升，使系统更为响应和可扩展。量化特性的引入，特别是与比特和字节以及 GPT-Q 相关的量化，进一步优化了 API 的效率，以适应各种使用场景。利用优化的变压器代码的能力，可确保在最受欢迎的架构上顺畅地进行推理。&lt;/p&gt;

&lt;p&gt;生成质量增强功能&lt;/p&gt;

&lt;p&gt;为了提高生成的质量，API 应该包括可以改变输出的功能。概率处理器包括温度缩放、top-p、top-k 和重复惩罚，允许用户根据自己的偏好调整输出。此外，停止序列提供了对生成过程的控制，使用户能够管理和优化内容生成过程。用于幻象检测的对数概率，是确保生成输出与预期上下文一致并避免误导信息的额外精炼层。&lt;/p&gt;

&lt;p&gt;安全性&lt;/p&gt;

&lt;p&gt;在处理大语言模型和企业应用案例时，API 的安全性至关重要。安全地加载权重的 Safetensors 是一项关键功能，通过防止对模型参数未授权的篡改，有助于安全部署模型。此外，水印技术的引入增加了额外的安全层，使得大语言模型的使用能够被追踪和负责。&lt;/p&gt;

&lt;p&gt;用户体验&lt;/p&gt;

&lt;p&gt;在用户体验方面，令牌流式传输作为关键功能浮现出来，它有助于实现无缝互动。使用服务器发送事件（SSE）进行令牌流传输，提高了 API 的实时响应能力，为用户提供了更流畅、更互动的体验。这确保用户可以逐渐接收生成的内容，从而改善了大语言模型的整体参与度和可用性。&lt;/p&gt;

&lt;h4 id=&quot;自托管推理&quot;&gt;自托管推理&lt;/h4&gt;

&lt;p&gt;自托管推理涉及到在 AWS、GCP 或 Azure 等云服务提供商提供的服务器上部署大语言模型。选择诸如 TGI、Ray 或 FastAPI 等服务器是一个直接影响系统性能和成本的关键决策。考虑的因素包括计算效率、部署的简易性以及与选定的大语言模型的兼容性。衡量大语言模型推理性能至关重要，像 &lt;a href=&quot;https://github.com/ray-project/llmperf-leaderboard&quot;&gt;Anyscale’s LLMPerf Leaderboard&lt;/a&gt; 这样的排行榜是非常有价值的。它根据关键性能指标对推理提供者进行排名，包括首令牌时间（TTFT）、令牌间延迟（ITL）和成功率。负载测试和正确性测试对评估托管模型的不同特性至关重要。&lt;/p&gt;

&lt;p&gt;在新方法中，&lt;a href=&quot;https://predibase.com/blog/lorax-the-open-source-framework-for-serving-100s-of-fine-tuned-llms-in&quot;&gt;Predibase 的 LoRAX&lt;/a&gt; 推出了一种高效服务多个精调大语言模型的创新方式。它解决了使用共享 GPU 资源为多个精调模型服务的挑战。&lt;/p&gt;

&lt;h4 id=&quot;私有-api-服务&quot;&gt;私有 API 服务&lt;/h4&gt;

&lt;p&gt;OpenAI、Fireworks、Anyscale、Replicate、Mistral、Perplexity 和 Together 等公司提供的大语言模型 API 服务呈现了替代的部署方法。了解它们的特性、定价模型和&lt;a href=&quot;https://www.rungalileo.io/blog/metrics-first-approach-to-llm-evaluation&quot;&gt;大语言模型性能指标&lt;/a&gt;至关重要。例如，OpenAI 的基于令牌的定价模型，对输入令牌和输出令牌区分开来，这可能会显著影响使用 API 的总成本。在比较私有 API 服务与自托管大语言模型的成本时，你必须考虑 GPU 成本、使用率和可扩展性问题。对某些人来说，请求速率的限制可能是限制性的因素（哈！）。&lt;/p&gt;

&lt;h3 id=&quot;提高-rag-的提示技术&quot;&gt;提高 RAG 的提示技术&lt;/h3&gt;

&lt;p&gt;有多种提示技术用于提高 RAG 的输出效果。在我们&lt;a href=&quot;https://www.rungalileo.io/blog/mastering-rag-llm-prompting-techniques-for-reducing-hallucinations&quot;&gt;精通 RAG 系列的第二部分&lt;/a&gt;中，我们深入探讨了五种最有效的技术。其中许多新技术的性能超过了思维链（Chain-of-Thought）。你也可以结合使用这些技术来尽量减少幻象。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.sanity.io/images/tf66morw/production/df2ad02b9ef391d29be5ca1335b96790be8543c3-3290x1718.png?w=3290&amp;amp;h=1718&amp;amp;auto=format&quot; alt=&quot;大语言模型的 RAG 提示技术&quot; /&gt;
大语言模型的 RAG 提示技术&lt;/p&gt;

&lt;h3 id=&quot;输出安全保护&quot;&gt;输出安全保护&lt;/h3&gt;

&lt;p&gt;输出安全保护的功能类似于输入安全保护，但专门用于检测生成输出中的问题。它重点检测幻象、竞争对手的提及以及潜在的品牌损害，这是&lt;a href=&quot;https://www.rungalileo.io/blog/mastering-rag-8-scenarios-to-test-before-going-to-production&quot;&gt;RAG 评估&lt;/a&gt;过程的一部分。其目标是阻止生成不准确或在伦理上存疑的信息，这些信息可能与品牌价值观不符。通过积极监视和分析生成的内容，输出安全保护确保生成的内容在事实上保持准确，伦理上可靠，并与品牌准则一致。&lt;/p&gt;

&lt;p&gt;这里有一个可能损害企业品牌的响应实例，但若有合适的输出安全保护将会被阻止：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://cdn.sanity.io/images/tf66morw/production/32c303c1da8f9feb1af5933d415944ea52bb88aa-1678x869.png?w=1678&amp;amp;h=869&amp;amp;auto=format&quot; alt=&quot;有害输出案例&quot; /&gt;
有害输出案例&lt;/p&gt;

&lt;h3 id=&quot;用户反馈-1&quot;&gt;用户反馈&lt;/h3&gt;

&lt;p&gt;当生成的输出交付给用户后，获得用户的正面或负面反馈是十分有益的。用户反馈对于提高 RAG 系统的持续改进非常有帮助，因为这是一个持续的过程，而非一次性的任务。这其中不仅涉及执行自动化任务，如重新索引和重复实验，而且还需要系统地融合用户的见解来大幅增强系统。&lt;/p&gt;

&lt;p&gt;系统改善中最有效的手段在于积极修复基础数据中的问题。RAG 系统应包括迭代性的工作流来处理用户反馈并推动持续改进。&lt;/p&gt;

&lt;h4 id=&quot;用户互动与反馈收集&quot;&gt;用户互动与反馈收集&lt;/h4&gt;

&lt;p&gt;用户与 RAG 应用交互，并使用点赞/点踩或星级评分等功能来提供反馈。这种多样的反馈方式为收集用户的体验和对系统性能的看法提供了宝贵的资源。&lt;/p&gt;

&lt;h4 id=&quot;问题识别与诊断检测&quot;&gt;问题识别与诊断检测&lt;/h4&gt;

&lt;p&gt;搜集反馈之后，团队可以进行全面的分析来确定哪些查询的性能可能不佳。此过程包括审查检索到的资源以及深入研究以确定性能问题是来自检索、生成还是底层数据源。&lt;/p&gt;

&lt;h4 id=&quot;数据改进策略&quot;&gt;数据改进策略&lt;/h4&gt;

&lt;p&gt;一旦识别出问题，尤其是那些根植于数据本身的问题，团队可以采取战略行动来提升数据品质。这可能包括更正不完整信息或重组组织混乱的内容。&lt;/p&gt;

&lt;h4 id=&quot;评估与测试协议&quot;&gt;评估与测试协议&lt;/h4&gt;

&lt;p&gt;在实施数据改进后，系统必须对先前性能不佳的查询进行严格评估。从这些评估中获得的见解可以被有序地融入测试套件中，确保基于实际交互持续检查和改进。&lt;/p&gt;

&lt;p&gt;通过在这一全面的反馈循环中积极参与用户，RAG 系统不仅解决了通过自动化过程发现的问题，还利用了用户体验的丰富性。&lt;/p&gt;

&lt;h3 id=&quot;监控性&quot;&gt;监控性&lt;/h3&gt;

&lt;p&gt;建立 RAG 系统并不是随着系统部署到生产环境就结束了。即便配备了强固的安全措施和高质量数据用于&lt;a href=&quot;https://www.rungalileo.io/blog/optimizing-llm-performance-rag-vs-finetune-vs-both&quot;&gt;微调&lt;/a&gt;，模型一旦部署到生产中，也需要持续的监测。生成式AI应用除了标准指标，如延迟和成本外，还需要特定的&lt;a href=&quot;https://docs.rungalileo.io/galileo/llm-studio/llm-monitor&quot;&gt;大语言模型监测性&lt;/a&gt;功能来检测和纠正像幻觉、越界查询和链路故障等问题。下面是大语言模型监测的几个关键点。&lt;/p&gt;

&lt;h4 id=&quot;提示分析及优化&quot;&gt;提示分析及优化&lt;/h4&gt;

&lt;p&gt;识别与提示相关的问题，并利用实时生产数据迭代，使用健全的评估机制来识别和解决诸如幻觉等问题。&lt;/p&gt;

&lt;h4 id=&quot;大语言模型应用的可追溯性&quot;&gt;大语言模型应用的可追溯性&lt;/h4&gt;

&lt;p&gt;捕捉像 Langchain 和 LlamaIndex 这样的通用框架产生的大语言模型轨迹，以调试提示语和步骤。&lt;/p&gt;

&lt;h4 id=&quot;信息检索优化&quot;&gt;信息检索优化&lt;/h4&gt;

&lt;p&gt;对 RAG 参数进行故障诊断和评估，以优化对大语言模型性能至关重要的检索过程。&lt;/p&gt;

&lt;h4 id=&quot;警报&quot;&gt;警报&lt;/h4&gt;

&lt;p&gt;在系统行为偏离预期时接收警报，例如错误增加、延迟增高和幻觉发生。&lt;/p&gt;

&lt;p&gt;首先，实时监控应用程序在生产环境中的性能、行为和整体状况至关重要。密切注意SLA的遵守情况，并设置警报机制，迅速处理任何偏离。通过分析使用模式和资源消耗来跟踪运行大语言模型应用的成本，辅助你进行成本优化。&lt;/p&gt;

&lt;p&gt;Galileo推出了&lt;a href=&quot;https://docs.rungalileo.io/galileo/#llm-studio&quot;&gt;大语言模型工作室&lt;/a&gt;，专门为大语言模型监测设计，可在用户投诉前即时发出警告并采取纠正措施。Galileo的安全保护指标旨在监督模型的质量和安全性，涵盖了实在性、不确定性、事实性、语调、毒性、个人身份信息等方面。这些在评估和测试阶段曾使用的指标现可无缝融入监测环节。&lt;/p&gt;

&lt;p&gt;另外，你可以根据具体需要定制监控过程中的自定义指标。利用监视数据生成的洞察和警报，及时掌握潜在问题、异常情况或需要关注的改进领域。这种全面的方法确保了你的大语言模型应用在现实世界场景中能够高效且安全运行。&lt;/p&gt;

&lt;h3 id=&quot;缓存&quot;&gt;缓存&lt;/h3&gt;

&lt;p&gt;对于那些大规模运营的公司来说，成本可能会成为一个限制因素。在这种情况下，缓存是一种极好的节约成本的方法。缓存的工作原理是将提示和相应的回复储存在数据库中，以便未来可以快捷地提取使用。这种策略性的缓存机制赋予了大语言模型应用三个明显的优势，它既加快了响应速度，又节约了成本。&lt;/p&gt;

&lt;h4 id=&quot;提升生产推理的效率&quot;&gt;提升生产推理的效率&lt;/h4&gt;

&lt;p&gt;在生产环节，缓存能够加速推理过程，使其更便宜且更高效。某些查询可以利用缓存的响应几乎达到零延迟，优化了用户体验。&lt;/p&gt;

&lt;h4 id=&quot;缩短开发周期&quot;&gt;缩短开发周期&lt;/h4&gt;

&lt;p&gt;在开发阶段，由于无需重复调用 API 来处理相同的提示，缓存可以显著减少开发所需时间，降低开发成本。&lt;/p&gt;

&lt;h4 id=&quot;数据存储-1&quot;&gt;数据存储&lt;/h4&gt;

&lt;p&gt;拥有存储全部提示的综合数据库简化了大语言模型的微调流程。利用存储的提示与回复对，可以根据积累的数据更加高效地优化模型。&lt;/p&gt;

&lt;p&gt;如果你确实需要，可以采用 &lt;a href=&quot;https://github.com/zilliztech/GPTCache&quot;&gt;GPTCache&lt;/a&gt; 来实施缓存，包括精确匹配和类似匹配。它为缓存的性能提供了如缓存命中率、延迟和准确性等关键指标，这些指标有助于持续优化，确保高效运行。&lt;/p&gt;

&lt;h3 id=&quot;多租户模式&quot;&gt;多租户模式&lt;/h3&gt;

&lt;p&gt;SaaS软件通常需要服务多个租户，既要保证简洁性，又要注重隐私保护。在RAG系统中实现多租户模式的目标是建立一个既有效获取信息又尊重每位用户数据隐私的系统。简而言之，每位用户与系统的互动都是独立的，从而确保系统仅查看和利用针对该用户的信息。&lt;/p&gt;

&lt;p&gt;一种简单建立多租户模式的方法是使用元数据。向系统添加文档时，我们会在元数据中包括特定的用户信息。这样，每个文档都与特定用户关联。当用户进行搜索时，系统会使用这些元数据进行筛选，只显示与该用户相关的文档。然后通过智能搜索为用户找到最重要的信息。这种做法避免了不同用户之间的私密信息混淆，保护了每个人的数据安全和私密性。&lt;/p&gt;

&lt;p&gt;了解如何利用 &lt;a href=&quot;https://blog.llamaindex.ai/building-multi-tenancy-rag-system-with-llamaindex-0d6ab4e0c44b&quot;&gt;Llamaindex 实现多租户&lt;/a&gt;的操作方法。&lt;/p&gt;

&lt;h2 id=&quot;结论&quot;&gt;结论&lt;/h2&gt;

&lt;p&gt;显而易见，构建一个健壮、可扩展的企业级 RAG 系统需要精心安排多个互连的组件。从用户认证到输入安全保护，再到查询重写、编码、文档插入以及像向量数据库和生成器这样的检索组件，每一步都在系统性能构建中发挥着关键作用。&lt;/p&gt;

&lt;p&gt;在不断演进的 RAG 系统领域，我们希望这份实用的指南能够为开发者和领导者提供实践性的洞察，助力他们取得实际成效！&lt;/p&gt;

</description>
      <pubDate>2024-01-28</pubDate>
      <link>https://ericsky.com/2024-01-28/Mastering-RAG-How-To-Architect-An-Enterprise-RAG-System-Galileo-zh.html</link>
      <guid isPermaLink="true">https://ericsky.com/2024-01-28/Mastering-RAG-How-To-Architect-An-Enterprise-RAG-System-Galileo-zh.html</guid>
    </item>
    
		
    
    <item>
      <title>Amazon 云服务（Amazon Web Services）浅显易懂的解释</title>
      <description>&lt;p&gt;嘿，你有听说过Amazon 云服务下的新产品：ContainerCache、ElastiCast和QR72吗？你当然不会听说过，因为它们是我刚刚编的😄。&lt;/p&gt;

&lt;p&gt;但面对Amazon 50多个名称晦涩难懂的服务，我们决定真的不能再忍了，需要用一些通俗的语言来解释一下。&lt;/p&gt;

&lt;h2 id=&quot;运行应用服务&quot;&gt;运行应用服务&lt;/h2&gt;

&lt;p&gt;无论你如何使用 AWS，你可能都会用到这些服务，因为它们是所有其他服务的交互点。&lt;/p&gt;

&lt;h3 id=&quot;ec2elastic-compute-cloud&quot;&gt;EC2(Elastic Compute Cloud)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 虚拟服务器&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  托管你视为电脑的那些部分。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  这听起来有点模糊，但 EC2 实例类似于你在 Linode、DigitalOcean 或 Rackspace 上使用的虚拟私有服务器。&lt;/p&gt;

&lt;h3 id=&quot;iamidentity-and-access-management&quot;&gt;IAM(Identity and Access Management)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  用户、密钥和证书&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  添加新用户，创建新的 AWS 密钥和策略。&lt;/p&gt;

&lt;h3 id=&quot;s3simple-storage-service&quot;&gt;S3(Simple Storage Service)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 无限 FTP 服务器&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  存储网站的图片和其他资源，备份和在各服务间共享文件，托管静态网站。另外，许多其它 AWS 服务也会在 S3 中读写数据。&lt;a href=&quot;https://expeditedsecurity.com/aws-in-plain-english/s3&quot;&gt;通俗易懂的 S3&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;vpcvirtual-private-cloud&quot;&gt;VPC(Virtual Private Cloud)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 虚拟租用机架&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  通过增加额外的安全层，来打消 “所有数据都在互联网上！” 的顾虑。它让你所有的 AWS 服务看起来如同在同一个小网络上，而不是互联网的一小部分。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  如果你懂计算机网络：和 VLAN 是类似的。&lt;/p&gt;

&lt;h3 id=&quot;lambda&quot;&gt;Lambda&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  AWS 应用脚本&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  运行小型的、自包含的 JS、Java 或 Python 脚本来完成特定任务。它既是队列又是执行的集合，用于存储然后执行你的 AWS 设置的变更，或响应 S3 或 DynamoDB 的事件。 &lt;a href=&quot;https://expeditedsecurity.com/aws-in-plain-english/lambda&quot;&gt;通俗易懂的 Lambda&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;网页开发者服务&quot;&gt;网页开发者服务&lt;/h2&gt;

&lt;p&gt;如果你正在搭建一个网页应用，那么主要可能会用到以下这些服务。这些与你在Heroku的插件市场里所能找到的很相似。&lt;/p&gt;

&lt;h3 id=&quot;api-gateway&quot;&gt;API Gateway&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  API 代理&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  让你的应用API经过此处代理，这样就可以限制不良的客户端流量，试验新的版本，且更直观地展示各种方法。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  3Scale&lt;/p&gt;

&lt;h3 id=&quot;rdsrelational-database-service&quot;&gt;RDS(Relational Database Service)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon SQL&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  作为你的应用的Mysql、Postgres及Oracle数据库。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Heroku Postgres&lt;/p&gt;

&lt;h3 id=&quot;route53&quot;&gt;Route53&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon DNS + 域名&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  购买新的域名并为该域名设置DNS记录。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  DNSimple, GoDaddy, Gandi&lt;/p&gt;

&lt;h3 id=&quot;sessimple-email-service&quot;&gt;SES(Simple Email Service)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 的事务性邮件&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  发送一次性的邮件，如重设密码、通知等。如果你自己写了所有的代码的话，你或许可以使用它发送通讯，不过这个想法并不是特别好。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  SendGrid, Mandrill, Postmark&lt;/p&gt;

&lt;h3 id=&quot;cloudfront&quot;&gt;CloudFront&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon CDN&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  通过让静态文件的分发更接近你的用户，从而让你的网站加载得更快。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  MaxCDN, Akamai&lt;/p&gt;

&lt;h3 id=&quot;cloudsearch&quot;&gt;CloudSearch&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 全文搜索&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  浏览在S3或RDS上的数据，并查找‘Jimmy’的每一个实例。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Sphinx, Solr, ElasticSearch&lt;/p&gt;

&lt;h3 id=&quot;dynamodb&quot;&gt;DynamoDB&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon NoSQL&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  作为你的应用的无差别存储的大规模可缩放的键-值存储。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  MongoLab&lt;/p&gt;

&lt;h3 id=&quot;elasticache&quot;&gt;Elasticache&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon Memcached&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  充任你的应用的 Memcached 或 Redis。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Redis to Go, Memcachier&lt;/p&gt;

&lt;h3 id=&quot;elastic-transcoder&quot;&gt;Elastic Transcoder&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 初级剪辑&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  解决视频格式的问题（如转换格式、压缩等）。&lt;/p&gt;

&lt;h3 id=&quot;sqssimple-queue-service&quot;&gt;SQS(Simple Queue Service)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 队列&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  在队列里存储未来需处理的数据。此处的”消息”指的是需保存的数据，跟电子邮件或者短信没关系。SQS 只是一个存取数据的地方，而没有其他功能。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  RabbitMQ, Sidekiq&lt;/p&gt;

&lt;h3 id=&quot;wafweb-application-firewall&quot;&gt;WAF(Web Application Firewall)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  AWS 防火墙&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  屏蔽对Cloudfront保护的网站的恶意请求（也就是阻止黑客对/wp-admin试验10000个密码的行为）。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Sophos, Kapersky&lt;/p&gt;

&lt;h2 id=&quot;移动应用开发者服务&quot;&gt;移动应用开发者服务&lt;/h2&gt;

&lt;p&gt;以下服务是专门为移动应用开发者设计的。&lt;/p&gt;

&lt;h3 id=&quot;cognito&quot;&gt;Cognito&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 的OAuth服务&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  让用户（非AWS用户）能通过如Google、Facebook等账号进行登录。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  OAuth.io&lt;/p&gt;

&lt;h3 id=&quot;device-farm&quot;&gt;Device Farm&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 的旧Android设备储藏室&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  同时在多款iOS和Android设备上进行应用测试。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  MobileTest、iOS模拟器&lt;/p&gt;

&lt;h3 id=&quot;mobile-analytics&quot;&gt;Mobile Analytics&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  符合实际，Amazon 产品经理应该注意一下&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  跟踪用户在你的应用内部都做了些什么。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Flurry&lt;/p&gt;

&lt;h3 id=&quot;snssimple-notification-service&quot;&gt;SNS(Simple Notification Service)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 信使（Messenger）&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  发送移动通知、电子邮件或者SMS短信。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  UrbanAirship, Twilio&lt;/p&gt;

&lt;h2 id=&quot;运营和代码部署服务&quot;&gt;运营和代码部署服务&lt;/h2&gt;

&lt;p&gt;以下服务主要帮助你自动化操作和部署代码到其他服务器上。&lt;/p&gt;

&lt;h3 id=&quot;codecommit&quot;&gt;CodeCommit&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 版Github&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  对你的代码进行版本管理 - 托管在Git上。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Github、BitBucket&lt;/p&gt;

&lt;h3 id=&quot;code-deploy&quot;&gt;Code Deploy&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  (这个名字OK)&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  以合理的方式从你的 CodeCommit 仓库（或Github）将代码部署到多个 EC2 实例上。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Heroku、Capistrano&lt;/p&gt;

&lt;h3 id=&quot;codepipeline&quot;&gt;CodePipeline&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 的持续集成服务&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  对代码进行自动化测试，然后根据测试结果进行相应处理。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  CircleCI、Travis&lt;/p&gt;

&lt;h3 id=&quot;ecselastic-container-service&quot;&gt;ECS(Elastic Container Service)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 的Docker服务&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  把Docker文件放入EC2实例，然后就可以运行网站了。&lt;/p&gt;

&lt;h3 id=&quot;elastic-beanstalk&quot;&gt;Elastic Beanstalk&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 的服务平台&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  当你的应用在Heroku上的开销过大时，可以将其搬迁至AWS。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Heroku、BlueMix、Modulus&lt;/p&gt;

&lt;h2 id=&quot;企业公司级服务&quot;&gt;企业/公司级服务&lt;/h2&gt;

&lt;p&gt;专为企业和网络提供的服务。&lt;/p&gt;

&lt;h3 id=&quot;appstream&quot;&gt;AppStream&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon Citrix&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  将应用程序的副本放在一个远程访问的 Windows 服务器上。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Citrix、RDP&lt;/p&gt;

&lt;h3 id=&quot;direct-connect&quot;&gt;Direct Connect&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  直连服务&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  付费给你的电信运营商和AWS，从你的数据中心或网络获得一条直达 AWS 的专属线路。对于数据流量，这比公网更为经济。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  宛如一条绕过拥堵的收费高速公路。&lt;/p&gt;

&lt;h3 id=&quot;directory-service&quot;&gt;Directory Service&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  目录服务&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  将所有需要 Microsoft Active Directory 操控的应用集成在一起。&lt;/p&gt;

&lt;h3 id=&quot;workdocs&quot;&gt;WorkDocs&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 无结构文件存储&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  与同事共享 Word 文档。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Dropbox，DataAnywhere&lt;/p&gt;

&lt;h3 id=&quot;workmail&quot;&gt;WorkMail&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 公司邮箱服务&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  赋予公司所有员工统一的邮箱系统和日历。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Google Apps for Domains&lt;/p&gt;

&lt;h3 id=&quot;workspaces&quot;&gt;Workspaces&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 远程计算机&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  获得一个可以远程控制的标准 Windows 桌面。&lt;/p&gt;

&lt;h3 id=&quot;service-catalog&quot;&gt;Service Catalog&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 预设&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  让你的团队中的其他 AWS 用户访问你已经建立的应用，这样他们就无需阅读复杂的指南了。&lt;/p&gt;

&lt;h3 id=&quot;storage-gateway&quot;&gt;Storage Gateway&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  将其伪装为你公司网络的S3&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  不再需要购买额外的存储空间用于保存Word文档。让从你的公司网络将文件自动迁移到S3变得更加简单。&lt;/p&gt;

&lt;h2 id=&quot;大数据服务&quot;&gt;大数据服务&lt;/h2&gt;

&lt;p&gt;提供摄取、处理和调整数据以达到你的要求的服务。&lt;/p&gt;

&lt;h3 id=&quot;data-pipeline&quot;&gt;Data Pipeline&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon ETL&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  从AWS的其他部分提取、转化和加载数据。你可以设定执行的时间，并在执行失败时接收警报。&lt;/p&gt;

&lt;h3 id=&quot;elastic-map-reduce&quot;&gt;Elastic Map Reduce&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon Hadooper&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  对保存在S3的大量原始数据文本文件进行迭代处理。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Treasure Data&lt;/p&gt;

&lt;h3 id=&quot;glacier&quot;&gt;Glacier&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  运行速度缓慢的Amazon S3&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  对存储在S3上的备份数据进行备份。注意，如果匆忙取出数据，可能会产生较高的成本。适合长期存档。&lt;/p&gt;

&lt;h3 id=&quot;kinesis&quot;&gt;Kinesis&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 高吞吐量&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  快速摄取大量数据（例如分析数据，或者是人们转发Kanye的推文等），然后使用其他的AWS服务进行分析。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Kafka&lt;/p&gt;

&lt;h3 id=&quot;redshift&quot;&gt;RedShift&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 数据仓库&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  存储大量的分析数据，进行一些处理，然后将其数据清空。&lt;/p&gt;

&lt;h3 id=&quot;machine-learning&quot;&gt;Machine Learning&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Skynet&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  根据现有的数据预测未来的行为，例如欺诈检测，或者是“购买x的人也买了y”。&lt;/p&gt;

&lt;h3 id=&quot;swfsimple-workflow-service&quot;&gt;SWF(Simple Workflow Service)&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon EC2队列&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  在EC2的基础上建立一个由“deciders”和“workers”组成的服务以完成特定任务。与SQS不同的是，它在服务内建立逻辑来确定什么应该发生以及如何发生。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  IronWorker&lt;/p&gt;

&lt;h3 id=&quot;snowball&quot;&gt;Snowball&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  AWS超大型便携式存储&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  获得一堆可以链接到你网络的硬盘驱动器，让（TB级别的）大量数据在AWS之间的传输更加简易。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  将网络连接存储设备发送至AWS&lt;/p&gt;

&lt;h2 id=&quot;amazon-云服务管理工具&quot;&gt;Amazon 云服务管理工具&lt;/h2&gt;

&lt;p&gt;因为Amazon 云服务的管理有时候会复杂难懂，所以他们创造出一套帮助你管理的服务并出售。&lt;/p&gt;

&lt;h3 id=&quot;cloudformation&quot;&gt;CloudFormation&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 云服务设置&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  一次性地设置一整套互联的Amazon 云服务。&lt;/p&gt;

&lt;h3 id=&quot;cloudtrail&quot;&gt;CloudTrail&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 日志记录&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  Log who is doing what in your AWS stack（如API调用等）。&lt;/p&gt;

&lt;h3 id=&quot;cloudwatch&quot;&gt;CloudWatch&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 状态通知器&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  在Amazon 云服务出问题或者断开连接时，接收警告提醒。&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  PagerDuty，Statuspage&lt;/p&gt;

&lt;h3 id=&quot;config&quot;&gt;Config&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 配置管理&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  如果你的Amazon 云服务设置较大，且有你想要追踪的变化发生，使用它可以有助于你保持理智。&lt;/p&gt;

&lt;h3 id=&quot;opsworks&quot;&gt;OpsWorks&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon Chef&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  管理像自动扩展等运行你的应用程序的事宜。&lt;/p&gt;

&lt;h3 id=&quot;trusted-advisor&quot;&gt;Trusted Advisor&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 省钱顾问&lt;br /&gt;
&lt;strong&gt;主要功能是&lt;/strong&gt;  帮你找出在Amazon 云服务设置中哪里支付过多（例如，未使用的 EC2 实例等）。&lt;/p&gt;

&lt;h3 id=&quot;inspector&quot;&gt;Inspector&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;更贴切的名字&lt;/strong&gt;  Amazon 审计员&lt;br /&gt;
&lt;strong&gt;用途是&lt;/strong&gt;  扫描你的Amazon 云服务设置，看你是否有不安全的配置&lt;br /&gt;
&lt;strong&gt;类似于&lt;/strong&gt;  Alert Logic&lt;/p&gt;

&lt;p&gt;原文地址: https://expeditedsecurity.com/aws-in-plain-english&lt;/p&gt;
</description>
      <pubDate>2024-01-16</pubDate>
      <link>https://ericsky.com/2024-01-16/Amazon-Web-Services-In-Plain-English-zh.html</link>
      <guid isPermaLink="true">https://ericsky.com/2024-01-16/Amazon-Web-Services-In-Plain-English-zh.html</guid>
    </item>
    
		
    
    <item>
      <title>构建高级 RAG 的参考指南和方法[译]</title>
      <description>&lt;p&gt;原文：&lt;a href=&quot;https://blog.llamaindex.ai/a-cheat-sheet-and-some-recipes-for-building-advanced-rag-803a9d94c41b&quot;&gt;A Cheat Sheet and Some Recipes For Building Advanced RAG&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：Andrei&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://miro.medium.com/v2/resize:fit:1400/1*2Isz5ye0KAw6GTiDJ4tZmw.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;font size=&quot;2&quot; color=&quot;grey&quot;&gt; 一份详尽的 RAG 指南，详细阐述了为何要使用 RAG，以及如何从初级或基础的 RAG 系统升级到更高级的系统。([高清版](https://d3ddy8balm3goa.cloudfront.net/llamaindex/rag-cheat-sheet-final.svg)) &lt;/font&gt;

&lt;p&gt;新的一年开始了，也许你打算正式步入 RAG 领域，创建你的第一个 RAG 系统。又或者，你已经打造过初级的 RAG 系统，现在希望将它们升级，以便更好地处理用户的查询和数据。&lt;/p&gt;

&lt;p&gt;无论是哪种情况，你可能都会面临一个难题：到底怎么开始呢？如果你有此困扰，那么这篇博客文章或许能为你指明方向，进一步的，当你创建高级 RAG 系统时，它能为你提供一个思考的框架。&lt;/p&gt;

&lt;p&gt;上面分享的 RAG 指南，在很大程度上是受到了一篇最近的 RAG 调研文章的启发（&lt;a href=&quot;https://arxiv.org/pdf/2312.10997.pdf&quot;&gt;“Retrieval-Augmented Generation for Large Language Models: A Survey” Gao, Yunfan, et al. 2023&lt;/a&gt;）。&lt;/p&gt;

&lt;h2 id=&quot;初级-rag&quot;&gt;初级 RAG&lt;/h2&gt;

&lt;p&gt;目前的主流 RAG 定义，涉及从外部知识库中检索文档，并将这些文档与用户的查询一同提交给大语言模型生成回复。也就是说，RAG 包括检索、外部知识库和生成三个部分。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LlamaIndex 初级 RAG 方法：&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VectorStoreIndex&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# load data
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# build VectorStoreIndex that takes care of chunking documents
# and encoding chunks to embeddings for future retrieval
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VectorStoreIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# The QueryEngine class is equipped with the generator
# and facilitates the retrieval and generation steps
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query_engine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;as_query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Use your Default RAG
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;A user&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s query&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rag系统成功的标准&quot;&gt;RAG系统成功的标准&lt;/h2&gt;

&lt;p&gt;要判断一个RAG系统是否成功（在为用户问题提供有用和相关答案方面），其实只需要满足两个关键性的需求：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;在执行搜索时，必须能够找到与用户问题最相关的文件。&lt;/li&gt;
  &lt;li&gt;在进行信息构造时，必须能够充分利用搜索到的文件来对用户的问题进行有效的回答。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;高级rag&quot;&gt;高级RAG&lt;/h2&gt;

&lt;p&gt;定义了成功的标准后，我们就可以明白，建立高级的RAG实际上就是要运用更复杂的技术和策略（主要应用到搜索或是信息构造阶段），以确保最终能满足这些需求。进一步说，我们可以把复杂的技术分为两大类，一类是能够独立满足任一成功标准的，另一类则是能够同时满足这两个标准的。&lt;/p&gt;

&lt;h2 id=&quot;高级的搜索技术必须能找到与用户问题最相关的文件&quot;&gt;高级的搜索技术必须能找到与用户问题最相关的文件&lt;/h2&gt;

&lt;p&gt;接下来我们简要介绍一些较为复杂的技术，帮助实现第一个成功标准。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;数据块大小优化&lt;/strong&gt;：由于大型语言模型受到上下文长度的限制，构建外部知识库时必须要对文件进行分块。如果块的大小过大或过小，都会对信息构造工作造成困扰，从而导致输出的答案不准确。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;LlamaIndex数据块大小优化方法&lt;/strong&gt;（&lt;a href=&quot;https://github.com/run-llama/llama_index/blob/main/docs/examples/param_optimizer/param_optimizer.ipynb&quot;&gt;notebook 指南&lt;/a&gt;）：&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ServiceContext&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index.param_tuner.base&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ParamTuner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RunResult&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index.evaluation&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SemanticSimilarityEvaluator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BatchEvalRunner&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;### Recipe
### Perform hyperparameter tuning as in traditional ML via grid-search
### 1. Define an objective function that ranks different parameter combos
### 2. Build ParamTuner object
### 3. Execute hyperparameter tuning with ParamTuner.tune()
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 1. Define objective function
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;objective_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;chunk_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;chunk_size&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;docs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;docs&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;top_k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;top_k&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;eval_qs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;eval_qs&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ref_response_strs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ref_response_strs&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# build RAG pipeline
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_build_index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunk_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;docs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# helper function not shown here
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;query_engine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;as_query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;similarity_top_k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;top_k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  
    &lt;span class=&quot;c1&quot;&gt;# perform inference with RAG pipeline on a provided questions `eval_qs`
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;pred_response_objs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_responses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;eval_qs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;show_progress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# perform evaluations of predictions by comparing them to reference
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# responses `ref_response_strs`
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;evaluator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SemanticSimilarityEvaluator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;eval_batch_runner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BatchEvalRunner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;semantic_similarity&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;evaluator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;workers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;show_progress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;eval_results&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_batch_runner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evaluate_responses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;eval_qs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;responses&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pred_response_objs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ref_response_strs&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# get semantic similarity metric
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;mean_score&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;np&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;semantic_similarity&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;mean&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RunResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;score&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mean_score&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 2. Build ParamTuner object
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_dict&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;chunk_size&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# params/values to search over
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fixed_param_dict&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# fixed hyperparams
&lt;/span&gt;  &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;top_k&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;docs&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;docs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;eval_qs&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eval_qs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;ref_response_strs&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ref_response_strs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;param_tuner&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ParamTuner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;param_fn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objective_function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;param_dict&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fixed_param_dict&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fixed_param_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;show_progress&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# 3. Execute hyperparameter search
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;param_tuner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;tune&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;best_result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;best_run_result&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;best_chunk_size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;best_run_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;chunk_size&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. 结构化的外部知识：&lt;/strong&gt; 在复杂的场景中，仅仅依靠基本的向量索引构建外部知识可能是不够的，我们可能需要增加一些结构性的元素，以实现递归检索或者针对明显区分开的外部知识源采用路由式检索。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LlamaIndex 递归检索步骤&lt;/strong&gt; (&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/retrievers/recursive_retriever_nodes.html&quot;&gt;notebook 指南&lt;/a&gt;)：&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VectorStoreIndex&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index.node_parser&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SentenceSplitter&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index.schema&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IndexNode&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;### Recipe
### Build a recursive retriever that retrieves using small chunks
### but passes associated larger chunks to the generation stage
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# load data
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;input_file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;some_data_path/llama2.pdf&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# build parent chunks via NodeParser
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node_parser&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SentenceSplitter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunk_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;base_nodes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node_parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_nodes_from_documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# define smaller child chunks
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sub_chunk_sizes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;512&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;sub_node_parsers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;SentenceSplitter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chunk_size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;chunk_overlap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sub_chunk_sizes&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;all_nodes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base_node&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base_nodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sub_node_parsers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sub_nodes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_nodes_from_documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sub_inodes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;IndexNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_text_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sn&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sub_nodes&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;all_nodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sub_inodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# also add original node to node
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;original_node&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IndexNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_text_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;base_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;all_nodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;original_node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# define a VectorStoreIndex with all of the nodes
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector_index_chunk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;VectorStoreIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;all_nodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service_context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service_context&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;vector_retriever_chunk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector_index_chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;as_retriever&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;similarity_top_k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# build RecursiveRetriever
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all_nodes_dict&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;all_nodes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;retriever_chunk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RecursiveRetriever&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;retriever_dict&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector_retriever_chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;node_dict&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all_nodes_dict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# build RetrieverQueryEngine using recursive_retriever
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query_engine_chunk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RetrieverQueryEngine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;retriever_chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;service_context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service_context&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# perform inference with advanced RAG (i.e. query engine)
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query_engine_chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Can you tell me about the key concepts for safety finetuning&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;其他有用的链接&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;我们有数个指南，展示了如何利用其他高级技巧，在复杂的情境中精确地检索信息。以下是我们推荐的一些链接：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/query_engine/knowledge_graph_rag_query_engine.html&quot;&gt;利用知识图谱构建外部知识&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/vector_stores/elasticsearch_auto_retriever.html&quot;&gt;使用自动检索器实现混合检索&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/retrievers/simple_fusion.html&quot;&gt;构建融合检索器&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/finetuning/embeddings/finetune_embedding.html&quot;&gt;微调检索过程中使用的嵌入模型&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/query_transformations/HyDEQueryTransformDemo.html&quot;&gt;查询嵌入的转换（HyDE）&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;高级生成技术应能善于利用已检索到的文档&quot;&gt;高级生成技术应能善于利用已检索到的文档&lt;/h2&gt;

&lt;p&gt;这部分的内容与前述部分有些类似，我们同样提供了一些复杂技术的实例，其总体目标是要确保检索到的文档与大语言模型（LLM）的生成器能够良好对接。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;信息压缩：&lt;/strong&gt; 大语言模型（LLM）的处理上下文长度是有限的，如果检索到的文档中含有过多的噪声（比如：无关的信息），可能会导致响应质量下降。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;LlamaIndex 信息压缩步骤&lt;/strong&gt; (&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/node_postprocessor/LongLLMLingua.html&quot;&gt;notebook 指南&lt;/a&gt;)：&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VectorStoreIndex&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index.query_engine&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RetrieverQueryEngine&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index.postprocessor&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LongLLMLinguaPostprocessor&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;### Recipe
### Define a Postprocessor object, here LongLLMLinguaPostprocessor
### Build QueryEngine that uses this Postprocessor on retrieved docs
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Define Postprocessor
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node_postprocessor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LongLLMLinguaPostprocessor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;instruction_str&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Given the context, please answer the final question&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;target_token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;rank_method&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;longllmlingua&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;additional_compress_kwargs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;condition_compare&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;condition_in_question&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;context_budget&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;+100&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;reorder_context&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# enable document reorder
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Define VectorStoreIndex
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input_dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VectorStoreIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Define QueryEngine
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;retriever&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;as_retriever&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;similarity_top_k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;retriever_query_engine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RetrieverQueryEngine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;retriever&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node_postprocessors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node_postprocessor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Used your advanced RAG
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;retriever_query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;A user query&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. 结果重排：&lt;/strong&gt; 大语言模型（LLM）常常会遭遇所谓的“迷失在中间”现象，也就是模型过于关注语境的两端。因此，在将检索到的文档提交给生成组件前进行一次重新排序，会带来积极的效果。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LlamaIndex 为优化生成效果的重排步骤&lt;/strong&gt; (&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/node_postprocessor/CohereRerank.html&quot;&gt;notebook 指南&lt;/a&gt;)：&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VectorStoreIndex&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index.postprocessor.cohere_rerank&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CohereRerank&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index.postprocessor&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LongLLMLinguaPostprocessor&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;### Recipe
### Define a Postprocessor object, here CohereRerank
### Build QueryEngine that uses this Postprocessor on retrieved docs
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Build CohereRerank post retrieval processor
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;environ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;COHERE_API_KEY&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;cohere_rerank&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CohereRerank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api_key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;api_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;top_n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Build QueryEngine (RAG) using the post processor
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;./data/paul_graham/&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VectorStoreIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;query_engine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;as_query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;similarity_top_k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;node_postprocessors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cohere_rerank&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Use your advanced RAG
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;What did Sam Altman do in this essay?&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;面向检索和生成要求的先进技巧&quot;&gt;面向检索和生成要求的先进技巧&lt;/h2&gt;

&lt;p&gt;在这一节中，我们将探讨一些高级方法，利用检索与生成的协同效益，旨在提高检索效果并得到对用户查询更精准的生成答案。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;生成器增强型检索：&lt;/strong&gt; 这些技术充分利用了大语言模型的内在推理能力，在进行检索前精准优化用户查询，直指解答需要的关键信息。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;LlamaIndex生成器增强型检索配方&lt;/strong&gt;(&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/query_engine/flare_query_engine.html&quot;&gt;教程指南&lt;/a&gt;)&lt;strong&gt;：&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index.llms&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OpenAI&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index.query_engine&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FLAREInstructQueryEngine&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;VectorStoreIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ServiceContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;### Recipe
### Build a FLAREInstructQueryEngine which has the generator LLM play
### a more active role in retrieval by prompting it to elicit retrieval
### instructions on what it needs to answer the user query.
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Build FLAREInstructQueryEngine
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;./data/paul_graham&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VectorStoreIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;index_query_engine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;as_query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;similarity_top_k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;service_context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ServiceContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_defaults&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;llm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OpenAI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;gpt-4&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;flare_query_engine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FLAREInstructQueryEngine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;query_engine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index_query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;service_context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service_context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;max_iterations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Use your advanced RAG
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flare_query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Can you tell me about the author&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s trajectory in the startup world?&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. 迭代型检索-生成器 RAG：&lt;/strong&gt; 对于一些复杂的问题，我们有时候需要通过多步推理来给出有用且相关的答案。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LlamaIndex迭代型检索-生成器方法&lt;/strong&gt; (&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/evaluation/RetryQuery.html#retry-query-engine&quot;&gt;notebook 指南&lt;/a&gt;)&lt;strong&gt;：&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index.query_engine&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RetryQueryEngine&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;llama_index.evaluation&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RelevancyEvaluator&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;### Recipe
### Build a RetryQueryEngine which performs retrieval-generation cycles
### until it either achieves a passing evaluation or a max number of
### cycles has been reached
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Build RetryQueryEngine
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleDirectoryReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;./data/paul_graham&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;VectorStoreIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;base_query_engine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;as_query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;query_response_evaluator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RelevancyEvaluator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# evaluator to critique 
&lt;/span&gt;                                                &lt;span class=&quot;c1&quot;&gt;# retrieval-generation cycles
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;retry_query_engine&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RetryQueryEngine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;base_query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query_response_evaluator&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Use your advanced rag
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;retry_response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;retry_query_engine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;A user query&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;rag的量度考量&quot;&gt;RAG的量度考量&lt;/h2&gt;

&lt;p&gt;对RAG系统进行评估无疑是至关重要的。Gao, Yunfan等人在他们的综述论文中，列出了7个主要的量度因素，可在我们提供的RAG应用方框表的右上方找到。llama-index库包含多个评估抽象和针对RAGAs的集成，以帮助开发者通过这些量度考量，了解他们的RAG系统达成目标的程度。下面，我们列出了部分精选的评估笔记本指南。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.llamaindex.ai/en/latest/examples/evaluation/answer_and_context_relevancy.html&quot;&gt;答案相关性与上下文相关性&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.notion.so/LlamaIndex-Platform-0754edd9af1c4159bde12649c184c8ef?pvs=21&quot;&gt;忠实度&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/run-llama/llama_index/blob/main/docs/examples/evaluation/retrieval/retriever_eval.ipynb&quot;&gt;检索评估&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.llamaindex.ai/en/stable/examples/evaluation/batch_eval.html&quot;&gt;批量评估与BatchEvalRunner&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;你现在已经做好准备开始rag的高级应用&quot;&gt;你现在已经做好准备，开始RAG的高级应用&lt;/h2&gt;

&lt;p&gt;阅读了这篇博客文章后，我们期望你能感觉更有自信，更有底气，去采取这些先进技术构建高级的RAG系统！&lt;/p&gt;
</description>
      <pubDate>2024-01-06</pubDate>
      <link>https://ericsky.com/2024-01-06/A-Cheat-Sheet-and-Some-Recipes-For-Building-Advanced-RAG-zh.html</link>
      <guid isPermaLink="true">https://ericsky.com/2024-01-06/A-Cheat-Sheet-and-Some-Recipes-For-Building-Advanced-RAG-zh.html</guid>
    </item>
    
		
    
    <item>
      <title>Password, Session, Cookie, Token, JWT, SSO, OAuth - 认证机制深度解析 - 第2部分[译]</title>
      <description>&lt;p&gt;原文：&lt;a href=&quot;https://blog.bytebytego.com/p/password-session-cookie-token-jwt-ec1&quot;&gt;Password, Session, Cookie, Token, JWT, SSO, OAuth - Authentication Explained - Part 2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：Alex Xu&lt;/p&gt;

&lt;h1 id=&quot;无需密码的身份验证&quot;&gt;无需密码的身份验证&lt;/h1&gt;

&lt;p&gt;到现在为止，我们已经研究了三种身份验证方式：HTTP基础验证、session-cookie验证和基于token的验证。所有这些方式都需要一个密码。然而，我们还有其它方法可以在不需要密码的情况下证明身份。&lt;/p&gt;

&lt;p&gt;提到身份验证，我们要考虑到三方面的因素：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;知识因素：你知道的东西，例如密码&lt;/li&gt;
  &lt;li&gt;所有权因素：你拥有的东西，例如设备或电话号码&lt;/li&gt;
  &lt;li&gt;内在因素：你特有的东西，例如你的生物特征&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;密码是属于“你知道的东西”类别。一次性密码（OTP）证明用户拥有一个手机或设备，而生物特征验证则证明了“你独有的东西”。&lt;/p&gt;

&lt;h2 id=&quot;一次性密码otp&quot;&gt;一次性密码（OTP）&lt;/h2&gt;

&lt;p&gt;一次性密码（OTP）被广泛应用为更安全的身份验证方式。与静态密码（可重复使用）不同, OTP仅在有限的时间内有效, 通常只有几分钟。也就是说, 即使有人窃取了OTP，他们也无法在之后使用它进行登录。此外，OTP需要在验证时结合“你拥有的东西”以及“你知道的东西”。这个“你拥有的东西”可以是用户能接收到的电话号码或电子邮件地址，这增加了黑客窃取的难度。&lt;/p&gt;

&lt;p&gt;然而，必须注意的是，使用短信作为OTP传达方式可能比其他方式更不安全。这是因为黑客可能截取或重定向短信，尤其是在用户的电话号码已经被窃取的情况下。有时，攻击者通过说服移动服务提供商把号码转移到一张新的SIM卡上，就能够接管这个电话号码。一旦攻击者掌控了这个电话号码，他们就能拦截任何通过短信发送的OTP。因此，一般建议尽可能使用其它传送方式，例如电子邮件或手机应用。&lt;/p&gt;

&lt;p&gt;下面是一次性密码如何工作的详细说明：&lt;/p&gt;

&lt;p&gt;步骤1：用户希望登录一个网站，会被问及用户名、电话号码或电子邮件地址。
步骤2：服务器产生一个有过期时间的OTP。
步骤3：服务器把OTP通过短信或电子邮件的方式，发送给用户的设备。
步骤4：用户在登录区域输入接收到的OTP。
步骤5-6：服务器比较产生的OTP和用户输入的OTP。如果两者相符，那么系统就允许用户登录。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb27865df-e833-47c8-9340-cba5510a90a0_1600x1069.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;同样，我们也可以使用硬件或软件密钥来生成一次性密码，以实现多因素认证（MFA）。比如说，Google的二次认证（2FA）就使用了一个能够在每30秒生成一次新的一次性密码的软件密钥。在用户登陆的时候，他们需要输入密码以及设备上显示的即时一次性密码。这样的做法增加了一层额外的安全保障，毕竟黑客要想盗取一次性密码，必须先要能够接触到用户的设备。关于多因素认证，我们后面会再详细讲解。&lt;/p&gt;

&lt;h2 id=&quot;单点登录sso&quot;&gt;单点登录（SSO）&lt;/h2&gt;

&lt;p&gt;单点登录，简称SSO，是一种用户认证机制，只需一套登录凭证，用户就可以登录并使用多个系统或应用。SSO极大地简化了登录流程，让用户在各个平台上的体验变得无缝衔接。&lt;/p&gt;

&lt;p&gt;SSO主要依赖于一个重要的节点，那就是中央认证服务（CAS）服务器。以下是SSO流程的详尽分解：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;当我们试图登录一个应用，比如Gmail，我们首先会被引导到CAS服务器。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;CAS服务器核对我们的登录信息，并生成一个准证发放票据（TGT）。这个TGT随后会以一个准证发放Cookie（TGC）的形式，保存在我们的浏览器中，这代表了我们的全局会话。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;CAS会为我们访问Gmail的行为生成一张服务票据（ST），然后带着这张ST，我们被引导回到了Gmail。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Gmail会使用这张ST，在CAS服务器那里进行登录验证。确认无误后，我们就可以正常使用Gmail了。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;当我们想要访问其他的应用，比如YouTube，流程就更为简便了：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;由于我们在登录Gmail的时候已经得到了一个TGC，CAS服务器可以识别出我们的登录状态。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;CAS服务器会再为我们访问YouTube生成一张新的ST，这样我们就可以在不用再次输入凭证的情况下，直接使用YouTube了。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这样一来，我们就无需记住并输入多套登录信息了。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fff52780c-e94e-4d80-a083-7c9cbead8b6f_1600x1473.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;实现SSO功能，有多种协议可供选择：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;SAML（安全断言标记语言），在企业应用中广泛使用。SAML所传输的认证和授权数据，是以XML的格式呈现。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;OIDC（OpenID Connect），在用户应用中深受喜爱。OIDC利用JSON Web Tokens（JWT）完成认证操作，并以此为基础建立在OAuth 2.0框架之上。这方面的细节，我们将会在下一小节进行讲解。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;对于新开发的应用，OIDC通常是首选。它支持各种类型的客户端，包括基于网页的、移动端，还有&lt;a href=&quot;https://openid.net/connect/&quot;&gt;基于JavaScript的客户端&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;SSO提供了一种高效又安全的认证方法，只要一套凭证，就可以让用户在各种应用间畅游。这种方法通过使用复杂且唯一的密码，降低了被欺诈的风险，从而提升了安全性。同时，此举也大幅度减轻了IT部门的管理工作量。&lt;/p&gt;

&lt;h2 id=&quot;oauth-20和openid-connectoidc&quot;&gt;OAuth 2.0和OpenID Connect（OIDC）&lt;/h2&gt;

&lt;p&gt;虽然OAuth 2.0主要是一个授权框架，但它也可以和OpenID Connect（OIDC）结合起来，共同进行身份验证。OIDC实际上是建立在OAuth 2.0之上的一个身份验证层，它能实现用户身份的验证，并控制受保护资源的访问。&lt;/p&gt;

&lt;p&gt;当使用“通过Google登录”或者类似的功能时，OAuth 2.0与OIDC携手共同简化了身份验证流程。OIDC用标准化的JSON Web Token（JWT）的格式提供用户身份数据。这个token包含了已认证用户的信息，让第三方的应用能够在无需单独注册的情况下，创建用户的个人档案。&lt;/p&gt;

&lt;p&gt;在这个机制中，&lt;a href=&quot;https://oauth.net/2/&quot;&gt;OAuth 2.0&lt;/a&gt;通过发放短期token，而不使用密码，实现了“安全的授权访问”，让第三方服务在得到资源所有者的允许后，能访问受保护的资源。这样做的好处是，第三方服务无需直接处理或者存储用户的密码，提高了安全性。&lt;/p&gt;

&lt;p&gt;下面的这张图，解释了在“通过 Google 登录”的情景中，这个协议是怎样起作用的。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a1f3e9-7bad-410a-b059-66ccd6189f6b_1600x998.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;举“通过Google登录”这个例子来说，OAuth 2.0定义了四个角色：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;资源所有者：最终的用户，他们在掌握自己的个人数据。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;资源服务器：托管用户个人档案的受保护资源的Google服务器。通过使用访问token，响应受保护资源的请求，确保只有获得授权的服务能获取这些数据。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;客户端：代表资源所有者发起请求的设备（PC或者智能手机）。这个设备代表着寻求访问用户数据的第三方应用。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;授权服务器：Google的授权服务器，他们负责向客户端发放token，管理资源服务器和客户端之间的token的安全流转。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;为了适应不同的情况，OAuth 2.0提供了四种类型的授权：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;授权码授权：最完整且通用的模式，适用于大部分类型的应用程序。后续还会有更详细的解释。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Implicit grant：为那些仅有前端的应用而设计，比如单页应用或者手机应用。但这种方式已经不再推荐了。后续还会有更详细的解释。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;资源所有者密码凭证授权：用户很信任某个第三方应用，完全可以把凭证交给他们保管，比如一个值得信任的手机应用。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;客户端凭证授权：适用于那些没有前端的情况，比如命令行工具，或者服务器与服务器之间的沟通，无需资源所有者介入即可。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这个标准提供了多种模式，以适应不同的应用场景和需求，确保了在面对多样化的情境时，依然能灵活适应。&lt;/p&gt;

&lt;p&gt;授权码授权是一个值得详述的例子。关于其他三种授权类型的具体规格，可以在&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc6749&quot;&gt;RFC-6749&lt;/a&gt;内找到。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://substackcdn.com/image/fetch/w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce0b4f94-1fae-4d70-a71e-1f82ef93220c_1600x1257.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</description>
      <pubDate>2024-01-05</pubDate>
      <link>https://ericsky.com/2024-01-05/Password-Session-Cookie-Token-JWT-SSO-OAuth-Authentication-Explained-Part2-zh.html</link>
      <guid isPermaLink="true">https://ericsky.com/2024-01-05/Password-Session-Cookie-Token-JWT-SSO-OAuth-Authentication-Explained-Part2-zh.html</guid>
    </item>
    
		
    
    <item>
      <title>Password, Session, Cookie, Token, JWT, SSO, OAuth - 认证机制深度解析 - 第1部分[译]</title>
      <description>&lt;p&gt;原文：&lt;a href=&quot;https://blog.bytebytego.com/p/password-session-cookie-token-jwt&quot;&gt;Password, Session, Cookie, Token, JWT, SSO, OAuth - Authentication Explained - Part 1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;作者：Alex Xu&lt;/p&gt;

&lt;p&gt;当我们使用各种应用程序和网站时，通常有三个核心的安全步骤在持续进行：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;身份识别&lt;/li&gt;
  &lt;li&gt;身份认证&lt;/li&gt;
  &lt;li&gt;授权许可&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;下面的示意图展示了这些方法在一个典型的网站架构中的应用范围以及它们的具体含义。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://substack-post-media.s3.amazonaws.com/public/images/ced6562d-3be6-4dd4-a141-fed9e6b02182_1600x1226.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;在接下来的两篇文章中，我们将深入研究各种认证方式，包括passwords、sessions、Cookies、Tokens、JWTs (JSON Web Tokens)、SSO（单点登录）以及OAuth2协议。我们会讨论每种方式所解决的问题，以及如何根据我们的需要来选择最适合的认证方式。&lt;/p&gt;

&lt;h1 id=&quot;密码认证&quot;&gt;密码认证&lt;/h1&gt;

&lt;p&gt;密码认证作为一种基本且广泛使用的身份验证方式，对于网站和应用程序来说至关重要。在此方法中，用户通过输入他们独一无二的用户名和密码组合，来获取对受保护资源的访问权限。系统会把输入的凭据与存储在系统中的用户信息进行比对，一旦核对匹配，用户就会被授权进入。&lt;/p&gt;

&lt;p&gt;尽管密码认证是一个基本的用户身份验证方式，但是它确实存在一些限制。例如，用户可能忘记密码，多个网站的用户名和密码过于复杂难以管理。此外，如果缺乏足够的安全防护措施，基于密码的系统可能会面临蛮力攻击或字典攻击等威胁。&lt;/p&gt;

&lt;p&gt;为了解决这些问题，现代系统通常会实施一些额外的安全措施，如多因素认证，或者利用其他认证机制（例如，基于session-cookie 或 Token的认证）来增强或取代密码认证机制，以便于用户之后能对保护资源进行访问。&lt;/p&gt;

&lt;p&gt;在接下来的这一部分，我们将首先详细介绍基于密码的认证机制，以便大家能更好地理解它的发展历程以及具体运作方式。&lt;/p&gt;

&lt;h2 id=&quot;http-basic-access-authentication&quot;&gt;HTTP Basic Access Authentication&lt;/h2&gt;

&lt;p&gt;HTTP基础访问认证是一种网络安全机制，它需要在用户访问受保护资源时提供用户名和密码。这些身份信息会通过Base64算法进行编码，然后放入HTTP的头字段&lt;em&gt;Authorization: Basic&lt;/em&gt;中。&lt;/p&gt;

&lt;p&gt;这个过程可以简单概述为以下几个步骤：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;客户端向服务器发送请求，试图访问某项保护资源。&lt;/li&gt;
  &lt;li&gt;如果客户端第一次请求并未提供有效的身份认证，服务器会返回一个”401 未授权”的状态代码，并附带一个WWW-Authenticate: Basic的头字段，以告知客户端必须进行基础认证。&lt;/li&gt;
  &lt;li&gt;客户端随后会提示用户输入用户名和密码，并以”username:password”的格式将它们整合成一串字符串。&lt;/li&gt;
  &lt;li&gt;这个字符串然后会被Base64编码，放入后续请求的“Authorization: Basic”字段中，比如”Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=”。&lt;/li&gt;
  &lt;li&gt;当服务器收到含有认证信息的请求后，会解码提供的Base64编码的身份信息，并提取出用户名和密码。服务器此后会将这些信息与存储在自身的用户数据库或者认证服务中的信息进行比对。&lt;/li&gt;
  &lt;li&gt;如果客户端提供的身份信息与服务器进行的核对相符，服务器会授权访问被请求的资源；反之，服务器会返回”401 未授权”的状态代码。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;然而，HTTP基础访问认证并非完美无缺，它存在一些明显的局限性。例如，使用Base64编码的用户名和密码能够被轻易解码。尽管现今大部分的网站会采用TLS(传输层安全协议)对浏览器和服务器间的数据进行加密以提升安全性，但用户的身份信息仍有可能面临被窃取或中间人攻击的风险。&lt;/p&gt;

&lt;p&gt;再者，虽然在HTTP基础访问认证中，浏览器会在每次请求同一域名下的保护资源时都发送带有身份信息的Authorization头，从而避免用户反复输入用户名和密码，但由于每个网站都维护着各自独特的用户名和密码，用户可能会觉得难以记住这些信息。&lt;/p&gt;

&lt;p&gt;综上所述，这种认证机制在现今的环境下已经相对过时，不再适用于许多现代网站。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://substack-post-media.s3.amazonaws.com/public/images/10e83d0a-8fb5-42f6-abeb-a5e8980450c3_1600x1275.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;session-cookie-认证&quot;&gt;Session-Cookie 认证&lt;/h2&gt;

&lt;p&gt;Session-Cookie认证可以解决 HTTP 基础访问认证无法追踪用户登录状态的问题。为了追踪用户在访问期间的状态，会生成一个session ID。这个session ID 会被记录在服务器和客户的cookie中，所以它可以作为一种认证机制。之所以被称为session-cookie，是因为它是一片内部储存有session ID 的cookie。用户在首次访问时需要提供用户名和密码，之后，服务器会为用户的访问建立一个session。后续的请求会包含cookie，这样服务器就可以比较客户端和服务器端的session ID 了。&lt;/p&gt;

&lt;p&gt;下面我们看看它是如何工作的：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;客户端发送请求要访问服务器上的某个受保护资源。如果客户端还未进行过认证，服务器会返回一个登录提示。此时客户端会向服务器提交他们的用户名和密码。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;服务器会根据自己的用户数据库或者身份验证服务核实提供的登陆凭证是否正确。如果凭证正确，服务器会生成一个唯一的session ID，并在服务器端的存储（比如，服务器内存、数据库或session服务器）中创建一个相应的session。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;服务器会将session ID 以cookie的形式发送给客户端，通常会设置到cookie header里。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;客户端会保存这个session cookie。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;对于后续的请求，客户端会将cookie放在request headers中一并发送。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;服务器会根据存储的session数据检查cookie中的session ID，以此来认证用户的身份。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;如果认证成功，服务器会授权用户访问请求的资源。当用户退出登录，或者到了设定的过期时间，服务器便会使这个session失效，客户端也会删除这个session cookie。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;https://substack-post-media.s3.amazonaws.com/public/images/9b3002be-d4f2-489c-99cd-f789012d76dc_1600x1173.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</description>
      <pubDate>2024-01-04</pubDate>
      <link>https://ericsky.com/2024-01-04/Password-Session-Cookie-Token-JWT-SSO-OAuth-Authentication-Explained-Part1-zh.html</link>
      <guid isPermaLink="true">https://ericsky.com/2024-01-04/Password-Session-Cookie-Token-JWT-SSO-OAuth-Authentication-Explained-Part1-zh.html</guid>
    </item>
    
		
    
    <item>
      <title>First do it, then do it right, then do it better[译]</title>
      <description>&lt;p&gt;“先行动起来，然后把它做对，最后把它做得更好。”&lt;/p&gt;

&lt;p&gt;就这样开始行动吧。成功之旅常常是从第一步迈出开始的，可正是这第一步往往最难迈出。人们很容易陷入对失败的恐惧或对事物完美的追求中，但我希望我在2013年首次分享的这句话，能够提醒我们，随着2024年的到来，开始行动的重要性何在。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;只需要找个地方开始&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;“如果必要，可以慢慢来。如果需要，从小事做起。如果不得已，那就私下开始。主要是行动。” - 詹姆斯·克莱尔&lt;/p&gt;

&lt;p&gt;采取第一步并不要求完美或立即成为大师。关键在于克服困顿，采取行动。正是这些行动，将带来进步、学习，如果你足够幸运且持之以恒，最终也许会带来成功。&lt;/p&gt;

&lt;p&gt;当你开始行动时，你给自己的成长和进步提供了机会。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;开始的力量&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;着手新项目或习惯往往看似令人畏惧。心理学家告诉我们，人们倾向于高估开始的困难，低估我们持续下去的能力。&lt;/p&gt;

&lt;p&gt;然而，研究显示，相比起初的热情或早期的进展，“小开始”能更好地预测最终的成功。这称为新开始效应：迈出第一步会让我们更有活力，进而提高动力。&lt;/p&gt;

&lt;p&gt;所以请专注于开始，不要对完美抱有压力。进步和后期的调整自会随之而来。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;首先，行动起来：接受MVP(最简可行产品)的理念&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;行动起来=制作最简单的MVP。&lt;/p&gt;

&lt;p&gt;最简可行产品（MVP）意味着你可以用最简易的版本来测试、收集反馈并不断迭代你的产品或想法。&lt;/p&gt;

&lt;p&gt;通过这种理念（做出一些成果——哪怕是粗糙的、原型的、草稿性的），你会专注于进展而不是完美，明白把东西推向世界，比等待那个看似“完美”的时刻来临更有价值。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;走出舒适圈&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;走出个人的舒适区可能会让人感到害怕。但是，主动面对不适不仅能培养信心和技能，研究还表明这能让我们更愿意学习。要认识到，恐惧常常是内心想要我们成长的信号。别让它阻碍你的前进步伐。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;然后，把它做对：持续改进和修正&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;做得更好=解决正确性问题。&lt;/p&gt;

&lt;p&gt;你一旦迈出了第一步，就可以开始对你推出的MVP进行打磨和修正。现在是从反馈中学习，识别改进点，并相应调整的时候了。&lt;/p&gt;

&lt;p&gt;这是一个对你的想法进行迭代的机会，确保它既能满足你的观众或客户的需求，同时也能符合你的愿景。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;培养好奇心和适应能力&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;以好奇心和强韧不拔的态度迎接每个新挑战，会让我们踏出舒适区时更具持续性和愉快。留心成长的机会，相信自己应对挑战的能力。通过设定小挑战来逐渐增加自己的能力范围。&lt;/p&gt;

&lt;p&gt;当遇到不可避免的挫折时，不要自我批评，而应依靠坚强的心态——一个能帮助你恢复、学习并持续前进的能力。&lt;/p&gt;

&lt;p&gt;在这里，自我同情、适应力和保有正确的视角至关重要。通过不懈努力，你会对自己开始行动、遇到困难、学习并追求精通的能力充满信心。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;最后，更上层楼：追求不断的完善&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;“做得更好 = 不断改进，迈向理想的最终状态（比如，变得更快）。”&lt;/p&gt;

&lt;p&gt;仅仅做得对并不意味着旅程的终点。&lt;/p&gt;

&lt;p&gt;最后一步是持续的改进，追求卓越和成长。&lt;/p&gt;

&lt;p&gt;通过不断追求理想的最终状态，你展示了对进步的承诺，确保你的产品或项目保持着相关性、创新性和成功性。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;设立新的目标&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;在你不断进步时，清晰地知道何时可以“完成”，或者更新你的目标。像顶级运动员一样，通过边际收益的累积，将小进步转化为竞争优势。找到潜在的改善领域，并设定可衡量的目标，无论是提高效率还是增加用户体验。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;克服前进道路上最大的障碍&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;“前进道路上最大的障碍不是资源或人才的匮乏，而是对失败的恐惧。”&lt;/p&gt;

&lt;p&gt;意识到对失败的恐惧是追求成功过程中最大的障碍，可以让我们勇敢面对它。&lt;/p&gt;

&lt;p&gt;通过面对这种恐惧，你将更专注于迈出第一步，知道一旦开始行动，继续前进就会变得更容易。&lt;/p&gt;

&lt;p&gt;记住，开始行动已经成功了一大半。不要等到感觉自己完全准备好了再开始，因为所谓完美的时机可能永远不会到来。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;最终&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;如其追求完美的执行，不如拥抱开始的力量——做出一个最简可行产品（MVP），软启动一个计划或设定一个里程碑。进步本身就能激发动力。通过开始行动，你已经为成长和创新打开了大门。剩下的，就会随之而来。&lt;/p&gt;

&lt;p&gt;拥抱开始的力量，然后不断迭代，直到你对成果感到满意。&lt;/p&gt;

&lt;p&gt;原文：&lt;a href=&quot;https://twitter.com/addyosmani/status/1739052802314539371&quot;&gt;“First do it, then do it right, then do it better.”&lt;/a&gt;&lt;/p&gt;
</description>
      <pubDate>2024-01-03</pubDate>
      <link>https://ericsky.com/2024-01-03/First-do-it-then-do-it-right-then-do-it-better-zh.html</link>
      <guid isPermaLink="true">https://ericsky.com/2024-01-03/First-do-it-then-do-it-right-then-do-it-better-zh.html</guid>
    </item>
    
		
  </channel>
</rss>
