> Discover all available pages from the documentation index: https://mastra.zisheng.pro/ko/llms.txt # Memory를 사용한 평가 Memory를 사용하는 Agent`thread`관찰 Memory를 포함한 범위에는 런타임 시 스레드 ID가 필요합니다. 평가가 Agent 없이 Agent를 호출하면 다음이 표시됩니다. ```text ObservationalMemory (scope: 'thread') requires a threadId, but none was found in RequestContext or MessageList. ``` 이 페이지에서는 Memory 지원 Agent에 대해 Mastra 평가를 실행하기 위한 세 가지 작업 패턴, 각 경로가 지원하는 항목 및 선택할 항목을 다룹니다. 세 가지 접근 방식 모두에 대한 완전한 실행 가능 재현이 제공됩니다.[`examples/evals-with-memory`](https://github.com/mastra-ai/mastra/tree/main/examples/evals-with-memory). ## 언제 어떤 접근법을 사용해야 하는가 | 목표 | 접근 방식 | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | | 모든 항목에서 하나의 공유 대화 사용 | [전역 `targetOptions.memory`를 사용하는 `runEvals`](#shared-thread-with-runevals) | | 항목마다 독립적인 스레드를 사용하는 집중된 CI 루프 | [항목별 `runEvals`](#per-item-threads-with-runevals) | | 저장된 `Dataset`으로 구동되는 항목별 스레드 | [인라인 작업을 사용하는 `dataset.startExperiment`](#dataset-experiments-with-an-inline-task) | | `RequestContext`에 `MastraMemory`를 미리 설정하는 것은 Memory를 Agent에 전달하는 지원 방식이 **아닙니다**. 스레드 확인은 `args.memory.thread`를 읽으며, Agent가 이미 스레드를 확인한 후 `prepare-memory-step`에서 `RequestContext.MastraMemory`가 채워집니다. | | ## 다음과 공유된 스레드`runEvals` `runEvals`는 `agent.generate()`에 전달되는 `targetOptions`를 받습니다. `memory: { thread, resource }`를 전달하면 모든 데이터 항목을 같은 스레드에서 실행하므로 여러 턴에 걸친 대화의 회상 능력을 테스트할 때 유용합니다. ```typescript 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` 각 데이터 항목에 자체 스레드가 필요한 일반적인 CI 구조라면, 항목마다 고유한 `targetOptions.memory`를 사용하여 `runEvals`를 한 번씩 호출하고 점수를 직접 집계하세요. ```typescript 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; 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 }`를 저장하세요. 채점자 파이프라인은 그대로 정상 실행됩니다. ```typescript 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 레퍼런스](https://mastra.zisheng.pro/ko/reference/evals/run-evals)와 [Dataset 레퍼런스](https://mastra.zisheng.pro/ko/reference/datasets/dataset)를 참조하세요. ## 관련된 - [CI의 득점자 실행](https://mastra.zisheng.pro/ko/docs/evals/running-in-ci) - [실험 진행 중](https://mastra.zisheng.pro/ko/docs/datasets/running-experiments) - [관찰 기억](https://mastra.zisheng.pro/ko/docs/memory/observational-memory) - [runEvals API 참조](https://mastra.zisheng.pro/ko/reference/evals/run-evals)