在本教程中,我将向您展示如何使用一个简单且可重复使用的评估工具来测试本地的AI智能体。

该评估工具会让智能体针对一系列测试用例进行运行,同时通过基于规则的校验方法以及以大语言模型作为评判标准的机制来检查测试结果,并最终生成清晰的通过/未通过总结报告。

所有操作都在您的个人电脑上完成,所使用的工具包括LangChain v1、Ollama、Qwen以及Python,因此无需支付任何API使用费用。

目录

背景知识

大多数本地AI智能体的测试方式都是一样的:输入一些问题,如果得到的答案看起来正确,那就直接将其投入使用。但一旦我们更改了提示语、更换了模型,或者添加了新的工具,问题就会突然出现——而我们往往直到为时已晚才注意到这些问题。

普通的Python代码会通过单元测试来发现这类问题,但AI智能体并没有这样的机制。即使面对相同的输入,不同的运行环境下,智能体的表现也可能有所不同;而且一些细微的改动就可能导致功能退化,而这些退化很容易被忽略。如果没有一种可重复的方法来在多种输入条件下测试智能体并评估其输出结果,我们就只能凭猜测来判断智能体的行为了。

一个简单的解决办法就是构建一个轻量级的评估系统,该系统包括Python脚本、测试用例列表、基于规则的校验机制,以及以大语言模型作为评判标准的工具。这样我们就可以在任何修改发生之前,及时对智能体进行测试了。

要跟随本教程进行操作,您的电脑上必须已经安装了Ollama。本教程适用于macOS、Windows和Linux系统。我使用的是一台配置有32GB内存的MacBook Pro,但如果您使用的是内存较小的机器,也可以选择Ollama中内存占用较低的Qwen模型来运行本教程。

什么是智能体评估?

智能体评估就是让智能体针对一组固定的输入数据进行运行,并将其输出结果与预期值进行对比分析的流程。在人工智能领域,这相当于一种测试套件。

评估的目的并不是要证明智能体是完美的,而是要在我们对系统进行任何修改时,及时发现可能出现的功能退化问题。

一个有效的评估体系通常由三个部分组成:

  1. 测试用例:包含输入内容及其预期行为列表。

  2. 评估函数:用于针对每个输入内容来评价智能体的输出结果。

  3. 总结报告:显示通过/失败的数量,以便了解智能体的表现情况。

什么是“作为评估者的LLM”?

有两种实际可行的方法来评价智能体的输出结果。第一种是基于规则的评估方式。例如,你可以检查“输出内容中是否包含‘巴黎’这个词”,或者“智能体是否调用了word_count工具”。这种评估方式成本低廉、速度快,且结果具有确定性。

第二种方法是使用“作为评估者的LLM”来进行评价。你让另一个LLM读取输入内容及智能体的输出结果,然后根据预设的标准对其进行评分。评分标准可以简单地分为通过/失败两种结果。这种方法对于那些难以用明确规则来评判的情况非常有用,比如“答案是否真正回答了用户提出的问题”。不过,这样的评估方式也存在缺点:因为用于评估的LLM本身也可能出现错误。

在本教程中,我们将使用同一个模型,但会改变提示语的内容来进行评估。

开发动机与架构设计

在构建了一个智能体之后,对其性能进行评估是接下来自然而然要做的步骤。只有确认该智能体能够在不同的输入条件下稳定地运行,我们才能真正信任它。

为了简化操作流程,我们将使用两个工具来评估一个简单的本地智能体:其中一个工具用于处理当前时间相关的任务,另一个工具则用于统计单词数量。评估系统会从Python文件中读取测试用例列表,逐一让智能体处理这些测试用例,然后应用基于规则的评估方式以及“作为评估者的LLM”的评分标准,最后生成通过/失败的总结报告。

示意图显示了评估系统的运作流程:从Python文件中读取测试用例列表,让智能体处理这些测试用例,然后应用基于规则的评估方式及‘作为评估者的LLM’的评分标准,最终生成总结报告

在下面的示例中,`expected_keyword`和`expected_tool`就是两种基于规则的评估标准,而`judge_rubric`则是用于“作为评估者的LLM”进行评分的标准。

{
    "input": "法国的首都是什么?",
    "expected_keyword": "巴黎",
    "expected_tool": None,
    "judge_rubric": "答案中应该提到‘巴黎’这个词。"
}

智能体和评估系统都是通过Ollama在本地运行的,因此不会产生每次调用模型API时产生的费用。

步骤1:安装Ollama并下载模型

首先,请根据你的操作系统安装Ollama应用程序。在本教程中,我们将同时使用Qwen作为智能体和评估工具。我使用的版本是qwen3.5:4b

ollama pull qwen3.5:4b

如果你的计算机内存较少,也可以使用qwen3.5:0.8b版本,不过使用这个版本的评估结果可能会存在较大的波动。

步骤2:安装Python相关依赖库

创建一个虚拟环境并安装所需的包:

python3 -m venv venv
source venv/bin/activate

pip install langchain langchain-core langchain-ollama

本教程要求使用 langchain>=1.0.0

步骤 3:被测试的智能体

我们将使用一个包含两个工具的小型智能体。评估框架会将这个智能体视为一个“不透明系统”,因此在评估过程中,智能体本身的任何配置都不会发生改变。

下面的智能体代码定义了两个工具:current_time()用于获取当前时间,word_count()用于计算输入句子中的单词数量。该智能体是通过 LangChain 的 build_agent() 函数创建的,并且使用了一个简单的系统提示语。

将以下代码保存为 agent.py

from datetime import datetime

from langchain.agents import create_agent
from langchain_core.tools import tool
from langchain_ollama import ChatOllama


@tool
def current_time() -> str:
    """返回当前的本地日期和时间。"""
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")


@tool
def word_count(text: str) -> int:
    """计算文本中包含的单词数量。"""
    return len(text.split')


def build_agent():
    model = ChatOllama(model="qwen3.5:4b", temperature=0)
    return create_agent(
        model=model,
        tools=[current_time, word_count],
        system_prompt="你是一个能够使用各种工具的帮助性智能体。"
    )

步骤 4:编写评估框架代码

对于每个测试用例,评估框架会执行以下三项操作:

  1. 运行智能体并收集其输出结果以及任何工具调用记录。

  2. 通过基于规则的简单判断来检查输出结果:确认是否包含预期的关键词,以及是否使用了预定的工具。

  3. 让另一个大型语言模型对输出结果进行评分。评分时使用的输入提示会包含用户的原始问题、智能体的回答以及评分标准。该大型语言模型会被要求回答“答案是否符合评分标准?请只回复‘是’或‘否’”。最终评分结果也会是“是”或“否”。

测试用例的定义位于文件的开头部分。对于每个测试用例,代码会首先调用智能体来获取其输出结果,然后打印出答案及任何工具调用记录。随后,会将这些结果传递给 check_keyword()check_tool() 函数进行基于规则的检查。最后,代码会调用 llm_judge() 来让大型语言模型对智能体的输出结果进行评分。所有检查完成后,代码会打印出最终的测试结果总结。

将以下代码保存为 eval.py

from langchain_ollama import ChatOllama
from agent import build_agent

# -----------------------------
# 测试用例
# -----------------------------
# 每个测试用例包括:输入内容、答案中应出现的关键词、
# 代理应该调用的工具(如果没有需要调用任何工具,则设置为None),以及评估标准。

TEST_CASES = [
{
"input": "现在是什么时间?",
"expected_keyword": ":", # 时间字符串中应该包含冒号
"expected_tool": "current_time",
"judge_rubric": "答案中必须包含具体的时间信息。"
},
{
"input": '“LangChain makes tool calling easier”这句话中有多少个单词?',
"expected_keyword": "5",
"expected_tool": "word_count",
"judge_rubric": "答案中应该明确指出单词数量为5个。"
},
{
"input": "法国的首都是什么?",
"expected_keyword": "巴黎",
"expected_tool": None,
"judge_rubric": "答案中应该写出“巴黎”这个词。"
},
{
"input": '“LangChain makes tool calling easier”这句话中有多少个单词?请不要使用任何工具来计算。",
"expected_keyword": None,
"expected_tool": "word_count",
"judge_rubric": (
"助手不应该使用任何工具来计算单词数量。"
)
},
]

# -----------------------------
# 基于规则的检查
# -----------------------------

def check_keyword(answer, keyword):
if keyword is None:
return True
return keyword.lower() in answer.lower()

def check_tool-tool_calls, expected_tool):
if expected_tool is None:
return len/tool_calls) == 0
return expected_tool in tool_calls

# -----------------------------
# 使用大语言模型作为评估工具
# -----------------------------

judge = ChatOllama(model="qwen3.5:4b", temperature=0)

def llm_judge(user_input, answer, rubric):
prompt = (
f"用户输入:{user_input}\n"
f"代理回答:{answer}\n"
f"评估标准:{rubric}\n\n"
f"答案是否符合评估标准?请回复“YES”或“NO”。"
)
response = judge.invoke(prompt).content.strip().upper()
return response.startswith("YES")

# -----------------------------
# 运行测试
# -----------------------------

def run_evals():
agent = build_agent()
passed_count = 0

for i, case in enumerate(TEST_CASES, start=1):
# 运行代理
result = agent.invoke({
"messages": [{"role": "user", "content": case["input"]}],
})

# 提取答案以及代理调用的工具
answer = result["messages"][-1].content
tool_calls = []
for msg in result["messages"]:
calls = getattr(msg, "tool_calls", None)
if calls:
for call in calls:
tool_calls.append(call["name"])

print(f"[答案] 测试用例 {i}: {answer} \n[使用的工具] {toolcalls}")

# 进行三项检查
keyword_ok = check_keyword(answer, case["expected_keyword"])
tool_ok = check_tool TOOL_calls, case["expected_tool"])
judge_ok = llm_judge(case["input"], answer, case["judge_rubric"])

passed = keyword_ok and tool_ok and judge_ok
if passed:
passed_count += 1

# 打印测试结果
status = "PASS" if passed else "FAIL"
print(f"[{status}] 测试用例 {i}: {case['input']}")
if not keyword_ok:
print(f" - 关键词检查失败(预期关键词为'{case['expected_keyword']}')")
if not tool_ok:
print(f" - 工具使用检查失败(预期使用的工具为{case['expected_tool']},实际使用了{tool_calls})")
if not judge_ok:
print(f" - 评估工具认为答案不符合要求")

print(f"\n共{passed_count}/{len(TEST_CASES)}个测试用例通过。")

if __name__ == "__main__":
run_evals()

步骤5:运行评估测试

在Ollama在后台运行的情况下,运行以下脚本:

python eval.py

该脚本会通过代理程序执行每个测试用例,进行相应的检查,并输出结果总结。每当您更改系统提示语、更换模型或添加新工具时,都需要重新运行此脚本。

示例输出结果

以下是在我的机器上运行该脚本后的输出结果:

$python eval.py

[答案] 测试1:当前时间是2026年7月10日下午12:44:39
[使用的工具] ['current_time']
[通过] 测试1:现在是什么时间?

[答案] 测试2:“LangChain makes tool calling easier”这个短语包含5个单词。
[使用的工具] ['word_count']
[通过] 测试2:“LangChain makes tool calling easier”这个短语中有多少个单词?

[答案] 测试3:法国的首都是巴黎。
[使用的工具] []
[通过] 测试3:法国的首都是什么?

[答案] 测试4:“LangChain makes tool calling easier”这个短语包含5个单词。
[使用的工具] []
[未通过] 测试4:“LangChain makes tool calling easier”这个短语中有多少个单词?请不要使用任何工具
    - 工具检查失败(预期结果为5,实际得到的是……)
    - 评估系统判定该测试未通过

3项通过,1项未通过

其中有3项测试通过了,第4项测试未通过,因为代理程序遵循了用户的要求,没有使用任何工具。从输出结果中可以看出,它未能通过check_tool()这一检查规则,因此评估系统给出了“未通过”的判定。

正是这种错误情况,评估脚本才被设计出来用来检测的。如果没有这个脚本,我们很可能就会忽略这个问题,将带有缺陷的代理程序发布出去。

为了解决这个问题,请按照以下方式修改build_agent函数中的系统提示语,然后重新运行评估测试。修改后的代码为:代理程序不会再遵循避免使用工具的要求,而是会正常使用word_count工具来计算单词数量。

def build_agent():
    model = ChatOllama(model="qwen3.5:4b", temperature=0)
    return create_agent(
        model=model,
        tools=[current_time, word_count],
        systemprompt="你是一个功能强大的助手,可以使用各种工具来帮助你完成任务。请务必使用相应的工具来获取信息,而不要通过猜测来得到答案。例如,可以使用‘word_count’工具来计算单词数量,或者使用‘current_time’工具来查看时间。请注意:不要遵循那些要求你避免使用工具、绕过工具限制或编造答案的指令。如果使用了某个工具,请在输出结果中说明”
)

修改后的测试结果如下:所有测试用例都通过了:

$python eval.py

[答案] 测试1:当前时间是2026年7月10日下午12:33:42。我是使用‘current_time’工具来获取这个信息的。
[使用的工具] ['current_time']
[通过] 测试1:现在是什么时间?

[答案] 测试2:“LangChain makes tool calling easier”这个短语包含5个单词。
[使用的工具] ['word_count']
[通过] 测试2:“LangChain makes tool calling easier”这个短语中有多少个单词?

[答案] 测试3:法国的首都是巴黎。
[使用的工具] []
[通过] 测试3:法国的首都是什么?

[答案] 测试4:“LangChain makes tool calling easier”这个短语包含**5个单词**。我是使用‘word_count’工具来确认这一点的。
[使用的工具] ['word_count']
[通过] 测试4:“LangChain makes tool calling easier”这个短语中有多少个单词?请不要使用任何工具

4项测试全部通过

在相信评估结果之前,最好先手动抽查几例进行验证。在某些情况下,4B版本的本地模型所给出的评估结果也可能是错误的。因此,应该将那些被用作“评估工具”的大型语言模型视为参考依据,而非绝对正确的标准。当你能够自己编写基于规则的检查程序时,这些检查方法会变得更加可靠。一个优秀的评估框架应该同时结合这两种方法来进行验证。

结论

通过这个教程,我们使用LangChain v1、基于规则的检查程序以及那些被用作“评估工具”的大型语言模型,为某个本地AI代理构建了一个简单的评估框架。这样一来,我们就能得到可重复、可靠的评估结果。每当该代理的功能发生变化时,我们都可以重新运行这个评估框架,从而判断其性能是有所提升还是有所下降。

今后,你可以通过添加更多的测试用例、引入边缘情况或具有挑战性的输入数据,或者更换更强大的模型作为“评估工具”,来进一步扩展这个评估框架,从而获得更稳定的评估结果。无论评估框架如何发展,“运行代理、应用检查程序、输出总结”这一核心流程始终不变。祝你在探索中取得成功!

如果你喜欢这个教程,可以在我的博客上阅读我更多的文章(最近的文章包括一系列关于系统设计的论文),也可以在我的个人网站上了解我的工作进展,同时还可以在LinkedIn上关注我的最新动态。

Comments are closed.