evaluatedBy.js 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import { ROOT, traceable } from "../../../traceable.js";
  2. import { testWrapperAsyncLocalStorageInstance, _logTestFeedback, trackingEnabled, } from "../globals.js";
  3. import { v4 } from "uuid";
  4. function isEvaluationResult(x) {
  5. return (x != null &&
  6. typeof x === "object" &&
  7. "key" in x &&
  8. typeof x.key === "string" &&
  9. "score" in x);
  10. }
  11. export function wrapEvaluator(evaluator) {
  12. return async (input, config) => {
  13. const context = testWrapperAsyncLocalStorageInstance.getStore();
  14. if (context === undefined || context.currentExample === undefined) {
  15. throw new Error([
  16. `Could not identify current LangSmith context.`,
  17. `Please ensure you are calling this matcher within "ls.test()"`,
  18. `See this page for more information: https://docs.smith.langchain.com/evaluation/how_to_guides/vitest_jest`,
  19. ].join("\n"));
  20. }
  21. const evalRunId = config?.runId ?? config?.id ?? v4();
  22. let evalResult;
  23. if (trackingEnabled(context)) {
  24. const wrappedEvaluator = traceable(async (_runTree, params) => {
  25. return evaluator(params);
  26. }, {
  27. id: evalRunId,
  28. trace_id: evalRunId,
  29. reference_example_id: context.currentExample.id,
  30. client: context.client,
  31. tracingEnabled: true,
  32. name: evaluator.name ?? "<evaluator>",
  33. project_name: "evaluators",
  34. ...config,
  35. });
  36. evalResult = await wrappedEvaluator(ROOT, input);
  37. }
  38. else {
  39. evalResult = await evaluator(input);
  40. }
  41. let normalizedResult;
  42. if (!Array.isArray(evalResult)) {
  43. normalizedResult = [evalResult];
  44. }
  45. else {
  46. normalizedResult = evalResult;
  47. }
  48. for (const result of normalizedResult) {
  49. if (isEvaluationResult(result)) {
  50. _logTestFeedback({
  51. exampleId: context?.currentExample?.id,
  52. feedback: result,
  53. context,
  54. runTree: context.testRootRunTree,
  55. client: context.client,
  56. sourceRunId: evalRunId,
  57. });
  58. }
  59. }
  60. return evalResult;
  61. };
  62. }
  63. export async function evaluatedBy(outputs, evaluator) {
  64. const context = testWrapperAsyncLocalStorageInstance.getStore();
  65. if (context === undefined || context.currentExample === undefined) {
  66. throw new Error([
  67. `Could not identify current LangSmith context.`,
  68. `Please ensure you are calling this matcher within "ls.test()"`,
  69. `See this page for more information: https://docs.smith.langchain.com/evaluation/how_to_guides/vitest_jest`,
  70. ].join("\n"));
  71. }
  72. const wrappedEvaluator = wrapEvaluator(evaluator);
  73. const evalRunId = v4();
  74. const evalResult = await wrappedEvaluator({
  75. inputs: context.currentExample?.inputs ?? {},
  76. referenceOutputs: context?.currentExample?.outputs ?? {},
  77. outputs,
  78. }, { runId: evalRunId });
  79. if (Array.isArray(evalResult)) {
  80. return evalResult.map((result) => result.score);
  81. }
  82. return evalResult.score;
  83. }