Bo's Oracle Station

【博客文章2025】Oracle Database 23ai:AI Vector Search笔记与实验8---在Oracle Database 23.5实现本地Ollama中文RAG支持

2025-2-5 20:52| 发布者: admin| 查看: 89| 评论: 0|原作者: Bo Tang

摘要: 本博客调用《AI Vector Search笔记与实验6》的func_text_input_ollama(v_question_key),把提问的问题向量化,并从语料库中提取前25行最接近的相似性查询信息作为提示工程。在不连接互联网的情况下,完全依靠Oracle Database 23.5中存储的语料信息,调用本地Ollama实现中文RAG对话。
 【博客文章2025】Oracle Database 23ai:AI Vector Search笔记与实验8---在Oracle Database 23.5实现本地Ollama中文RAG支持


1. 调用本地Ollama:

    本博客的实验环境延续本系列《AI Vector Search笔记与实验》之前的环境。
1.1 使用Ollama的qwen2:7b-instruct大语言模型:
    qwen2:7b-instruct大语言模型的概况如下:

[root@station1 23.5.0]# ollama  show qwen2:7b-instruct  
Model
architecture qwen2
parameters 7.6B
context length 32768
embedding length 3584
quantization Q4_0

Parameters
stop "<|im_start|>"
stop "<|im_end|>"

System
You are a helpful assistant.

License
Apache License
Version 2.0, January 2004

    如果实验环境允许,还可以使用参数为72B的qwen2:72b-instruct大语言模型,那么可以得到更加令人满意的AI输出。注意:要使用指令微调训练过的的,后缀带有“-instruct”的大语言模型。
1.2 调用《AI Vector Search笔记与实验6》的func_text_input_ollama(v_question_key),把提问的问题向量化,并从语料库中提取前25行最接近的相似性查询信息作为提示工程:

create or replace procedure proc_ollama_rag_zh(p_question varchar2, p_question_key varchar2 default null)
is
v_question_key varchar2(4000);
v_ollama_in clob;
v_rag_hint clob;
v_apex_out clob;
v_json apex_json.t_values;
v_result clob;
begin
if p_question_key is null then
v_question_key := p_question;
else
v_question_key :=p_question_key;
end if;
apex_web_service.g_request_headers(1).name := 'Content-Type';
apex_web_service.g_request_headers(1).value := 'application/json';
--Search by using vector embedding
for rec in (select chunk_data from hr.t1chunksollama order by vector_distance(chunk_embedding , func_text_input_ollama(v_question_key), cosine)
fetch first 25 rows only)
loop
v_rag_hint := v_rag_hint || rec.chunk_data || chr(10);
end loop;
v_rag_hint := replace(replace(replace(v_rag_hint, '''', ''), '"', '\"'), chr(10), '\n');
--
v_ollama_in := '{
"model": "qwen2:7b-instruct",
"messages": [
{"role": "system", "content": "' || v_rag_hint || '"},
{"role": "user", "content": "' || p_question || '"}
]
}';
v_apex_out := apex_web_service.make_rest_request(
p_url => 'http://172.25.250.1:11434/v1/chat/completions',
p_http_method => 'POST',
p_body => v_ollama_in,
p_transfer_timeout => 300000
);
apex_json.parse(v_json, v_apex_out);
v_result:= apex_json.get_varchar2(p_path => 'choices[%d].message.content', p0 => 1, p_values => v_json);
dbms_output.put_line('*** Result: ' || chr(10) || v_result);
end;

    以上存储过程需要两个形式参数:第1个形式参数是提问的问题本身,第2个形式参数用于精确地进行相似性查询(第2个参数可以不提供。这种情况时,第2个参数取与第1个参数相同的值)。为了方便调用,需要再编制一个调用上述存储过程的存储过程:

create or replace procedure proc_qa(p_key varchar2) is
 v1 VARCHAR2(4000) :='限定在给定的文本中找出'||p_key||',字数要求1000字以上';
begin
 if func_text_input_ollama(p_key) is null then
  raise_application_error(-20003,'Embedding Errors');
 end if;
 proc_ollama_rag_zh(v1,p_key);
end;

2. 实现中文RAG支持:

    以下所有测试提问,都不连接互联网,完全靠Oracle Database 23.5中存储的语料信息作答:
2.1 第1次测试提问:“老荒游福州的所有景点”:

SQL>set serveroutput on;
SQL> exec  proc_qa('老荒游福州的所有景点');
*** Result:

根据所提供的文本,可以找到老荒游览福州的过程中的各个景点如下:

北京 ->
福州

到达后,具体逛了以下福州的地点:
1. **华林寺**
2.
**西湖**(包括周边景点)
3. **福建省博物馆**
4. **三坊七巷**
5.
**青云山**(前往福州市区途中经过)
6. **归元寺**
7. **地藏寺**
8.
**白马双溪**
9. **林则徐纪念馆**
10. **乌山**
11.
**于山宾馆**(位于于山脚下,包含瀑布和温泉设施的游览)  
12.
**马尾罗星公园**
13. **闽侯十八重溪**
14. **金山寺**
15.
**鼓山白云洞**以及鼓山内其它位置如:**涌泉寺**

这些是依据文本中描述的实际游玩或
提及的福州旅游地点。

PL/SQL 过程已成功完成。


    在以上的回答中,我们可以非常明确的看出:基于相似性查询的RAG提示工程生效了,见以下红色加粗字体:

DOC_IDCHUNK_DATA
18老荒游福州 (2006.1.29 - 2.3) 大年初一:北京-福州,华林寺-西湖-福建省博物馆-三坊七巷 狗年的第一顿饭是在海航的飞机上吃了一盒饺子。中午,从机场
18纪念馆没有游客留言簿。但我真想说一句: 福州出了个林则徐! 下午还去了两座庙 - 归元寺地藏寺,都是免费。归元寺里有一 尊古代铁佛,约40吨重,也不知何人所铸。来寺进香的主要是本地
18大年初五:白马双溪,福州:林则徐纪念馆-归元寺-地藏寺 今天经历了三件讨厌事,对福建的印象有跌幅。 第一件:从青云山回永泰县城,摩的司机开价要20元。到达后,
18票五元,看来福州不是典型的旅游城市,不以门票宰客。公园旁边是 船政学堂和造船厂故址。1866年,闽浙总督左宗棠奏请在福州办船 政。船政初始,左宗棠调任陕甘总督,赴任前,力荐沈葆桢总理船政
18回到宾馆用温泉砸了砸。想到福州小吃甜、油、过分细腻,不利 于体能恢复。在胃的建议下,去找回民吃了两碗拉面。晚上逛了台江 路步行街和榕城古街,没啥意思,这种市面,全国都大同小异。我出
18乘大巴到福州市区,入住于山宾馆于山宾馆位于福州的黄金地段, 背依于山,面朝五一广场,闹中取静。我选择的标间位于最高的四层, 朝山,可以洗温泉,观瀑布。过年吗,奢侈一把,195元。
18淡清静。要是在福州长住,我还真打算带上几本闲书,入此山门挂单 几日,往自己的心里走一遭。 晚饭吃了传说中的沙县小吃,原料和味道都平常,可取之处就是 便宜。 大年初六:于山,福州-北京
18不如人,迂腐颓势的文化未尝不也是败因之一。 唏嘘之后,回到福州,于天色将晚之时登上乌山。福州小山多, 市民好福气。老年人爬山,找个石桌打麻将;年轻人爬山,找个石凳
18寺内著名的素面现称"平安发财面"。我见用料普通,又不是非要发 财不可,就下山去马尾了。好在于山宾馆的早餐有各式福州小吃,我 塞得很饱。 一直以为马尾是海港,到了才发现原来还没出闽江。罗星公园门
18谈恋爱。我饿了,下山觅食,吃了雪菜光饼、花生汤、竹筒蛋羹扇贝 等等。 大年初三:闽侯十八重溪-金山寺 一早去客运西站乘中巴到闽侯南屿,下车一打听,才知十八重溪 在下一个镇 -
18生活的人,不仅字写得极好,还爱研究水果,著有《荔枝谱》。品茶 也很在行,著有《茶录》。老蔡还是一位造桥专家,首创了流线型桥 墩,即科学,又美观。 福州是林则徐的出生地,是左宗棠客死的他乡。关于林则徐,我
18定和其他三人拼车打的回福州。在福州西站下车后,司机立刻开车狂 奔,我立刻意识到他找给我的是一张五十的假币。他完全是故意的, 真想薅丫头发往车上撞。 第三件:本来觉得于山宾馆服务很好,但此番回来,住了188的
18我面朝瀑布喊:"有没有女鬼,有没有女鬼?" 自然,保持她一贯的沉默,因为她从不承诺。 沐浴完毕,唱着山歌归去。由于景区封闭,沿公路走了很久,才 打到摩的。至南通,换乘客车回福州西站。又去了距此地不远江中的
18大年初二:鼓山白云洞-涌泉寺-马尾罗星公园-乌山 听说白云洞山高路远,就去看看。在咨询了公交售票员之后,于 下院前两站的远洋下车,花四块钱打摩的,至一村口。司机指着公厕
18的白马山庄。春节期间,标间涨到198一天。我开了一间,条件很一 般,所幸热水器很大。仔细研究了一下门票:四个景区,每个单独售 票25,学生票15;任意两个景区联票40。我后来花55元游遍了四
18金山寺。 木船摆渡过去,加门票共收费两元。金山寺极小,置于江中石上, 惟一僧、一塔、一樟、一榕,两进院落而已。前院供妈祖,后院供西 方三圣。暮霭沉沉,闽江东去,逝者如斯。
18是到了郊县,要格外防备存心使坏的出租和摩的。我想,如果带着一 个家庭生活,福州实在是个宜居的城市。但如果是一个人吃饱就全家 不饿了,住在福州,或许会感到不够痛快。
18来他们是四川来福建打工的,相约到此旅游。我发现,凡是游客相对 稀少的景区,人与人往往相当友善。 两位好人去追赶他们的同伴,我独自上行,逐一欣赏每一出瀑布。
9乃衮宦游憩之地,创有凉亭,雕栏画栋,极其华丽。壁间悬⼤家名笔,⼏上列稀世奇珍,佳联掇画,⽿⽬繁华,⼤额标题古今坟典,诚⼈间之蓬 岛,凡世之⼴寒也。⽣每与端游玩其间,或题咏,或琴棋,留连光景,取乐不⼀。
18事务。沈葆桢是林则徐的女婿,他后来赶走过侵台的日人,还对台湾 的开发贡献很大。 公园面朝马尾海战战场。我登上罗星塔观望,以江面作为战场, 过于狭窄,不利于进攻的一方。况且,福建水师的三艘军舰战前已经
18参照一张简易的地图,步行经西湖公园去省博物馆。西湖岸上游 人如织,博物馆里倒颇清静。就布展来说,淡化了阶级斗争,突出了 传统文化。闽籍的历史名人中,蔡襄给我印象较深。因为他是个热爱
18却要40元,说是返程费用。我说,那你应该事先和我讲清楚,这是 你的不对了。念十多公里路也不近,又给了他10元。 第二件:此事最为可恶。因永泰至福州的客车排队数百人,我决
12去。那个森林太奇怪了,人一走进似乎被下了迷药,脑袋都昏沉起来。 " " 我走过两次,但走到一半,就迷路了。上次跟育走过一次,结果转到樱花林这边来了。我们明明没有转弯。 " 我想起上次的
18翻山经小鼓、大鼓、观音掌,下行很远至涌泉寺。鼓山各景点相 距甚远,显得支离破碎。涌泉寺规模不小,咋说也比少林寺大,门票 三元。建寺虽早,但造像的配置和模样皆为近制。烧香祈福的人很多。
12感觉整个人是在一个立体感十足的空间走着,入眼的除了乾枯的樱花树还是樱花树,似乎整个树林都被樱花树埋没了。

2.2 第2次测试提问:“老荒游福州的行程”:
    在回答中,我们可以非常明确的看出:基于相似性查询的RAG提示工程生效了:

QL> exec proc_qa('老荒游福州的行程');
*** Result:
根据您给定的文档,关于‘老荒游福州’的行程主要涵盖以下几个方面:

1.
**大年初一至五:北京-福州的初体验**


开年第一餐在飞机上享用饺子后抵达福州。当天首站是华林寺、西湖及福建省博物馆以理解
历史底蕴,然后逛三坊七巷感受传统文化氛围。

2.
**大年初四:游玩于自然与人文之中**

   -
题为‘白马双溪之旅’描述一次早起避票游溪的体验。
   -
拜访林则徐纪念馆归元寺地藏寺,对历史人物有了更深刻的感悟,并在游历后感叹福建
的文化底蕴。

3. **大年初六:福州城市的深度探索**


上午游览于山,并特别提到有洗温泉体验;晚上参与市井的热闹生活及本地活动。次日从闽
十八重溪金山寺,感受到自然与人文的和谐共存。

文档中展现出老荒对历史文化遗产
的高度兴致和社会生活的深入体验。其中涉及到福州的自然风光、古老寺庙、名人文化如林
则徐以及市民生活的多元面相都逐一铺展开来。

每一部分行程都有其所代表的独特福州市
内元素:古代遗址的探寻,现代风俗的感知,从华林寺福建省博物馆的历史脉络交织,再
到市井之间的人情冷暖。这样的游历体验不仅丰富了对福州城市印象的理解深度,也让人们
对中国的多元文化生态有了更直接的感受。

通过以上总结描述可以看出,老荒游福州并不
仅仅停留在表面风景或古迹的探索上,而是将旅行深度地浸入城市的历史、人文和生活方式
之中,形成了一个立体且丰富的旅程体验。这样独特的游记不仅展现了旅游的目的地魅力,
也为阅读者提供了一条深入了解福建的独特途径。

以上是根据给定文档摘要的分析结果,
通过总结关键点及细节描述构建了老荒在福州旅行整体的经历框架。

PL/SQL 过程已成功完成。

已用时间:  00: 01: 53.07


2.3 第3和第4次测试提问小游记中的局部景点:“'十八重溪”:
    在回答中,我们可以非常明确的看出:基于相似性查询的RAG提示工程生效了:

SQL>set serveroutput on;
SQL>  exec  proc_qa('十八重溪');
*** Result:
在给定的文本中,找到的所有与"十八重溪"相关的内容如下:

-
这条十八条溪原本就是初步开发,又经去年台风一场,**回归了未开发状态**,这正合我心意
。源溪行,夹岸高山层峦叠翠,蓝天空谷,好不惬意。

---

看来,"十八重溪"在这个文本中
的引用有两处关键:

1.
**恢复未开发状态**:文本提到这条原本就已经初步开发的十八条溪在经过去年台风后回归
了其原始(未开发)的状态。这表明十八重溪是一条具有自然风光的水体或山谷,可能是受
到开发而被部分改变或者维护,然而在经历自然力量如台风之后,它恢复到了其最初、更为
自然的形式和状态。

2.
**描述其地理位置**:十八重溪还与"高家的水库,夹在两座山中间"这一地理场景相联系。
说明十八重溪不仅具有风景如画的特点,在特定的位置上还有着独特的景观特征,即它位于
两个山峰之间,并且与周围的自然环境(如水库)形成了一幅美丽的画面。

通过这两个语
境,我们可以了解到十八重溪是一个结合了自然风光、经历人工和自然力量影响的地理区域


PL/SQL 过程已成功完成。

已用时间:  00: 01: 27.17


    参考《AI Vector Search笔记与实验7》中的《老荒游福州》fz.pdf原文本,我们可以验证以上回答的逻辑性很强:

大年初三: 闽侯十八重溪-金山寺
一早去客运西站乘中巴到闽侯南屿, 下车一打听, 才知十八重溪
在下一个镇
南通。 携程上写错了, 《藏羚羊》 说得对。 路边一个骑
摩托的小伙子说, 我给他 14 块钱, 他就带我去十八重溪。 这个价格
很公道, 我没有理由不接受。 南方的冬天, 田里还是绿油油的。 路上,
司机自我介绍说他在福州做试车手。 我说, 我还以为你是赛车手呢。
司机又说自己什么车都会修。 我说, 看出来了, 这摩托就是你自己攒
的。 没料到路相当远, 我给了司机 15 元。
十八重溪的售票处贴着告示: 由于台风破坏, 景区禁止游客进入。
我不甘心, 对门卫说自己大老远来的, 让我进去看看吧。 对方很通融,
并且没要求我购票。 赛车手也赶上来, 免费把我送到步道, 真是投桃
报李。
这十八重溪原本就是初步开发, 又经去年台风一场, 回归了未开
发, 这正合我心意。 源溪行, 夹岸高山层峦叠翠, 蓝天空谷, 好不惬

意。 半小时后至第九溪, 野渡无人舟不横。 幸水浅, 趟水过去。 此后
主要是在石头上跳跃, 攀上爬下一个半小时, 至一面悬崖, 见一两叠
瀑布。 第一叠约十余米, 下泄入一漏斗般洞穴。 再出, 如白练飞流直
下三四十米, 落入一潭中。 瀑布之上, 悬崖缺口望去, 见三重山、 三
重天。
突然想起论语上的曾皙, 产生了裸泳的念头。 脱去所有身外之物,
试水, 太凉, 旋作罢。 改为风浴。 面朝瀑布, 伫立石上, 伸开四肢,
独享自然的恩赐。
我面对高山喊: “有没有狐仙, 有没有狐仙? ”
我面朝瀑布喊: “有没有女鬼, 有没有女鬼? ”
自然, 保持她一贯的沉默, 因为她从不承诺。
沐浴完毕, 唱着山歌归去。 由于景区封闭, 沿公路走了很久, 才
打到摩的。 至南通, 换乘客车回福州西站。 又去了距此地不远江中的
金山寺。







路过

雷人

握手

鲜花

鸡蛋

QQ|手机版|Bo's Oracle Station   

GMT+8, 2025-2-11 14:39 , Processed in 0.039188 second(s), 21 queries .

返回顶部