LangSmith是LangChain的一个子产品,是一个大模型应用开发平台。它提供了从原型到生产的全流程工具和服务,帮助开发者构建、测试、评估和监控基于LangChain或其他 LLM 框架的应用程序。
对于一个Rag系统的评估包含以下步骤: 1. 创建一个测试用的数据集 2. 定义一个问答系统 3. 使用 LangSmith 运行评估 4. 迭代 5. 改进系统
注意:截止到2024年12月,安装这个版本没有问题,因为每次版本更新会附带库和代码的更新。
pip install langsmith==0.1.137
打开 langsmith 官网, 地址: https://smith.langchain.com/
进行登录。

创建API Key ,选择Personal Access Token,弹出API key窗口时需要复制并保存好。

导入测试数据有两种方法: - CSV文件导入 - 代码导入方式
上传.csv文件->选择并上传->预览数据。

点击create,生成了好多QA。
下面的代码执行后,也可以在LangSmith中新建一个测试集。
import pandas as pd
# 读取csv文件
df = pd.read_csv("黑悟空.csv")
# 将dataFrame转换成列表元组的形式
example_inputs = list(df.itertuples(index=False, name=None))
# print(example_inputs)
from langsmith import Client
client = Client(api_key="lsv2_pt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
dataset_name = "example"
dataset = client.create_dataset(dataset_name=dataset_name)
for q, a in example_inputs:
client.create_example(
inputs={"问题": q}, outputs={"答案": a}, dataset_id=dataset.id
)

测试数据准备好之后,就可以开始对系统进行评估了。LangSmith的后台可以生成评估的代码。我们可以参考官网提供的评估的代码修改优化如下(先使用不带有rag系统进行评估):
from langchain_openai import ChatOpenAI
chat_model = ChatOpenAI(
openai_api_key="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
base_url="https://api.siliconflow.cn/v1",
model="Qwen/Qwen2.5-7B-Instruct"
)
from langchain_core.prompts import ChatPromptTemplate
system_message = "你是一个机器人"
prompt = ChatPromptTemplate.from_messages([
("system", system_message),
("user", "{问题}")
])
from langchain_core.output_parsers import StrOutputParser
output_parser = StrOutputParser()
chain = prompt | chat_model | output_parser
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGCHAIN_API_KEY"] = "lsv2_pt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
from langsmith import evaluate, Client
from langsmith.schemas import Example, Run
# 1. Create and/or select your dataset
client = Client()
dataset_name = "example"
dataset = client.clone_public_dataset("https://smith.langchain.com/public/a63525f9-bdf2-4512-83e3-077dc9417f96/d", dataset_name=dataset_name)
# 2. Define an evaluator
def is_concise_enough(root_run: Run, example: Example) -> dict:
score = len(root_run.outputs["output"]) < 3 * len(example.outputs["答案"])
return {"key": "is_concise", "score": int(score)}
# 3. Run an evaluation
# For more info on evaluators, see: https://docs.smith.langchain.com/concepts/evaluation#evaluators
# To evaluate an LCEL chain, replace lambda with chain.invoke
# To evaluate a LangGraph graph, replace lambda with graph.invoke
evaluate(
lambda x: chain.invoke(x["问题"]),
# chain.invoke
# graph.invoke
data=dataset_name,
evaluators=[is_concise_enough],
experiment_prefix="my first dataset experiment "
)
使用LangChain和LangSmith工具链,结合大语言模型(LLM)进行文本处理和评估: 1. 初始化模型与提示模板: 导入所需模块后,设置了一个简单的LangChain提示模板( ChatPromptTemplate ),包括系统消息和用户输入格式。然后通过 ChatOpenAI连接自定义的大模型服务(Qwen2___5-7B-Instruct ),并配置API密钥和服务 地址。 2. 定义环境变量: 使用 os.environ 设置LangSmith相关环境变量,用于启用LangChain的跟踪和连接LangSmith平台。这些变量包括API端点和访问密钥。 3. 数据集管理: 使用LangSmith的 Client 类创建或克隆一个公共数据集( test-code ),用于模型评估。数据集通过指定的URL导入。 4. 自定义评估函数: 定义了 is_concise_enough 函数来评估模型输出是否足够简洁。它通过比较模型输出与预期答案长度来确定得分,返回布尔值。 5. 设置评估器: 创建了一个LangChainStringEvaluator 实例,用于评估模型在特定任务(如逐步推理问答)上的表现。 6. 执行评估: 调用 evaluate 函数,对模型链进行评估,运行自定义数据集上的实验并存储结果。评估过程中使用链的输出与标准答案进行比较。
可以看到,在10个里面有3个符合长度限制,即“评估为简洁的”。注意:你的实验可能结果不同,因为大模型每次输出并不可控!

可以点击进去查看详细情况,包括输入、参考输出和实际输出。

现在我们可以定义一个rag系统,实际上就是将我们之前的rag系统放到代码中。
注意这里改为“{问题}”是因为之前定义数据集两个字段的时候使用了“问题”。同时可以采用三种不同的方式去进行评估。 1. 简洁度评估 2. 通过其它模型(可能是一个更大的模型进行回答是否准确评估,LangChainStringEvaluator 使用的是prompt的形式) 3. 使用余弦相似度评估
上面是第一种:简洁度评估的实现代码,我这里不再赘述。下来看第二种:通过其它模型的评估。
from langchain_community.vectorstores import FAISS # 导入FAISS向量存储库
from langchain_huggingface import HuggingFaceEmbeddings # 导入Hugging Face嵌入模型
from langchain_community.document_loaders import TextLoader # 导入文本加载器
from langchain.text_splitter import RecursiveCharacterTextSplitter # 导入递归字符文本分割器
from langchain_openai import ChatOpenAI # 导入ChatOpenAI模型
# 使用 OpenAI API 的 ChatOpenAI 模型
chat_model = ChatOpenAI(
openai_api_key="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
base_url="https://api.siliconflow.cn/v1",
model="Qwen/Qwen2.5-7B-Instruct"
)
# 加载文本文件 "黑悟空.txt",编码格式为 'utf-8'
loader = TextLoader("黑悟空.txt", encoding='utf-8')
docs = loader.load() # 将文件内容加载到变量 docs 中
# 把文本分割成 200 字一组的切片,每组之间有 20 字重叠
text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=20)
chunks = text_splitter.split_documents(docs) # 将文档分割成多个小块
# 初始化嵌入模型,使用预训练的语言模型 'bge-large-zh-v1___5'
embedding = HuggingFaceEmbeddings(model_name='models/AI-ModelScope/bge-large-zh-v1___5')
# 构建 FAISS 向量存储和对应的 retriever
vs = FAISS.from_documents(chunks, embedding) # 将文本块转换为向量并存储在FAISS中
retriever = vs.as_retriever() # 创建一个检索器用于从向量存储中获取相关信息
from langchain.chains import RetrievalQA # 导入RetrievalQA链
from langchain.prompts import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
# 创建一个系统消息,用于定义机器人的角色
system_message = SystemMessagePromptTemplate.from_template(
"根据以下已知信息回答用户问题。\n 已知信息{context}"
)
# 创建一个人类消息,用于接收用户的输入
human_message = HumanMessagePromptTemplate.from_template(
"用户问题:{question}"
)
# 将这些模板结合成一个完整的聊天提示
chat_prompt = ChatPromptTemplate.from_messages([
system_message,
human_message,
])
"""使用LECL实现"""
# 格式化文档,将多个文档连接成一个
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
# 创建字符串输出解析器,用于解析LLM的输出
from langchain_core.output_parsers import StrOutputParser
output_parser = StrOutputParser()
from langchain_core.runnables import RunnablePassthrough
# 创建 rag_chain
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()} # 构建上下文字典
| chat_prompt
| chat_model
| output_parser
)
# print(rag_chain.invoke("黑熊精自称为?"))
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGCHAIN_API_KEY"] = "lsv2_pt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
from langsmith import evaluate, Client
from langsmith.schemas import Example, Run
# 1. Create and/or select your dataset
client = Client()
dataset_name = "example"
dataset = client.clone_public_dataset("https://smith.langchain.com/public/a63525f9-bdf2-4512-83e3-077dc9417f96/d",
dataset_name=dataset_name)
# 方式一:原始的代码:评估简洁度
# 2. Define an evaluator
def is_concise_enough(root_run: Run, example: Example) -> dict:
score = len(root_run.outputs["output"]) < 3 * len(example.outputs["答案"])
return {"key": "is_concise", "score": int(score)}
"""方式2:用更大的模型将原始答案与生成答案进行准确度评估"""
from langsmith.evaluation import LangChainStringEvaluator
eval_model = ChatOpenAI(
model="Qwen/Qwen2.5-72B-Instruct",
api_key="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
base_url="https://api.siliconflow.cn/v1",
)
evaluators = LangChainStringEvaluator("cot_qa", config={"llm": eval_model})
evaluate(
lambda x: rag_chain.invoke(x["问题"]),
# chain.invoke
# graph.invoke
data=dataset_name,
#evaluators=[is_concise_enough],
#evaluators=evaluators,
evaluators=[evaluators],
experiment_prefix="my first dataset experiment "
)
我们发现准确度效果明显改善很多。

第三种:使用余弦相似度评估
from langchain_community.vectorstores import FAISS # 导入FAISS向量存储库
from langchain_huggingface import HuggingFaceEmbeddings # 导入Hugging Face嵌入模型
from langchain_community.document_loaders import TextLoader # 导入文本加载器
from langchain.text_splitter import RecursiveCharacterTextSplitter # 导入递归字符文本分割器
from langchain_openai import ChatOpenAI # 导入ChatOpenAI模型
# 使用 OpenAI API 的 ChatOpenAI 模型
chat_model = ChatOpenAI(
openai_api_key="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
base_url="https://api.siliconflow.cn/v1",
model="Qwen/Qwen2.5-7B-Instruct"
)
# 加载文本文件 "黑悟空.txt",编码格式为 'utf-8'
loader = TextLoader("黑悟空.txt", encoding='utf-8')
docs = loader.load() # 将文件内容加载到变量 docs 中
# 把文本分割成 200 字一组的切片,每组之间有 20 字重叠
text_splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=20)
chunks = text_splitter.split_documents(docs) # 将文档分割成多个小块
# 初始化嵌入模型,使用预训练的语言模型 'bge-large-zh-v1___5'
embedding = HuggingFaceEmbeddings(model_name='models/AI-ModelScope/bge-large-zh-v1___5')
# 构建 FAISS 向量存储和对应的 retriever
vs = FAISS.from_documents(chunks, embedding) # 将文本块转换为向量并存储在FAISS中
retriever = vs.as_retriever() # 创建一个检索器用于从向量存储中获取相关信息
from langchain.chains import RetrievalQA # 导入RetrievalQA链
from langchain.prompts import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
# 创建一个系统消息,用于定义机器人的角色
system_message = SystemMessagePromptTemplate.from_template(
"根据以下已知信息回答用户问题。\n 已知信息{context}"
)
# 创建一个人类消息,用于接收用户的输入
human_message = HumanMessagePromptTemplate.from_template(
"用户问题:{question}"
)
# 将这些模板结合成一个完整的聊天提示
chat_prompt = ChatPromptTemplate.from_messages([
system_message,
human_message,
])
"""使用LECL实现"""
# 格式化文档,将多个文档连接成一个
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
# 创建字符串输出解析器,用于解析LLM的输出
from langchain_core.output_parsers import StrOutputParser
output_parser = StrOutputParser()
from langchain_core.runnables import RunnablePassthrough
# 创建 rag_chain
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()} # 构建上下文字典
| chat_prompt
| chat_model
| output_parser
)
# print(rag_chain.invoke("黑熊精自称为?"))
import os
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGCHAIN_API_KEY"] = "lsv2_pt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
from langsmith import evaluate, Client
from langsmith.schemas import Example, Run
# 1. Create and/or select your dataset
client = Client()
dataset_name = "example"
dataset = client.clone_public_dataset("https://smith.langchain.com/public/a63525f9-bdf2-4512-83e3-077dc9417f96/d", dataset_name=dataset_name)
"""方式3:通过余弦相似度进行评估"""
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("models/AI-ModelScope/bge-large-zh-v1___5")
from sklearn.metrics.pairwise import cosine_similarity
def cal_cosine_similarity(root_run: Run, example: Example) -> dict:
model_output = root_run.outputs["output"]
reference_answer = example.outputs["答案"]
embeddings = model.encode([model_output, reference_answer])
similarity = cosine_similarity([embeddings[0]], [embeddings[1]])[0][0]
score = similarity >= 0.75
return {"key": "cosine_similarity", "score": int(score)}
# 3. Run an evaluation
# For more info on evaluators, see: https://docs.smith.langchain.com/concepts/evaluation#evaluators
# To evaluate an LCEL chain, replace lambda with chain.invoke
# To evaluate a LangGraph graph, replace lambda with graph.invoke
evaluate(
lambda x: rag_chain.invoke(x["问题"]),
# chain.invoke
# graph.invoke
data=dataset_name,
evaluators=[cal_cosine_similarity],
experiment_prefix="my first dataset experiment "
)

可以看到,使用余弦相似度进行评估(阈值为0.75),10个问题全部答对。