메시지 메타데이터

메시지 메타데이터 (Message Metadata)

메시지 메타데이터를 사용하면 메시지 수준에서 커스텀 정보를 메시지에 붙일 수 있습니다. 타임스탬프, 모델 정보, 토큰 사용량, 사용자 컨텍스트, 그 외 메시지 수준 데이터를 추적하는 데 유용합니다.

메시지 메타데이터는 data parts와 달리 메시지 콘텐츠의 일부가 아니라 메시지 수준에 붙습니다. data parts는 메시지를 구성하는 동적 콘텐츠에 이상적인 반면, 메타데이터는 메시지 자체에 대한 정보를 담기에 적합합니다.

출처: 공식문서

본문

시작하기

메타데이터 타입 정의

타입 안전성을 위해 먼저 메타데이터 타입을 정의합니다:

app/types.ts

import { UIMessage } from 'ai';
import { z } from 'zod';

// Define your metadata schema
export const messageMetadataSchema = z.object({
  createdAt: z.number().optional(),
  model: z.string().optional(),
  totalTokens: z.number().optional(),
});

export type MessageMetadata = z.infer<typeof messageMetadataSchema>;

// Create a typed UIMessage
export type MyUIMessage = UIMessage<MessageMetadata>;

서버에서 메타데이터 보내기

toUIMessageStreammessageMetadata 콜백으로 다양한 스트리밍 단계에서 메타데이터를 보냅니다:

app/api/chat/route.ts

import {
  convertToModelMessages,
  createUIMessageStreamResponse,
  streamText,
  toUIMessageStream,
} from 'ai';
import type { MyUIMessage } from '@/types';

export async function POST(req: Request) {
  const { messages }: { messages: MyUIMessage[] } = await req.json();

  const result = streamText({
    model: "xai/grok-4.6",
    messages: await convertToModelMessages(messages),
  });

  return createUIMessageStreamResponse({
    stream: toUIMessageStream({
      stream: result.stream,
      originalMessages: messages, // pass this in for type-safe return objects
      messageMetadata: ({ part }) => {
        // Send metadata when streaming starts
        if (part.type === 'start') {
          return {
            createdAt: Date.now(),
            model: 'your-model-id',
          };
        }

        // Send additional metadata when streaming completes
        if (part.type === 'finish') {
          return {
            totalTokens: part.totalUsage.totalTokens,
          };
        }
      },
    }),
  });
}

messageMetadata에서 타입 안전한 메타데이터 반환 객체를 활성화하려면 originalMessages 파라미터를 UIMessage 타입으로 전달하세요.

클라이언트에서 메타데이터 접근

message.metadata 속성으로 메타데이터에 접근합니다:

app/page.tsx

'use client';
import { useChat } from '@ai-sdk/react';
import { DefaultChatTransport } from 'ai';
import type { MyUIMessage } from '@/types';

export default function Chat() {
  const { messages } = useChat<MyUIMessage>({
    transport: new DefaultChatTransport({
      api: '/api/chat',
    }),
  });

  return (
    <div>
      {messages.map(message => (
        <div key={message.id}>
          <div>
            {message.role === 'user' ? 'User: ' : 'AI: '}
            {message.metadata?.createdAt && (
              <span className="text-sm text-gray-500">
                {new Date(message.metadata.createdAt).toLocaleTimeString()}
              </span>
            )}
          </div>
          {/* Render message content */}
          {message.parts.map((part, index) =>
            part.type === 'text' ? <div key={index}>{part.text}</div> : null,
          )}
          {/* Display additional metadata */}
          {message.metadata?.totalTokens && (
            <div className="text-xs text-gray-400">
              {message.metadata.totalTokens} tokens
            </div>
          )}
        </div>
      ))}
    </div>
  );
}

생성 중에 변하는 임의 데이터를 스트리밍하려면 data parts를 고려하세요.

흔한 유스케이스

메시지 메타데이터는 다음에 이상적입니다:

  • 타임스탬프: 메시지가 생성되거나 완료된 시점.
  • 모델 정보: 어떤 AI 모델이 사용되었는지.
  • 토큰 사용량: 비용과 사용 한도 추적.
  • 사용자 컨텍스트: 사용자 ID, 세션 정보.
  • 성능 지표: 생성 시간, 첫 토큰까지의 시간.
  • 품질 지표: 종료 사유, 신뢰 점수.

더 알아보기