Firebase Genkit이 Compass 앱에 AI를 추가하는 데 어떻게 도움이 되었나요?

5월 15, 2024
Alexander Nohe Developer Relations Engineer
Arthur Thompson Developer Relations Engineer

생성형 AI를 앱에 통합하면 비즈니스를 차별화하고 사용자를 만족시키는 데 도움이 될 수 있지만, 프로토타입을 넘어서는 AI 기반 기능을 개발하고 개선하는 것은 여전히 어려운 일입니다. 이제 막 AI 개발 여정을 시작한 앱 개발자들과 대화를 나눈 후에 우리는 많은 사람들이 수많은 새로운 개념을 배워야 하고 실제 제작 시 이러한 기능을 확장 가능하고 안전하며 안정적인 기능으로 만드는 작업에 큰 부담이 있다는 것을 알게 되었습니다.

따라서 우리는 개발자 친화적인 패턴과 패러다임을 사용하여 정교한 AI 기능을 앱에 구축하기 위한 오픈 소스 프레임워크인 Firebase Genkit을 만들었습니다. 여기에는 개발자가 AI 워크로드를 구축, 테스트, 배포 및 모니터링하는 데 도움이 되는 라이브러리, 도구 및 플러그인이 포함되어 있습니다. 현재 JavaScript/TypeScript에서 사용할 수 있으며 Go 지원도 곧 예정되어 있습니다.

이 게시물에서는 Genkit의 주요 기능과 이를 사용하여 여행 계획 앱인 Compass에 생성형 AI를 추가하는 방법에 대해 알아봅니다.


강력한 개발자 도구

생성형 AI의 고유한 비결정성 특성으로 인해 일관된 품질의 제작 결과를 얻기 위해 작업할 때는 가능한 솔루션을 효율적으로 탐색하고 평가하는 데 도움이 되는 전문 도구가 필요합니다.

전용 CLI와 브라우저 기반 로컬 개발자 UI를 포함하는 Genkit은 강력한 도구 경험을 제공합니다. Genkit CLI를 사용하면 AI 플로우를 몇 초 만에 초기화할 수 있습니다. 그런 다음 개발자 UI를 실행하여 로컬로 실행할 수 있습니다. 개발자 UI는 플로우(엔드 투 엔드 로직), 모델, 프롬프트, 인덱서, 검색기, 도구 등과 같은 Genkit 구성 요소와 상호작용을 할 수 있는 외관에 해당합니다. 코드와 구성된 플러그인을 기반으로 구성요소를 실행할 수 있게 됩니다. 이를 통해 다양한 프롬프트와 쿼리를 통해 구성요소를 쉽게 테스트하고 핫 리로딩을 통해 결과를 빠르게 반복할 수 있습니다.

Welcome to Firebase Genkit

플로우를 통한 엔드-투-엔드 관측 가능성

모든 Genkit 구성요소는 오픈 텔레메트리 및 사용자 정의 메타데이터로 계측되어 다운스트림 관찰 및 모니터링이 가능합니다. Genkit은 여러 단계와 AI 구성요소를 응집력 있는 엔드 투 엔드 워크플로우로 묶는 방법으로 "플로우" 프리미티브를 제공합니다. 플로우는 강력한 형식의, 스트리밍 가능하고, 로컬 및 원격 호출이 가능하며, 완전히 관측 가능한 특수 기능입니다.

놀라운 도구 덕분에 개발자 UI에서 플로우를 실행할 때 플로우를 "검사"하여 각 단계 및 구성요소에 대한 추적 및 측정항목을 볼 수 있습니다. 추적에는 모든 단계의 입력과 출력이 포함되어 있어 AI 논리를 디버그하거나 개선할 수 있는 병목 현상을 찾는 것이 더 쉬워집니다. 프로덕션 환경에서 실행된 배포된 플로우에 대한 추적도 볼 수 있습니다.

AI flow in Genkit

Dotprompt를 사용한 프롬프트 관리

프롬프트 엔지니어링은 단순히 텍스트를 수정하는 것 이상입니다. 사용하는 모델, 제공하는 매개변수, 요청하는 형식은 모두 출력 품질에 영향을 미칩니다.

Genkit은 코드와 함께 보관하는 단일 파일에 모든 것을 넣을 수 있는 파일 형식인 dotprompt를 제공하므로 테스트 및 구성을 더 쉽게 할 수 있습니다. 즉, 일반 코드와 함께 프롬프트를 관리하고, 동일한 버전 제어 시스템에서 추적하고, 함께 배포할 수 있습니다. Dotprompt 파일을 사용하면 모델과 해당 구성 지정, 핸들바를 기반으로 유연한 템플릿 제공, 입력 및 출력 스키마를 정의할 수 있어 개발 시 모델 상호작용을 검증하는 데 도움을 줄 수 있습니다.

---
model: vertexai/gemini-1.0-pro
config:
  temperature: 1.0
input:
  schema:
    properties:
      place: {type: string}
    required: [place]
  default:
    place: New York City
output:
  schema:
    type: object
    properties:
      hotelName: {type: string, description: "hotelName"}
      description: {type: string, description: "description"}
---
 
이 위치를 고려하여 {{place}}에는 가상의 호텔 이름과
{{place}}에 적합한 호텔에 대한 가상의 설명이 나옵니다.

플러그인 생태계: Google Cloud, Firebase, Vertex AI 등!

Genkit은 Google과 커뮤니티가 구축한 플러그인의 개방형 생태계를 통해 모델, 벡터 저장소, 도구, 평가자, 관측 가능성 등에 대한 사전 구축된 구성요소 및 통합에 대한 액세스를 제공합니다. Google 및 커뮤니티의 기존 플러그인 목록을 보려면 npm에서 #genkit-plugin 키워드를 탐색하세요.

당사 Compass 앱에서는 Google Cloud 플러그인을 사용하여 원격 측정 데이터를 Google Cloud Logging and Monitoring으로 내보내고, Firebase 플러그인을 사용하여 추적을 Cloud Firestore로 내보내고, Vertex AI 플러그인을 사용하여 Google의 최신 Gemini 모델에 액세스했습니다.


Genkit을 사용한 방식

Genkit의 기능을 직접 살펴볼 수 있게 익숙한 사용 사례를 보여주도록 설계된 여행 계획 앱 Compass를 만들었습니다.

Genkit-Inline-2 (1)

Compass의 초기 버전은 표준 양식 기반의 여행 계획 환경을 제공했지만 Genkit에 AI 기반 여행 계획 환경을 추가한다면 어떻게 될지 궁금했습니다.


위치 속성에 대한 임베드 생성

기존 콘텐츠 데이터베이스가 있었기 때문에 Postgres용 pgVector 확장 기능 및 Go의 Vertex AI에서 textembedding-gecko API를 사용하여 콘텐츠에 대해 대역 외 임베딩을 추가했습니다. 우리의 목표는 사용자가 각 장소의 "알려진" 내용이나 일반적인 설명을 기반으로 검색할 수 있도록 하는 것이었습니다. 이를 달성하기 위해 당사는 각 위치에 대한 "knownFor" 속성을 추출하고 임베딩을 생성한 다음 효율적인 쿼리를 위해 데이터와 함께 기존 테이블에 삽입했습니다.

// generateEmbeddings creates embeddings from text provided.
func GenerateEmbeddings(
	contentToEmbed,
	project,
	location,
	publisher,
	model,
	titleOfContent string) ([]float64, error) {
	ctx := context.Background()
 
	apiEndpoint := fmt.Sprintf(
		"%s-aiplatform.googleapis.com:443", location)
 
	client, err := aiplatform.NewPredictionClient(
		ctx, option.WithEndpoint(apiEndpoint))
	handleError(err)
	defer client.Close()
 
	base := fmt.Sprintf(
		"projects/%s/locations/%s/publishers/%s/models",
		project,
		location,
		publisher)
 
	url := fmt.Sprintf("%s/%s", base, model)
 
	promptValue, err := structpb.NewValue(
		map[string]interface{}{
			"content":   contentToEmbed,
			"task_type": "RETRIEVAL_DOCUMENT",
			"title":     titleOfContent,
		})
	handleError(err)
 
	// PredictRequest: create the model prediction request
	req := &aiplatformpb.PredictRequest{
		Endpoint:  url,
		Instances: []*structpb.Value{promptValue},
	}
 
	// PredictResponse: receive the response from the model
	resp, err := client.Predict(ctx, req)
	handleError(err)
	pred := resp.Predictions[0]
 
	embeddings := pred.GetStructValue().AsMap()["embeddings"]
	embedInt, ok := embeddings.(map[string]interface{})
	if !ok {
		fmt.Printf("Cannot convert")
	}
	predSlice := embedInt["values"]
	outSlice := make([]float64, 0)
	for _, v := range predSlice.([]any) {
		outSlice = append(outSlice, v.(float64))
	}
 
	return outSlice, nil
}

관련 위치에 대한 시맨틱 검색

다음은 위치의 "knownFor" 필드에 초점을 맞춰 사용자 쿼리를 기반으로 의미론적으로 관련 있는 데이터를 검색하는 검색기를 만들었습니다. 이를 달성하기 위해 우리는 Genkit의 임베드 함수를 사용하여 사용자 쿼리의 임베드를 생성했습니다. 이 임베딩은 검색기로 전달되어 데이터베이스를 효율적으로 쿼리하고 쿼리와 "knownFor" 속성 간의 의미적 유사성을 기반으로 가장 관련성이 높은 위치 결과를 반환합니다.

export const placeRetriever = defineRetriever(
  {
    name: "postgres/placeRetriever",
    configSchema: QueryOptions,
  },
  async (input, options) => {
    const inputEmbedding = await embed({
      embedder: textEmbeddingGecko,
      content: input,
    });
    const results = await sql`
      SELECT ref, name, country, continent, "knownFor", tags, "imageUrl"
        FROM public.places
        ORDER BY embedding <#> ${toSql(inputEmbedding)} LIMIT ${options.k ?? 3};
    `;
    return {
      documents: results.map((row) => {
        const { knownFor, ...metadata } = row;
        return Document.fromText(knownFor, metadata);
      }),
    };
  },
);

프롬프트 개선

당사는 Genkit 프로젝트 루트의 전용 /prompts 디렉토리 내에 dotprompt 파일로 프롬프트를 구성했습니다. 프롬프트 반복을 위해 다음 두 가지 경로가 가능합니다.

  1. 플로우 내 테스트: 최종 애플리케이션에서 작동하는 방식으로 검색기에서 데이터를 가져와서 프롬프트에 전달하는 플로우에 프롬프트를 로드합니다.

2. 개발자 UI 테스트: 개발자 UI에 프롬프트를 로드합니다. 이 방식으로 프롬프트 파일의 프롬프트를 업데이트하고 프롬프트의 변경 사항을 즉시 테스트하여 출력 품질에 미치는 영향을 측정할 수 있습니다

프롬프트가 만족스러운 경우, 평가자 플러그인을 사용하여 충실도, 관련성,악성과 같은 일반적인 LLM 측정항목을 평가했으며, 응답을 판단하기 위해 다른 LLM을 사용하였습니다.


Cloud Run에 배포됨

배포는 Genkit의 DNA에 깊이 새겨져 있습니다. 이 프로젝트는 Firebase용 클라우드 Functions(Firebase Authentication 및 App Check 포함)과 자연스럽게 통합되지만 우리는 프로젝트에 Cloud Run을 사용하기로 결정했습니다. Cloud Run에 배포했기 때문에 배포 시 선언된 모든 플로우에 대해 HTTPS 엔드포인트를 자동으로 생성하는 defineFlow를 사용했습니다.

Genkit-Inline-3 (1)

Genkit을 직접 사용해 보세요

​​Genkit은 개발부터 제작까지 AI 개발 프로세스를 간소화합니다. 직관적인 개발자 UI는 AI 여행 계획 기능을 추가하는 데 중요한 부분인 프롬프트 반복을 쉽게 만드는 획기적인 요소입니다. 플러그인을 사용하면 원활한 성능 모니터링과 다양한 AI 제품 및 서비스와의 통합이 가능합니다. 깔끔하게 버전을 관리할 수 있는 Genkit 플로우 및 프롬프트를 통해 필요한 경우 쉽게 되돌릴 수 있다는 사실을 알기 때문에 자신 있게 변경 작업을 수행할 수 있습니다. Firebase Genkit 문서를 탐색하여 Genkit이 앱에 AI 기능을 추가하는 데 어떻게 도움이 되는지 알아보고, 이 Firebase Genkit Codelab을 사용해 유사한 솔루션을 직접 구현해 보세요.