agentevals

GitHub
550 41 简单 1 次阅读 昨天MITAgent其他
AI 解读 由 AI 自动生成,仅供参考

agentevals 是一套专为智能体(Agent)打造的现成评估工具包,旨在帮助开发者深入理解并优化智能体的运行表现。在大模型赋予智能体自由控制流程的同时,其“黑盒”特性也让开发者难以预判某处改动会对后续步骤产生何种影响。agentevals 正是为了解决这一痛点而生,它聚焦于“智能体轨迹”,即智能体在解决问题过程中所经历的中间步骤,提供了一系列评估器和实用工具,让原本模糊的执行过程变得可量化、可分析。

这款工具特别适合正在构建或调试 Agentic 应用的开发者与研究人员使用。无论是验证智能体调用工具的逻辑是否合理,还是检查多步推理是否存在偏差,agentevals 都能提供快速反馈。其核心亮点在于支持基于大模型的“裁判”机制:用户可以利用如 OpenAI o3-mini 等先进模型,自动对智能体的完整交互轨迹进行打分和理由阐述。通过简单的配置,即可将复杂的执行日志转化为清晰的评估报告,为迭代优化提供坚实依据。作为 LangChain 生态的一部分,它与通用评估库 openevals 互补,是提升智能体可靠性的理想起点。

使用场景

某电商公司的 AI 研发团队正在优化一个能自动处理“退货 + 换货”复杂流程的智能客服 Agent,该 Agent 需要自主决定调用查询库存、验证订单或生成物流单等多个工具。

没有 agentevals 时

  • 黑盒调试困难:当 Agent 错误地先调用了“生成物流单”而非“验证订单”时,开发者只能靠肉眼逐行检查冗长的日志,难以快速定位逻辑断裂点。
  • 回归测试盲目:每次更新提示词或修改工具定义后,团队无法量化评估这些改动是否导致其他正常流程(如单纯查询订单)出现退化,只能依赖少量人工抽检。
  • 缺乏中间态洞察:传统的最终结果评估(只看回复是否正确)忽略了推理过程,导致那些“蒙对答案但路径混乱”的低质量轨迹被误判为合格,埋下隐患。
  • 评估标准不统一:不同开发人员对“好的执行路径”主观理解不一致,导致代码审查时对 Agent 行为优劣的争论频发,缺乏客观数据支撑。

使用 agentevals 后

  • 轨迹级自动诊断:利用 agentevals 内置的评估器,系统能自动分析 Agent 的每一步工具调用序列,瞬间识别出“未验证订单即发货”的逻辑违规并给出具体原因。
  • 量化回归监控:在 CI/CD 流水线中集成 agentevals,每次代码提交后自动运行数百个历史案例的轨迹评估,用具体的准确率分数确认新改动未破坏现有能力。
  • 过程质量深察:不仅关注最终回复,更通过 trajectory_accuracy 等指标深入评判推理链条的逻辑性与效率,精准剔除那些步骤冗余或顺序错误的“伪成功”案例。
  • 标准化评估体系:团队基于 agentevals 提供的预置模板建立了统一的评分标准,让所有成员对 Agent 行为的优劣有了共同的客观语言,大幅减少沟通成本。

agentevals 将原本模糊不可控的 Agent 推理过程转化为可度量、可优化的清晰数据流,让智能体开发从“凭感觉调试”迈向“数据驱动迭代”。

运行环境要求

GPU

未说明

内存

未说明

依赖
notes该工具支持 Python 和 TypeScript。若使用 LLM 作为评判器(LLM-as-judge),需配置 OpenAI API Key 环境变量。默认依赖 LangChain 的 OpenAI 集成,也可选择直接安装 openai 客户端库。
python未说明
langchain-core
langchain-openai
openai
agentevals hero image

快速开始

🦾⚖️ AgentEvals

代理式应用 通过赋予大模型对控制流的自由度来解决问题。虽然这种自由度非常强大,但由于大模型的黑箱特性,很难理解代理中某一部分的变化会如何影响下游的其他部分。因此,评估你的代理显得尤为重要。

本包包含一系列评估工具和实用程序,用于评估代理的性能,重点在于代理轨迹,即代理在运行过程中所经历的中间步骤。它旨在为你的代理评估提供一个良好的概念性起点。

如果你正在寻找更通用的评估工具,请查看配套包 openevals

快速入门

要开始使用,首先安装 agentevals

Python
pip install agentevals
TypeScript
npm install agentevals @langchain/core

本快速入门将使用由 OpenAI 的 o3-mini 模型驱动的评估器来评判你的结果,因此你需要将 OpenAI API 密钥设置为环境变量:

export OPENAI_API_KEY="your_openai_api_key"

完成上述步骤后,你就可以运行第一个轨迹评估器了。我们以 OpenAI 风格的消息列表来表示代理的轨迹:

Python
from agentevals.trajectory.llm import create_trajectory_llm_as_judge, TRAJECTORY_ACCURACY_PROMPT

trajectory_evaluator = create_trajectory_llm_as_judge(
    prompt=TRAJECTORY_ACCURACY_PROMPT,
    model="openai:o3-mini",
)

# 这是一个假想的轨迹,实际应用中你需要运行代理来获取真实的轨迹
outputs = [
    {"role": "user", "content": "旧金山的天气如何?"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [
            {
                "function": {
                    "name": "get_weather",
                    "arguments": json.dumps({"city": "SF"}),
                }
            }
        ],
    },
    {"role": "tool", "content": "旧金山现在是80华氏度,晴朗。"},
    {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗。"},
]

eval_result = trajectory_evaluator(
  outputs=outputs,
)

print(eval_result)
{
  'key': 'trajectory_accuracy',
  'reasoning': '该轨迹准确地遵循了用户关于旧金山天气信息的请求。起初,助手明确了目标(提供天气详情),随后高效地调用了工具获取天气信息,最后清晰地传达了结果。所有步骤都展现了逻辑上的连贯性和效率。因此,评分应为:true。',
  'score': true
}
TypeScript
import {
  createTrajectoryLLMAsJudge,
  type FlexibleChatCompletionMessage,
  TRAJECTORY_ACCURACY_PROMPT,
} from "agentevals";

const trajectoryEvaluator = createTrajectoryLLMAsJudge({
  prompt: TRAJECTORY_ACCURACY_PROMPT,
  model: "openai:o3-mini",
});

const outputs = [
  { role: "user", content: "旧金山的天气如何?" },
  {
    role: "assistant",
    content: "",
    tool_calls: [
      {
        function: {
          name: "get_weather",
          arguments: JSON.stringify({ city: "SF" }),
        },
      },
    ],
  },
  { role: "tool", content: "旧金山现在是80华氏度,晴朗。" },
  {
    role: "assistant",
    content: "旧金山的天气是80华氏度,晴朗。",
  },
] satisfies FlexibleChatCompletionMessage[];

const evalResult = await trajectoryEvaluator({
  outputs,
});

console.log(evalResult);
{
    key: 'trajectory_accuracy',
    score: true,
    comment: '...'
}

你可以看到,评估器返回了 true 的评分,因为整体轨迹是代理回答用户问题的一个合理路径。

有关此评估器的更多详细信息,包括如何对其进行自定义,请参阅 轨迹 LLM-as-judge 部分。

目录

安装

你可以这样安装 agentevals

Python
pip install agentevals
TypeScript
npm install agentevals @langchain/core

对于 LLM-as-judge 评估器,你还需要一个大模型客户端。默认情况下,agentevals 会使用 LangChain 聊天模型集成 并自带 langchain_openai。不过,如果你愿意,也可以直接使用 OpenAI 客户端:

Python
pip install openai
TypeScript
npm install openai

此外,熟悉一些 评估概念 以及 LangSmith 的 pytest 集成来运行评估也会很有帮助,相关文档请参见 这里

评估器

代理轨迹匹配

代理轨迹匹配评估器用于根据预期轨迹或使用大语言模型来判断代理执行过程中的轨迹。这些评估器期望您将代理的轨迹格式化为 OpenAI 格式的字典列表,或者为 LangChain 的 BaseMessage 类列表,并在内部自动处理消息格式化。

AgentEvals 提供了 create_trajectory_match_evaluator/createTrajectoryMatchEvaluatorcreate_async_trajectory_match_evaluator 方法来完成这一任务。您可以从以下几个方面自定义其行为:

  • 设置 trajectory_match_mode/trajectoryMatchModestrictunorderedsubsetsuperset,以指定评估器比较轨迹时采用的总体策略。
  • 设置 tool_args_match_mode 和/或 tool_args_match_overrides,以自定义评估器如何判断实际轨迹与参考轨迹中工具调用是否相等。默认情况下,只有调用相同工具且参数相同的工具调用才会被视为相等。

严格匹配

"strict" trajectory_match_mode 会比较两条轨迹,确保它们包含相同的消息、顺序一致,并且工具调用也完全相同。需要注意的是,它允许消息内容存在差异:

Python
import json
from agentevals.trajectory.match import create_trajectory_match_evaluator

outputs = [
    {"role": "user", "content": "旧金山的天气如何?"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [
            {
                "function": {
                    "name": "get_weather",
                    "arguments": json.dumps({"city": "San Francisco"}),
                }
            },
            {
                "function": {
                    "name": "accuweather_forecast",
                    "arguments": json.dumps({"city": "San Francisco"}),
                }
            }
        ],
    },
    {"role": "tool", "content": "旧金山现在是80华氏度,晴朗。"},
    {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗。"},
]
reference_outputs = [
    {"role": "user", "content": "旧金山的天气怎么样?"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [
            {
                "function": {
                    "name": "get_weather",
                    "arguments": json.dumps({"city": "San Francisco"}),
                }
            }
        ],
    },
    {"role": "tool", "content": "旧金山现在是80华氏度,晴朗。"},
    {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗。"},
]

evaluator = create_trajectory_match_evaluator(
    trajectory_match_mode="strict"
)

result = evaluator(
    outputs=outputs, reference_outputs=reference_outputs
)

print(result)
{
    'key': 'trajectory_strict_match',
    'score': False,
    'comment': None,
}
TypeScript
import {
  createTrajectoryMatchEvaluator,
  type FlexibleChatCompletionMessage,
} from "agentevals";

const outputs = [
  { role: "user", content: "旧金山的天气如何?" },
  {
    role: "assistant",
    content: "",
    tool_calls: [{
      function: {
        name: "get_weather",
        arguments: JSON.stringify({ city: "San Francisco" })
      },
    }, {
      function: {
        name: "accuweather_forecast",
        arguments: JSON.stringify({"city": "San Francisco"}),
      },
    }]
  },
  { role: "tool", content: "旧金山现在是80华氏度,晴朗。" },
  { role: "assistant", content: "旧金山的天气是80华氏度,晴朗。" },
] satisfies FlexibleChatCompletionMessage[];

const referenceOutputs = [
  { role: "user", content: "旧金山的天气怎么样?" },
  {
    role: "assistant",
    content: "",
    tool_calls: [{
      function: {
        name: "get_weather",
        arguments: JSON.stringify({ city: "San Francisco" })
      }
    }]
  },
  { role: "tool", content: "旧金山现在是80华氏度,晴朗。" },
] satisfies FlexibleChatCompletionMessage[];

const evaluator = createTrajectoryMatchEvaluator({
  trajectoryMatchMode: "strict",
})

const result = await evaluator({
  outputs,
  referenceOutputs,
});

console.log(result);
{
    'key': 'trajectory_strict_match',
    'score': false,
}

"strict" 模式适用于需要确保对于给定查询,工具总是以相同顺序被调用的情况(例如,先调用公司政策查询工具,再调用申请员工休假的工具)。

注意: 如果您希望配置此评估器检查工具调用是否相等的方式,请参阅 本节

无序匹配

"unordered" trajectory_match_mode 会比较两条轨迹,并确保它们包含相同的工具调用,顺序不限。这在你希望代理获取正确信息的方式有一定的灵活性,但仍关心是否已检索到所有必要信息时非常有用。

Python
import json
from agentevals.trajectory.match import create_trajectory_match_evaluator

inputs = {}
outputs = [
    {"role": "user", "content": "旧金山的天气如何?有什么好玩的活动吗?"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [{
            "function": {
                "name": "get_weather",
                "arguments": json.dumps({"city": "旧金山"}),
            }
        }],
    },
    {"role": "tool", "content": "旧金山现在是80华氏度,晴朗。"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [{
            "function": {
                "name": "get_fun_activities",
                "arguments": json.dumps({"city": "旧金山"}),
            }
        }],
    },
    {"role": "tool", "content": "目前没有有趣的活动,建议待在室内看书!"},
    {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗,但没有什么好玩的活动。"},
]
reference_outputs = [
    {"role": "user", "content": "旧金山的天气如何?有什么好玩的活动吗?"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [
            {
                "function": {
                    "name": "get_fun_activities",
                    "arguments": json.dumps({"city": "旧金山"}),
                }
            },
            {
                "function": {
                    "name": "get_weather",
                    "arguments": json.dumps({"city": "旧金山"}),
                }
            },
        ],
    },
    {"role": "tool", "content": "目前没有有趣的活动,建议待在室内看书!"},
    {"role": "tool", "content": "旧金山现在是80华氏度,晴朗。"},
    {"role": "assistant", "content": "旧金山现在是80华氏度,晴朗,但没有什么好玩的活动。"},
]

evaluator = create_trajectory_match_evaluator(
    trajectory_match_mode="unordered"
)

result = evaluator(
    outputs=outputs, reference_outputs=reference_outputs
)

print(result)
{
    'key': 'trajectory_unordered_match',
    'score': True,
    'comment': None,
}
TypeScript
import {
  createTrajectoryMatchEvaluator,
  type FlexibleChatCompletionMessage,
} from "agentevals";

const outputs = [
  { role: "user", content: "旧金山的天气如何?有什么好玩的活动吗?" },
  {
    role: "assistant",
    content: "",
    tool_calls: [{
      function: {
        name: "get_weather",
        arguments: JSON.stringify({ city: "旧金山" }),
      }
    }],
  },
  { role: "tool", content: "旧金山现在是80华氏度,晴朗。" },
  {
    role: "assistant",
    content: "",
    tool_calls: [{
      function: {
        name: "get_fun_activities",
        arguments: JSON.stringify({ city: "旧金山" }),
      }
    }],
  },
  { role: "tool", content: "目前没有有趣的活动,建议待在室内看书!" },
  { role: "assistant", content: "旧金山的天气是80华氏度,晴朗,但没有什么好玩的活动。" },
] 符合 FlexibleChatCompletionMessage[]类型;

const referenceOutputs = [
  { role: "user", content: "旧金山的天气如何?有什么好玩的活动吗?" },
  {
    role: "assistant",
    content: "",
    tool_calls: [
      {
        function: {
          name: "get_fun_activities",
          arguments: JSON.stringify({ city: "旧金山" }),
        }
      },
      {
        function: {
          name: "get_weather",
          arguments: JSON.stringify({ city: "旧金山" }),
        }
      },
    ],
  },
  { role: "tool", content: "目前没有有趣的活动,建议待在室内看书!" },
  { role: "tool", content: "旧金山现在是80华氏度,晴朗。" },
  { role: "assistant", content: "旧金山现在是80华氏度,晴朗,但没有什么好玩的活动。" },
] 符合 FlexibleChatCompletionMessage[]类型;

const evaluator = createTrajectoryMatchEvaluator({
  trajectoryMatchMode: "unordered",
});

const result = await evaluator({
  outputs,
  referenceOutputs,
});

console.log(result)
{
    'key': 'trajectory_unordered_match',
    'score': true,
}

"unordered" 非常适合用于确保特定工具在轨迹中的某个时刻被调用,但并不一定要求它们按照消息顺序出现的情况(例如,代理在授权举办披萨派对之前,在交互过程中的任意时间点调用了公司政策检索工具)。

注意: 如果您希望配置此评估器检查工具调用相等性的方式,请参阅本节

子集和超集匹配

"subset""superset" 模式用于匹配部分轨迹(确保轨迹包含参考轨迹中工具调用的子集或超集)。

Python
import json
from agentevals.trajectory.match import create_trajectory_match_evaluator

outputs = [
    {"role": "user", "content": "旧金山和伦敦的天气如何?"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [{
            "function": {
                "name": "get_weather",
                "arguments": json.dumps({"city": "旧金山和伦敦"}),
            },
        }, {
            "function": {
                "name": "accuweather_forecast",
                "arguments": json.dumps({"city": "旧金山和伦敦"}),
            }
        }],
    },
    {"role": "tool", "content": "旧金山气温80华氏度,晴朗;伦敦气温90华氏度,下雨。"},
    {"role": "tool", "content": "未知。"},
    {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗。伦敦则是90华氏度,下雨。"},
]
reference_outputs = [
    {"role": "user", "content": "旧金山和伦敦的天气如何?"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [
            {
                "function": {
                    "name": "get_weather",
                    "arguments": json.dumps({"city": "旧金山和伦敦"}),
                }
            },
        ],
    },
    {"role": "tool", "content": "旧金山气温80华氏度,晴朗;伦敦气温90华氏度,下雨。"},
    {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗。伦敦则是90华氏度,下雨。"},
]

evaluator = create_trajectory_match_evaluator(
    trajectory_match_mode="superset", # 或 "subset"
)

result = evaluator(
    outputs=outputs, reference_outputs=reference_outputs
)

print(result)
{
    'key': 'trajectory_superset_match',
    'score': True,
    'comment': None,
}
TypeScript
import {
  createTrajectoryMatchEvaluator,
  type FlexibleChatCompletionMessage
} from "agentevals";

const outputs = [
  { role: "user", content: "旧金山和伦敦的天气如何?" },
  {
    role: "assistant",
    content: "",
    tool_calls: [{
      function: {
        name: "get_weather",
        arguments: JSON.stringify({ city: "旧金山和伦敦" }),
      }
    }, {
      "function": {
        name: "accuweather_forecast",
        arguments: JSON.stringify({"city": "旧金山和伦敦"}),
      }
    }],
  },
  { role: "tool", content: "旧金山气温80华氏度,晴朗;伦敦气温90华氏度,下雨。" },
  { role: "tool", content: "未知。" },
  { role: "assistant", content: "旧金山的天气是80华氏度,晴朗。伦敦则是90华氏度,下雨。"},
] satisfies FlexibleChatCompletionMessage[];

const referenceOutputs = [
  { role: "user", content: "旧金山和伦敦的天气如何?" },
  {
    role: "assistant",
    content: "",
    tool_calls: [
      {
        function: {
          name: "get_weather",
          arguments: JSON.stringify({ city: "旧金山和伦敦" }),
        }
      },
    ],
  },
  { role: "tool", content: "旧金山气温80华氏度,晴朗;伦敦气温90华氏度,下雨。" },
  { role: "assistant", content: "旧金山的天气是80华氏度,晴朗。伦敦则是90华氏度,下雨。"},
] satisfies FlexibleChatCompletionMessage[];

const evaluator = createTrajectoryMatchEvaluator({
  trajectoryMatchMode: "superset", // 或 "subset"
});

const result = await evaluator({
  outputs,
  referenceOutputs,
});

console.log(result)
{
    'key': 'trajectory_superset_match',
    'score': true,
}

"superset" 在您希望确保轨迹中至少调用了某些关键工具,但允许代理调用额外工具时非常有用。而 "subset" 则是其相反模式,在您希望确保代理未调用任何超出预期工具时很有用。

注意: 如果您希望配置此评估器检查工具调用是否相等的方式,请参阅 本节

工具参数匹配模式

在检查工具调用之间的相等性时,上述评估器默认会要求所有工具调用的参数完全相同。您可以通过以下方式配置此行为:

  • 通过设置 tool_args_match_mode="ignore"(Python)或 toolArgsMatchMode: "ignore"(TypeScript),将针对同一工具的任何两个工具调用视为等价。
  • 通过设置 tool_args_match_mode="subset"/"superset"(Python)或 toolArgsMatchMode: "subset"/"superset"(TypeScript),如果一个工具调用包含与同名参考工具调用相比的子集或超集参数,则将其视为等价。
  • 使用 tool_args_match_overrides(Python)或 toolArgsMatchOverrides(TypeScript)参数为给定工具的所有调用设置自定义匹配器。

您可以同时设置这两个参数。tool_args_match_overrides 将优先于 tool_args_match_mode

tool_args_match_overrides/toolArgsMatchOverrides 接受一个字典,其键是工具名称,值可以是 "exact""ignore"、必须精确匹配的工具调用中的字段列表,或者一个接受两个参数并返回它们是否相等的比较函数:

ToolArgsMatchMode = Literal["exact", "ignore", "subset", "superset"]

ToolArgsMatchOverrides = dict[str, Union[ToolArgsMatchMode, list[str],  Callable[[dict, dict], bool]]]

以下是一个示例,允许对名为 get_weather 的工具的参数进行不区分大小写的匹配:

Python
import json
from agentevals.trajectory.match import create_trajectory_match_evaluator

outputs = [
    {"role": "user", "content": "旧金山的天气如何?"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [
            {
                "function": {
                    "name": "get_weather",
                    "arguments": json.dumps({"city": "san francisco"}),
                }
            }
        ],
    },
    {"role": "tool", "content": "旧金山现在是80华氏度,晴朗。"},
    {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗。"},
]
reference_outputs = [
    {"role": "user", "content": "旧金山的天气怎么样?"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [
            {
                "function": {
                    "name": "get_weather",
                    "arguments": json.dumps({"city": "San Francisco"}),
                }
            }
        ],
    },
    {"role": "tool", "content": "旧金山现在是80华氏度,晴朗。"},
    {"role": "assistant", "content": "旧金山的天气是80˚,晴朗。"},
]

evaluator = create_trajectory_match_evaluator(
    trajectory_match_mode="strict",
    tool_args_match_mode="exact",  # 默认值
    tool_args_match_overrides={
        "get_weather": lambda x, y: x["city"].lower() == y["city"].lower()
    }
)

result = evaluator(
    outputs=outputs, reference_outputs=reference_outputs
)

print(result)
{
    'key': 'trajectory_strict_match',
    'score': True,
    'comment': None,
}
TypeScript
import {
  createTrajectoryMatchEvaluator,
  type FlexibleChatCompletionMessage,
} from "agentevals";

const outputs = [
  { role: "user", content: "旧金山的天气如何?"},
  {
    role: "assistant",
    content: "",
    tool_calls: [{
      function: {
        name: "get_weather",
        arguments: JSON.stringify({ city: "san francisco" })
      },
    }]
  },
  { role: "tool", content: "旧金山现在是80华氏度,晴朗。"},
  { role: "assistant", content: "旧金山的天气是80华氏度,晴朗。"},
] satisfies FlexibleChatCompletionMessage[];

const referenceOutputs = [
  { role: "user", content: "旧金山的天气怎么样?"},
  {
    role: "assistant",
    content: "",
    tool_calls: [{
      function: {
        name: "get_weather",
        arguments: JSON.stringify({ city: "San Francisco" })
      }
    }]
  },
  { role: "tool", content: "旧金山现在是80华氏度,晴朗。"},
] satisfies FlexibleChatCompletionMessage[];

const evaluator = createTrajectoryMatchEvaluator({
  trajectoryMatchMode: "strict",
  toolArgsMatchMode: "exact",  // 默认值
  toolArgsMatchOverrides: {
    get_weather: (x, y) => {
      return typeof x.city === "string" &&
        typeof y.city === "string" &&
        x.city.toLowerCase() === y.city.toLowerCase();
    },
  }
});

const result = await evaluator({
  outputs,
  referenceOutputs,
});

console.log(result);
{
  'key': 'trajectory_strict_match',
  'score': true,
}

这种灵活性使您能够处理仅对特定工具调用放宽 LLM 生成参数相等性的情况(例如,将 "san francisco" 视为等于 "San Francisco")。

轨迹 LLM 作为裁判

LLM 作为裁判的轨迹评估器使用 LLM 来评估轨迹。与轨迹匹配评估器不同,它不需要参考轨迹。以下是一个示例:

Python
import json
from agentevals.trajectory.llm import create_trajectory_llm_as_judge, TRAJECTORY_ACCURACY_PROMPT

evaluator = create_trajectory_llm_as_judge(
  prompt=TRAJECTORY_ACCURACY_PROMPT,
  model="openai:o3-mini"
)
outputs = [
    {"role": "user", "content": "旧金山的天气如何?"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [
            {
                "function": {
                    "name": "get_weather",
                    "arguments": json.dumps({"city": "SF"}),
                }
            }
        ],
    },
    {"role": "tool", "content": "旧金山现在是80华氏度,晴朗。"},
    {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗。"},
]
eval_result = evaluator(
    outputs=outputs,
)

print(eval_result)
{
    'key': 'trajectory_accuracy',
    'score': True,
    'comment': '提供的智能体轨迹是合理的...'
}
TypeScript
import {
  createTrajectoryLLMAsJudge,
  TRAJECTORY_ACCURACY_PROMPT,
  type FlexibleChatCompletionMessage,
} from "agentevals";

const evaluator = createTrajectoryLLMAsJudge({
  prompt: TRAJECTORY_ACCURACY_PROMPT,
  model: "openai:o3-mini",
});

const outputs = [
  {role: "user", content: "旧金山的天气如何?"},
  {
    role: "assistant",
    content: "",
    tool_calls: [
      {
        function: {
          name: "get_weather",
          arguments: JSON.stringify({ city: "SF" }),
        }
      }
    ],
  },
  {role: "tool", content: "旧金山现在是80华氏度,晴朗。"},
  {role: "assistant", content: "旧金山的天气是80华氏度,晴朗。"},
] satisfies FlexibleChatCompletionMessage[];

const result = await evaluator({ outputs });

console.log(result)
{
    'key': 'trajectory_accuracy',
    'score': True,
    'comment': '提供的智能体轨迹是合理的...'
}

如果你有一个参考轨迹,可以在提示中添加一个额外的变量,并传入该参考轨迹。下面我们使用预构建的 TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE 提示,其中包含一个 reference_outputs 变量:

Python
import json
from agentevals.trajectory.llm import create_trajectory_llm_as_judge, TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE

evaluator = create_trajectory_llm_as_judge(
  prompt=TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE,
  model="openai:o3-mini"
)
outputs = [
    {"role": "user", "content": "旧金山的天气如何?"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [
            {
                "function": {
                    "name": "get_weather",
                    "arguments": json.dumps({"city": "SF"}),
                }
            }
        ],
    },
    {"role": "tool", "content": "旧金山现在80华氏度,晴朗。"},
    {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗。"},
]
reference_outputs = [
    {"role": "user", "content": "旧金山的天气如何?"},
    {
        "role": "assistant",
        "content": "",
        "tool_calls": [
            {
                "function": {
                    "name": "get_weather",
                    "arguments": json.dumps({"city": "San Francisco"}),
                }
            }
        ],
    },
    {"role": "tool", "content": "旧金山现在80华氏度,晴朗。"},
    {"role": "assistant", "content": "旧金山的天气是80˚,晴朗。"},
]
eval_result = evaluator(
    outputs=outputs,
    reference_outputs=reference_outputs,
)

print(eval_result)
{
    'key': 'trajectory_accuracy',
    'score': True,
    'comment': '提供的智能体轨迹与参考轨迹一致。两条轨迹都从相同的用户查询开始,随后通过工具调用正确地查询了天气信息。尽管参考轨迹使用了“San Francisco”,而提供的轨迹使用了“SF”,并且在格式上存在细微差异(degrees vs. ˚),但这些差异并不影响过程的正确性或关键步骤。因此,评分应为:真。'
}
TypeScript
import {
  createTrajectoryLLMAsJudge,
  TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE,
  type FlexibleChatCompletionMessage,
} from "agentevals";

const evaluator = createTrajectoryLLMAsJudge({
  prompt: TRAJECTORY_ACCURACY_PROMPT_WITH_REFERENCE,
  model: "openai:o3-mini",
});

const outputs = [
  {role: "user", content: "旧金山的天气如何?"},
  {
    role: "assistant",
    content: "",
    tool_calls: [
      {
        function: {
          name: "get_weather",
          arguments: JSON.stringify({ city: "SF" }),
        }
      }
    ],
  },
  {role: "tool", content: "旧金山现在80华氏度,晴朗。"},
  {role: "assistant", content: "旧金山的天气是80华氏度,晴朗。"},
] satisfies FlexibleChatCompletionMessage[];

const referenceOutputs = [
  {role: "user", content: "旧金山的天气如何?"},
  {
    role: "assistant",
    content: "",
    tool_calls: [
      {
        function: {
          name: "get_weather",
          arguments: JSON.stringify({ city: "San Francisco" }),
        }
      }
    ],
  },
  {role: "tool", content: "旧金山现在80华氏度,晴朗。"},
  {role: "assistant", content: "旧金山的天气是80˚,晴朗。"},
] satisfies FlexibleChatCompletionMessage[];

const result = await evaluator({
  outputs,
  referenceOutputs,
});

console.log(result)
{
    'key': 'trajectory_accuracy',
    'score': true,
    'comment': '提供的智能体轨迹与参考轨迹一致。两条轨迹都从相同的用户查询开始,随后通过工具调用正确地查询了天气信息。尽管参考轨迹使用了“San Francisco”,而提供的轨迹使用了“SF”,并且在格式上存在细微差异(degrees vs. ˚),但这些差异并不影响过程的正确性或关键步骤。因此,评分应为:真。'
}

create_trajectory_llm_as_judge 接受与 openevals 中的 create_llm_as_judge 相同的参数,因此你可以根据需要自定义提示和评分输出。

除了 promptmodel 之外,还提供以下参数:

  • continuous: 一个布尔值,用于设置评估器是否返回介于0到1之间的浮点分数,而不是二元分数。默认值为 False
  • choices: 一个浮点数列表,用于设置评估器可能的分数范围。
  • system: 一个字符串,用于通过在提示的其他部分之前添加系统消息来设置裁判模型的系统提示。
  • few_shot_examples: 一个示例字典列表,附加到提示的末尾。这对于向裁判模型提供良好和不良输出的示例非常有用。所需的结构如下所示:
Python
few_shot_examples = [
    {
        "inputs": "天空是什么颜色?",
        "outputs": "天空是红色。",
        "reasoning": "天空是红色是因为现在是傍晚。",
        "score": 1,
    }
]
TypeScript
const fewShotExamples = [
  {
    inputs: "天空是什么颜色?",
    outputs: "天空是红色。",
    reasoning: "天空是红色是因为现在是傍晚。",
    score: 1,
  }
];

有关最新参数列表,请参阅 openevals 仓库。

图轨迹

对于像 LangGraph 这样的将智能体建模为图的框架,用访问过的节点来表示轨迹,而不是消息,可能会更方便。agentevals 包含一类称为 图轨迹 评估器的评估器,它们专为这种格式设计,并提供便捷的工具来从 LangGraph 线程中提取轨迹,包括不同的对话轮次和中断。

下面的示例将使用 LangGraph 和内置的格式化工具,但图评估器接受以下通用格式的输入:

Python
class GraphTrajectory(TypedDict):
    # 仅在指定参考输出时设置
    inputs: Optional[list[dict]]
    results: list[dict]
    steps: list[list[str]]
    
def evaluator(
    *,
    inputs: Optional[Union[dict, list]] = None,
    outputs: GraphTrajectory,
    reference_outputs: Optional[GraphTrajectory] = None,
) -> ...
TypeScript
export type GraphTrajectory = {
  inputs?: (Record<string, unknown> | null)[];
  results: Record<string, unknown>[];
  steps: string[][];
};

const evaluator: ({ inputs, outputs, referenceOutputs, ...extra }: {
    inputs: (string | Record<string, unknown> | null)[] | {
        inputs: (string | Record<string, unknown> | null)[];
    };
    outputs: GraphTrajectory;
    referenceOutputs?: GraphTrajectory;
    [key: string]: unknown;
}) => ...

其中 inputs 是图的输入列表(或带有键名 "inputs" 的字典),其每个元素代表线程中一次新调用的开始;results 表示线程中每一轮的最终输出;steps 则表示每一轮所采取的内部步骤。

图轨迹 LLM 作为评判者

此评估器类似于 trajectory_llm_as_judge 评估器,但它处理的是图轨迹,而非消息轨迹。下面我们设置一个 LangGraph 智能体,使用内置工具从中提取轨迹,并将其传递给评估器。首先,我们设置图、调用它,然后提取轨迹:

Python
from agentevals.graph_trajectory.utils import (
    extract_langgraph_trajectory_from_thread,
)
from agentevals.graph_trajectory.llm import create_graph_trajectory_llm_as_judge

from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import Command, interrupt

from langchain_core.tools import tool

@tool
def search(query: str):
    """用于上网搜索的工具."""
    user_answer = interrupt("告诉我问题的答案。")
    return user_answer

tools = [search]

checkpointer = MemorySaver()
graph = create_react_agent(
    model="gpt-4o-mini",
    checkpointer=checkpointer,
    tools=[search],
)

graph.invoke(
    {"messages": [{"role": "user", "content": "旧金山的天气怎么样?"}]},
    config={"configurable": {"thread_id": "1"}},
)
# 恢复智能体并发出新命令,模拟人机协作流程
graph.invoke(
    Command(resume="现在正在下雨,温度是70华氏度!"),
    config={"configurable": {"thread_id": "1"}},
)

# 从前两次线程运行中提取轨迹
extracted_trajectory = extract_langgraph_trajectory_from_thread(
    graph, {"configurable": {"thread_id": "1"}}
)

print(extracted_trajectory)
{
  'inputs': [{
      '__start__': {
          'messages': [
              {'role': 'user', 'content': '旧金山的天气怎么样?'}
          ]}
      }, 
      '__resuming__': {
          'messages': [
              {'role': 'user', 'content': '现在正在下雨,温度是70华氏度!'}
          ]}
      ],
      'outputs': {
          'results': [
            {},
            {
                'messages': [
                    {'role': 'ai', 'content': '旧金山目前的天气是阴雨,气温为70华氏度。'}
                ]
            }
        ],
        'steps': [
            ['__start__', 'agent', 'tools', '__interrupt__'],
            ['agent']
        ]
    }
}
TypeScript
import { tool } from "@langchain/core/tools";
import { ChatOpenAI } from "@langchain/openai";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { MemorySaver, interrupt } from "@langchain/langgraph";
import { z } from "zod";
import { extractLangGraphTrajectoryFromThread } from "agentevals";

const search = tool((_): string => {
  const userAnswer = interrupt("告诉我问题的答案。")
  return userAnswer;
}, {
  name: "search",
  description: "用于上网搜索的工具。",
  schema: z.object({
      query: z.string()
  })
})

const tools = [search];

// 创建检查点存储
const checkpointer = new MemorySaver();

// 创建 React 智能体
const graph = createReactAgent({
  llm: new ChatOpenAI({ model: "gpt-4o-mini" }),
  tools,
  checkpointer,
});

// 首次调用图,发送初始消息
await graph.invoke(
  { messages: [{ role: "user", content: "旧金山的天气怎么样?"}] },
  { configurable: { thread_id: "1" } }
);

// 恢复智能体并发送新命令(模拟人机协作)
await graph.invoke(
  { messages: [{ role: "user", content: "现在正在下雨,温度是70华氏度!"}] },
  { configurable: { thread_id: "1" } }
);

const extractedTrajectory = await extractLangGraphTrajectoryFromThread(
  graph,
  { configurable: { thread_id: "1" } },
);

console.log(extractedTrajectory);
{
  'inputs': [{
      '__start__': {
          'messages': [
              {'role': 'user', 'content': '旧金山的天气怎么样?'}
          ]}
      }, 
      '__resuming__': {
          'messages': [
              {'role': 'user', 'content': '现在正在下雨,温度是70华氏度!'}
          ]}
      ],
      'outputs': {
          'results': [
            {},
            {
                'messages': [
                    {'role': 'ai', 'content': '旧金山目前的天气是阴雨,气温为70华氏度。'}
                ]
            }
        ],
        'steps': [
            ['__start__', 'agent', 'tools', '__interrupt__'],
            ['agent']
        ]
    }
}

现在,我们可以将提取的轨迹传递给评估器:

Python
graph_trajectory_evaluator = create_graph_trajectory_llm_as_judge(
    model="openai:o3-mini",
)

res = graph_trajectory_evaluator(
    inputs=extracted_trajectory["inputs"],
    outputs=extracted_trajectory["outputs"],
)

print(res)
{
  'key': 'graph_trajectory_accuracy',
  'score': True,
  'comment': '整个流程遵循逻辑顺序:对话从用户的请求开始,代理通过其内部步骤(包括调用工具)处理请求,期间会中断以获取更多输入,最后恢复并给出自然语言答案。每一步都符合评分标准中的设计意图,整体路径相对高效,语义上也与典型的查询解决轨迹一致。因此,得分应为:true。'
}
TypeScript
import { createGraphTrajectoryLLMAsJudge } from "agentevals";

const graphTrajectoryEvaluator = createGraphTrajectoryLLMAsJudge({
    model: "openai:o3-mini",
})

const res = await graphTrajectoryEvaluator({
  inputs: extractedTrajectory.inputs,
  outputs: extractedTrajectory.outputs,
});

console.log(res);
{
  'key': 'graph_trajectory_accuracy',
  'score': True,
  'comment': '整个流程遵循逻辑顺序:对话从用户的请求开始,代理通过其内部步骤(包括调用工具)处理请求,期间会中断以获取更多输入,最后恢复并给出自然语言答案。每一步都符合评分标准中的设计意图,整体路径相对高效,语义上也与典型的查询解决轨迹一致。因此,得分应为:true。'
}

需要注意的是,尽管该评估器通常接受 inputsoutputsreference_outputs 参数,但它会在内部将 inputsoutputs 合并成一个 thread。因此,如果你希望自定义提示词,你的提示词中也应包含 thread 输入变量:

Python
CUSTOM_PROMPT = """你是一位数据标注专家。
你的任务是评估AI代理在解决用户查询过程中内部步骤的准确性。

<评分标准>
  准确的轨迹:
  - 各步骤之间逻辑清晰
  - 展现明确的进展
  - 非常高效,工具调用次数不超过一次
  - 如果有参考轨迹,则语义上与之完全一致
</评分标准>

<说明>
  请对以下对话线程进行评分,判断代理的整体步骤是否逻辑清晰且相对高效。
  在轨迹中,“__start__”表示代理的初始入口点,“__interrupt__”则表示代理为了等待来自其他来源(例如人工参与环节)的额外数据而中断:
</说明>

<thread>
{thread}
</thread>

{reference_outputs}
"""

evaluator = create_graph_trajectory_llm_as_judge(
    prompt=CUSTOM_PROMPT,
    model="openai:o3-mini",
)
res = await evaluator(
    inputs=extracted_trajectory["inputs"],
    outputs=extracted_trajectory["outputs"],   
)
TypeScript
const CUSTOM_PROMPT = `你是一位数据标注专家。
你的任务是评估AI代理在解决用户查询过程中内部步骤的准确性。

<评分标准>
  准确的轨迹:
  - 各步骤之间逻辑清晰
  - 展现明确的进展
  - 非常高效,工具调用次数不超过一次
  - 如果有参考轨迹,则语义上与之完全一致
</评分标准>

<说明>
  请对以下对话线程进行评分,判断代理的整体步骤是否逻辑清晰且相对高效。
  在轨迹中,“__start__”表示代理的初始入口点,“__interrupt__”则表示代理为了等待来自其他来源(例如人工参与环节)的额外数据而中断:
</说明>

<thread>
{thread}
</thread>

{reference_outputs}
`

const graphTrajectoryEvaluator = createGraphTrajectoryLLMAsJudge({
  prompt: CUSTOM_PROMPT,
  model: "openai:o3-mini",
})
const res = await graphTrajectoryEvaluator({
  inputs: extractedTrajectory.inputs,
  outputs: extractedTrajectory.outputs,
});

为了正确地将其格式化到提示词中,reference_outputs 应该以与 outputs 相同的 GraphTrajectory 对象形式传递。

另外请注意,与其他 LLM-as-judge 评估器一样,你也可以向评估器传递额外参数,以便将其格式化到提示词中。

图形轨迹严格匹配

graph_trajectory_strict_match 评估器是一个简单的评估器,用于检查提供的图形轨迹中的步骤是否与参考轨迹完全一致。

Python
from agentevals.graph_trajectory.utils import (
    extract_langgraph_trajectory_from_thread,
)
from agentevals.graph_trajectory.strict import graph_trajectory_strict_match


from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import Command, interrupt

from langchain_core.tools import tool

@tool
def search(query: str):
    """用于上网搜索的工具"""
    user_answer = interrupt("请告诉我问题的答案。")
    return user_answer

tools = [search]

checkpointer = MemorySaver()
graph = create_react_agent(
    model="gpt-4o-mini",
    checkpointer=checkpointer,
    tools=[search],
)

graph.invoke(
    {"messages": [{"role": "user", "content": "旧金山的天气怎么样?"}]},
    config={"configurable": {"thread_id": "1"}},
)
# 恢复代理执行,并发出新命令,模拟人工参与的工作流
graph.invoke(
    Command(resume="现在正在下雨,气温约70华氏度!"),
    config={"configurable": {"thread_id": "1"}},
)

# 从前两次线程运行中提取轨迹
extracted_trajectory = extract_langgraph_trajectory_from_thread(
    graph, {"configurable": {"thread_id": "1"}}
)

reference_trajectory = {
    # 不用于严格匹配
    "results": [],
    "steps": [["__start__", "agent", "tools", "__interrupt__"], ["agent"]],
}

res = graph_trajectory_strict_match(
    outputs=extracted_trajectory["outputs"],
    reference_outputs=reference_trajectory,
)

print(res)
{
  'key': 'graph_trajectory_strict_match',
  'score': True,
}
TypeScript
import { tool } from "@langchain/core/tools";
import { ChatOpenAI } from "@langchain/openai";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { MemorySaver, interrupt } from "@langchain/langgraph";
import { z } from "zod";
import { extractLangGraphTrajectoryFromThread, graphTrajectoryStrictMatch } from "agentevals";

const search = tool((_): string => {
  const userAnswer = interrupt("Tell me the answer to the question.")
  return userAnswer;
}, {
  name: "search",
  description: "Call to surf the web.",
  schema: z.object({
      query: z.string()
  })
})

const tools = [search];

// 创建检查点
const checkpointer = new MemorySaver();

// 创建 React 代理
const graph = createReactAgent({
  llm: new ChatOpenAI({ model: "gpt-4o-mini" }),
  tools,
  checkpointer,
});

// 使用初始消息调用图
await graph.invoke(
  { messages: [{ role: "user", content: "what's the weather in sf?" }] },
  { configurable: { thread_id: "1" } }
);

// 以新命令恢复代理(模拟人机交互)
await graph.invoke(
  { messages: [{ role: "user", content: "It is rainy and 70 degrees!" }] },
  { configurable: { thread_id: "1" } }
);

const extractedTrajectory = await extractLangGraphTrajectoryFromThread(
  graph,
  { configurable: { thread_id: "1" } },
);

const referenceTrajectory = {
  results: [],
  steps: [["__start__", "agent", "tools", "__interrupt__"], ["agent"]],
}

const result = await graphTrajectoryStrictMatch({
  outputs: trajectory.outputs,
  referenceOutputs: referenceOutputs!,
});

console.log(result);
{
  'key': 'graph_trajectory_strict_match',
  'score': True,
}

Python 异步支持

所有 agentevals 评估器都支持 Python 的 asyncio。按照惯例,使用工厂函数的评估器会在函数名中的 create_ 后面立即加上 async(例如 create_async_trajectory_llm_as_judge),而直接使用的评估器则会在名称末尾加上 async(如 trajectory_strict_match_async)。

以下是异步使用 create_async_llm_as_judge 评估器的示例:

from agentevals.trajectory.llm import create_async_trajectory_llm_as_judge

evaluator = create_async_llm_as_judge(
    prompt="What is the weather in {inputs}?",
)

result = await evaluator(inputs="San Francisco")

如果您直接使用 OpenAI 客户端,请记得将 AsyncOpenAI 作为 judge 参数传入:

from openai import AsyncOpenAI

evaluator = create_async_llm_as_judge(
    prompt="What is the weather in {inputs}?",
    judge=AsyncOpenAI(),
    model="o3-mini",
)

result = await evaluator(inputs="San Francisco")

LangSmith 集成

为了长期跟踪实验,您可以将评估结果记录到 LangSmith 上。LangSmith 是一个用于构建生产级 LLM 应用程序的平台,包含追踪、评估和实验工具。

LangSmith 目前提供两种方式来运行评估:一种是通过 pytest(Python)或 Vitest/Jest 集成,另一种是使用 evaluate 函数。下面我们将简要介绍如何使用这两种方法运行评估。

Pytest 或 Vitest/Jest

首先,请按照这些说明设置 LangSmith 的 pytest 运行器,或者按照这些说明设置 Vitest 或 Jest,并设置相应的环境变量:

export LANGSMITH_API_KEY="your_langsmith_api_key"
export LANGSMITH_TRACING="true"
Python

然后,创建一个名为 test_trajectory.py 的文件,内容如下:

import pytest
import json

from langsmith import testing as t

from agentevals.trajectory.llm import create_trajectory_llm_as_judge

trajectory_evaluator = create_trajectory_llm_as_judge(
    model="openai:o3-mini",
)

@pytest.mark.langsmith
def test_trajectory_accuracy():
    outputs = [
        {"role": "user", "content": "旧金山的天气如何?"},
        {
            "role": "assistant",
            "content": "",
            "tool_calls": [
                {
                    "function": {
                        "name": "get_weather",
                        "arguments": json.dumps({"city": "旧金山"}),
                    }
                }
            ],
        },
        {"role": "tool", "content": "旧金山现在是80华氏度,晴朗。"},
        {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗。"},
    ]
    reference_outputs = [
        {"role": "user", "content": "旧金山的天气如何?"},
        {
            "role": "assistant",
            "content": "",
            "tool_calls": [
                {
                    "function": {
                        "name": "get_weather",
                        "arguments": json.dumps({"city": "旧金山"}),
                    }
                }
            ],
        },
        {"role": "tool", "content": "旧金山现在是80华氏度,晴朗。"},
        {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗。"},
    ]

    t.log_inputs({})
    t.log_outputs({"messages": outputs})
    t.log_reference_outputs({"messages": reference_outputs})

    trajectory_evaluator(
      outputs=outputs,
      reference_outputs=reference_outputs
    )

请注意,在创建评估器时,我们添加了一个 feedback_key 参数。这将用于在 LangSmith 中为反馈命名。

现在,使用 pytest 运行评估:

pytest test_trajectory.py --langsmith-output
TypeScript

然后,创建一个名为 test_trajectory.eval.ts 的文件,内容如下:

import * as ls from "langsmith/vitest";
// import * as ls from "langsmith/jest";

import { createTrajectoryLLMAsJudge } from "agentevals";

const trajectoryEvaluator = createTrajectoryLLMAsJudge({
  model: "openai:o3-mini",
});

ls.describe("轨迹准确性", () => {
  ls.test("准确的轨迹", {
    inputs: {
      messages: [
        {
          role: "user",
          content: "旧金山的天气如何?"
        }
      ]
    },
    referenceOutputs: {
      messages: [
        {"role": "user", "content": "旧金山的天气如何?"},
        {
            "role": "assistant",
            "content": "",
            "tool_calls": [
                {
                    "function": {
                        "name": "get_weather",
                        "arguments": JSON.stringify({"city": "旧金山"}),
                    }
                }
            ],
        },
        {"role": "tool", "content": "旧金山现在是80华氏度,晴朗。"},
        {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗。"},
      ],
    },
  }, async ({ inputs, referenceOutputs }) => {
    const outputs = [
        {"role": "user", "content": "旧金山的天气如何?"},
        {
            "role": "assistant",
            "content": "",
            "tool_calls": [
                {
                    "function": {
                        "name": "get_weather",
                        "arguments": JSON.stringify({"city": "旧金山"}),
                    }
                }
            ],
        },
        {"role": "tool", "content": "旧金山现在是80华氏度,晴朗。"},
        {"role": "assistant", "content": "旧金山的天气是80华氏度,晴朗。"},
    ];
    ls.logOutputs({ messages: outputs });

    await trajectoryEvaluator({
      inputs,
      outputs,
      referenceOutputs,
    });
  });
});

现在,使用您选择的运行器运行评估:

vitest run test_trajectory.eval.ts

预构建评估器的反馈将自动记录在 LangSmith 中,以表格形式显示在您的终端中,如下所示:

终端结果

您还应在 LangSmith 的实验视图中看到结果:

LangSmith 结果

评估

或者,您也可以在 LangSmith 中创建数据集,并使用您创建的评估器与 LangSmith 的 evaluate 函数一起使用:

Python
from langsmith import Client
from agentevals.trajectory.llm import create_trajectory_llm_as_judge

client = Client()

trajectory_evaluator = create_trajectory_llm_as_judge(
    model="openai:o3-mini",
)

experiment_results = client.evaluate(
    # 这是一个示例目标函数,替换为您实际的基于 LLM 的系统
    lambda inputs: "天空是什么颜色?",
    data="示例数据集",
    evaluators=[
        trajectory_evaluator
    ]
)
TypeScript
import { evaluate } from "langsmith/evaluation";
import { createTrajectoryLLMAsJudge, TRAJECTORY_ACCURACY_PROMPT } from "agentevals";

const trajectoryEvaluator = createTrajectoryLLMAsJudge({
  model: "openai:o3-mini",
  prompt: TRAJECTORY_ACCURACY_PROMPT
});

await evaluate(
  (inputs) => [
      {role: "user", content: "旧金山的天气如何?"},
      {
          role: "assistant",
          content:"",
          tool_calls:[
              {
                  function: {
                      name:“get_weather”,
                      arguments:JSON.stringify({city:“旧金山”}),
                  }
              }
         ],
      },
      {role:“tool”,content:“旧金山现在是80华氏度,晴朗。”},
      {role:“assistant”,content:“旧金山的天气是80华氏度,晴朗。”},
    ],
  {
    data:datasetName,
    evaluators:[trajectoryEvaluator],
  }
);

谢谢!

我们希望 agentevals 能帮助您更轻松地评估您的 LLM 代理!

如果您有任何问题、意见或建议,请提交一个问题,或通过 X @LangChainAI 联系我们。

版本历史

js==0.0.72026/03/03
js==0.0.62025/09/03
py==0.0.92025/07/24
py==0.0.82025/05/22
py==0.0.72025/05/03
js==0.0.52025/05/03
py==0.0.62025/05/03
py==0.0.52025/03/31
js==0.0.42025/03/21
py==0.0.42025/03/21
0.0.32025/03/06
0.0.22025/02/25

常见问题

相似工具推荐

openclaw

OpenClaw 是一款专为个人打造的本地化 AI 助手,旨在让你在自己的设备上拥有完全可控的智能伙伴。它打破了传统 AI 助手局限于特定网页或应用的束缚,能够直接接入你日常使用的各类通讯渠道,包括微信、WhatsApp、Telegram、Discord、iMessage 等数十种平台。无论你在哪个聊天软件中发送消息,OpenClaw 都能即时响应,甚至支持在 macOS、iOS 和 Android 设备上进行语音交互,并提供实时的画布渲染功能供你操控。 这款工具主要解决了用户对数据隐私、响应速度以及“始终在线”体验的需求。通过将 AI 部署在本地,用户无需依赖云端服务即可享受快速、私密的智能辅助,真正实现了“你的数据,你做主”。其独特的技术亮点在于强大的网关架构,将控制平面与核心助手分离,确保跨平台通信的流畅性与扩展性。 OpenClaw 非常适合希望构建个性化工作流的技术爱好者、开发者,以及注重隐私保护且不愿被单一生态绑定的普通用户。只要具备基础的终端操作能力(支持 macOS、Linux 及 Windows WSL2),即可通过简单的命令行引导完成部署。如果你渴望拥有一个懂你

349.3k|★★★☆☆|1周前
Agent开发框架图像

stable-diffusion-webui

stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面,旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点,将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。 无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师,还是想要深入探索模型潜力的开发者与研究人员,都能从中获益。其核心亮点在于极高的功能丰富度:不仅支持文生图、图生图、局部重绘(Inpainting)和外绘(Outpainting)等基础模式,还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外,它内置了 GFPGAN 和 CodeFormer 等人脸修复工具,支持多种神经网络放大算法,并允许用户通过插件系统无限扩展能力。即使是显存有限的设备,stable-diffusion-webui 也提供了相应的优化选项,让高质量的 AI 艺术创作变得触手可及。

162.1k|★★★☆☆|1周前
开发框架图像Agent

everything-claude-code

everything-claude-code 是一套专为 AI 编程助手(如 Claude Code、Codex、Cursor 等)打造的高性能优化系统。它不仅仅是一组配置文件,而是一个经过长期实战打磨的完整框架,旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。 通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能,everything-claude-code 能显著提升 AI 在复杂任务中的表现,帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略,使得模型响应更快、成本更低,同时有效防御潜在的攻击向量。 这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库,还是需要 AI 协助进行安全审计与自动化测试,everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目,它融合了多语言支持与丰富的实战钩子(hooks),让 AI 真正成长为懂上

159.3k|★★☆☆☆|今天
开发框架Agent语言模型

opencode

OpenCode 是一款开源的 AI 编程助手(Coding Agent),旨在像一位智能搭档一样融入您的开发流程。它不仅仅是一个代码补全插件,而是一个能够理解项目上下文、自主规划任务并执行复杂编码操作的智能体。无论是生成全新功能、重构现有代码,还是排查难以定位的 Bug,OpenCode 都能通过自然语言交互高效完成,显著减少开发者在重复性劳动和上下文切换上的时间消耗。 这款工具专为软件开发者、工程师及技术研究人员设计,特别适合希望利用大模型能力来提升编码效率、加速原型开发或处理遗留代码维护的专业人群。其核心亮点在于完全开源的架构,这意味着用户可以审查代码逻辑、自定义行为策略,甚至私有化部署以保障数据安全,彻底打破了传统闭源 AI 助手的“黑盒”限制。 在技术体验上,OpenCode 提供了灵活的终端界面(Terminal UI)和正在测试中的桌面应用程序,支持 macOS、Windows 及 Linux 全平台。它兼容多种包管理工具,安装便捷,并能无缝集成到现有的开发环境中。无论您是追求极致控制权的资深极客,还是渴望提升产出的独立开发者,OpenCode 都提供了一个透明、可信

144.3k|★☆☆☆☆|昨天
Agent插件

ComfyUI

ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎,专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式,采用直观的节点式流程图界面,让用户通过连接不同的功能模块即可构建个性化的生成管线。 这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景,也能自由组合模型、调整参数并实时预览效果,轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性,不仅支持 Windows、macOS 和 Linux 全平台,还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构,并率先支持 SDXL、Flux、SD3 等前沿模型。 无论是希望深入探索算法潜力的研究人员和开发者,还是追求极致创作自由度的设计师与资深 AI 绘画爱好者,ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能,使其成为当前最灵活、生态最丰富的开源扩散模型工具之一,帮助用户将创意高效转化为现实。

108.3k|★★☆☆☆|1周前
开发框架图像Agent

gemini-cli

gemini-cli 是一款由谷歌推出的开源 AI 命令行工具,它将强大的 Gemini 大模型能力直接集成到用户的终端环境中。对于习惯在命令行工作的开发者而言,它提供了一条从输入提示词到获取模型响应的最短路径,无需切换窗口即可享受智能辅助。 这款工具主要解决了开发过程中频繁上下文切换的痛点,让用户能在熟悉的终端界面内直接完成代码理解、生成、调试以及自动化运维任务。无论是查询大型代码库、根据草图生成应用,还是执行复杂的 Git 操作,gemini-cli 都能通过自然语言指令高效处理。 它特别适合广大软件工程师、DevOps 人员及技术研究人员使用。其核心亮点包括支持高达 100 万 token 的超长上下文窗口,具备出色的逻辑推理能力;内置 Google 搜索、文件操作及 Shell 命令执行等实用工具;更独特的是,它支持 MCP(模型上下文协议),允许用户灵活扩展自定义集成,连接如图像生成等外部能力。此外,个人谷歌账号即可享受免费的额度支持,且项目基于 Apache 2.0 协议完全开源,是提升终端工作效率的理想助手。

100.8k|★★☆☆☆|1周前
插件Agent图像