View in English

  • Apple Developer
    • 시작하기

    시작하기 탐색

    • 개요
    • 알아보기
    • Apple Developer Program

    알림 받기

    • 최신 뉴스
    • Hello Developer
    • 플랫폼

    플랫폼 탐색

    • Apple 플랫폼
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    피처링

    • 디자인
    • 배포
    • 게임
    • 액세서리
    • 웹
    • 홈
    • CarPlay
    • 기술

    기술 탐색

    • 개요
    • Xcode
    • Swift
    • SwiftUI

    피처링

    • 손쉬운 사용
    • 앱 인텐트
    • Apple Intelligence
    • 게임
    • 머신 러닝 및 AI
    • 보안
    • Xcode Cloud
    • 커뮤니티

    커뮤니티 탐색

    • 개요
    • Apple과의 만남 이벤트
    • 커뮤니티 주도 이벤트
    • 개발자 포럼
    • 오픈 소스

    피처링

    • WWDC
    • Swift Student Challenge
    • 개발자 이야기
    • App Store 어워드
    • Apple 디자인 어워드
    • 문서

    문서 탐색

    • 문서 라이브러리
    • 기술 개요
    • 샘플 코드
    • 휴먼 인터페이스 가이드라인
    • 비디오

    릴리즈 노트

    • 피처링 업데이트
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • 다운로드

    다운로드 탐색

    • 모든 다운로드
    • 운영 체제
    • 애플리케이션
    • 디자인 리소스

    피처링

    • Xcode
    • TestFlight
    • 서체
    • SF Symbols
    • Icon Composer
    • 지원

    지원 탐색

    • 개요
    • 도움말
    • 개발자 포럼
    • 피드백 지원
    • 문의하기

    피처링

    • 계정 도움말
    • 앱 심사 지침
    • App Store Connect 도움말
    • 새로 추가될 요구 사항
    • 계약 및 지침
    • 시스템 상태
  • 빠른 링크

    • 이벤트
    • 뉴스
    • 포럼
    • 샘플 코드
    • 비디오
 

비디오

메뉴 열기 메뉴 닫기
  • 컬렉션
  • 전체 비디오
  • 소개

더 많은 비디오

  • 소개
  • 요약
  • 자막 전문
  • 코드
  • 에이전틱 앱에 대한 강력한 평가 기능 구현하기

    Evaluations 프레임워크의 고급 기능을 활용하여 앱에 대한 강력한 평가 기능을 빌드하는 방법을 알아보세요. 도구 호출과 동적 조건을 사용하여 평가 흐름을 살펴보고, 사용 사례에 맞는 올바른 동작 기준을 정의하는 방법을 알아보세요. 합성 데이터를 생성하고, 심사위원을 효과적으로 사용하며, 신뢰할 수 있는 결과를 위해 데이터세트를 검증하는 방법을 살펴보세요.

    챕터

    • 0:00 - Introduction
    • 2:21 - The dataset problem in BookTracker
    • 3:46 - Generating synthetic data with makeSamples
    • 6:27 - Customizing generation with SampleGenerator
    • 8:38 - Sampling strategies
    • 10:11 - Validating synthetic samples
    • 13:04 - Comparing evaluation results
    • 15:09 - Tool calling and tool evaluations
    • 18:54 - Trajectory expectations
    • 21:26 - Building a tool call evaluation
    • 22:02 - Synthetic data for tool evaluations
    • 23:49 - Next steps

    리소스

    • Book Tracker: Using Evaluations to evaluate an intelligent feature
    • Generating synthetic datasets
    • Evaluating tool-calling behavior
    • Scoring with model-as-judge evaluators
      • HD 비디오
      • SD 비디오
  • 비디오 검색…

    안녕하세요, 저는 Ada입니다! 저는 Kyle입니다! 저희는 Evaluations 팀 소속 엔지니어입니다! 오늘은 여러분께 Evaluations 프레임워크의 고급 기능을 안내해 드리게 되어 기쁩니다! Evaluations 프레임워크는 Swift 앱에서 인텔리전스 기반 기능을 평가하는 방법을 제공합니다 시간 경과에 따른 개선을 추적하고 프로덕션 품질을 보장합니다 이 프레임워크는 Xcode 27의 새로운 기능으로 macOS, iOS, watchOS, visionOS를 지원합니다 아직 확인하지 않으셨다면 "Meet the Evaluations framework" 영상을 통해 Evaluations 프레임워크의 기본 구성 요소를 학습하세요 또한 "Improve your prompts by hill climbing with Evaluations" 영상을 통해 인텔리전스 기능 개선을 위한 다양한 전략을 살펴보세요

    이 영상에서는 평가의 복잡성과 확장성을 어떻게 해결하는지 알아봅니다 먼저 평가 데이터셋을 확장하는 방법을 살펴보겠습니다 합성 데이터를 생성하고 검증하는 방법입니다 그런 다음 에이전틱 워크플로에 강력한 평가를 구축하는 방법을 다룹니다 여기에는 툴 호출이라는 특별한 모델 동작이 포함됩니다

    "Meet the Evaluations framework" 영상에서 힐 클라이밍 프로세스를 소개했습니다 이는 인텔리전트 기능을 구축하고 테스트하며 출시하는 과정을 보여줍니다 이 영상에서는 주로 개발 및 평가 단계에 집중합니다 개발 단계에서는 보통 소수의 샘플로 평가를 시작하지만 기능은 데이터셋이 커버할 수 있는 범위보다 훨씬 복잡합니다 구축하는 데 시간이 걸리고 확장하기도 어려우며 필요한 다양성을 거의 포착하지 못합니다 실제 환경에서 기능이 어떻게 작동하는지 이해하기 위해서입니다 평가 결과의 품질은 그 기반이 되는 데이터에 달려 있습니다 그리고 좋은 평가 데이터를 작성하기란 쉽지 않습니다 바로 여기서 합성 데이터가 필요합니다 Evaluations 프레임워크는 API를 제공하여 샘플 생성을 코드로 완전히 정의할 수 있게 해줍니다 자체 생성 파이프라인을 구축하고 커맨드라인에서 실행하거나 기존 워크플로에 직접 연결할 수 있습니다 텍스트 기반 데이터를 지원하고 generable 매크로를 활용하여 구조화된 합성 데이터를 생성합니다 저와 동료들은 BookTracker를 개발하고 있습니다 이는 인텔리전스 기반 기능을 사용하는 개인 도서 관리 앱입니다 작성된 리뷰를 바탕으로 책에 자동으로 태그를 지정합니다 각 책을 어떻게 정의하는지 살펴보겠습니다 Book이라는 클래스에 제목이 포함되어 있으며 저자, 리뷰, 태그, 평점도 있습니다 커버 디자인을 지원하는 다른 변수들도 정의합니다 또한 13개의 Book 샘플 배열인 sampleBooks를 정의합니다 여기 Pride and Prejudice에 관한 샘플이 하나 있습니다 이 13개 샘플이 합리적인 출발점처럼 보일 수 있지만 이 작은 데이터셋은 좁은 시야만 제공할 뿐입니다 기능 성능을 파악하기에 충분하지 않습니다 평가 결과가 훌륭해 보여도 완전히 잘못 이해하고 있을 수 있습니다 태그 생성 기능을 평가하는 데 사용되는 데이터의 다양성을 생각해 보세요!

    책의 종류는 무수히 많습니다 수백 가지 장르가 있습니다

    그리고 사용자가 방금 읽은 책을 리뷰하는 방식도 매우 다양합니다 또한 실제 세계의 이야기이기도 합니다 요약이 모호하거나 불완전할 수 있습니다 13개의 샘플로는 이 모든 것을 담을 수 없습니다 더 많은 커버리지가 필요하고 예시를 직접 작성하는 데 며칠을 쓰지 않아도 됩니다! 그렇다면 데이터셋을 확장하여 더 많은 다양성을 포착하는 방법을 알아봅시다 간단하게 시작하겠습니다 makeSamples API에는 세 가지 구성 요소가 필요합니다 프롬프트, 데이터셋, 목표 수량입니다 목표 수량은 샘플 수입니다 제공한 데이터셋을 포함하여 합성으로 생성하고 싶은 수량입니다 여기서 프롬프트를 정의하여 모델에게 더 다양한 책 리뷰 샘플을 제안해 달라고 했습니다 잘 정의된 프롬프트를 작성하려면 모델이 작업을 잘 이해하기 위해 어떤 정보가 필요한지 고려하세요 사용자가 제공할 수 있는 다양한 입력을 처리하기 위해서입니다 데이터셋으로는 sampleBooks를 전달합니다 초기 13개 샘플이 포함되어 있습니다

    여기서 새로운 ModelSamples API를 활용하여 책의 리뷰를 포함시킵니다 프롬프트로는 책 리뷰를, 예상 출력으로는 책 태그를 사용합니다 목표 수량은 우선 100개 샘플로 설정했습니다! targetCount는 결과 데이터셋의 전체 크기입니다 처음 시작한 샘플들도 포함되므로 실제로 모델은 87개의 새 샘플을 생성합니다 얼마나 많은 데이터가 충분한지 궁금하실 겁니다 그 답은 상황에 따라 다릅니다 BookTracker 앱의 경우 목표 수량 100개는 시작점에 불과합니다! 합성 데이터 생성은 종종 반복적인 프로세스입니다 초기 데이터셋을 정의하고 합성 데이터를 생성하고 샘플을 검증합니다 그런 다음 데이터가 충분히 대표성을 갖는지 분석하고 확신이 생길 때까지 이 과정을 반복합니다! 따라서 평가 데이터셋의 올바른 목표 수량은 기능에 따라 완전히 달라집니다 기능이 무엇을 하는지, 누가 사용하는지, 사람들이 얼마나 다양한 방식으로 사용하는지 양보다 훨씬 중요한 것은 커버리지입니다!

    샘플이 몇 개 필요한지 묻는 대신에 스스로에게 물어보세요 이 기능이 실제로 사용되는 다양한 방식을 충분히 커버했나요? 이제 필요한 변수를 정의했으니 makeSamples 메서드를 사용할 수 있습니다 새로 생성된 샘플의 비동기 스트림을 반환합니다 이를 반복하면서 각 새 샘플이 expandedDataset이라는 변수에 추가됩니다 시작 데이터셋으로 초기화한 변수입니다 기본적으로 프레임워크는 온디바이스 모델을 생성에 사용합니다 온디바이스 모델은 대부분의 경우 훌륭한 옵션이지만 자체 모델을 사용하거나 모델이 작동하는 지침을 사용자 정의하고 싶을 수 있습니다 프레임워크는 유연성을 제공하여 샘플 생성을 위한 자체 구성을 정의할 수 있게 해줍니다 방법을 살펴보겠습니다!

    프롬프트, 데이터셋, 목표 수량을 넘어서는 더 복잡한 구성의 경우 프레임워크는 SampleGenerator를 제공합니다 생성 프로세스를 완전히 제어할 수 있습니다 이러한 구성 중 일부를 살펴보겠습니다!

    sessionProvider는 LanguageModelSession을 반환하는 클로저입니다 어떤 모델이 생성을 주도하는지 제어하는 곳입니다 작업을 구성하는 시스템 수준 지침도 여기서 설정합니다 합성 데이터 생성을 위해 PrivateCloudComputeLanguageModel을 사용하겠습니다 컨텍스트 크기가 더 크기 때문에 그런 다음 특정 책, 장르, 분위기에 집중하도록 커스텀 지침을 추가합니다

    생성된 샘플에 대한 기대치에 대한 규칙 목록도 지정합니다 이에 대해서는 나중에 다루겠습니다 세션이 사용되는 방식에 대해 한 가지 참고할 점이 있습니다 프레임워크는 배치 크기를 자동으로 처리합니다 배치 크기는 생성 중에 처리되는 샘플 수입니다 생성기는 실행 시작 시 sessionProvider를 한 번 호출합니다 그런 다음 배치 전반에 걸쳐 해당 세션을 재사용합니다 이를 통해 모델이 생성이 진행됨에 따라 컨텍스트를 유지할 수 있습니다

    하지만 세션에는 성장할 수 있는 크기 제한이 있습니다 요청이 많거나 프롬프트가 크거나 출력이 많은 경우가 예외입니다 실행 중간에 세션의 컨텍스트 창이 소진되어 오류가 발생할 수 있습니다 그 경우 생성기는 sessionProvider를 다시 호출하여 새로운 세션을 가져와 생성을 계속합니다 하지만 이전 세션의 컨텍스트는 포함되지 않습니다 따라서 sessionProvider의 지침이 자체 완결적인지 확인하세요 한 번만 호출된다고 가정하지 않아야 합니다 컨텍스트 크기 제한을 완화하는 더 많은 방법을 알아보려면 "Build agentic app experiences with Foundation Models" 영상을 보세요 이제 커스텀 세션 공급자로 SampleGenerator를 사용하여 samplingStrategy를 사용자 정의할 수도 있습니다

    생성기가 예시를 선택하는 방식을 제어합니다 초기 데이터셋에서 모델에게 컨텍스트 내 예시로 보여줄 것들을 선택합니다 지정할 수 있는 두 가지 샘플링 전략 유형이 있습니다 첫 번째는 무작위 샘플링입니다

    이 전략은 초기 샘플에서 무작위 부분집합을 선택합니다 모델에게 예시로 보여주되 중복이 없도록 합니다 초기 샘플의 순서를 신중하게 고려하지 않아도 됩니다 출력을 다양하게 유지합니다 사용할 수 있는 두 번째 샘플링 전략은 슬라이딩 윈도우입니다

    이 전략은 초기 샘플을 순차적으로 단계별로 처리합니다 진행하면서 중복을 건너뜁니다 데이터셋에 의미 있는 순서가 있다면 이 슬라이딩 윈도우 전략을 사용하는 것을 고려하세요

    저희 생성기에서는 무작위 전략을 사용합니다 초기 샘플에 의미 있는 순서가 없기 때문입니다 기본 전략이므로 여기서 명시적으로 정의할 필요가 없습니다

    이제 커스텀 sessionProvider로 생성기를 구성했으니 .run 함수를 호출할 수 있습니다 새로 합성된 샘플의 스트림을 반환합니다 각각을 반복하면서 앞서 정의한 expandedDataset에 추가됩니다

    이제 구성을 설정했으니 합성 데이터가 예상대로인지 어떻게 확인할 수 있는지 살펴봅시다 바로 여기서 validator 클로저가 유용하게 쓰입니다 validator를 통해 자체 로직을 정의하여 생성된 모든 샘플을 허용하거나 거부할 수 있습니다 앞서 이미 규칙 세트를 정의했습니다 앞서 세션 공급자의 지침에 정의했지만 출력이 실제로 규칙을 따를 것이라고 보장하지는 않습니다 검토해 보겠습니다 첫 번째로 정의한 규칙은 리뷰가 최소 100자 이상이어야 한다는 것입니다 각 리뷰는 다양한 장르, 분위기, 톤을 다루어야 합니다 리뷰 길이도 다양해야 합니다 모델은 3~8개의 책 태그를 생성해야 합니다 태그는 소문자여야 합니다 샘플의 어떤 부분을 검증할지 이해하려면 이러한 규칙을 기반으로 체계적으로 확인할 수 있는 것을 고려해야 합니다 또한 validation 클로저는 각 샘플 생성을 독립적으로 검증합니다 다른 샘플에 대한 컨텍스트는 없습니다 이 규칙들을 검토하면 리뷰의 다양성에는 더 많은 판단이 필요하다는 것을 알 수 있습니다 단순한 validation 검사를 넘어서는 판단입니다 리뷰의 길이는 모든 샘플에 걸쳐 평가해야 합니다

    다른 규칙에 대해서는 체계적으로 평가할 수 있습니다 validation 클로저를 사용합니다 첫 번째 규칙에 대해 리뷰 길이 validation을 정의할 수 있습니다 우리 모두 잘 아는 고전 책을 예로 들겠습니다 Mary Shelley의 "Frankenstein"입니다 생성된 샘플이 리뷰를 정의하는지 확인할 수 있습니다 최소 100자 이상이어야 합니다 모델은 각 리뷰에 대한 태그도 생성합니다 태그가 3~8개 사이인지 검증할 수 있습니다

    마지막으로 태그가 모두 소문자인지 확인할 수 있습니다

    여기서 이미 SampleGenerator에 3가지 validation 지표를 정의했습니다 샘플이 예상 구조를 충족하는지 확인합니다 결과는 어디에 저장될까요? 생성이 진행됨에 따라 유효한 샘플은 SyntheticGenerator의 samples 프로퍼티에 수집됩니다 이 validator들을 통과하지 못한 샘플은 자동으로 invalidSamples로 따로 분류됩니다 실행 중 실시간으로 두 가지 모두 업데이트되므로 언제든지 접근할 수 있습니다 반복 중에 진행 상황을 확인하거나 루프 완료 후에도 확인할 수 있습니다 이 결과를 앱에서 직접 사용하거나 데이터셋을 로컬에 저장할 수 있습니다 이제 13개의 초기 샘플로 평가를 검토해 보겠습니다 Xcode 27에서 새로운 Evaluations Report를 도입했습니다 결과를 시각화합니다 13개의 초기 샘플로 실행한 BookTaggingEvaluation입니다 보시다시피 태그 품질에서 꽤 높은 점수를 받았습니다 관련성과 유용성 모두를 평가합니다 새 100개 샘플 데이터셋으로 평가를 실행했습니다 이제 Compare 버튼을 사용하여 두 평가를 비교할 수 있습니다 점수가 낮아질 것으로 예상합니다!

    예상이 맞았습니다! 품질 점수가 낮아졌습니다 태그 생성 기능이 이전에는 잘 수행되는 것처럼 보였지만 포괄적인 데이터셋으로 테스트하지 않았기 때문입니다 더 큰 데이터셋으로 평가를 실행하면 점수 하락은 다양한 것을 나타낼 수 있습니다 이 신호가 무엇을 시사하는지 생각해 보세요 점수 변화는 프롬프트나 지침의 문제 때문일 수 있습니다 필요에 더 잘 맞도록 하나 또는 둘 다 개선할 수 있습니다 인텔리전스 기능의 격차도 고려할 수 있습니다 또는 실제로 무엇을 평가하는지 이해하기 위해 평가를 조정하고 싶을 수 있습니다 마지막으로 데이터셋이 아직 충분히 대표적이지 않을 수 있습니다 더 많은 변형을 포착해야 합니다 데이터셋을 계속 늘리거나 더 많은 엣지 케이스를 포함할 수 있습니다 합성 데이터 API를 사용합니다 이것들이 결과를 더욱 개선하는 핵심 방법입니다

    이제 합성 데이터를 사용하여 강력한 평가 데이터셋을 구축하는 탄탄한 접근 방식을 갖추었으니 한 단계 더 나아가고 싶습니다 지금까지 책 태그 기능을 평가했지만 앱이 더 복잡해지면 어떻게 될까요 검색 같은 작업을 완료하기 위해 여러 작업이 필요한 경우입니다 바로 여기서 툴 호출이 등장합니다 Kyle에게 넘겨서 어떻게 작동하는지 보여드리겠습니다! 감사합니다, Ada!

    이제 평가 주도 개발을 계속 진행하겠습니다 툴 평가를 다루겠습니다 지금까지는 모델이 생성하는 것을 평가했습니다 저희 기능의 경우 책에 대한 태그입니다 하지만 인텔리전스 기능은 종종 무대 뒤에서 많은 단계를 거칩니다 출력을 생성하기 위해서입니다 앱에서 여러 작업을 수행하여 각각 결과에 기여합니다 툴은 모델 워크플로에 구조를 추가합니다 앱 사용자를 위한 작업을 완료할 때입니다

    사람들이 매일 사용하는 실제 데이터로 작동합니다

    정의한 커스텀 비즈니스 로직으로 작동할 수 있습니다

    사용자가 직접 호출할 수 있는 기능을 호출하거나 인텔리전스 기능을 위한 완전히 새로운 로직이거나 둘 다 결합할 수 있습니다 여기서 중요한 점이 있습니다 모델이 합리적으로 들리는 답변을 줄 수 있습니다 올바른 툴을 한 번도 호출하지 않고서도요 최종 출력이 올바르게 보여도 그 과정이 올바르지 않을 수 있습니다 그 문제들에 대해 이야기해 봅시다 그리고 툴 평가가 어떻게 도움이 되는지

    첫째, 지침 따르기입니다 각 툴 사용 방법을 모델에 알려야 합니다 세부 사항에 기울이는 주의가 중요합니다

    직접 지침을 단어 하나하나 따라 해보세요 단계를 놓치는지 확인하기 위해서입니다

    그 다음은 툴 복잡성입니다 단순한 지침을 받아들이거나 파라미터 범위를 미세 조정해야 할 수 있습니다

    그리고 엣지 케이스가 있습니다 툴이 일반적인 입력에서는 잘 작동하는 것처럼 보일 수 있지만 드문 입력에서는 예상치 못한 동작을 할 수 있습니다

    그래서 툴 평가가 필요합니다 무엇만이 아니라 방법도 검증할 수 있습니다

    모델은 올바른 툴을 호출해야 합니다 예상하는 순서로 올바른 인수를 사용하여 그리고 그 과정에서 중간에 예상치 못한 툴 호출이 없었는지 이중 확인합니다

    이를 실제로 살펴보고 첫 번째 툴 평가를 구축해 봅시다 BookTracker 앱에서 라이브러리 어시스턴트를 추가했습니다 사용자가 책을 검색할 수 있습니다 제목과 다른 문자열을 기반으로 책을 필터링하는 대신 모델이 앱의 커스텀 툴을 사용하여 관련 책을 찾습니다

    비슷한 태그를 가진 책을 찾는 searchBooks 툴이 있습니다 그런 다음 책 메타데이터를 추출하는 getBookDetails 툴이 있습니다 검색에서 출판일 같은 정보를 가져옵니다

    그 다음 findSimilarBooks 툴이 있습니다 유사한 책에 대한 시맨틱 검색을 수행합니다 여러 단계를 연결하고 있습니다 각각이 툴 호출입니다 SearchBooksTool입니다

    Tool 프로토콜을 준수하며 모델이 보는 이름이 있습니다 그리고 이 툴이 언제 유용한지 알려주는 설명이 있습니다

    인수는 Generable 구조체입니다 모두 옵셔널임을 주목하세요 모델이 사용자의 요청을 기반으로 어떤 필터를 사용할지 결정합니다

    모델에 "gothic 책 찾기"라는 프롬프트를 주면 tag 인수를 채울 것으로 예상합니다 모델에 "기분 좋은 것을 보여줘"라는 프롬프트를 주면 기분 검색을 생성할 것으로 예상합니다 바로 이런 결정들을 평가하고 싶습니다 툴에 대한 내용을 복습했습니다 이제 첫 번째 툴 평가를 작성하고 어떻게 작동하는지 살펴봅시다 툴 평가의 주요 구성 요소는 trajectory expectation입니다 세션 기록에는 프롬프트와 응답 사이에 툴 호출이 포함됩니다

    trajectory expectation은 순서를 확인합니다 언어 모델 세션에서 각 툴 호출의 종류와 순서입니다 trajectory expectation 확인은 경로를 계획할 때 내린 결정 목록을 검토하는 것과 같습니다 자동차, 자전거, 버스는 모두 툴입니다 각각 어딘가에 도달하는 데 제때와 장소가 있습니다 특정 여행의 각 구간에 대한 유용성을 평가할 수 있습니다

    expectation은 모든 툴 호출을 찾습니다 그런 다음 각각에 대해 평가에 작성한 expectation에 대해 실행합니다 코드 형식의 간단한 예시입니다 프롬프트는 "gothic 태그 책 찾기"입니다 하나의 툴 호출 "searchBooks"를 예상합니다 이것이 TrajectoryExpectation입니다 모델의 기록에서 예상하는 툴 호출을 설명합니다 여기서 unordered는 이 툴 호출이 언제 발생하는지는 상관없다는 의미입니다 발생하기만 하면 됩니다 expectation에 인수를 추가하여 더 세밀하게 설정할 수 있습니다 여기서 "gothic" 태그를 예상하는 인수를 추가합니다 정확한 일치가 항상 원하는 것은 아닙니다 프롬프트가 "기분 좋은 것 찾기"라면 모델은 uplifting, happy, cheerful 중 어느 것이든 전달할 수 있습니다

    .naturalLanguage 매처는 값이 의도와 일치하는지 확인합니다 정확한 문자열이 아닙니다 다양한 상황을 위한 전체 매처 세트가 있습니다 contains, oneOf, pattern, range 등이 있습니다 자세한 내용은 개발자 문서를 확인하세요 멀티스텝 작업에서는 순서가 중요합니다

    여기서 모델은 먼저 "searchBooks"를 호출해야 합니다 그런 다음 "getBookDetails"를 호출합니다 에이전트가 먼저 세부 정보를 가져오려 하면 아직 bookId가 없습니다 그것은 버그입니다 trajectory expectation이 이를 포착합니다 경로를 확인하기 때문입니다 목적지만이 아닙니다

    에이전트가 하지 말아야 하는 것도 중요할 때가 있습니다

    프롬프트에 "유사한 책을 찾지 마세요"라는 아이디어가 포함된 경우 모델은 지침을 따라야 합니다 disallowed 파라미터는 기록에 나타나서는 안 되는 툴을 지정합니다 에이전트가 "findSimilarBooks"를 호출하면 그것은 실패입니다 모든 trajectory expectation이 모이는 곳입니다 전체 평가입니다 샘플 데이터셋을 정의합니다 각각 프롬프트와 trajectory expectation이 있습니다 ToolCallEvaluator를 사용하여 점수를 매깁니다 ToolCallEvaluator는 LanguageModelSession을 툴과 결합합니다 응답을 받고 구조화된 기록을 캡처합니다

    툴 호출 평가 결과는 Xcode 어시스턴트에 표시됩니다 나머지 결과와 함께 인텔리전스 기반 기능이 어떻게 작동하는지 전체 그림을 볼 수 있습니다 잠깐만요! Evaluations API를 사용하여 툴 평가를 위한 합성 데이터를 생성할 수도 있습니다!

    네, 해봅시다! trajectory expectation도 generable입니다 툴 평가를 위한 데이터셋 확장은 꽤 복잡할 수 있습니다 Evaluations 프레임워크로 그 작업을 훨씬 쉽게 만들었습니다! 툴 호출 평가는 ModelSample을 활용하므로 그리고 generable인 TrajectoryExpectation을 사용하므로 이전처럼 Sample generator를 사용하여 더 많은 샘플을 합성 생성할 수 있습니다 프롬프트를 미리 정의했습니다 sessionProvider에 대한 커스텀 지침도 있습니다 툴 평가를 위한 합성 데이터를 만들 때 유의할 점이 있습니다 모델은 어떤 툴을 정의했는지 모릅니다 또는 툴을 어떤 순서로 호출해야 하는지도 모릅니다 그래서 여기서 사용 가능한 툴과 그 목적을 지정했습니다 순서 기대치 및 모델이 필요할 수 있는 기타 컨텍스트도 포함합니다 그런 다음 sampleGenerator를 정의할 수 있습니다 기존 데이터셋을 초기 샘플로 사용하고 targetCount는 100입니다 여기서 validation 지표도 지정할 수 있습니다! 항상 expectation이 있는지 확인했습니다 합성 샘플에 최소한 하나의 툴이 포함되도록 했습니다 마지막으로 호출된 모든 툴은 이미 정의한 실제 툴입니다 이렇게 하면 생성하고 툴 평가를 위한 합성 샘플을 검증할 수 있습니다! 합성 데이터 API는 강력한 방법입니다 기존 데이터셋을 역량 이상으로 확장하는 데 활용할 수 있습니다! 데이터가 더 대표적일수록 점수가 현실을 더 잘 반영합니다 좋아요 Kyle, 넘기겠습니다! 모든 것이 하나로 모이는 곳입니다 앞서 책 태그 평가를 구축했습니다 모델이 생성하는 것을 확인합니다 태그 수, 장르 커버리지, 품질 점수입니다 이제 툴 평가가 있습니다 모델이 어떻게 도달하는지 확인합니다 올바른 툴, 올바른 인수, 올바른 순서입니다 같은 평가 스위트에서 둘 다 실행하면 기능에 대한 종단 간 신뢰를 구축하게 됩니다 평가를 더욱 강력하게 만드는 방법을 다루었으니 앱과 평가 데이터셋에 이 아이디어를 적용할 수 있습니다 시작하려면 자체 합성 데이터를 만들어 보세요 앱의 커스텀 툴을 평가하고 샘플 앱과 개발자 문서의 다른 문서도 확인하세요

    와 Ada, 오늘 많은 것을 다뤘네요! 네, 정말 그렇네요! 하지만 진짜 반전은 여러분이 그걸로 무엇을 만드느냐입니다 스포일러는 없을게요! Evaluations 프레임워크에 대해 즐겁게 배우셨으면 좋겠습니다!

    • 5:16 - Generate synthetic data with makeSamples

      // Synthetic data
        let prompt = Prompt("""
            Generate diverse range of book reviews and corresponding tags.
            Cover a wide range of genres, time periods, cultures, and
            reader personas. Do not repeat books already in the dataset.
            """)
        
        let dataset = Book.sampleBooks.map { book in
            ModelSample(prompt: book.review, expected: BookTags(tags: book.tags))
        }
        
        let targetCount = 100
        var expandedDataset = dataset
      
        for try await sample in dataset.makeSamples(prompt, targetCount: targetCount) {
            expandedDataset.append(sample)
            print("Generated \(expandedDataset.count) samples so far.")
        }
      
        2. Configure a custom SampleGenerator — slides 30–43
        
        // Define your own configuration
        let generator = SampleGenerator<ModelSample<BookTags>>(
            prompt,
            samples: dataset,
            targetCount: targetCount,
            sessionProvider: {
                LanguageModelSession( 
                    model: PrivateCloudComputeLanguageModel(),
                    instructions: """
                        You are a synthetic data generator for a book-tracking app's evaluation suite.
                        Your job is to produce realistic, diverse book entries that will stress-test
                        a tagging system.
      
                        Rules:
                        - Review must be at least 100 characters long.
                        - Review should cover a mix of genre, mood/tone, and themes.
                        - Reviews should vary in length.
                        - Create between 3 and 8 tags.
                        - Tags must be lowercase.
                        """ 
                )
            }
        )
    • 5:53 - Configure a custom SampleGenerator

      // Define your own configuration
        let generator = SampleGenerator<ModelSample<BookTags>>(
            prompt,
            samples: dataset,
            targetCount: targetCount,
            sessionProvider: {
                LanguageModelSession( 
                    model: PrivateCloudComputeLanguageModel(),
                    instructions: """
                        You are a synthetic data generator for a book-tracking app's evaluation suite.
                        Your job is to produce realistic, diverse book entries that will stress-test
                        a tagging system.
      
                        Rules:
                        - Review must be at least 100 characters long.
                        - Review should cover a mix of genre, mood/tone, and themes.
                        - Reviews should vary in length.
                        - Create between 3 and 8 tags.
                        - Tags must be lowercase.
                        """ 
                )
            }
        )
    • 10:37 - Validate generated samples

      // Define validation metrics
        validator: { sample in
            guard let book = sample.expected else { return false }
      
            // Review must be at least 100 characters
            guard sample.promptDescription.count >= 100 else { return false }
      
            // Must have between 3 and 8 tags
            guard (3...8).contains(book.tags.count) else { return false }
      
            // All tags must be lowercase
            guard book.tags.allSatisfy({ $0 == $0.lowercased() }) else { return false }
      
            return true
        }
    • 10:58 - Access valid and invalid results

      // Accessing results
        for try await sample in generator.run() {
            // During iteration
            expandedDataset.append(sample)
        }
      
        // After iteration
        let allSamples = await generator.samples
        let invalidSamples = await generator.invalidSamples
        
        print("Generated \(allSamples.count) new samples. Total: \(expandedDataset.count)")
    • 15:30 - Define a tool's Generable argument

      @Generable
        struct SearchBooksArguments {
            @Guide(description: "A freeform search term to match against titles, reviews, or tags")
            var query: String?
        
            @Guide(description: "Filter results to books with this specific tag")
            var tag: String?
      
            @Guide(description: "Filter results by mood")
            var mood: String?
      
            @Guide(description: "Filter results by genre")
            var genre: String?
      
            @Guide(description: "Maximum number of results to return. Defaults to 5.")
            var limit: Int? 
        }
    • 16:37 - A basic trajectory expectation

      // "Find books tagged gothic"
        TrajectoryExpectation(
            unordered: [
                ToolExpectation(
                    "searchBooks",
                    arguments: [
                        .exact(argumentName: "tag", value: .string("gothic"))
                    ]
                )
            ]
        )
    • 17:07 - Match arguments by intent (naturalLanguage)

      // "Find something cheerful"
        TrajectoryExpectation(
            "searchBooks",
            arguments: [
                .naturalLanguage(
                    argumentName: "mood",
                    criteria: "Should relate to uplifting, hopeful, or positive feelings"
                )
            ]
        )
        Other matchers available: .contains, .oneOf, .pattern, .range, and more.
    • 17:34 - Expect tool calls in order

      // "Find gothic books and show details on the first"
        TrajectoryExpectation(
            ordered: [
                ToolExpectation(
                    "searchBooks",
                    arguments: [
                        .exact(argumentName: "tag", value: .string("gothic"))
                    ]
                ),
                ToolExpectation(
                    "getBookDetails",
                    arguments: [
                        .keyOnly(argumentName: "bookId")
                    ]
                )
            ]
        )
    • 17:55 - Disallow specific tool calls

      // "Show only sci-fi books. Don't look for similar ones."
        TrajectoryExpectation(
            unordered: [
                ToolExpectation(
                    "searchBooks",
                    arguments: [
                        .naturalLanguage(
                            argumentName: "genre",
                            criteria: "Should refer to science fiction")
                    ]
                )
            ],
            disallowed: [
                ToolExpectation("findSimilarBooks")
            ]
        )
    • 18:14 - Build a tool call evaluation

      // Tool call evaluations
        let samples = SampleArrayLoader(samples: [
            ModelSample(
                prompt: "Find all the books tagged with 'gothic'.",
                instructions: "Help the user explore their book collection.",
                expectations: TrajectoryExpectation(  )
            )
        ])
      
        struct BookLibraryToolCallEval: Evaluation {
            var dataset = samples
      
            let pass = Metric("All Passed")
            let percent = Metric("Percentage Passed")
      
            var evaluators: Evaluators { 
                ToolCallEvaluator(allPass: pass, percentagePass: percent)
            }
        }
    • 19:20 - Synthesize tool-evaluation samples

      // Tool call evaluations
        let prompt = Prompt("""
            Generate diverse user queries for a personal book library assistant.
            Each sample needs a prompt (what the user says), and a trajectory
            expectation describing which tools should be called and in what order.
            """)
      
        let instructions = """
            AVAILABLE TOOLS:
            - searchBooks(query?, tag?, mood?, genre?, limit?): search the library
            - getBookDetails(bookId): full details for one book
            - findSimilarBooks(bookId, maxResults?): find books sharing tags
            ORDER REQUIREMENTS:
            - searchBooks must comes before getBookDetails or findSimilarBooks
            - Use TrajectoryExpectation(ordered:) when sequence matters, else (unordered:)
            USE THESE ARGUMENT MATCHERS:
            - .exact for precise values, .naturalLanguage for fuzzy matching
            - .keyOnly when any value is acceptable, .range for numeric constraints
            - .contains/.hasPrefix/.hasSuffix for partial string matching
            """
    • 19:51 - Validate tool-evaluation samples

      // Tool call evaluations
        validator: { sample in
            // Must have expectations defined
            guard sample.output.expectations != nil else { return false }
      
            let expectations = sample.output.expectations!
      
            // Must reference at least one tool
            let totalExpectations = expectations.ordered.count + expectations.unordered.count
            guard totalExpectations > 0 else { return false }
      
            // All tool names must be from the valid set
            let validTools: Set<String> = ["searchBooks", "getBookDetails", "findSimilarBooks"]
            let allExpectations = expectations.ordered + expectations.unordered + expectations.disallowed
            for expectation in allExpectations {
                guard validTools.contains(expectation.name) else { return false }
            }
        
            return true
        }
      
        ---
    • 0:00 - Introduction
    • Ada Wong and Kyle Murray introduce advanced features of the Evaluations framework (new in Xcode 27). Outlines the agenda: growing your dataset with synthetic data, then building robust evaluations for agentic, tool-calling workflows, focused on the develop-and-evaluate step of hill-climbing.

    • 2:21 - The dataset problem in BookTracker
    • The BookTracker app auto-tags books from reviews, but its 13 hand-written sampleBooks give only a narrow view. Real-world reviews span countless books, genres, lengths, and styles, too much variety to capture by hand.

    • 3:46 - Generating synthetic data with makeSamples
    • The makeSamples API takes a prompt, a dataset (ModelSample with review to tags), and a target count (the full resulting size, including your seeds). It returns an async stream of new samples; coverage of real usage matters more than raw quantity.

    • 6:27 - Customizing generation with SampleGenerator
    • For more control, SampleGenerator exposes a sessionProvider closure to pick the model (such as Private Cloud Compute) and instructions. The session is reused across batches but can exhaust its context window mid-run, so make instructions self-contained since the provider may be called again.

    • 8:38 - Sampling strategies
    • The samplingStrategy controls which seed samples are shown to the model as in-context examples: random (a varied subset, the default) or slidingWindow (sequential, for datasets with meaningful order).

    • 10:11 - Validating synthetic samples
    • A validator closure accepts or rejects each generated sample in isolation against systematic rules: review length at least 100 characters, 3 to 8 tags, lowercase tags. Valid samples collect in samples, rejects in invalidSamples, both updated in real time.

    • 13:04 - Comparing evaluation results
    • Using the Xcode 27 Evaluations Report, compare the 13-sample run against the 100-sample run. The quality scores drop, the feature only looked good on the small dataset, and a drop can signal issues in the prompt, the feature, the evaluation, or the dataset.

    • 15:09 - Tool calling and tool evaluations
    • Tool evaluations: features often take multiple behind-the-scenes tool calls, and a plausible answer can come from the wrong path. Tool evaluations verify the how: correct tools, correct arguments, correct order, no surprises, illustrated with searchBooks, getBookDetails, and findSimilarBooks.

    • 18:54 - Trajectory expectations
    • A TrajectoryExpectation checks the kind and order of tool calls in a session transcript. Refine with argument matchers (exact, naturalLanguage, contains, oneOf, pattern, range), plus ordered expectations and a disallowed set for tools that must not be called.

    • 21:26 - Building a tool call evaluation
    • Bring the trajectory expectations together: a dataset of samples (each a prompt plus expectation) scored by ToolCallEvaluator, which combines a LanguageModelSession with the tools, captures the structured transcript, and reports alongside your other results in Xcode.

    • 22:02 - Synthetic data for tool evaluations
    • Because ModelSample and TrajectoryExpectation are Generable, you can synthesize tool-evaluation samples too, describing the available tools, order expectations, and context in the prompt, then validating that each sample has an expectation, at least one tool, and only real tools.

    • 23:49 - Next steps
    • Run BookTaggingEvaluation (what the model produces) and tool evaluations (how it gets there) in one suite for end-to-end confidence. Next steps: create your own synthetic data, evaluate your app's custom tools, and explore the sample app and documentation.

Developer Footer

  • 비디오
  • WWDC26
  • 에이전틱 앱에 대한 강력한 평가 기능 구현하기
  • 메뉴 열기 메뉴 닫기
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    메뉴 열기 메뉴 닫기
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    메뉴 열기 메뉴 닫기
    • 손쉬운 사용
    • 액세서리
    • Apple Intelligence
    • 앱 확장 프로그램
    • App Store
    • 오디오 및 비디오(영문)
    • 증강 현실
    • 디자인
    • 배포
    • 교육
    • 서체(영문)
    • 게임
    • 건강 및 피트니스
    • 앱 내 구입
    • 현지화
    • 지도 및 위치
    • 머신 러닝 및 AI
    • 오픈 소스(영문)
    • 보안
    • Safari 및 웹(영문)
    메뉴 열기 메뉴 닫기
    • 문서(영문)
    • 튜토리얼
    • 다운로드
    • 포럼(영문)
    • 비디오
    메뉴 열기 메뉴 닫기
    • 지원 문서
    • 문의하기
    • 버그 보고
    • 시스템 상태(영문)
    메뉴 열기 메뉴 닫기
    • Apple Developer
    • App Store Connect
    • 인증서, 식별자 및 프로파일(영문)
    • 피드백 지원
    메뉴 열기 메뉴 닫기
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(영문)
    • Mini Apps Partner Program
    • News Partner Program(영문)
    • Video Partner Program(영문)
    • Security Bounty Program(영문)
    • Security Research Device Program(영문)
    메뉴 열기 메뉴 닫기
    • Apple과의 만남
    • Apple Developer Center
    • App Store 어워드(영문)
    • Apple 디자인 어워드
    • Apple Developer Academy(영문)
    • WWDC
    최신 뉴스 읽기.
    Apple Developer 앱 받기.
    Copyright © 2026 Apple Inc. 모든 권리 보유.
    약관 개인정보 처리방침 계약 및 지침