Jean's Blog

一个专注软件测试开发技术的个人博客

0%

RAG系统简单快速上手

RAG的快速上手,可使用以下方式进行RAG的实现:

  • 使用框架
    • LIamaIndex的五步示例
    • LangChain的直接实现
    • LangChain的LCEL链重构
    • LangGraph的重构
  • 不使用框架
    • 自选Embedding模型、向量数据库和LLM
  • 使用可视化工具
    • Coze、Dify、RagFlow等

使用框架快速上手RAG

LIamaIndex

示例如下:

1
2
3
4
5
6
7
8
9
10
# 第一行代码:导入相关的库
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
# 第二行代码:加载数据
documents = SimpleDirectoryReader(input_files=["data/黑悟空/设定.txt"]).load_data()
# 第三行代码:构建索引
index = VectorStoreIndex.from_documents(documents)
# 第四行代码:创建问答引擎
query_engine = index.as_query_engine()
# 第五行代码: 开始问答
print(query_engine.query("黑神话悟空中有哪些战斗工具?"))

以上是简单的五步代码,代码中没有看到使用的大模型和嵌入模型,是LIamaIndex已经内置了Open AI的模型,因此在运行该代码时要在本地的环境变量中设置OpenAI API密钥

1
2
3
4
5
在Linux/Mac系统中,可以通过以下命令设置:
export OPENAI_API_KEY='your-api-key'

在Windows系统中,可以通过以下命令设置:
set OPENAI_API_KEY=your-api-key

默认的模型是gpt-3.5-turbo

下面我们也可以使用国产大模型DeepSeek进行替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# @Time:2025/8/1 10:43
# @Author:jinglv
# 1.导入相关的库
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from llama_index.llms.deepseek import DeepSeek
from dotenv import load_dotenv
import os

# 加载环境变量
load_dotenv()

# 加载本地嵌入模型,如果本地没有该模型,则首次执行代码,会从huggingface下载该模型(需要科学上网),下载到本地的.cache目录下
embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-zh")

# 创建 Deepseek LLM
llm = DeepSeek(
model=os.getenv("DEEPSEEK_MODEL_NAME"),
api_key=os.getenv("DEEPSEEK_API_KEY"),
api_base=os.getenv("DEEPSEEK_BASE_URL")
)

# 第二行代码:加载数据
documents = SimpleDirectoryReader(input_files=["../data/黑悟空/设定.txt"]).load_data()

# 第三行代码:构建索引
index = VectorStoreIndex.from_documents(
documents,
embed_model=embed_model
)

# 第四行代码:创建问答引擎
query_engine = index.as_query_engine(
llm=llm
)

# 第五行代码: 开始问答
print(query_engine.query("黑神话悟空中有哪些战斗工具?"))

执行结果,输出内容

1
《黑神话:悟空》中并未明确提及具体的战斗工具信息。根据设定,游戏融合了中国文化和自然地标,并包含佛教与道教哲学元素,但关于武器或战斗系统的细节在提供的上下文中没有具体说明。

简单说明,RAG系统中需要使用LLM大语言模型、Embedding嵌入模型、向量数据库等……,从以上代码看,已经有使用大语言模型、嵌入模型,没有使用到常用的向量数据库,为什么还可以成功执行呢,从官网有下面一段话

1
2
LlamaIndex provides a in-memory vector database allowing you to run it locally, when you have a large amount of documents vector databases provides more features and better scalability and less memory constraints depending of your hardware.
LlamaIndex 提供了一个内存中矢量数据库,允许您在本地运行它,当您有大量文档时,矢量数据库提供了更多的功能和更好的可扩展性,并且根据您的硬件,可以减少内存限制。

从上面介绍,我们了解到,原来LIamaIndex提供了一个内存向量数据库呀。

以上代码中使用到的LIamaIndex介绍:

Vector Database LIamaIndex官方地址:https://docs.llamaindex.ai/en/stable/community/faq/vector_database/

LIamaIndex中存储组件中的向量存储官方地址:https://docs.llamaindex.ai/en/stable/module_guides/storing/vector_stores/#vector-store-options--feature-support

LIamaIndex中查询组件中的Query Engine官方地址:https://docs.llamaindex.ai/en/stable/module_guides/deploying/query_engine/

LangChain

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# @Time:2025/8/1 11:27
# @Author:jinglv
# 1. 加载文档
import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

from langchain_community.document_loaders import WebBaseLoader # pip install langchain-community

loader = WebBaseLoader(
web_paths=("https://zh.wikipedia.org/wiki/黑神话:悟空",)
)
docs = loader.load()

# 2. 文档分块
from langchain_text_splitters import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
all_splits = text_splitter.split_documents(docs)

# 3. 设置嵌入模型
from langchain_huggingface import HuggingFaceEmbeddings # pip install langchain-huggingface

embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-small-zh",
model_kwargs={'device': 'cpu'},
encode_kwargs={'normalize_embeddings': True}
)

# 4. 创建向量存储
from langchain_core.vectorstores import InMemoryVectorStore

vector_store = InMemoryVectorStore(embeddings)
vector_store.add_documents(all_splits)

# 5. 构建用户查询
question = "黑悟空有哪些游戏场景?"

# 6. 在向量存储中搜索相关文档,并准备上下文内容
retrieved_docs = vector_store.similarity_search(question, k=3)
docs_content = "\n\n".join(doc.page_content for doc in retrieved_docs)

# 7. 构建提示模板
from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_template("""
基于以下上下文,回答问题。如果上下文中没有相关信息,
请说"我无法从提供的上下文中找到相关信息"。
上下文: {context}
问题: {question}
回答:"""
)

# 8. 使用大语言模型生成答案
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
model=os.getenv("DEEPSEEK_MODEL_NAME"), # DeepSeek API 支持的模型名称
temperature=0.7, # 控制输出的随机性
max_tokens=2048, # 最大输出长度
api_key=os.getenv("DEEPSEEK_API_KEY"), # 从环境变量加载API key
base_url=os.getenv("DEEPSEEK_BASE_URL")
)
answer = llm.invoke(prompt.format(question=question, context=docs_content))
print(answer)
  • 调用特点:
    • 会显示大模型调用过程中的详细交互信息
    • 包括token使用情况(prompt tokens/completion tokens)
    • 最终回答存储在content元素中
  • 参数设置:
    • temperature控制输出随机性(0-1)
    • max_tokens限制最大输出长度
    • top_p控制输出多样性(0-1)
    • presence_penalty防止重复(-2.0到2.0)
    • frequency_penalty减少重复内容(-2.0到2.0)

执行结果,输出内容

1
content='根据提供的上下文,以下是《黑神话:悟空》中提到的游戏场景及相关取景地信息:\n\n1. **中国古建筑取景地**  \n   - 游戏中的场景大量借鉴了中国传统古建筑,尤其是山西的古建(36个取景地中有27个位于山西),例如晋祠、悬空寺等(来源:文博日历丨《黑神话:悟空》里的中国古建取景地、36个取景地27个在山西)。\n\n2. **具体场景示例**  \n   - 游戏中出现的“古刹丛林”“荒原雪岭”等场景,均以实景古建为原型设计,并通过幕后花絮展示了拍摄过程(来源:IGN中国取景地幕后花絮)。\n\n3. **文化符号融入**  \n   - 场景中融入了石窟造像、壁画等元素,如云冈石窟、永乐宫壁画等(来源:Game8关于中国文化 treasures 的报道)。\n\n若需更具体的场景名称或关卡设计细节,上下文中未明确列出,可能需要参考游戏内的探索攻略或官方完整资料。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 228, 'prompt_tokens': 1331, 'total_tokens': 1559, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'deepseek-ai/DeepSeek-V3', 'system_fingerprint': '', 'id': '019863b18528f5d950a772c8bc3216a0', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--5f5f3ff4-d693-4835-b03a-64c291f55f9f-0' usage_metadata={'input_tokens': 1331, 'output_tokens': 228, 'total_tokens': 1559, 'input_token_details': {}, 'output_token_details': {}}

LangChain调用大模型的不同方式

image-20250801134242847

LangChain重构LCEL

  • 组件式设计
  • 管道式(Pipeline)数据流
  • 高度可组合性
  • 兼容异步执行
  • 易于调试和扩展

LCEL链的构建与特点

  • 核心优势:相比传统瀑布式开发,LCEL采用类似Unix命令管道的设计理念,通过”|”符号串联不同处理逻辑组件
  • 典型组件:包含提示模板(ChatPromptTemplate)、语言模型(ChatOpenAI)、输出解析器(StrOutputParser)等模块
  • 重构差异:将原本分步执行的文档加载、分块、嵌入、存储等流程整合为统一管道

组件化设计与管道式数据流

  • 组件式设计:各功能模块如提示模板、LLM、输出解析器等可像乐高积木自由组合
  • 管道式数据流:数据通过chain = (\{"context": retriever | lambda..., "question": RunnablePassthrough()\} | prompt | llm | StrOutputParser())形式流动
  • 开发体验:部分开发者认为比传统分步执行更清晰,但也存在适应成本

高度可组合性与异步执行

  • 组合灵活性:支持任意调整组件位置(但RAG等固定流程需保持顺序)
  • 异步支持:所有chain天然支持异步调用模式,可通过简单切换实现同步/异步转换
  • 调试集成:与LangSmith深度集成,可追踪token消耗、调用次数等指标

LCEL与LangChain的集成

  • 工具兼容:保留原有LangChain的tracing等调试功能
  • 平滑过渡:开发者可从传统LangChain逐步迁移到LCEL
  • 特有优势:主要改进在于提供更直观的管道式编程体验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# @Time:2025/8/1 13:52
# @Author:jinglv
# 1. 加载文档
from langchain_community.document_loaders import WebBaseLoader

loader = WebBaseLoader(
web_paths=("https://zh.wikipedia.org/wiki/黑神话:悟空",)
)
docs = loader.load()

# 2. 分割文档
from langchain_text_splitters import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
all_splits = text_splitter.split_documents(docs)

# 3. 设置嵌入模型
from langchain_huggingface import HuggingFaceEmbeddings # pip install langchain-huggingface

embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-small-zh",
model_kwargs={'device': 'cpu'},
encode_kwargs={'normalize_embeddings': True}
)

# 4. 创建向量存储
from langchain_core.vectorstores import InMemoryVectorStore

vectorstore = InMemoryVectorStore(embeddings)
vectorstore.add_documents(all_splits)

# 5. 创建检索器
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

# 6. 创建提示模板
from langchain_core.prompts import ChatPromptTemplate

prompt = ChatPromptTemplate.from_template("""
基于以下上下文,回答问题。如果上下文中没有相关信息,
请说"我无法从提供的上下文中找到相关信息"。
上下文: {context}
问题: {question}
回答:""")

# 7. 设置语言模型和输出解析器
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()
llm = ChatOpenAI(
model=os.getenv("DEEPSEEK_MODEL_NAME"), # DeepSeek API 支持的模型名称
api_key=os.getenv("DEEPSEEK_API_KEY"), # 从环境变量加载API key
base_url=os.getenv("DEEPSEEK_BASE_URL")
)

# 8. 构建 LCEL 链
# 管道式数据流像使用 Unix 命令管道 (|) 一样,将不同的处理逻辑串联在一起
chain = (
{
"context": retriever | (lambda docs: "\n\n".join(doc.page_content for doc in docs)),
"question": RunnablePassthrough()
}
| prompt
| llm
| StrOutputParser()
)

# 查看每个阶段的输入输出
question = "黑悟空有哪些游戏场景?"
# 1. 检索器阶段
retriever_output = retriever.invoke(question)
print("检索器输出:", retriever_output)

# 2. 合并文档阶段
context = "\n\n".join(doc.page_content for doc in retriever_output)
print("合并文档输出:", context)

# 3. 提示模板阶段
prompt_output = prompt.invoke({"context": context, "question": question})
print("提示模板输出:", prompt_output)

# 4. LLM阶段
llm_output = llm.invoke(prompt_output)
print("LLM输出:", llm_output)

# 5. 解析器阶段
final_output = StrOutputParser().invoke(llm_output)
print("最终输出:", final_output)

# 9. 执行查询
question = "黑悟空有哪些游戏场景?"
response = chain.invoke(question) # 同步,可以换成异步执行

  • 检索阶段:
    • 输入:问题字符串
    • 输出:Document列表
  • Lambda处理:
    • 输入:Document列表
    • 输出:合并后的文本字符串
  • RunnablePassthrough:
    • 输入:原始问题
    • 输出:原样传递问题
  • 提示模板:
    • 输入:字典{“context”:文本, “question”:问题}
    • 输出:格式化后的提示字符串
  • LLM阶段:
    • 输入:提示模板字符串
    • 输出:ChatMessage对象
  • 输出解析:
    • 输入:ChatMessage对象
    • 输出:纯文本回答

重构之LangGraph

  • 基于状态(State)驱动的执行模型
  • DAG(有向无环图)任务流
  • 任务模块化
  • 灵活的控制流
  • 并行执行

image-20250801140040152

适用场景:特别适合需要复杂控制流(如循环判断)的RAG系统和Agent开发

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# @Time:2025/8/1 14:19
# @Author:jinglv
# 1. 加载文档
from langchain_community.document_loaders import WebBaseLoader

loader = WebBaseLoader(
web_paths=("https://zh.wikipedia.org/wiki/黑神话:悟空",)
)
docs = loader.load()

# 2. 文档分块
from langchain_text_splitters import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
all_splits = text_splitter.split_documents(docs)

# 3. 设置嵌入模型
from langchain_huggingface import HuggingFaceEmbeddings

embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-small-zh",
model_kwargs={'device': 'cpu'},
encode_kwargs={'normalize_embeddings': True}
)

# 4. 创建向量存储aa
from langchain_core.vectorstores import InMemoryVectorStore

vector_store = InMemoryVectorStore(embeddings)
vector_store.add_documents(all_splits)

# 5. 定义RAG提示词
from langchain import hub

prompt = hub.pull("rlm/rag-prompt")

# 6. 定义应用状态
from typing import List
from typing_extensions import TypedDict
from langchain_core.documents import Document


class State(TypedDict):
question: str
context: List[Document]
answer: str


# 7. 定义检索步骤
def retrieve(state: State):
retrieved_docs = vector_store.similarity_search(state["question"])
return {"context": retrieved_docs}


# 8. 定义生成步骤
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI

# 加载环境变量
load_dotenv()
llm = ChatOpenAI(
model=os.getenv("DEEPSEEK_MODEL_NAME"), # DeepSeek API 支持的模型名称
api_key=os.getenv("DEEPSEEK_API_KEY"), # 从环境变量加载API key
base_url=os.getenv("DEEPSEEK_BASE_URL")
)


def generate(state: State):
docs_content = "\n\n".join(doc.page_content for doc in state["context"])
messages = prompt.invoke({"question": state["question"], "context": docs_content})
response = llm.invoke(messages)
return {"answer": response.content}


# 9. 构建和编译应用
from langgraph.graph import START, StateGraph # pip install langgraph

graph = (
StateGraph(State)
.add_sequence([retrieve, generate])
.add_edge(START, "retrieve")
.compile()
)

# 10. 运行查询
question = "黑悟空有哪些游戏场景?"
response = graph.invoke({"question": question})
print(f"\n问题: {question}")
print(f"答案: {response['answer']}")

代码详解:

  • DAG基本概念与特点

    • 定义:DAG(有向无环图)是由节点和有向边组成的图结构,不能形成循环路径
    • 核心特性:
      • 有向性:边具有明确方向,如A→B表示从A到B的单向流动
      • 无环性:不能出现A→B→C→A这样的循环路径
      • 状态传递:每个节点都有明确的输入输出状态,保证数据流顺序性
    • 应用价值:特别适合Agent工作流排程和复杂RAG流程设计
  • RAG流程与节点设置

    • 标准流程节点:
      • Start:流程起始节点
      • Retrieve:检索相关文档片段
      • Generate:生成最终回答
    • 状态传递机制:
      • 问题状态(question):用户原始提问
      • 上下文状态(context):检索到的文档片段列表
      • 回答状态(answer):生成的最终答案
  • 应用状态与图构建

    • 状态定义
    • 图构建方法
      • 使用StateGraph初始化图结构
      • 通过add_sequence添加节点执行顺序
      • 用add_edge明确节点间流向
      • 最终调用compile完成编译
  • 复杂查询与多路径检索

    • 扩展性设计:

      • 可设置多个检索路径,如retrieve_vector_db1和retrieve_vector_db2

      • 根据问题类型路由到不同向量数据库(如按地域划分)

    • 优势对比:

      • 简单RAG:5行代码即可实现基础功能
      • 复杂RAG:需要图结构处理错误纠正和多路检索
    • 典型案例:游戏《黑神话:悟空》场景查询,涉及重庆大足石刻、山西小西天等多个地点
  • 解决方案选择与需求匹配

    • LlamaIndex:适合简单检索场景(5行代码实现)
      • LangChain:适合中等复杂度流程控制
      • LangGraph:适合需要状态管理和多路径的复杂场景
    • 开发建议:
      • 从简单方案开始,按需升级复杂度
      • 预留扩展接口应对未来需求变化
      • 复杂系统可能需要结合多种框架优势

LangGraph vs. 传统 LangChain

image-20250801142342987

  • 执行方式:
    • LangChain采用线性执行(pipeline),适合简单任务
    • LangGraph采用DAG(有向无环图)执行,支持并行和条件分支,适合复杂任务
  • 状态管理:
    • LangChain需要手动管理变量传递
    • LangGraph通过统一State对象自动传递状态
  • 任务复用:
    • LangChain组件化但流程固定
    • LangGraph各步骤可单独测试和替换
  • 分支逻辑:
    • LangChain需要手动编写if-else
    • LangGraph通过add_conditional_edges()方法实现
  • 并行执行:
    • LangChain需要手动编写async/await
    • LangGraph通过add_parallel()自动实现并行
  • 适用场景:
    • LangChain适用于简单任务
    • LangGraph适用于需要并行检索多数据源(如同时检索关系数据库和向量数据库)的复杂任务

不使用框架,手工构建RAG

  1. 手工设置嵌入模型
  2. 手工设置向量数据库
  3. 手工构建提示词
  4. 手工调用LLM API

示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# @Time:2025/8/1 14:29
# @Author:jinglv
# 1. 准备文档数据
import os

from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

docs = [
"黑神话悟空的战斗如同武侠小说活过来一般,当金箍棒与妖魔碰撞时,火星四溅,招式行云流水。悟空可随心切换狂猛或灵动的战斗风格,一棒横扫千军,或是腾挪如蝴蝶戏花。",
"72变神通不只是变化形态,更是开启新世界的钥匙。化身飞鼠可以潜入妖魔巢穴打探军情,变作金鱼能够探索深海遗迹的秘密,每一种变化都是一段独特的冒险。",
"每场BOSS战都是一场惊心动魄的较量。或是与身躯庞大的九头蟒激战于瀑布之巅,或是在雷电交织的云海中与雷公电母比拼法术,招招险象环生。",
"驾着筋斗云翱翔在这片神话世界,瑰丽的场景令人屏息。云雾缭绕的仙山若隐若现,古老的妖兽巢穴中藏着千年宝物,月光下的古寺钟声回荡在山谷。",
"这不是你熟悉的西游记。当悟空踏上寻找身世之谜的旅程,他将遇见各路神仙妖魔。有的是旧识,如同样桀骜不驯的哪吒;有的是劲敌,如手持三尖两刃刀的二郎神。",
"作为齐天大圣,悟空的神通不止于金箍棒。火眼金睛可洞察妖魔真身,一个筋斗便是十万八千里。而这些能力还可以通过收集天外陨铁、悟道石等材料来强化升级。",
"世界的每个角落都藏着故事。你可能在山洞中发现上古大能的遗迹,云端天宫里寻得昔日天兵的宝库,或是在凡间集市偶遇卖人参果的狐妖。",
"故事发生在大唐之前的蛮荒世界,那时天庭还未定鼎三界,各路妖王割据称雄。这是一个神魔混战、群雄逐鹿的动荡年代,也是悟空寻找真相的起点。",
"游戏的音乐如同一首跨越千年的史诗。古琴与管弦交织出战斗的激昂,笛萧与木鱼谱写禅意空灵。而当悟空踏入重要场景时,古风配乐更是让人仿佛穿越回那个神话的年代。"
]

# 2. 设置嵌入模型
from sentence_transformers import SentenceTransformer

model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
doc_embeddings = model.encode(docs)
print(f"文档向量维度: {doc_embeddings.shape}")

# 3. 创建向量存储
import faiss
import numpy as np

dimension = doc_embeddings.shape[1]
index = faiss.IndexFlatL2(dimension)
index.add(doc_embeddings.astype('float32'))
print(f"向量数据库中的文档数量: {index.ntotal}")

# 4. 执行相似度检索
question = "黑神话悟空的战斗系统有什么特点?"
query_embedding = model.encode([question])[0]
distances, indices = index.search(
np.array([query_embedding]).astype('float32'),
k=3
)
context = [docs[idx] for idx in indices[0]]
print("\n检索到的相关文档:")
for i, doc in enumerate(context, 1):
print(f"[{i}] {doc}")

# 5. 构建提示词
prompt = f"""根据以下参考信息回答问题,并给出信息源编号。
如果无法从参考信息中找到答案,请说明无法回答。
参考信息:
{chr(10).join(f"[{i + 1}] {doc}" for i, doc in enumerate(context))}
问题: {question}
答案:"""

# 6. 使用DeepSeek生成答案
from openai import OpenAI

client = OpenAI(
api_key=os.getenv("DEEPSEEK_API_KEY"), # 从环境变量加载API key
base_url=os.getenv("DEEPSEEK_BASE_URL")
)

response = client.chat.completions.create(
model=os.getenv("DEEPSEEK_MODEL_NAME"),
messages=[{
"role": "user",
"content": prompt
}],
max_tokens=1024
)
print(f"\n生成的答案: {response.choices[0].message.content}")

  • 嵌入模型设置:直接调用SentenceTransformer等库,如SentenceTransformer(‘sentence-transformers/all-MiniLM-LG-v2’)
  • 向量数据库构建:
    • 使用FAISS创建索引:faiss.IndexFlatL2(dimension)
    • 添加文档向量:index.add(doc_embeddings.astype(‘float32’))
  • 检索实现:
    • 问题编码:model.encode([question])
    • 相似度搜索:distances, indices = index.search(np.array([query_embedding]).astype(‘float32’), k)
  • 提示词构建:需包含参考信息整合逻辑,如[f”[{i+1}] {doc}” for i, doc in enumerate(context)]
  • LLM调用:直接调用API如DeepSeek,注意设置max_tokens等参数
  • 适用场景:当项目需求简单明确时,手工构建比使用框架更轻量高效,可避免不必要的框架依赖
  • 核心优势:完全掌控每个环节,适合需要深度定制的场景,如特殊数据处理流程或非标准评估需求