2026-01-16

01月16日

一、今日完成情况

  • 跑一下rag项目把,顺便熟悉一下jupter notebook的环境 https://www.bilibili.com/video/BV1wc3izUEUb –完成
  • orion 搜索几个有意思的话题
    • 韩信之死
    • 面相
    • 算命风水
  • 梳理一下Java的发展历史和架构

二、今日感悟

  • 核心业务数据​:
  • ​今日工作总结:​
  • ​明日工作计划:
  • ​今日学习成长:​
    • 白鹿原,白嘉轩说 ”人是个贱虫,人一天到晚坐着浑身不自在,吃饭不香,睡觉不实,总觉得慌惶兮兮。人一干活,吃饭香了,睡觉也踏实了,觉得皇帝都不怯了。‘ 人物隐喻检索 https://www.zgnfys.com/m/a/nfwx-56662.shtml
    • 因为是一个小任务,我就不打开一篇文章专门写了。不过经验还是非常有必要总结的,在和翟老师对接人物的时候,关于学校放假的时间,我不太确定,半信半疑的说是XX日,翟老师说是XX日。 这个事情,说明在和上级领导说话的时候,三思而后说,而且如果数据不确定的话,就可以不说,不说比说错要好。 然后关于其他的问题,我问的是万一有同学回家了怎么办,问出来之后我就后悔了,觉得没有经过思考。这是第二个问题,为什么,因为我没有猜测领导的意图,他的任务是什么,是通知同学们这样子,要求同学这样子,而我的身份是什么,是通知同学这样子,全称不需要知道谁回家了,老师也是尽团队的义务,同学自己到底怎么安排,主要是导师的事情吧,所以我这个问题,就让翟老师有些难堪。 话说的慢一点,想一下再说,这是两个非常好的习惯,这一点我需要向小黑学习。

三、备注

四、rag项目思路总结(AI生成)

一分钟速读

本视频通过Python代码实战,完整拆解了RAG(检索增强生成)系统的两大流程:数据准备(分片、索引)与问答生成(召回、重排、生成)。适合希望从零理解RAG核心原理,并掌握其具体实现步骤的开发者。

一、 RAG系统核心流程总览

  • 核心论点: RAG系统分为用户提问前的数据准备和提问后的问答生成两大部分。
  • 关键细节:
  1. 数据准备阶段: 包括分片(将文档切分为片段)和索引(将片段向量化并存入数据库)。
  2. 问答生成阶段: 包括召回(用问题向量检索相似片段)、重排(精排召回结果)和生成(结合片段生成最终答案)。

二、 项目环境搭建与依赖说明

  • 核心论点: 使用uv包管理器和Jupyter Notebook交互环境构建项目,并安装必要的Python库。
  • 关键细节:
  1. 工具选择:
  • uv: Python包管理器,用于管理依赖。
  • Jupyter Notebook: 交互式代码环境,便于调试。
  1. 核心依赖库及功能:
  • sentence-transformers: 用于加载Embedding模型和CrossEncoder模型。
  • chromadb: 向量数据库。
  • google-generativeai: 调用Google的Gemini模型进行答案生成。
  • python-dotenv: 用于管理API密钥等环境变量。

三、 数据准备阶段:分片与索引

  • 核心论点: 将原始文档处理成可供检索的向量形式并存储。
  • 关键细节:
  1. 分片 (Splitting):
  • 操作: 编写split_into_chunks函数,读取文档并按行切分成字符串列表。
  • 测试: 对示例文档(一篇关于哆啦A梦的虚构文章)进行分片,得到10个片段。
  1. 索引 (Indexing):
  • 向量化: 使用sentence-transformers加载Embedding模型(如all-MiniLM-L6-v2),编写embed_chunk函数将文本片段转换为768维向量。
  • 存储: 使用chromadb创建内存型客户端(PersistentClient可持久化),创建集合(collection),将片段内容、对应向量及ID一并存入。

四、 问答生成阶段:召回、重排与生成

  • 核心论点: 基于用户问题,从知识库中精准检索相关信息并合成答案。
  • 关键细节:
  1. 召回 (Retrieval):
  • 操作: 编写retrieve函数。将用户问题转换为向量,在chromadb中查询最相似的top_k个片段。
  • 问题: 仅靠向量相似度检索,结果排序可能不准确(如正确答案未排第一)。
  1. 重排 (Reranking):
  • 操作: 编写rerank函数。使用CrossEncoder模型对召回的所有片段进行精排。
  • 步骤: 将“用户问题+片段”组合列表输入模型进行打分,按分数倒序排列,取前top_k个片段。
  • 效果: 重排模型能更准确地将相关片段排到前列,有效弥补了单纯向量检索的不足。
  1. 生成 (Generation):
  • 模型选择: 使用Google的gemini-2.0-flash模型(免费)。
  • 准备: 获取API Key并存入.env文件,通过python-dotenv加载。
  • 操作: 编写generate函数。构建包含用户问题和重排后片段的Prompt,发送给大模型生成最终答案。

💡 核心亮点与实操建议

  • 实操/行动指南:
  1. 环境搭建: 使用 uv init 初始化项目,用 uv add 安装sentence-transformerschromadbgoogle-generativeaipython-dotenv
  2. 分片逻辑: 最简单的分片可按行进行,复杂场景可使用基于语义的滑动窗口。
  3. 向量数据库选择: 快速验证用内存型EphemeralClient,生产环境用持久化PersistentClient
  4. 模型调用: Embedding和CrossEncoder模型首次运行会从Hugging Face下载(约400MB),需保持网络畅通。
  5. 重排必要性: 在召回后加入CrossEncoder重排步骤,能显著提升最终答案的相关性。
  • 独家洞察:
  • 流程缺陷揭示: 视频通过展示召回结果排序不佳,直观证明了仅依靠Embedding相似度检索的局限性,从而自然引出重排环节的必要性。
  • 性价比选择: 在生成阶段推荐使用免费的Gemini-2.0-flash模型,降低了学习和实践的门槛。

❓ 延伸思考

问题: 在RAG系统中,如果重排模型(CrossEncoder)已经能非常精准地判断相关性,是否可以直接用它替代召回阶段的向量检索,以简化流程?

启发式解答: 理论上可以,但效率是核心瓶颈。CrossEncoder模型需要对“问题”与“知识库中每一个片段”进行两两计算,当知识库片段数量巨大时(如百万级),计算开销将变得无法承受。而向量检索通过近似最近邻(ANN)算法,能快速从海量向量中筛选出少量候选集。因此,当前“向量检索(粗筛)+ 重排模型(精排)”是兼顾效率精度的经典架构。

五、rag项目代码

使用刚才的思路跑通了流程,因为也是照猫画虎,所以不会遇到什么太极端的问题,都在掌控之中,简单记录一下效果日志:
rag_refactoredmain

Pasted image 20260116160635

每次尝试APi的时候都是涉及到代理网络不通的问题,我打算开一个小坑,看看如何快速排查当前终端可以访问到国外的APi接口。

curl -I https://www.google.com
curl -x http://127.0.0.1:7897 -I https://api.openai.com
Pasted image 20260116160914

快捷指令开启代理端口转发终端流量到Clash verge当中:

proxy_on

开启之后直接就ping通了:

Pasted image 20260116161103

如果运行python代码依然报错的话,那可能是通信协议的问题,

ImportError: Using SOCKS proxy, but the 'socksio' package is not installed. Make sure to install httpx using pip install httpx[socks].

问题原因:

all_proxy=socks5://127.0.0.1:7897 告诉 Python 使用 SOCKS5 协议。而 Google 的新版 SDK 底层使用的是 httpx 这个库。httpx 默认只支持 HTTP 代理

我的代理开关是这样设置的:

``` txt
# 代理开关控制
function proxy_on() {
    export http_proxy="http://127.0.0.1:7897"
    export https_proxy="http://127.0.0.1:7897"
    export all_proxy="socks5://127.0.0.1:7897"
    echo -e "\033[32m代理已开启 (Port: 7897)\033[0m"
    # 验证一下
    curl -I https://www.google.com
}

function proxy_off() {
    unset http_proxy
    unset https_proxy
    unset all_proxy
    echo -e "\033[31m代理已关闭\033[0m"
}

明明设置了 http_proxy,为什么 Python 偏偏要去抓那个会报错的 all_proxy
原因在于 Python 库(特别是 httpxrequests)处理环境变量的优先级逻辑

在 Linux 和 macOS 的标准规范中,环境变量的优先级通常是:

all_proxy > https_proxy > http_proxy

当你的 proxy_on 函数同时导出了这三个变量时,Google SDK 底层的 httpx 库会扫描环境变量。它发现 all_proxy 存在,就会优先使用它。

每日小知识


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 kipleyarch@gmail.com
Obsidian