์ฝ˜ํ…์ธ ๋กœ ์ด๋™

๋ผ์ด๋ธŒ ์—์ด์ „ํŠธ๋ฅผ ์œ„ํ•œ ๊ฐ€๋“œ๋ ˆ์ผ

ADK์—์„œ ์ง€์›Python v2.8.0

๊ฐ€๋“œ๋ ˆ์ผ์€ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์‹ค์‹œ๊ฐ„ ์Œ์„ฑ ์—์ด์ „ํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ• ์ง€๋ฅผ ํ†ต์ œํ•˜์—ฌ ๋Œ€ํ™”๊ฐ€ ์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚˜์ง€ ์•Š๊ณ (on-topic), ์ •์ฑ…์„ ์ค€์ˆ˜ํ•˜๋ฉฐ(on-policy), ์•ˆ์ „(safe)ํ•˜๊ฒŒ ์œ ์ง€๋˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์‹ค์‹œ๊ฐ„ ์—ฐ๊ฒฐ์—์„œ๋Š” ์˜ค๋””์˜ค๊ฐ€ ์ง€์†์ ์œผ๋กœ ์ŠคํŠธ๋ฆฌ๋ฐ๋˜๊ณ  ๋ชจ๋ธ์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐœํ™”๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ADK๋Š” ๋Œ€ํ™” ์ง€์—ฐ ์‹œ๊ฐ„(latency)์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์„ ์ตœ์†Œํ™”ํ•˜๋ฉด์„œ ๋Œ€ํ™”๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•ด ํ•จ๊ป˜ ์ž‘๋™ํ•˜๋Š” ๋‹ค์ค‘ ๊ณ„์ธต ๋ณดํ˜ธ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ์ฝœ๋ฐฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๋ฐ ํ”Œ๋Ÿฌ๊ทธ์ธ ๋“ฑ๋ก ๋ฐฉ๋ฒ•์€ ์ฝœ๋ฐฑ ์œ ํ˜• ๋ฐ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ฐธ์กฐํ•˜์„ธ์š”.

๊ฐ€๋“œ๋ ˆ์ผ ๊ณ„์ธต

๊ณ„์ธต ์—ญํ•  ๋ณดํ˜ธ ์ดˆ์  ์ง€์—ฐ ์‹œ๊ฐ„ ์˜ํ–ฅ
์‹œ์Šคํ…œ ์ง€์นจ (System instructions) ํ†ค, ๋Œ€ํ™” ๊ทœ์น™ ๋ฐ ๊ฒฝ๊ณ„๋ฅผ ํ˜•์„ฑ ํ–‰๋™ ๊ฐ€์ด๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ถ”๊ฐ€ ์ง€์—ฐ ์‹œ๊ฐ„ ์—†์Œ
์•ˆ์ „ ์„ค์ • (Safety settings) ์ฝ˜ํ…์ธ  ์•ˆ์ „์— ๋Œ€ํ•œ ํ”Œ๋žซํผ ์ž„๊ณ„๊ฐ’์„ ์ ์šฉ ํ”Œ๋žซํผ ์•ˆ์ „ ํ•„ํ„ฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ถ”๊ฐ€ ์ง€์—ฐ ์‹œ๊ฐ„ ์—†์Œ
์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ (Input validation) ํ”„๋กฌํ”„ํŠธ ์ธ์ ์…˜ ๋ฐ ๊ธˆ์ง€๋œ ์ฃผ์ œ ๊ฐ์ง€ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฒ€์ฆ ์ตœ์†Œํ™” (ํ„ด๋‹น ์‹คํ–‰)
์‘๋‹ต ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ (Response validation) ๋น„์ฆˆ๋‹ˆ์Šค ์ •์ฑ…์— ๋”ฐ๋ผ ์—์ด์ „ํŠธ ์‘๋‹ต์„ ์„ ๋ณ„ ์—์ด์ „ํŠธ ์‘๋‹ต ๊ฒ€์ฆ ๊ฒ€์‚ฌ ๋ฐฉ์‹์— ๋”ฐ๋ผ ๋‹ค๋ฆ„
๋„๊ตฌ ๊ฐ€๋“œ๋ ˆ์ผ (Tool guardrails) ๋„๊ตฌ ์‹คํ–‰์„ ๊ฐ€๋กœ์ฑ„๊ณ  ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ฒ€์ฆ ๋„๊ตฌ ์‹คํ–‰ ์•ˆ์ „์„ฑ ์ตœ์†Œํ™” (๋„๊ตฌ ํ˜ธ์ถœ๋‹น ์‹คํ–‰)

์ด๋Ÿฌํ•œ ๊ณ„์ธต๋“ค์€ ํ•จ๊ป˜ ์—ฐ๊ณ„๋˜์–ด ์‹ฌ์ธต ๋ฐฉ์–ด(defense in depth)๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์‹œ์Šคํ…œ ์ง€์นจ์€ ์ž์—ฐ์Šค๋Ÿฌ์šด ๋Œ€ํ™” ํ๋ฆ„์„ ํ˜•์„ฑํ•˜๊ณ , ํ”Œ๋žซํผ ์•ˆ์ „ ํ•„ํ„ฐ๋Š” ๊ธฐ๋ณธ์ ์ธ ์œ ํ•ด์„ฑ ๊ฒฝ๊ณ„๋ฅผ ์ ์šฉํ•˜๋ฉฐ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฒ€์ฆ๊ธฐ๋Š” ์ž…๋ ฅ, ์‘๋‹ต ๋ฐ ๋„๊ตฌ ํ˜ธ์ถœ์„ ๋…๋ฆฝ์ ์œผ๋กœ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. ๋ช…ํ™•ํ•œ ์ง€์นจ๊ณผ ๋…๋ฆฝ์ ์ธ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ๊ฒฐํ•ฉํ•˜๋ฉด ํ•œ ๊ณ„์ธต์„ ์šฐํšŒํ•˜๋Š” ์˜ˆ์™ธ์ ์ธ ์ผ€์ด์Šค(edge case)๊ฐ€ ๋ฐœ์ƒํ•˜๋”๋ผ๋„ ๋‹ค๋ฅธ ๊ณ„์ธต์—์„œ ์ด๋ฅผ ์ฐจ๋‹จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ง€์นจ ๋ฐ ์•ˆ์ „ ์„ค์ •

์ง€์นจ๊ณผ ์•ˆ์ „ ์„ค์ •์€ ์„ธ์…˜ ์ „์ฒด์˜ ๊ธฐ์ค€ ๋™์ž‘์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ์„ค์ • ๋ชจ๋‘ ์„ธ์…˜์„ ์ƒ์„ฑํ•  ๋•Œ ์—์ด์ „ํŠธ์— ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

from google.adk.agents import Agent
from google.genai import types

root_agent = Agent(
    model='gemini-live-2.5-flash-native-audio',
    name='support_agent',
    instruction=(
        'You help customers with billing questions. '
        'Never quote a price; offer to transfer to sales instead. '
        'Never discuss a competitor.'
    ),
    generate_content_config=types.GenerateContentConfig(
        safety_settings=[
            types.SafetySetting(
                category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
                threshold=types.HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE,
            ),
        ]
    ),
)

๋ชจ๋ธ์€ ๋Œ€ํ™” ์ปจํ…์ŠคํŠธ๊ฐ€ ๋ˆ„์ ๋จ์— ๋”ฐ๋ผ ๋ชจ๋“  ํ„ด์— ๊ฑธ์ณ ์‹œ์Šคํ…œ ์ง€์นจ์„ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์‹ค์‹œ๊ฐ„ ์—์ด์ „ํŠธ๋ฅผ ์œ„ํ•œ ์ง€์นจ์„ ์„ค๊ณ„ํ•  ๋•Œ๋Š” ํŽ˜๋ฅด์†Œ๋‚˜, ๋Œ€ํ™” ๊ทœ์น™, ๋Œ€ํ™” ๊ฐ€๋“œ๋ ˆ์ผ์„ ์ˆœ์„œ๋Œ€๋กœ ์ •์˜ํ•˜์„ธ์š”. ์—„๊ฒฉํ•œ ์ œ์•ฝ ์กฐ๊ฑด์˜ ๊ฒฝ์šฐ ๋Œ€์•ˆ์„ ์ œ์‹œํ•˜๊ฑฐ๋‚˜ ๋ฐœ์‹ ์ž๋ฅผ ์ƒ๋‹ด์›์—๊ฒŒ ํ˜ธ์ „ํ™˜(transfer)ํ•˜๋Š” ๋“ฑ ๊ฒฝ๊ณ„ ์กฐ๊ฑด์— ๋ถ€๋”ชํ˜”์„ ๋•Œ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ๋ช…์‹œ์ ์ธ ์ฒ˜๋ฆฌ ๊ทœ์น™์„ ์ œ๊ณตํ•˜์„ธ์š”.

์•ˆ์ „ ์„ค์ •์€ ์‹ค์‹œ๊ฐ„ ์„ธ์…˜์— ์•ˆ์ „ ๋ฐ ์ฝ˜ํ…์ธ  ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋ธ์ด ๊ตฌ์„ฑ๋œ ์ž„๊ณ„๊ฐ’์„ ์ดˆ๊ณผํ•˜๋Š” ์ฝ˜ํ…์ธ ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ํ”Œ๋žซํผ์—์„œ ์ƒ์„ฑ์„ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค.

์‹ค์‹œ๊ฐ„ ์—ฐ๊ฒฐ์€ ์‹œ์ž‘ ์‹œ์ ์— ์ด๋Ÿฌํ•œ ์„ค์ •์„ ์„ค์ •ํ•˜๋ฏ€๋กœ ์„ธ์…˜ ์ง€์† ์‹œ๊ฐ„ ๋™์•ˆ ๊ณ ์ •๋œ ์ƒํƒœ๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ์„ธ์…˜ ์ƒํƒœ๋ฅผ ๋ณด๊ฐ„(interpolate)ํ•˜๋Š” ์ง€์นจ ๋ฌธ์ž์—ด์€ ์„ธ์…˜์ด ์‹œ์ž‘๋  ๋•Œ ํ•œ ๋ฒˆ ๋ Œ๋”๋ง๋˜๋ฉฐ, ์žฌ๊ฐœ๋œ ์—ฐ๊ฒฐ์€ ํ•ด๋‹น ๋ Œ๋”๋ง๋œ ์ง€์นจ์„ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋Œ€ํ™” ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

๋Œ€ํ™” ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋Š” ์‚ฌ์šฉ์ž์˜ ๋ฐœํ™”์™€ ์—์ด์ „ํŠธ์˜ ์‘๋‹ต์„ ๋…๋ฆฝ์ ์œผ๋กœ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๊ด€๋ฆฌํ˜• ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์ •์ฑ…์˜ ๊ฒฝ์šฐ, Model Armor ํ”Œ๋Ÿฌ๊ทธ์ธ์ด Google Cloud ํ…œํ”Œ๋ฆฟ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ”„๋กฌํ”„ํŠธ ์ธ์ ์…˜, ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ ๋ฐ ์ •์ฑ… ์œ„๋ฐ˜ ์‚ฌํ•ญ์„ ์„ ๋ณ„ํ•ฉ๋‹ˆ๋‹ค. ADK ๋ชจ๋ธ ์ฝœ๋ฐฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ปค์Šคํ…€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

before_model_callback ํ›…์€ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๊ฐ€๋กœ์ฑ•๋‹ˆ๋‹ค. ์ด ์ฝœ๋ฐฑ์€ ์ž…๋ ฅ๋œ ํ…์ŠคํŠธ๊ฐ€ ๋ชจ๋ธ์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์— ํ‰๊ฐ€ํ•˜๋ฏ€๋กœ, ์ฐจ๋‹จ ์‹œ ์—ฐ๊ฒฐ์„ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ๋ฉ”์‹œ์ง€๊ฐ€ ์ปจํ…์ŠคํŠธ์— ํฌํ•จ๋˜์ง€ ์•Š๋„๋ก ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์Œ์„ฑ ์˜ค๋””์˜ค์˜ ๊ฒฝ์šฐ ์ฝœ๋ฐฑ์€ ๋ชจ๋ธ์ด ์ด๋ฏธ ์˜ค๋””์˜ค๋ฅผ ์ˆ˜์‹ ํ•œ ํ›„์— ์ „์‚ฌ๋œ ๋ฐœํ™” ์ „์ฒด๋ฅผ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ฐจ๋‹จ์ด ๋ฐœ์ƒํ•˜๋ฉด ๋ผ์ด๋ธŒ ์„ธ์…˜์„ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜์—ฌ ์ด๋ฏธ ์ „์†ก ์ค‘์ธ ์‘๋‹ต์„ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.

๊ฒ€์‚ฌ์—์„œ ์ •์ฑ… ์œ„๋ฐ˜์ด ํ™•์ธ๋˜๋ฉด LlmResponse๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์‚ฌ์šฉ์ž์˜ ํ„ด์„ ์•ˆ์ „ํ•œ ๋Œ€์ฒด ์‘๋‹ต์œผ๋กœ ๊ต์ฒดํ•ฉ๋‹ˆ๋‹ค.

from typing import Optional

from google.adk.agents.callback_context import CallbackContext
from google.adk.models.llm_request import LlmRequest
from google.adk.models.llm_response import LlmResponse
from google.genai import types


def block_input(
    callback_context: CallbackContext,
    llm_request: LlmRequest,
) -> Optional[LlmResponse]:
  """๊ฒฝ์Ÿ์‚ฌ๋ฅผ ์–ธ๊ธ‰ํ•˜๋Š” ์‚ฌ์šฉ์ž ํ„ด์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค."""
  text = ''.join(
      part.text or ''
      for content in llm_request.contents
      for part in content.parts or []
  )

  if 'competitor' not in text.lower():
    return None

  return LlmResponse(
      content=types.Content(
          role='model',
          parts=[types.Part(text="I can't discuss that.")],
      )
  )

์—์ด์ „ํŠธ ์‘๋‹ต ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

after_model_callback ํ›…์€ ๋ชจ๋ธ ์‘๋‹ต์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌ๋˜๊ธฐ ์ „์ด๋‚˜ ์ „๋‹ฌ๋˜๋Š” ๋„์ค‘์— ์ด๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋Š” ์Œ์„ฑ ํ„ด ์ค‘์— ๋ˆ„์ ๋˜๋Š” ์ „์‚ฌ ํ…์ŠคํŠธ๋ฅผ ๊ฒ€์‚ฌํ•˜์—ฌ ์œ„๋ฐ˜ ์‚ฌํ•ญ์„ ์กฐ๊ธฐ์— ํฌ์ฐฉํ•˜๊ฑฐ๋‚˜, ์ „์ฒด ํ„ด์˜ ์ „์‚ฌ ํ…์ŠคํŠธ๋ฅผ ํ‰๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

def block_output(
    callback_context: CallbackContext,
    llm_response: LlmResponse,
) -> Optional[LlmResponse]:
  """๋‹ต๋ณ€์— ๊ฐ€๊ฒฉ์ด ์–ธ๊ธ‰๋˜๋ฉด ์‘๋‹ต์„ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค."""
  transcription = llm_response.output_transcription
  text = transcription.text if transcription else ''

  if '$' not in text:
    return None

  return LlmResponse(
      content=types.Content(
          role='model',
          parts=[types.Part(text='Let me connect you with sales.')],
      )
  )

์ถœ๋ ฅ ์ฝœ๋ฐฑ์—์„œ LlmResponse๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋ชจ๋ธ ์ƒ์„ฑ์„ ์ฆ‰์‹œ ์ค‘๋‹จํ•˜๊ณ  ๋Œ€์ฒด ๋ฉ”์‹œ์ง€๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋ธ์ด ์ด๋ฏธ ์ž…๋ ฅ ์ฒ˜๋ฆฌ๋ฅผ ์‹œ์ž‘ํ•œ ์Œ์„ฑ ํ„ด์˜ ๊ฒฝ์šฐ, ๊ฑฐ๋ถ€๋œ ์ฝ˜ํ…์ธ ๊ฐ€ ๋Œ€ํ™” ์ปจํ…์ŠคํŠธ์— ๋‚จ์•„ ์žˆ์ง€ ์•Š๋„๋ก ADK๊ฐ€ ํ˜„์žฌ ํ„ด์„ ์ง€์›๋‹ˆ๋‹ค.

๋„๊ตฌ ๊ฐ€๋“œ๋ ˆ์ผ

๋„๊ตฌ ์ฝœ๋ฐฑ์€ ์™ธ๋ถ€ ์‹œ์Šคํ…œ์„ ๋ณดํ˜ธํ•˜๊ณ  ์ž‘์—…์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค. before_tool_callback ํ›…์€ ๋„๊ตฌ๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ์ „์— ์ธ์ˆ˜๋ฅผ ๊ฒ€์‚ฌํ•˜์—ฌ ์Šน์ธ๋˜์ง€ ์•Š์€ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๊ฑฐ๋ถ€ํ•˜๊ฑฐ๋‚˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. after_tool_callback ํ›…์€ ๊ฒฐ๊ณผ๊ฐ€ ๋ชจ๋ธ๋กœ ๋ฐ˜ํ™˜๋˜๊ธฐ ์ „์— ๋ฏผ๊ฐํ•œ ๊ฒฐ๊ณผ๋ฅผ ์‚ญ์ œ(redact)ํ•ฉ๋‹ˆ๋‹ค.

from typing import Any, Optional

from google.adk.tools import BaseTool
from google.adk.tools import ToolContext


def validate_refund(
    tool: BaseTool,
    args: dict[str, Any],
    tool_context: ToolContext,
) -> Optional[dict[str, Any]]:
  """์ž„๊ณ„๊ฐ’์„ ์ดˆ๊ณผํ•˜๋Š” ์Šน์ธ๋˜์ง€ ์•Š์€ ํ™˜๋ถˆ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค."""
  if tool.name == 'issue_refund' and args.get('amount', 0) > 100:
    return {'error': 'Refund exceeds automatic approval limit.'}
  return None

๋„๊ตฌ ์ฝœ๋ฐฑ์—์„œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋„๊ตฌ ์‹คํ–‰์„ ์šฐํšŒํ•˜๊ณ  ๋ฐ˜ํ™˜๊ฐ’์„ ๋ชจ๋ธ์— ์ง์ ‘ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋„๊ตฌ ์‹คํ–‰ ์ฝœ๋ฐฑ์„ ์ฐธ์กฐํ•˜์„ธ์š”.

์‹ค์‹œ๊ฐ„ ์˜ค๋””์˜ค ์ŠคํŠธ๋ฆผ์€ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•œ ์‚ฌ๋žŒ์˜ ํ™•์ธ์„ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ ์œ„ํ•ด ์ผ์‹œ ์ค‘์ง€๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์‹ค์‹œ๊ฐ„ ์—์ด์ „ํŠธ๊ฐ€ ๋†’์€ ๊ถŒํ•œ์ด ํ•„์š”ํ•œ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ฝœ๋ฐฑ ๋‚ด์—์„œ ์ธ์ˆ˜๋ฅผ ์ž๋™์œผ๋กœ ๊ฒ€์ฆํ•˜๊ฑฐ๋‚˜ ์š”์ฒญ์„ ์‚ฌ๋žŒ์—๊ฒŒ ์ธ๊ณ„(handoff)ํ•˜๋„๋ก ๋ผ์šฐํŒ…ํ•˜์„ธ์š”.

์š”๊ตฌ์‚ฌํ•ญ ๋ฐ ๋ชจ๋ฒ” ์‚ฌ๋ก€

  • ์ „์‚ฌ(Transcription) ํ™œ์„ฑ ์ƒํƒœ ์œ ์ง€: ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ๋Œ€ํ™” ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋Š” ์Œ์„ฑ ์ „์‚ฌ์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค. RunConfig.input_audio_transcription๊ณผ RunConfig.output_audio_transcription์€ ๋ชจ๋‘ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ฅผ None์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ํ•ด๋‹น ๊ฒ€๋ณ„ ๊ณ„์ธต์ด ๋น„ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค.
  • ๊ฒ€์ฆ๊ธฐ ๊ฒฝ๋Ÿ‰ํ™” ์œ ์ง€: ๋ผ์ด๋ธŒ ์ˆ˜์‹  ๋ฃจํ”„์˜ ์ฝœ๋ฐฑ์€ ์˜ค๋””์˜ค ์ฒ˜๋ฆฌ์™€ ์ธ๋ผ์ธ์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๋น ๋ฅธ ๋กœ์ปฌ ๊ฒ€์‚ฌ๋ฅผ ํ†ตํ•ด ๋Œ€ํ™”์˜ ์‘๋‹ต์„ฑ์„ ์œ ์ง€ํ•˜์„ธ์š”. ๋” ๋ฌด๊ฑฐ์šด ๊ฒ€์‚ฌ์˜ ๊ฒฝ์šฐ ์ „์ฒด ํ„ด ์ „์‚ฌ๋ฅผ ํ‰๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์žฅ์‹œ๊ฐ„ ์‹คํ–‰๋˜๋Š” ๋ถ„์„์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์˜คํ”„๋กœ๋“œํ•˜์„ธ์š”.
  • ์—์ด์ „ํŠธ ์ „๋ฐ˜์— ๊ฑธ์นœ ์ •์ฑ… ์ ์šฉ: App์— Model Armor์™€ ๊ฐ™์€ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ๋“ฑ๋กํ•˜๋ฉด ์ฝœ๋ฐฑ ์ฝ”๋“œ๋ฅผ ์ค‘๋ณตํ•˜์ง€ ์•Š๊ณ ๋„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ชจ๋“  ์—์ด์ „ํŠธ์— ์ผ๊ด€๋œ ๋ณด์•ˆ ๊ทœ์น™์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ถ”๊ฐ€ ๋ฆฌ์†Œ์Šค