RAG:检索增强生成(Retrieval-Augmented Generation),是一种通过将人工智能(AI)模型与外部知识库连接来优化其性能的架构。RAG可帮助大语言模型(LLM)以更高质量提供更相关的响应。
RAG允许生成式AI模型(generative AI model)访问其他外部知识库,例如内部组织数据、学术期刊和专业数据集。通过将相关信息集成到生成过程中,聊天机器人(chatbots)和其他自然语言处理(NLP)工具无需进一步训练即可创建更准确的特定领域内容。
生成式AI模型具有知识截止点,即其训练数据上次更新的时间点。随着模型的老化,其相关性会逐渐降低。RAG系统实时连接模型与补充外部数据,并将最新信息整合到生成的响应中。
RAG模型还可以通过应用程序编程接口(API)连接到互联网,并访问实时社交媒体信息和消费者评论,从而更好地了解市场情绪。同时,由于模型将检索到的信息整合到文本生成过程中,访问突发新闻和搜索引擎可以带来更准确的响应。
诸如OpenAI的GPT之类的生成式AI模型通过检测数据中的模式来工作,然后利用这些模式预测用户输入的最可能结果。有时,模型会检测到不存在的模式。当模型将不正确或虚构的信息呈现为事实时,就会出现幻觉或虚构。
RAG通过将信息检索模型(information retrieval model)与生成式AI模型相结合来生成更权威的内容。RAG系统会查询知识库,并在生成响应之前为用户提示词添加更多上下文。
RAG包含两个阶段:检索和内容生成。在检索阶段,算法搜索并检索与用户提示或问题相关的信息片段。这些外部知识会被附加到用户的提示中,并传递给语言模型。在生成阶段,LLM会从增强的提示词及其训练数据的内部表示中提取信息,以合成一个针对用户当时情况的答案。
构建RAG管道(pipeline)的第一步是将数据导入向量数据库(vector database)。
这里问答式数据来自于本人的csdn博客,question为博客标题,answer为对应标题的链接,csdn.jsonl内容示例如下:
{"question": "C++20中线程类std::jthread的使用", "answer": "https://blog.youkuaiyun.com/fengbingchun/article/details/152172174"}
{"question": "通过提示词工程(Prompt Engineering)方法重新生成从Ollama下载的模型", "answer": "https://blog.youkuaiyun.com/fengbingchun/article/details/151902070"}
{"question": "使用C++实现与Ollama通信:ollama-hpp", "answer": "https://blog.youkuaiyun.com/fengbingchun/article/details/151677357"}
{"question": "Ollama Python库的使用", "answer": "https://blog.youkuaiyun.com/fengbingchun/article/details/151286661"}
{"question": "解析、创建Excel文件的开源库OpenXLSX介绍", "answer": "https://blog.youkuaiyun.com/fengbingchun/article/details/151259362"}
{"question": "Qt中的QSS介绍", "answer": "https://blog.youkuaiyun.com/fengbingchun/article/details/151020879"}
{"question": "深度学习中的模型量化及实现示例", "answer": "https://blog.youkuaiyun.com/fengbingchun/article/details/150703580"}
{"question": "图像相似度算法汇总及Python实现", "answer": "https://blog.youkuaiyun.com/fengbingchun/article/details/150451109"}
{"question": "深度学习中的模型知识蒸馏", "answer": "https://blog.youkuaiyun.com/fengbingchun/article/details/149878692"}
{"question": "深度学习中基于响应的模型知识蒸馏实现示例", "answer": "https://blog.youkuaiyun.com/fengbingchun/article/details/150112972"}
下面是实现示例代码,依赖ollama python库,向量数据库使用chroma,不依赖sentence-transformers和langchain,当用户输入问题时,首先检索数据库,若命中则直接返回对应的链接;若未命中,则调用Ollama的模型进行推理
def parse_args():
parser = argparse.ArgumentParser(description="ollama rag chat")
parser.add_argument("--llm_model", type=str, default="qwen3:1.7b", help="llm model name, for example:qwen3:1.7b")
parser.add_argument("--embed_model", type=str, default="nomic-embed-text:v1.5", help="embedded model, for example:nomic-embed-text:v1.5")
parser.add_argument("--jsonl", type=str, default="csdn.jsonl", help="jsonl(JSON Lines) file")
parser.add_argument("--db_dir", type=str, default="chroma_db_ollama", help="vector database(chromadb) storage path, for example:chroma_db_ollama")
parser.add_argument("--similarity_threshold", type=float, default=0.8, help="similarity threshold, the higher the stricter")
parser.add_argument("--question", type=str, help="question")
args = parser.parse_args()
return args
def build_vector_db(db_dir, jsonl, embed_model):
client = chromadb.PersistentClient(path=db_dir)
collection = client.get_or_create_collection("csdn_qa_ollama")
if collection.count() > 0:
return collection
print("start building vector database ...")
with open(jsonl, "r", encoding="utf-8") as f:
data = [json.loads(line.strip()) for line in f]
for i, item in enumerate(tqdm(data, desc="Embedding with Ollama")):
question = item["question"]
answer = item["answer"]
res = ollama.embeddings(model=embed_model, prompt=question)
emb = res["embedding"]
collection.add(
ids=[str(i)],
embeddings=[emb],
metadatas=[{"question": question, "answer": answer}]
)
time.sleep(0.05)
print(f"vector database is built and a total of {len(data)} entries are imported")
return collection
def retrieve_answer(embed_model, collection, similarity_threshold, question):
res = ollama.embeddings(model=embed_model, prompt=question)
query_vec = res["embedding"]
results = collection.query(query_embeddings=[query_vec], n_results=1)
if not results["ids"]:
return None
meta = results["metadatas"][0][0]
score = 1 - results["distances"][0][0]
if score >= similarity_threshold:
return f"question: {meta['question']}; link: {meta['answer']}"
return None
def chat(llm_model, embed_model, jsonl, db_dir, similarity_threshold, question):
collection = build_vector_db(db_dir, jsonl, embed_model)
ans = retrieve_answer(embed_model, collection, similarity_threshold, question)
if ans:
print(ans)
else:
try:
stream = ollama.chat(model=llm_model, messages=[{"role": "user", "content": question}], stream=True)
print("Answer: ", end="", flush=True)
for chunk in stream:
if 'message' in chunk and 'content' in chunk['message']:
content = chunk['message']['content']
print(content, end="", flush=True)
print() # line break
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
colorama.init(autoreset=True)
args = parse_args()
chat(args.llm_model, args.embed_model, args.jsonl, args.db_dir, args.similarity_threshold, args.question)
print(colorama.Fore.GREEN + "====== execution completed ======")
当命中时输出结果如下:

当未命中时输出结果如下:

RAG与Ollama实现问答定制化回复
1680

被折叠的 条评论
为什么被折叠?



