【大模型学习笔记】一篇文档读懂 RAG 常用用法

一文读懂AI大模型时代的RAG技术 RAG(Retrieval-Augmented Generation,检索增强生成) 是一种结合检索技术与生成模型的技术架构,旨在通过动态引入外部知识库增强大语言模型(LLM)的生成能力。其核心思想是通过检索系统从外部数据源(如企业知识库、实时文档等)获取相关信息,并将检索结果作为上下文输入生成模型,以提高生成答案的准确性、时效性和专业性 阅读详情

轻松一刻:ai能写代码能写文档,为啥不用ai代替程序员呢?ai不给钱就不干活,而且还不能背锅,所以咱们还是得招俩程序员,又能吃饼又能背锅

(文末有调用实例代码rag_qa.py)

1. 为什么要学 RAG

普通 LLM 是闭卷考试:只能答脑子里背过的题,没背过就瞎编。RAG(Retrieval-Augmented Generation,检索增强生成)是开卷考试:先翻书找到相关页面,照着资料答题。

三个普通 LLM解决不了的痛点,决定了RAG的地位:

  • 知识截止:模型只知道训练截止日期之前的事,问“上周的”就抓瞎
  • 私有知识:你公司的制度文档、你电脑里的 PDF,模型从来没见过
  • 幻觉:不知道还硬答,一本正经地胡说八道

什么时候不需要 RAG:写诗改文案(靠模型能力)、数学推理(靠模型脑子,最多配个计算器工具)。判断标准一句话:问题是“知道不知道”,就需要 RAG;问题是“会不会”,就不需要。

💡 为什么不微调(Fine-tune)?

① 微调贵且慢,知识更新要重训;② 微调擅长改风格,不擅长记事实,容易记混;③ RAG 答案可溯源到文档,微调不能。企业知识库场景 95% 选 RAG。两者也可结合:微调教“怎么说”,RAG 给“说什么”。

2. 核心概念速览

RAG 系统分两条流水线:入库(离线,做一次)和查询(在线,每次提问)。

组件

作用

rag_qa.py代码里的对照

Embedding

把文本变成高维向量,语义近则距离近

OpenAIEmbeddings(text-embedding-v3)

TextSplitter

把长文档切成小块

RecursiveCharacterTextSplitter

VectorStore

存块+向量,按语义距离查找

Chroma + persist_directory

Retriever

检索的统一抽象,可进 LCEL 管道

store.as_retriever()

format_docs

把检索结果拼成带编号的资料

rag_qa.py 里的 format_docs()

RAG Prompt

强制“只根据资料回答”

RAG_PROMPT 常量

Reranker

对召回结果精排(进阶)

暂未用

一句话理解:RAG = 先检索后生成。入库像图书馆编目上架,查询像读者查索引卡翻到对应页,再让 LLM 阅读理解后作答。

3. Embedding —— 把文字变成坐标

3.1 基本用法

Embedding 模型把一段文本映射成一个数组(text-embedding-v3 是 1024 维),并且让语义相近的文本向量距离也近。想象把全世界的句子钉在一张地图上:“猫在吃鱼”和“小猫进食”钉在一起,“猫在吃鱼”和“股票大跌”离得很远——Embedding 就是句子的语义坐标。

from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings(
    model="text-embedding-v3",          # 阿里的向量模型,中文效果好
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    check_embedding_ctx_length=False,      # 坑:不关会报 contents is neither str...
)

⚠️ 容易踩的坑(重要)

OpenAIEmbeddings 默认先用 tiktoken 把文本切成 token 数组再发(OpenAI 官方接口支持),但 DashScope 兼容接口只收字符串,报错 contents is neither str nor list of str。设 check_embedding_ctx_length=False 改为直接发字符串。以后接任何国产模型 Embedding 都要想到这层。

3.2 距离怎么算

度量

直觉

备注

余弦相似度

两向量方向是否一致,不看长度

文本检索主流,越大越相似

欧氏距离 L2

坐标空间两点的直线距离

Chroma 默认,越小越相似

⚠️ 方向别搞反

Chroma 的 similarity_search_with_score 返回的是距离,越小越好;很多教程里的“相似度分数”越大越好。方向反了,阈值过滤就会反向淘汰好结果。

3.3 常用模型选型

模型

来源

特点

text-embedding-v3

阿里

OpenAI 兼容接口,中文强,便宜

bge-large-zh / bge-m3

智源开源

可本地部署,中文榜单前列,免费

text-embedding-3-small/large

OpenAI

效果标杆,需海外网络

🚨 铁律

入库和查询必须用同一个 Embedding 模型。不同模型的向量空间完全不同——A 模型入库、B 模型查询,等于用英语索引卡查中文书。升级模型 = 全量重新入库。

# 感受"语义距离":数值越大越相似
pairs = [
    ("小猫在吃鱼", "猫正在进食"),
    ("小猫在吃鱼", "今天股票大跌"),
    ("怎么退款", "退款流程是什么"),
]
for a, b in pairs:
    va, vb = embeddings.embed_query(a), embeddings.embed_query(b)
    score = np.dot(va, vb) / (np.linalg.norm(va) * np.linalg.norm(vb))
    print(f"{a} vs {b}: {score:.4f}")  # 括号里那对会明显更高

4. 文档加载 —— Loader

LangChain 用一整套 Loader 处理不同格式,统一输出 Document 对象(page_content + metadata)。rag_qa.py 里为了教学用的是直接 open() 读文件,实际项目换 Loader 就行:

from langchain_community.document_loaders import TextLoader, PyPDFLoader, Docx2txtLoader
# from langchain_community.document_loaders import WebBaseLoader   # 网页
# from langchain_community.document_loaders import CSVLoader       # 表格

docs = PyPDFLoader("产品手册.pdf").load()      # 每页一个 Document
for d in docs:
    d.metadata["source"] = "产品手册.pdf"   # 手动补来源,检索时可过滤、回答时可溯源

格式

Loader

需安装

txt / md

TextLoader

—

PDF

PyPDFLoader

pip install pypdf

Word

Docx2txtLoader

pip install docx2txt

网页

WebBaseLoader

pip install beautifulsoup4

文件夹批量

DirectoryLoader("docs/", glob="**/*.pdf")

—

⚠️ PDF 是个深坑

扫描件 PDF 没有文字层,读出来是空的,需要 OCR;表格被拆散、双栏排版顺序错乱也常见。企业级方案通常用专门的文档解析服务。

5. 文本切分 —— RAG 效果的第一决定因素

5.1 为什么要切

① Embedding 模型有输入长度限制;② 长文本的向量是“平均味”——一整篇文章压成一个向量,什么都像又什么都不像;③ 只把相关小块给 LLM,省 token 又聚焦。

5.2 RecursiveCharacterTextSplitter(默认首选)

递归策略:优先按段落切(\n\n),块还超尺寸就降级到行(\n)、再降到句号、逗号,最后才硬切字符——尽量让每块语义完整。

splitter = RecursiveCharacterTextSplitter(
    chunk_size=300,        # 每块目标字符数
    chunk_overlap=50,     # 相邻块重叠 50 字符
    separators=["\n\n", "\n", "。", ";", ",", " ", ""],  # 中文要加"。"";"
)

5.3 chunk_size 怎么选

块大小

优点

缺点

适合

小(100-300)

向量味纯,检索准

上下文碎

FAQ、条款类

大(800-1500)

上下文完整

向量语义稀释,检索粗

长论述推理

没有万能值,一定拿自己的语料实验

5.4 chunk_overlap 为什么存在

防止关键信息骑在切块边界上被腰斩:“年费是 5 万——”和“元,含免费维护”切成两块,两块都不完整。重叠 50 字符就是给相邻块留缓冲带。你实测里“支持私有化部署”的信息排在召回第 4 位,就是靠重叠内容被带进上下文的。

5.5 Markdown 结构化切分

from langchain_text_splitters import MarkdownHeaderTextSplitter

headers = [("#", "h1"), ("##", "h2"), ("###", "h3")]
md_split = MarkdownHeaderTextSplitter(headers, strip_headers=False)
sections = md_split.split_text(markdown_text)   # 每个小节一个块,且 metadata 带 h1/h2/h3
# metadata["h2"] == "主要产品线" → 检索时可按章节过滤,回答时可标注"出自哪一章"

💡 生产常用组合拳

先用 MarkdownHeaderTextSplitter 按章节切开(拿干净 metadata),再对每章用 RecursiveCharacterTextSplitter 二次切小。既保结构,又保粒度。

6. 向量数据库 —— Chroma

6.1 建库与落盘

from langchain_chroma import Chroma

# 建库并落盘(persist_directory 让数据存到磁盘,重启不丢)
store = Chroma.from_texts(
    texts=chunks,
    embedding=embeddings,
    persist_directory="./rag_chroma_db",
    metadatas=[{"source": "company_knowledge.md"}] * len(chunks),  # 可选:溯源用
    collection_name="my_kb",   # 多个知识库分开存,一个 collection = 一个库
)

# 下次启动直接加载,不重复算 Embedding(省时间省钱)
store = Chroma(persist_directory="./rag_chroma_db", embedding_function=embeddings)

rag_qa.py 里的 build_vectorstore(force_rebuild) 就是这个逻辑:目录存在就加载,不存在就建——改了语料才需要重建。

6.2 检索的几种方式

# 检索:返回 Top-K 相似的块
docs = store.similarity_search("怎么退款", k=3)

# 带分数检索(分数是距离,越小越相似——注意不是越大越好!)
docs_scores = store.similarity_search_with_score("怎么退款", k=3)

# 增量添加新文档(不用重建整个库)
store.add_texts(["新的知识内容..."])

# 按 metadata 过滤检索(多知识库/权限隔离的基础)
docs = store.similarity_search("价格", k=3, filter={"source": {"$eq": "price.pdf"}})

6.3 选型速查

方案

类型

适合

Chroma

嵌入式(本地文件)

学习、原型、单机小项目(你在用)

FAISS

库(Meta 开源)

单机、量大、追求速度

Milvus / Qdrant

独立服务(分布式)

生产、海量、高并发

pgvector

PostgreSQL 插件

已有 PG 栈,数据要和业务表 JOIN

💡 好消息

LangChain 屏蔽了差异:Chroma/FAISS/Qdrant 接口一致(from_documents / similarity_search / as_retriever)。学习期用 Chroma,将来切 Milvus 基本只改 import 和建库两行。

7. 检索策略 —— 不只是 Top-K

7.1 as_retriever():向量库的管道化

任何东西只要能“输入问题、输出文档列表”,就能包装成 Retriever 插进 LCEL 管道——这是 RAG 链能写成 {retriever | format_docs} 的基础:

retriever = store.as_retriever(search_kwargs={"k": 3})
docs = retriever.invoke("DocMind 怎么收费")   # 和 similarity_search(k=3) 等价
# 它能直接进 LCEL 管道 —— 这就是 RAG 链的 {retriever | format_docs} 部分

7.2 三种基础模式

模式

行为

什么时候用

similarity(默认)

最相近的 K 个

绝大多数场景

mmr

既相关又彼此不重复的 K 个

召回总是换汤不换药的重复块时

similarity_score_threshold

只留相似度过线的

过滤弱相关噪声

# Maximal Marginal Relevance: 先找最相关的 1 块,再挑"相关但和已选的不重复"的
retriever = store.as_retriever(
    search_type="mmr",
    search_kwargs={"k": 4, "fetch_k": 20},  # 先粗取20块,再从里头挑多样的4块
)

7.3 K 值怎么调

K 太小(1-2)答案只看局部,漏信息;K 太大(10+)噪声块涌入,模型被带偏还烧 token。经验起点 3-5,配合 Reranker 效果最好。动手实验:把 answer() 里的 k=3 改成 k=1,再问“云帆智能有哪些产品线”——答案立刻残缺,这就是 K 值的意义。

8. 高级检索 —— 检索不准了怎么救

基础检索打不稳,问题多半出在问题的表述和文档的表述对不上。四个招数按成本从低到高:

8.1 MultiQueryRetriever:让 LLM 把问题问出花来

用户问“这玩意儿贵不贵”,文档写的是“计费方式:按容量收费”——向量对不上。MultiQuery 让 LLM 先把问题改写成多个角度,各查一遍再合并去重:

from langchain.retrievers.multi_query import MultiQueryRetriever
import logging
logging.getLogger("langchain.retrievers.multi_query").setLevel(logging.INFO)  # 能看到改写出的问题

mq_retriever = MultiQueryRetriever.from_llm(retriever=base_retriever, llm=llm)
# "多少钱" → 被改写成: "价格是多少" "收费标准" "计费方式" → 各查3块 → 合并去重

8.2 HyDE:先编一个假答案,拿它去搜

反直觉但好用:让 LLM 先假想一个答案(细节可以是编的),用假答案去检索——因为答案和文档的向量距离,往往比问题和文档更近:

from langchain.retrievers import HypotheticalDocumentEmbedder

hyde = HypotheticalDocumentEmbedder.from_llm(llm, base_embeddings, prompt_key="web_search")
# 问题"DocMind私有化多少钱" → LLM编一个假的产品页段落 → 用它检索 → 命中真产品页

8.3 父子块:小块检索,大块回答

解决“块小检索准,但上下文不够”的矛盾:用小块(子)算向量和检索,命中后返回它所属的大块(父)给 LLM:

from langchain.retrievers import ParentDocumentRetriever
from langchain.storage import InMemoryStore

# 子切分器(检索用,小块) / 父切分器(回答用,大块)
child_splitter = RecursiveCharacterTextSplitter(chunk_size=150)
parent_splitter = RecursiveCharacterTextSplitter(chunk_size=1000)
docstore = InMemoryStore()   # 存"子块id → 父块全文"的映射

pdr = ParentDocumentRetriever(
    vectorstore=store, docstore=docstore,
    child_splitter=child_splitter, parent_splitter=parent_splitter,
)

8.4 混合检索:向量 + 关键词

向量检索擅长“意思相近”,但对型号、编号、人名这类精确关键词反而拉胯(H-2000 和 H2001 的向量可能很近)。BM25 是传统关键词检索,两者互补,结果用 RRF 融合:

# 思路示意:两路检索,各取Top-K,按排名倒数融合
vec_docs = store.similarity_search(q, k=5)          # 语义路
kw_docs  = bm25_retriever.invoke(q)                  # 关键词路(BM25Retriever)
# doc 在两路中的排名 r 越靠前,RRF 分数 = 1/(60+rank) 越高 → 合并排序

💡 怎么选?决策顺序

① 跑基础检索看 bad case:是“没召回”还是“召回了但排序差”?② 没召回 → MultiQuery(成本最低);③ 召回对了但缺上下文 → 父子块;④ 精确关键词查不到 → 混合检索;⑤ 好块排后面 → Reranker(下一章)。

9. Reranker —— 粗排之后的精排

Embedding 检索是“海选”:快但粗。Reranker 是“评委席”:慢(每对〈查询,文档〉单独打分)但准。区别在结构——Embedding 是双塔(问题和文档分别编码再比距离,没“见过面”),Reranker 是交叉编码(拼在一起进模型,逐字互动)。

生产标配是两阶段:Embedding 召回 Top-20/50 → Reranker 精排 → 取 Top-2/3 进 LLM。好块本来在第 8 名,精排后提到第 1。

from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CrossEncoderReranker
from langchain_community.cross_encoders import HuggingFaceCrossEncoder

# 本地跑一个开源 reranker(BGE 系列,中文强)。需: pip install sentence-transformers
reranker = CrossEncoderReranker(
    model=HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-base"),
    top_n=2,   # 20个候选精排后只留最好的2块给LLM
)
compression_retriever = ContextualCompressionRetriever(
    base_compressor=reranker, base_retriever=store.as_retriever(search_kwargs={"k": 20})
)

10. Prompt 组装与防幻觉

检索是“把书翻到对的那页”,Prompt 是“考场的答题要求”。rag_qa.py 里的 RAG_PROMPT 包含三个关键要素:

你是一位知识库问答助手。请只根据下面的【检索资料】回答用户问题。        # ① 角色约束
如果资料里没有相关内容,直接说"知识库中未找到相关信息",禁止编造。    # ② 兜底出口 ★最重要
回答末尾标注依据的资料编号,例如[资料1]。                             # ③ 溯源要求

【检索资料】
{context}

用户问题: {question}

为什么兜底出口最重要:LLM 天性是“一定给你答点什么”,不给台阶它就硬编。有了这句,问“OpenAI 是谁创立的”才能得到“未找到相关信息”而不是一篇编造的百科。允许模型说不知道,是防幻觉的第一道闸。

10.1 组块格式:带编号,方便引用

def format_docs(docs):
    return "\n\n".join(f"[资料{i+1}] (来源:{d.metadata.get('source','未知')})\n{d.page_content}"
                   for i, d in enumerate(docs))

10.2 生成参数

temperature 建议 0~0.2(你用的 0.1):要忠于原文,不要自由发挥。max_tokens 按需设上限,防止长篇大论稀释重点。

🤔 答案对不上资料,怪谁?排查顺序

① 检索根本没召回正确块(检索问题,第 7-9 章的药)→ ② 召回了但 Prompt 没约束住(Prompt 问题)→ ③ 资料本身自相矛盾(数据治理问题)。RAG 效果差八成是第一种——调试时永远先看“检索到了什么”再看“模型答了什么”。你界面里的“检索到的原文块”面板就是为这个准备的。

11. 完整 RAG 链 —— LCEL 标准写法

rag_qa.py 的 answer() 为了在界面展示检索详情写得偏教学,生产标准写法是文件末尾注释里那版——检索只调一次,整条链一个表达式:

# 准备 20 个测试问题 + 每题标注的正确块id
hits = 0
for q, gold_id in test_set:
    docs = retriever.invoke(q)
    if gold_id in [d.metadata["id"] for d in docs]:
        hits += 1
print(f"Hit Rate: {hits/len(test_set):.1%}")
# 改了 chunk_size / 加了 Reranker → 重跑一遍 → 数字对比 → 调优有依据

对照你学过的 LangChain:这就是 LCEL 管道符——retriever | format_docs 表示检索结果自动流给格式化函数;字典做并行分发(context 走检索,question 原样传递);后面接 Prompt、LLM、解析器。Day 2 的管道符 + Day 3 的检索,拼起来就是一条生产级 RAG 链。

12. 评估 —— 怎么知道做得好不好

分两层看:检索层(正确块进 Top-K 了吗)和生成层(答案忠于资料吗)。最朴素但够用的方法——Hit Rate:

# 准备 20 个测试问题 + 每题标注的正确块id
hits = 0
for q, gold_id in test_set:
    docs = retriever.invoke(q)
    if gold_id in [d.metadata["id"] for d in docs]:
        hits += 1
print(f"Hit Rate: {hits/len(test_set):.1%}")
# 改了 chunk_size / 加了 Reranker → 重跑一遍 → 数字对比 → 调优有依据

自动化评估用 Ragas(pip install ragas,LLM 当裁判)四个核心指标:

# pip install ragas  —— 用 LLM 自动打分
from ragas import evaluate
from ragas.metrics import faithfulness, answer_relevancy, context_precision, context_recall

result = evaluate(
    dataset,  # 包含 question / answer / retrieved_contexts / ground_truth 四列
    metrics=[faithfulness, answer_relevancy, context_precision, context_recall],
)

指标

含义

对应层

context_recall

该召回的都召回了?

检索

context_precision

召回的都有用?好块排在前面?

检索

faithfulness

答案每句话都有资料支撑?

生成

answer_relevancy

答案答的是问的问题?

生成

💡 实用主义评估法

没有标注集时:准备 15-20 个真实问题,人工看两件事——检索面板里第一条对不对(检索质量)、答案有没有编(生成质量)。糙,但能发现 80% 的问题,而且你的 rag_qa.py 现在就能做。

13. 常见坑速查表

症状

根因

解法

答案完全是编的

检索没命中 + Prompt 没兜底出口

加“没找到就明说”,查召回日志

中文场景效果差

separators 没加中文标点

切分器加“。”和“;”

召回一堆重复块

纯 similarity + 块重叠大

换 mmr

型号/编号查不到

纯向量检索

混合检索 + BM25

改了语料没生效

旧向量库被直接加载

删 rag_chroma_db 重建或增量更新

API 报 contents neither str

OpenAIEmbeddings 发 token 数组

check_embedding_ctx_length=False

分数过滤反向淘汰

把距离当相似度

Chroma 的 score 越小越相似

升级模型后检索崩了

新旧向量空间混用

换 Embedding 模型必须全量重建

14. 速查表

从零搭一条 RAG 链的最短路径(背下来):

1. 加载:  TextLoader / PyPDFLoader → Document 列表

2. 切分:  RecursiveCharacterTextSplitter(chunk_size=300, chunk_overlap=50)

3. 入库:  Chroma.from_texts(texts, embeddings, persist_directory=...)

4. 检索:  store.as_retriever(search_kwargs={"k": 3})

5. 组装:  {context: retriever | format_docs, question: RunnablePassthrough()}

6. 生成:  | RAG_PROMPT | llm | StrOutputParser()

调优优先级(效果不对时按这个顺序查):切分参数 → 检索 K 值/模式 → MultiQuery/混合检索 → Reranker → Prompt 约束 → 换 Embedding 模型(最后才动,要全量重建)。

下一步:RAG 之后是 LangGraph——把 RAG 包成 Agent 的一个工具,让 Agent 自己决定“这个问题要不要查知识库”。那时你会同时用到 Day 1 的 Function Calling 和这份笔记里的 RAG。

实例代码rag_qa.py

import os
import time
from dotenv import load_dotenv

load_dotenv()  # 读取 .env 里的 DEEPSEEK_API_KEY / DASHSCOPE_API_KEY

# ============================================================
# 模型配置
# ============================================================
# LLM 用 DeepSeek(生成回答)
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

llm = ChatOpenAI(
    model="deepseek-chat",
    api_key=os.getenv("DEEPSEEK_API_KEY"),
    base_url="https://api.deepseek.com",
    temperature=0.1,  # RAG 场景建议低温:答案要忠于检索到的原文,不要自由发挥
)

# Embedding 用通义千问(DeepSeek 没有提供 Embedding 接口,
# 阿里的 DashScope 提供 OpenAI 兼容接口, langchain_openai 可以直接调)
embeddings = OpenAIEmbeddings(
    model="text-embedding-v3",
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
    # 关键坑: 默认会把文本先切成 token 数组再发, 但 DashScope 只收字符串,
    # 不关这个参数会报 "contents is neither str nor list of str"
    check_embedding_ctx_length=False,
)

# ============================================================
# 第一步: 加载文档
# ============================================================
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_chroma import Chroma

KNOWLEDGE_FILE = os.path.join(os.path.dirname(__file__), "rag_docs", "company_knowledge.md")
PERSIST_DIR = os.path.join(os.path.dirname(__file__), "rag_chroma_db")  # 向量库落盘位置


def load_document(path: str) -> str:
    """读文件。真实项目里会用 PyPDFLoader/Docx2txtLoader 等,这里从简."""
    with open(path, encoding="utf-8") as f:
        return f.read()


# ============================================================
# 第二步: 切分文档
# ============================================================
def split_document(text: str):
    """
    RecursiveCharacterTextSplitter 的"递归"体现在:
    先尝试用 \n\n(段落)切 → 块太大就退而用 \n(行)→ 再大就切句 → 最后硬切字符。
    目的是尽量让每个块语义完整。

    chunk_size:    每块目标字符数
    chunk_overlap: 相邻块重叠的字符数,防止关键信息正好被切断
    """
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=300,
        chunk_overlap=50,
        separators=["\n\n", "\n", "。", ";", ",", " ", ""],  # 中文场景记得加"。"和";"
    )
    chunks = splitter.split_text(text)
    return chunks


# ============================================================
# 第三步: 向量化并写入 Chroma
# ============================================================
def build_vectorstore(force_rebuild: bool = False):
    """
    如果本地已经落盘过(rag_chroma_db 目录存在)就直接加载,不用重新算 Embedding
    (省时间也省钱)。force_rebuild=True 时强制重建——改了语料后需要重建。
    """
    if os.path.exists(PERSIST_DIR) and not force_rebuild:
        print(f"[向量库] 直接加载已有库: {PERSIST_DIR}")
        return Chroma(
            persist_directory=PERSIST_DIR,
            embedding_function=embeddings,
        )

    text = load_document(KNOWLEDGE_FILE)
    chunks = split_document(text)
    print(f"[切分] 原文 {len(text)} 字符 → {len(chunks)} 个块")
    for i, c in enumerate(chunks[:3]):
        print(f"  块{i + 1} ({len(c)}字): {c[:60]}...")

    store = Chroma.from_texts(
        texts=chunks,
        embedding=embeddings,
        persist_directory=PERSIST_DIR,  # 传了这个参数就会自动落盘
    )
    print(f"[入库] {len(chunks)} 个块已向量化并存入 Chroma")
    return store


# ============================================================
# 第四步: 检索
# ============================================================
def retrieve(store: Chroma, question: str, k: int = 3):
    """
    similarity_search 做的事:
    1. 把 question 也变成向量(用同一个 Embedding 模型!)
    2. 在 Chroma 里找语义距离最近的 k 个块
    """
    docs = store.similarity_search(question, k=k)
    print(f"\n[检索] 问题: {question!r}")
    for i, d in enumerate(docs):
        # page_content 是块内容, metadata 里可以放来源/页码(溯源用)
        print(f"  召回{i + 1}: {d.page_content[:70]}...")
    return docs


# ============================================================
# 第五、六步: 组装 Prompt + LCEL 生成
# ============================================================
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

# RAG 的灵魂就是这个 Prompt: 强制模型"只根据给定资料回答"
RAG_PROMPT = ChatPromptTemplate.from_messages([
    ("system",
     "你是知识库问答助手。请只根据下面的【检索资料】回答用户问题。\n"
     "如果资料里没有相关内容,直接说'知识库中未找到相关信息',禁止编造。\n"
     "回答末尾标注依据的资料编号,例如[资料1]。\n\n"
     "【检索资料】\n{context}"),
    ("human", "{question}"),
])


def format_docs(docs) -> str:
    """把检索到的块拼成带编号的资料文本(编号方便模型引用溯源)"""
    return "\n\n".join(
        f"[资料{i + 1}] {d.page_content}" for i, d in enumerate(docs)
    )


def answer(question: str, use_rag: bool, store: Chroma) -> tuple[str, str]:
    """
    返回 (回答, 检索过程文本)。
    use_rag=False 时走普通 LLM —— 用于直观对比"没有检索会怎样"。
    """
    if not use_rag:
        print(f"\n[直答] 问题: {question!r} (未使用RAG)")
        chain = ChatPromptTemplate.from_messages([("human", "{question}")]) | llm | StrOutputParser()
        return chain.invoke({"question": question}), "(未启用检索)"
    docs = retrieve(store, question, k=3)
    retrieved_text = "\n\n".join(
        f"召回{i + 1}: {d.page_content[:120]}..."
        for i, d in enumerate(docs)
    )

    # 检索只发生一次,结果直接作为 context 塞进链里
    chain = RAG_PROMPT | llm | StrOutputParser()
    answer_text = chain.invoke({
        "context": format_docs(docs),
        "question": question,
    })
    return answer_text, retrieved_text


# ============================================================
# Gradio 界面 (Gradio 6.0: theme 参数放在 launch 里)
# ============================================================
import gradio as gr


def create_interface():
    store = build_vectorstore()

    def on_submit(question: str, use_rag: bool):
        if not question.strip():
            return "请输入问题", ""
        try:
            ans, retrieved = answer(question, use_rag, store)
            return ans, retrieved
        except Exception as e:
            return f"出错了: {e}", ""

    with gr.Blocks(title="RAG 文档问答系统") as demo:
        gr.Markdown(
            "## 📚 RAG 文档问答系统\n"
            "**知识库**: rag_docs/company_knowledge.md (虚构公司资料,模型不可能认识——"
            "全靠检索)\n\n"
            "试试问: 云帆智能是做什么的 / DocMind 怎么收费 / 免费试用政策是什么"
        )
        with gr.Row():
            with gr.Column():
                question = gr.Textbox(
                    label="你的问题",
                    placeholder="例如: 云帆智能的 DocMind 是怎么收费的?",
                    lines=2,
                )
                use_rag = gr.Checkbox(label="使用 RAG 检索(取消勾选=纯LLM直答,观察幻觉)", value=True)
                btn = gr.Button("提问", variant="primary")
            with gr.Column():
                output = gr.Markdown(label="回答")
        with gr.Accordion("🔍 检索到的原文块", open=False):
            retrieved_box = gr.Textbox(label="召回内容", lines=8)

        btn.click(on_submit, [question, use_rag], [output, retrieved_box])
        question.submit(on_submit, [question, use_rag], [output, retrieved_box])
    return demo


if __name__ == "__main__":
    demo = create_interface()
    demo.launch(server_name="127.0.0.1", server_port=7862, theme=gr.themes.Soft())

CVAT自动标注避坑指南:从nuctl安装到YOLOv5模型部署的完整流程 本文详细介绍了在CVAT中部署YOLOv5自动标注功能的完整流程与避坑指南。重点解决了从nuctl工具安装、项目创建时因网络问题导致的镜像拉取失败,到最终模型函数部署与CVAT集成的关键步骤。针对国内网络环境,提供了实用的镜像替换方案,帮助用户顺利完成基于CPU的自动化标注环境搭建。 阅读详情

相关推荐

深入解析.Net中SM2与sm-crypto的跨平台加解密实践

本文深入探讨了在.Net平台与前端sm-crypto库之间实现SM2国密算法跨平台加解密的实践方案。针对对接中常见的密钥格式、密文拼接顺序(C1C3C2与C1C2C3)等核心难点,提供了基于BouncyCastle的完整工具类实现、前后端联调示例及问题排查指南,旨在帮助开发者构建安全、兼容的数据加密通道。

weixin_29322855的博客 370

一文读懂:大模型RAG(检索增强生成)

本文概述 RAG 的核心算法,并举例说明其中的一些方法。RAG融合是一个强大的功能,能够提高RAG应用的语义搜索效率。通过使用语言模型生成多个查询并对搜索结果进行重新排序,RAG融合可以呈现更丰富多样的内容,并提供了一个额外的层次,用于调整应用。此外,RAG融合还可以实现自动纠正、节省成本以及增加内容多样性。但是,需要注意一些权衡,比如潜在的延迟问题、自动纠正的挑战以及成本影响。对于依赖常见概念但可能出现内部行话或重叠词汇的应用来说,RAG融合尤其有用。

m0_59164304的博客 4万+

一文搞懂雷达脉冲压缩和匹配滤波器

为了解决传统单频脉冲雷达面临的作用距离和空间分辨力之间的矛盾,脉冲压缩理论被提出。在接收端设计一个和发射信号能够“共轭匹配”的网络来实现脉冲压缩。接收到的回波信号通过匹配滤波器时,滤波器的增益在信号越强的频率点越大;在信号越弱的频率点,增益越小,通过这样的方式使信号在时域更加集中。脉冲压缩技术大致可分为线性调频(LFM)和相位编码。其中LFM信号易于通过硬件或各种技术产生,但是进行匹配滤波后主旁瓣比高达13.2dB,在检测多个目标时,强目标的回波旁瓣可能会把弱小信号覆盖,导致弱小信号的检测受到影响。

FPGA入门到跑路 9937

大模型RAG:文档分块方案与RAG全流程

我们知道,大模型在预训练阶段获取的知识是有限的,一般需要数据增强模块引入外部知识库,通过知识检索的方式搜索于用户提问相关的知识,这也是RAG相关应用架构出现的原因。但这又引申出另一个问题,外部知识文档往往比较长,可能是包含几十页甚至数百页的内容,如果直接使用会存在以下问题:大模型在预训练过程都有上下文长度限制,如果超过长度限制大模型会将超出部分丢弃,从而影响回答的性能表现。

qingkahui24689的博客 2957

DINOv2 基于自定义数据集进行图片分类预测

(前提是安装好pytorch)1. pip安装2. 下载dinov2提供的预训练模型,需要自行前往网站上查找dinov2模型进行下载。模型需要下载三个文件:下载完成后将上述三个文件放置在本地一个名为dinov2_base的文件夹中即可。

sinat_34770838的博客 6665

【算法设计与分析】期末复习题(超详细)

刚刚整理了一下电脑的文件,发现了这份上学期的算法设计与分析期末复习题,有需要的文后自取。

a1234567822的博客 6614

一文读懂大模型RAG(非常详细),零基础入门到精通,看这一篇就够了

一文读懂大模型RAG(非常详细),零基础入门到精通,看这一篇就够了

分享Python知识 2351

AI Agent实战:WorkBuddy安装部署、任务执行与模型接入全教程

AI Agent是当前自动化办公与智能工作流的核心技术,它区别于传统问答式AI,能够理解目标、拆解任务并调用工具交付完整成果。其底层原理基于任务规划、工具调用与结果验证的循环机制,让机器从“提供建议”进化为“完成任务”。在工程实践中,合理配置模型服务(如接入DeepSeek)、设计标准化Skill(技能包)与自定义指令,可以显著提升Agent在报告生成、数据分析、竞品调研等场景中的稳定性与效率。WorkBuddy作为典型的任务式AI工作台,为运营、产品、开发等多角色提供了统一入口,覆盖安装部署、任务描述公式

weixin_26712075的博客 289

AI大模型RAG实战教程,从入门到精通,非常详细,看这一篇就够了!!

RAG(Retrieval Augmented Generation, 检索增强生成)是一种技术框架,其核心在于当 LLM 面对解答问题或创作文本任务时,首先会在大规模文档库中搜索并筛选出与任务紧密相关的素材,继而依据这些素材精准指导后续的回答生成或文本构造过程,旨在通过此种方式提升模型输出的准确性和可靠性。RAG 技术架构图介绍:富文本 主要存储于 txt 文件中,因为排版比较整洁,所以获取方式比较简单实战技巧:【版面分析——富文本txt读取】

m0_48891301的博客 5019

jira的详细使用教程

​jira的详细使用教程,1,Jira- 是一款缺陷管理软件工具,用其进行缺陷的管理和跟踪。(是B/S架构的软件) 2,主要涉及的角色: 3,具体工作流 添加工作流 1.点击项目设置

计算机毕业论文源码,学生个人网页制作html源码。贴近用户做网络推广和互联网优化。 3295

基于STM32单片机智能循迹小车毕业设计

本文介绍了一种利用STM32F103C8T6单片机为控制核心,结合多种传感器以及PID算法实现循迹避障功能的智能小车。随着我国高科技水平的不断提高和工业自动化进程的不断推进,智能小车被广泛应用于各种玩具和其他产品的设计中,极大地丰富了人们的生活。本次设计利用反射式红外光电传感器探测路面黑线实现小车循迹,利用超声波测距传感器探测路径上的障碍,控制小车自动避障,整个系统具有自动循迹、自动避障、速度检测和无线遥控功能。其中,控制部分采用STM32F103C8T6单片机,STM32F103C8T6单片机是一

qq_48771816的博客 3974

RAGFlow:让大模型真正读懂公司所有文档的开源 RAG 引擎

RAGFlow 是 infiniflow 团队开源的一款 基于深度文档理解的 RAG(Retrieval-Augmented Generation)引擎。

2301_81888214的博客 1752

YOLOv26全流程实战手册:从yaml配置拆解到训练推理参数调优(附虚拟环境搭建)

以“车辆、行人、小型物体”3类数据集为例,修改# 1. 修改类别数nc: 3# 2. 调整锚框(适配小目标)anchors:- [12,16, 16,24, 33,23] # 增加小锚框# 3. 轻量化调整(边缘部署)depth_multiple: 0.25 # 降低深度系数width_multiple: 0.20 # 降低宽度系数# 其余Backbone/Head结构不变yaml配置:核心是调整nc(类别数)、(轻量化)、anchors(适配目标尺度);虚拟环境。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 878

一文读懂AI大模型时代的RAG技术,看这一篇就够了!

大模型的「阿喀琉斯之踵」 知识截止:ChatGPT等大模型知识停留在2023年10月,无法处理2024年的实时数据 幻觉问题:在专业领域(医疗/法律)容易生成错误信息,如虚构「Googly Retriever」犬种 数据壁垒:企业私域数据无法安全注入通用大模型

weixin_72959097的博客 2850

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【大模型学习笔记】一篇文档读懂 LangChain 常用用法

还在用 requests.post() 手写大模型调用?本文带你用 LangChain 的 | 管道符,把模型调用、提示词模板、输出解析、记忆、RAG 检索和 Agent 串联成一条条清晰可复用的链。从基础对话到 RAG 全链路,配速查表与学习路线,助你彻底告别重复样板代码。

tiny_monster的博客 336

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

大模型 RAG:文档分块方案与 RAG 全流程

大模型在预训练阶段获取的知识是有限的,一般需要数据增强模块引入外部知识库,通过知识检索的方式搜索于用户提问相关的知识,这也是 RAG 相关应用架构出现的原因。但这又引申出另一个问题,外部知识文档往往比较长,可能是包含几十页甚至数百页的内容,如果直接使用会存在以下问题所以我们需要根据一定策略将文本切分为小块,以便适应大模型的上下文窗口,同时提高知识检索的精度。分块的目标RAG分块策略:主流方法(递归、jina-seg)+前沿推荐(Meta-chunking、Late chunking、SLM-SFT)

weixin_44245188的博客 2057

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

【AI大模型】一文读懂从RAG到多模态RAG,收藏这一篇就够了!!

如果说2023年见证了大语言模型的“寒武纪大爆发”,那么2024年则是多模态大模型“元年”。GPT-4o的出现让大家见识到多模态能力引入,给下游应用生态带来的巨大改变。随之而来的,RAG技术也将逐渐从单语言模态的RAG进化到多模态RAG。本文将带大家速览多模态RAG技术的原理及实现。

Android23333的博客 1084

langchain学习笔记之基于RAG实现文档问答

本节将介绍使用langchain基于RAG的文档问答以及具体实现方法。

静静的学习就好 1389

一文读懂大模型:LLM大模型RAG

RAG(中文为检索增强生成) = 检索技术 + LLM 提示。例如,我们向 LLM 提问一个问题(answer),RAG 从各种数据源检索相关的信息,并将检索到的信息和问题(answer)注入到 LLM 提示中,LLM 最后给出答案。

Y525698136的博客 1121

【AI大模型】如何从文档创建 RAG 评估数据集,收藏这一篇就够了!!

检索增强生成 (RAG) [1] 是一种允许 LLM 访问外部知识库的技术。 通过上传 PDF 文件并将其存储在矢量数据库中,我们可以通过矢量相似性搜索检索这些知识,然后将检索到的文本作为附加上下文插入到 LLM 提示中。 这为LLM提供了新的知识,并减少了LLM编造事实(幻觉)的可能性。

2401_85327249的博客 1241

大模型RAG入门到实战基础教程(非常详细),大模型RAG入门到精通,收藏这一篇就够了!

大模型(Large Language Model,LLM)的浪潮已经席卷了几乎各行业,但当涉及到专业场景或行业细分域时,通用大模型就会面临专业知识不足的问题。相对于成本昂贵的“Post Train”或“SFT”,基于RAG的技术方案往成为一种更优选择。本文从RAG架构入手,详细介绍相关技术细节,并附上一份实践案例。前排提示,文末有大模型AGI-优快云独家资料包哦!本文列举了LLM的问题。简单介绍了什么是 RAG ,以及 RAG 的流程。最后使用了一个简单的LangChain代码示例来展示 RAG 的使用。

2301_76161259的博客 3775

一文读懂:DeepSeek大模型时代,RAG是什么?为什么需要 RAG?RAG的原理和流程?

一文读懂:DeepSeek大模型时代,RAG是什么?为什么需要 RAG?RAG的原理和流程?

吴所畏惧 5059

AI大模型RAG实战指南:从入门到精通,一篇掌握核心技巧!

RAG(Retrieval Augmented Generation, 检索增强生成)是一种技术框架,其核心在于当 LLM 面对解答问题或创作文本任务时,首先会在大规模文档库中搜索并筛选出与任务紧密相关的素材,继而依据这些素材精准指导后续的回答生成或文本构造过程,旨在通过此种方式提升模型输出的准确性和可靠性。RAG 技术架构图介绍:富文本 主要存储于 txt 文件中,因为排版比较整洁,所以获取方式比较简单实战技巧:【版面分析——富文本txt读取】

2401_84495872的博客 1445

一文读懂:从RAG到多模态RAG

如果说2023年见证了大语言模型的“寒武纪大爆发”,那么2024年则是多模态大模型“元年”。GPT-4o的出现让大家见识到多模态能力引入,给下游应用生态带来的巨大改变。随之而来的,RAG技术也将逐渐从单语言模态的RAG进化到多模态RAG。本文将带大家速览多模态RAG技术的原理及实现。

2401_85325726的博客 1416

一文读懂:LLM大模型RAG

检索增强生成(Retrieval Augmented Generation),简称 RAG,已经成为当前最火热的LLM应用方案。

AAI666666的博客 4971
上一篇: 【大模型学习笔记】一篇文档读懂 LangChain 常用用法
小怪兽的世界
博客等级 码龄6年 5粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值