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 |
RequestContext에 MastraMemory를 미리 설정하는 것은 Memory를 Agent에 전달하는 지원 방식이 아닙니다. 스레드 확인은 args.memory.thread를 읽으며, Agent가 이미 스레드를 확인한 후 prepare-memory-step에서 RequestContext.MastraMemory가 채워집니다. |
다음과 공유된 스레드runEvalsshared-thread-with-runevals에 대한 직접 링크
runEvals는 agent.generate()에 전달되는 targetOptions를 받습니다. memory: { thread, resource }를 전달하면 모든 데이터 항목을 같은 스레드에서 실행하므로 여러 턴에 걸친 대화의 회상 능력을 테스트할 때 유용합니다.
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에는 항목별 재정의가 없습니다.
항목별 스레드runEvalsper-item-threads-with-runevals에 대한 직접 링크
각 데이터 항목에 자체 스레드가 필요한 일반적인 CI 구조라면, 항목마다 고유한 targetOptions.memory를 사용하여 runEvals를 한 번씩 호출하고 점수를 직접 집계하세요.
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 }를 저장하세요. 채점자 파이프라인은 그대로 정상 실행됩니다.
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 레퍼런스를 참조하세요.