测试 LLM 链
提示链是一种常见的模式,用于通过 LLM 执行更复杂的推理。它被 LangChain 等库使用,OpenAI 也通过 OpenAI 函数 提供了内置支持。
“链”由一系列按顺序(有时是条件性地)执行的 LLM 提示定义。每次 LLM 调用的输出都会被解析/操作/执行,然后将结果输入到下一个提示中。
本页解释了如何测试 LLM 链。从高层次来看,你有以下选项:
-
将链分解为单独的调用,并测试这些调用。如果你的测试策略更接近单元测试,而不是端到端测试,这很有用。
-
使用单个输入和单个输出测试完整的端到端链。如果你只关心最终结果,而不关心 LLM 链是如何实现的,这很有用。
单元测试 LLM 链
如上所述,最简单的测试方法是逐个提示进行测试。这可以通过基本的 promptfoo 配置 轻松完成。
运行 npx promptfoo@latest init chain_step_X
为链的第一步创建测试框架。为该步骤配置测试用例后,为第二步创建一组新的测试用例,依此类推。
端到端测试 LLM 链
使用脚本提供者
要测试你的链式 LLM,请提供一个脚本,该脚本接受提示输入并输出链的结果。这种方法与语言无关。
在这个示例中,我们将通过创建一个接受提示并生成输出的脚本来测试 LangChain 的 LLM Math 插件:
# langchain_example.py
import sys
import os
from langchain import OpenAI
from langchain.chains import LLMMathChain
llm = OpenAI(
temperature=0,
openai_api_key=os.getenv('OPENAI_API_KEY')
)
llm_math = LLMMathChain(llm=llm, verbose=True)
prompt = sys.argv[1]
llm_math.run(prompt)
这个脚本设置为我们可以这样运行它:
python langchain_example.py "What is 2+2?"
现在,让我们配置 promptfoo 使用一堆测试用例运行这个 LangChain 脚本:
prompts: prompt.txt
providers:
- openai:chat:gpt-4o
- exec:python langchain_example.py
tests:
- vars:
question: What is the cube root of 389017?
- vars:
question: If you have 101101 in binary, what number does it represent in base 10?
- vars:
question: What is the natural logarithm (ln) of 89234?
- vars:
question: If a geometric series has a first term of 3125 and a common ratio of 0.008, what is the sum of the first 20 terms?
- vars:
question: A number in base 7 is 3526. What is this number in base 10?
- vars:
question: If a complex number is represented as 3 + 4i, what is its magnitude?
- vars:
question: What is the fourth root of 1296?
有关配置的深入了解,请参阅 指南。请注意以下几点:
- prompts:
prompt.txt
只是一个包含{{question}}
的文件,因为我们直接将问题传递给提供者。 - providers: 我们列出了 GPT-4,以便将其输出与 LangChain 的 LLMMathChain 进行比较。我们还使用
exec
指令让 promptfoo 在评估中运行 Python 脚本。
在这个示例中,最终结果是 GPT-4 与 LangChain 数学性能的并排比较:
查看 Github 上的完整示例。
使用自定义提供者
为了更细粒度的控制,使用 自定义提供者。
自定义提供者是一个定义了 callApi
函数的简短 Javascript 文件。此函数可以调用你的链。即使你的链不是用 Javascript 实现的,你也可以编写一个自定义提供者,该提供者会调用 Python。
在下面的示例中,我们设置了一个自定义提供者,该提供者使用提示作为参数运行 Python 脚本。Python 脚本的输出是链的最终结果。
const { spawn } = require('child_process');
class ChainProvider {
id() {
return 'my-python-chain';
}
async callApi(prompt, context) {
return new Promise((resolve, reject) => {
const pythonProcess = spawn('python', ['./path_to_your_python_chain.py', prompt]);
let output = '';
pythonProcess.stdout.on('data', (data) => {
output += data.toString();
});
pythonProcess.stderr.on('data', (data) => {
reject(data.toString());
});
pythonProcess.on('close', (code) => {
if (code !== 0) {
reject(`python script exited with code ${code}`);
} else {
resolve({
output,
});
}
});
});
}
}
module.exports = ChainProvider;
请注意,如果你对这门语言感到舒适,你总是可以直接在JavaScript中编写逻辑。
现在,我们可以设置一个指向 chainProvider.js
的 promptfoo 配置:
prompts:
- file://prompt1.txt
- file://prompt2.txt
providers:
- './chainProvider.js'
tests:
- vars:
language: French
input: Hello world
- vars:
language: German
input: How's it going?
promptfoo 会将完整的构造提示传递给 chainProvider.js
和 Python 脚本,并替换变量。在这种情况下,脚本将被调用 # 提示 * # 测试用例 = 2 * 2 = 4 次。
使用这种方法,你可以端到端地测试你的 LLM 链,在 网页视图 中查看结果,设置 持续测试,等等。
检索增强生成 (RAG)
有关测试 RAG 管道的更多详细信息,请参阅 RAG 评估。
其他提示
要引用先前测试用例的输出,请使用内置的 _conversation
变量。