Mistral AI와 Phoenix로 구조화 데이터 추출 서비스 관측 가능성 확보하기

Mistral AI와 Phoenix로 구조화 데이터 추출 서비스 관측 가능성 확보하기

Mistral AI의 도구 호출(tool calling) 기능으로 구조화 데이터 추출 서비스를 만들고, Mistral 클라이언트를 OpenInference 트레이서로 계측해 Phoenix에서 트레이스와 스팬을 검사하는 방법을 배우는 문서예요.

출처: 문서

본문

이 튜토리얼에서 여러분은 다음을 하게 돼요:

  • Mistral의 도구 호출 기능을 사용해 구조화 데이터 추출 수행하기 — 구조화되지 않은 입력(예: 자연어 사용자 요청)을 구조화 형식(예: 테이블 형식)으로 변환하는 작업이에요.
  • Mistral AI 클라이언트를 계측해 OpenInference 트레이싱 형식으로 트레이스 데이터 기록하기.
  • 애플리케이션의 트레이스와 스팬을 검사해 트레이스 데이터를 시각화하기.

배경 (Background)

Mistral AI 채팅 완성(chat completions) API의 강력한 기능 중 하나는 **도구 호출(tool calling)**이에요. 사용자가 하나 이상의 도구의 시그니처와 인자를 JSON Schema와 자연어 설명으로 Mistral AI API에 설명하면, LLM이 대화 컨텍스트에 따라 각 도구를 언제 쓸지 결정하고 인자 값을 제공해요. 도구 호출은 함수 입력·출력을 채팅 메시지 시퀀스에 통합하는 주 목적 외에도 구조화 데이터 추출에 유용해요. 구조화 출력의 원하는 형식을 설명하는 "함수"를 지정할 수 있기 때문이에요. 구조화 데이터 추출은 ETL이나 추천 시스템 같은 다른 ML 모델의 입력 등 다양한 목적에 유용해요.

신중한 프롬프팅으로 도구 호출 없이도 구조화 출력을 만들 수 있지만, 도구 호출이 특정 형식에 맞는 출력을 만드는 데 더 신뢰할 수 있어요. Mistral AI 도구 호출 API에 대한 자세한 내용은 Mistral AI 문서를 참고하세요.

1. 의존성 설치와 라이브러리 임포트 (Install Dependencies and Import Libraries)

이 노트북에는 Mistral AI API 키가 필요해요.

!pip install -q arize-phoenix jsonschema openinference-instrumentation-mistralai
!pip install -qU mistralai
import os
from getpass import getpass
from typing import Any, Dict
import pandas as pd
import phoenix as px
from phoenix.otel import register
from mistralai.client import Mistral
from mistralai.client.models import UserMessage, SystemMessage
from openinference.instrumentation.mistralai import MistralAIInstrumentor

pd.set_option("display.max_colwidth", None)

2. Mistral API 키 설정 (Configure Your Mistral API Key)

if not (api_key := os.getenv("MISTRAL_API_KEY")):
    api_key = getpass("🔑 Enter your Mistral AI API key: ")

client = Mistral(api_key=api_key)

3. Phoenix 백그라운드 실행 (Run Phoenix in the Background)

계측된 Mistral 클라이언트가 내보내는 트레이스 데이터를 수집하려고 Phoenix를 백그라운드 세션으로 실행해요. Phoenix 셀프호스팅 또는 원격 Phoenix 인스턴스 연결에 대한 자세한 내용은 Phoenix 문서를 참고하세요.

session = px.launch_app()
tracer_provider = register()

4. Mistral 클라이언트 계측 (Instrument Your Mistral Client)

OpenInference 형식의 텔레메트리 데이터를 내보내는 트레이서로 Mistral 클라이언트를 계측해요. OpenInference는 LLM 애플리케이션 트레이스를 캡처·저장하는 오픈 표준으로, Phoenix 같은 LLM 관측 가능성 솔루션과 원활하게 통합되게 해줘요.

MistralAIInstrumentor().instrument(tracer_provider=tracer_provider)

5. 구조화 데이터 추출 (Extract Your Structured Data)

다음 10개의 여행 요청 목록에서 구조화 데이터를 추출할 거예요.

travel_requests = [
    "Can you recommend a luxury hotel in Tokyo with a view of Mount Fuji for a romantic honeymoon?",
    "I'm looking for a mid-range hotel in London with easy access to public transportation for a solo backpacking trip. Any suggestions?",
    "I need a budget-friendly hotel in San Francisco close to the Golden Gate Bridge for a family vacation. What do you recommend?",
    "Can you help me find a boutique hotel in New York City with a rooftop bar for a cultural exploration trip?",
    "I'm planning a business trip to Tokyo and I need a hotel near the financial district. What options are available?",
    "I'm traveling to London for a solo vacation and I want to stay in a trendy neighborhood with great shopping and dining options. Any recommendations for hotels?",
    "I'm searching for a luxury beachfront resort in San Francisco for a relaxing family vacation. Can you suggest any options?",
    "I need a mid-range hotel in New York City with a fitness center and conference facilities for a business trip. Any suggestions?",
    "I'm looking for a budget-friendly hotel in Tokyo with easy access to public transportation for a backpacking trip. What do you recommend?",
    "I'm planning a honeymoon in London and I want a luxurious hotel with a spa and romantic atmosphere. Can you suggest some options?",
]

Mistral AI API는 JSON Schema와 자연어 설명으로 호출할 함수의 시그니처를 지정해요. 이 경우 구조화되지 않은 텍스트 입력의 다음 속성을 기록하는 함수를 설명할 거예요:

  • location: 원하는 목적지
  • budget_level: 범주형 예산 선호도
  • purpose: 여행 목적

JSON Schema를 사용하면 출력에서 각 필드의 타입을 정의하고, 범주형 출력의 경우 유효한 값도 열거할 수 있어요. 따라서 Mistral AI 도구 호출은 이전에 NER(named-entity recognition)나 분류 모델로 수행하던 작업에도 사용할 수 있어요.

parameters_schema = {
    "type": "object",
    "properties": {
        "location": {
            "type": "string",
            "description": 'The desired destination location. Use city, state, and country format when possible. If no destination is provided, return "unstated".',
        },
        "budget_level": {
            "type": "string",
            "enum": ["low", "medium", "high", "not_stated"],
            "description": 'The desired budget level. If no budget level is provided, return "not_stated".',
        },
        "purpose": {
            "type": "string",
            "enum": ["business", "pleasure", "other", "non_stated"],
            "description": 'The purpose of the trip. If no purpose is provided, return "not_stated".',
        },
    },
    "required": ["location", "budget_level", "purpose"],
}

function_schema = {
    "name": "record_travel_request_attributes",
    "description": "Records the attributes of a travel request",
    "parameters": parameters_schema,
}

tool_schema = {
    "type": "function",
    "function": function_schema,
}

system_message = "You are an assistant that parses and records the attributes of a user's travel request."

def extract_raw_travel_request_attributes_string(
    travel_request: str,
    tool_schema: Dict[str, Any],
    system_message: str,
    client: Mistral,
    model: str = "mistral-large-latest",
) -> str:
    chat_completion = client.chat.complete(
        model=model,
        messages=[
            SystemMessage(role="system", content=system_message),
            UserMessage(role="user", content=travel_request),
        ],
        tools=[tool_schema],
        # By default, the LLM will choose whether or not to use a tool given the conversation context.
        # The line below forces the LLM to use a tool so that the output conforms to the schema.
        # tool_choice=ToolChoice.any,
    )
    return chat_completion.choices[0].message.tool_calls[0].function.arguments

추출을 실행해요.

raw_travel_attributes_column = []
for travel_request in travel_requests:
    print("Travel request:")
    print("==============")
    print(travel_request)
    print()
    raw_travel_attributes = extract_raw_travel_request_attributes_string(
        travel_request, tool_schema, system_message, client
    )
    raw_travel_attributes_column.append(raw_travel_attributes)
    print("Raw Travel Attributes:")
    print("=====================")
    print(raw_travel_attributes)
    print()

6. Phoenix에서 트레이스 확인 (View traces in Phoenix)

이제 Phoenix에서 트레이스를 볼 수 있어요.

print(f"Current Phoenix URL: {session.url}")

7. 트레이스 데이터 내보내기 (Export Your Trace Data)

OpenInference 트레이스 데이터는 Phoenix가 수집하며, 추가 분석과 평가를 위해 pandas dataframe으로 내보낼 수 있어요.

trace_df = px.Client().get_spans_dataframe()
trace_df

8. 요약 (Recap)

축하해요! 이 튜토리얼에서 여러분은:

  • Mistral AI 도구 호출로 구조화되지 않은 텍스트에 구조화 데이터 추출을 수행하는 서비스를 구축했어요.
  • 서비스를 OpenInference 트레이서로 계측했어요.
  • Phoenix에서 텔레메트리 데이터를 검사했어요.

더 알아보기 (Learn more)