본문으로 건너뛰기

Memory를 사용한 평가

Memory를 사용하는 Agentthread관찰 Memory를 포함한 범위에는 런타임 시 스레드 ID가 필요합니다. 평가가 Agent 없이 Agent를 호출하면 다음이 표시됩니다.

ObservationalMemory (scope: 'thread') requires a threadId, but none was found in RequestContext or MessageList.

이 페이지에서는 Memory 지원 Agent에 대해 Mastra 평가를 실행하기 위한 세 가지 작업 패턴, 각 경로가 지원하는 항목 및 선택할 항목을 다룹니다. 세 가지 접근 방식 모두에 대한 완전한 실행 가능 재현이 제공됩니다.examples/evals-with-memory.

언제 어떤 접근법을 사용해야 하는가
언제 어떤 접근법을 사용해야 하는가에 대한 직접 링크

목표접근 방식
모든 항목에서 하나의 공유 대화 사용전역 targetOptions.memory를 사용하는 runEvals
항목마다 독립적인 스레드를 사용하는 집중된 CI 루프항목별 runEvals
저장된 Dataset으로 구동되는 항목별 스레드인라인 작업을 사용하는 dataset.startExperiment
RequestContextMastraMemory를 미리 설정하는 것은 Memory를 Agent에 전달하는 지원 방식이 아닙니다. 스레드 확인은 args.memory.thread를 읽으며, Agent가 이미 스레드를 확인한 후 prepare-memory-step에서 RequestContext.MastraMemory가 채워집니다.

다음과 공유된 스레드runEvals
shared-thread-with-runevals에 대한 직접 링크

runEvalsagent.generate()에 전달되는 targetOptions를 받습니다. memory: { thread, resource }를 전달하면 모든 데이터 항목을 같은 스레드에서 실행하므로 여러 턴에 걸친 대화의 회상 능력을 테스트할 때 유용합니다.

src/mastra/agents/support-agent.test.ts
import { runEvals } from '@mastra/core/evals'
import { supportAgent } from './support-agent'
import { recallScorer } from '../scorers/recall-scorer'

const memory = await supportAgent.getMemory()
await memory!.createThread({ threadId: 'eval-thread', resourceId: 'ci-user' })

const result = await runEvals({
target: supportAgent,
scorers: [recallScorer],
targetOptions: {
memory: { thread: 'eval-thread', resource: 'ci-user' },
},
data: [
{ input: 'My order number is 12345' },
{ input: 'What is my order number?', groundTruth: '12345' },
],
})

targetOptions호출별 전역 옵션입니다. 현재 RunEvalsDataItem에는 항목별 재정의가 없습니다.

항목별 스레드runEvals
per-item-threads-with-runevals에 대한 직접 링크

각 데이터 항목에 자체 스레드가 필요한 일반적인 CI 구조라면, 항목마다 고유한 targetOptions.memory를 사용하여 runEvals를 한 번씩 호출하고 점수를 직접 집계하세요.

src/mastra/agents/support-agent.test.ts
import { randomUUID } from 'node:crypto'
import { runEvals } from '@mastra/core/evals'
import { supportAgent } from './support-agent'
import { recallScorer } from '../scorers/recall-scorer'

const memory = await supportAgent.getMemory()
const resourceId = 'ci-user'

const items = [
{ input: 'Cats are mammals', groundTruth: 'mammals' },
{ input: 'Dogs are mammals too', groundTruth: 'mammals' },
]

// `runEvals` returns `{ scores: Record<string, number>; summary: { totalItems } }`.
const scores: number[] = []
for (const item of items) {
const threadId = `eval-${randomUUID()}`
await memory!.createThread({ threadId, resourceId, title: item.input })

const result = await runEvals({
target: supportAgent,
scorers: [recallScorer],
targetOptions: { memory: { thread: threadId, resource: resourceId } },
data: [item],
})

scores.push(result.scores[recallScorer.id])
}

const average = scores.reduce((a, b) => a + b, 0) / scores.length

:::참고 평가를 실행하기 전에 스레드를 생성하세요. 관찰 Memory의 thread 범위는 이미 존재하는 레코드에서 데이터를 읽습니다. :::

인라인 작업을 사용한 데이터 세트 실험
인라인 작업을 사용한 데이터 세트 실험에 대한 직접 링크

dataset.startExperiment({ target: agent })memory 옵션을 Agent에 전달하지 않고 requestContext만 전달합니다. 저장된 데이터 세트를 Memory가 활성화된 Agent에서 실행하려면 인라인 task 함수를 사용하고 각 항목의 metadata{ threadId, resourceId }를 저장하세요. 채점자 파이프라인은 그대로 정상 실행됩니다.

src/mastra/evals/dataset-experiment.ts
import { randomUUID } from 'node:crypto'
import { mastra } from '../index'
import { supportAgent } from '../agents/support-agent'
import { recallScorer } from '../scorers/recall-scorer'

const memory = await supportAgent.getMemory()
const resourceId = 'ci-user'

const items = [
{ input: 'Cats are mammals', groundTruth: 'mammals', thread: `ds-${randomUUID()}` },
{ input: 'Dogs are mammals too', groundTruth: 'mammals', thread: `ds-${randomUUID()}` },
]

for (const it of items) {
await memory!.createThread({ threadId: it.thread, resourceId, title: it.input })
}

const dataset = await mastra.datasets.create({
name: 'support-recall',
description: 'Per-item memory via inline task + item metadata',
})

await dataset.addItems({
items: items.map(it => ({
input: it.input,
groundTruth: it.groundTruth,
metadata: { threadId: it.thread, resourceId },
})),
})

const summary = await dataset.startExperiment({
scorers: [recallScorer],
task: async ({ input, metadata }) => {
const { threadId, resourceId: rid } = (metadata ?? {}) as {
threadId: string
resourceId: string
}
const result = await supportAgent.generate(input as string, {
memory: { thread: threadId, resource: rid },
})
return result.text
},
})

인라인 task는 항목의 metadata를 받으므로 Agent나 채점자를 변경하지 않고도 각 행에서 자체 스레드를 사용할 수 있습니다. 전체 구성은 runEvals 레퍼런스Dataset 레퍼런스를 참조하세요.