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

์—์ด์ „ํŠธ ์ตœ์ ํ™”

ADK์—์„œ ์ง€์›Python v1.24.0

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

์ •์˜

  • ์ƒ˜ํ”Œ๋Ÿฌ: ์ƒ˜ํ”Œ๋Ÿฌ๋Š” ์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ํ›„๋ณด ์ตœ์ ํ™” ์—์ด์ „ํŠธ๋ฅผ ํ‰๊ฐ€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญ์ด ์žˆ์„ ๋•Œ ์ƒ˜ํ”Œ๋Ÿฌ๋Š” eval ๊ธฐ๋ฐ˜ ์—์ด์ „ํŠธ ์ตœ์ ํ™”์— ์œ ์šฉํ•œ ์ƒ์„ธ ํ‰๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ ์˜ตํ‹ฐ๋งˆ์ด์ €์— ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • ์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ €: ์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ์ƒ˜ํ”Œ๋Ÿฌ์˜ ํ‰๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€ํ† ํ•˜๊ณ  ์ด๋ฅผ ์‚ฌ์šฉํ•ด ์—์ด์ „ํŠธ๋ฅผ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ - adk optimize๋กœ ๊ฐ„๋‹จํ•œ ์—์ด์ „ํŠธ ์ตœ์ ํ™”ํ•˜๊ธฐ

์ด ์˜ˆ์‹œ์—์„œ๋Š” ์ž‘์€ eval ์„ธํŠธ์— ๋Œ€ํ•œ ํ‰๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ hello_world ์ƒ˜ํ”Œ ์—์ด์ „ํŠธ์˜ ์ง€์นจ์„ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ ์œ„ํ•ด adk optimize ๋ช…๋ น์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

1๋‹จ๊ณ„: ์˜ˆ์‹œ ๋ฐ์ดํ„ฐ์…‹ ์ง€์ •ํ•˜๊ธฐ

๊ธฐ๋ณธ hello_world ์—์ด์ „ํŠธ ์ง€์นจ์€ ์ˆซ์ž๊ฐ€ ์†Œ์ˆ˜์ธ์ง€ ํŒ๋ณ„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ˆ์‹œ์˜ eval ์„ธํŠธ์—๋Š” ์—์ด์ „ํŠธ์—๊ฒŒ ์ง€์‹œํ•˜์ง€ ์•Š์€ ๋˜ ๋‹ค๋ฅธ ์ธก๋ฉด์ด ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ์ˆซ์ž๋Š” ์†Œ์ˆ˜ ์—ฌ๋ถ€์— ๋”ฐ๋ผ "good" ๋˜๋Š” "bad"๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ์ด ์ƒˆ๋กœ์šด ๊ทœ์น™์„ ๋„์ถœํ•ด ์—์ด์ „ํŠธ ์ง€์นจ์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

contributing/samples/hello_world/์— train_eval_set.evalset.json ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  ๋‹ค์Œ ๋‚ด์šฉ์„ ๋„ฃ์Šต๋‹ˆ๋‹ค.

{
  "eval_set_id": "train_eval_set",
  "name": "train_eval_set",
  "eval_cases": [
    {
      "eval_id": "simple",
      "conversation": [
        {
          "invocation_id": "inv1",
          "user_content": {
            "parts": [ {"text": "Is 7 prime?"} ],
            "role": "user"
          },
          "final_response": {
            "parts": [ {"text": "7 is a prime number."} ],
            "role": "model"
          }
        }
      ],
      "session_input": {
        "app_name": "hello_world",
        "user_id": "user"
      }
    },
    {
      "eval_id": "is_good",
      "conversation": [
        {
          "invocation_id": "inv1",
          "user_content": {
            "parts": [ {"text": "Is 4 a bad number?"} ],
            "role": "user"
          },
          "final_response": {
            "parts": [ {"text": "4 is not prime so it is a good number."} ],
            "role": "model"
          }
        }
      ],
      "session_input": {
        "app_name": "hello_world",
        "user_id": "user"
      }
    },
    {
      "eval_id": "is_bad",
      "conversation": [
        {
          "invocation_id": "inv1",
          "user_content": {
            "parts": [ {"text": "Is 5 a bad number?"} ],
            "role": "user"
          },
          "final_response": {
            "parts": [ {"text": "5 is prime so it is a bad number."} ],
            "role": "model"
          }
        }
      ],
      "session_input": {
        "app_name": "hello_world",
        "user_id": "user"
      }
    }
  ]
}

2๋‹จ๊ณ„: ์ƒ˜ํ”Œ๋Ÿฌ ๊ตฌ์„ฑ ์ •์˜ํ•˜๊ธฐ

์ƒ˜ํ”Œ๋Ÿฌ ๊ตฌ์„ฑ์€ ํ›„๋ณด ์ตœ์ ํ™” ์—์ด์ „ํŠธ๋ฅผ ํ‰๊ฐ€ํ•˜๋Š” ๊ณผ์ •์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์—์ด์ „ํŠธ ์ถœ๋ ฅ์˜ ์ •๋‹ต ๊ธฐ์ค€์„ ์ง€์ •ํ•˜๊ณ , ์—์ด์ „ํŠธ๋ฅผ ์ตœ์ ํ™”ํ•  ๋•Œ ์‚ฌ์šฉํ•  eval ์„ธํŠธ๋„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

์ „์ฒด ๊ตฌ์„ฑ ์˜ต์…˜ ๋ชฉ๋ก์€ ์•„๋ž˜์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ์€ contributing/samples/hello_world/์— sampler_config.json ํŒŒ์ผ์„ ๋‹ค์Œ ๋‚ด์šฉ์œผ๋กœ ๋งŒ๋“ค๋ฉด ๋ฉ๋‹ˆ๋‹ค.

{
  "eval_config": {
    "criteria": {
      "response_match_score": 0.75
    }
  },
  "app_name": "hello_world",
  "train_eval_set": "train_eval_set"
}

3๋‹จ๊ณ„: ์ตœ์ ํ™” ์ž‘์—… ์‹คํ–‰ํ•˜๊ธฐ

adk optimize ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉด์„œ, hello_world ์—์ด์ „ํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์ง€์ •ํ•˜๊ณ  ์œ„์—์„œ ๋งŒ๋“  ๊ตฌ์„ฑ ํŒŒ์ผ์„ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

adk optimize contributing/samples/hello_world \
--sampler_config_file_path contributing/samples/hello_world/sampler_config.json

์ตœ์ข… ์ถœ๋ ฅ์€ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ, ๋‹ค์Œ๊ณผ ๋น„์Šทํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<logs and intermediate output>
================================================================================
Optimized root agent instructions:
--------------------------------------------------------------------------------
<existing unmodified instructions omitted for brevity>

**Special Rules for "Good" and "Bad" Numbers:**
*   A "bad number" is defined as a prime number.
*   A "good number" is defined as a non-prime number (i.e., a composite number or 1).
*   If a user asks if a number is "good" or "bad", you must always use the `check_prime` tool to determine its primality first.
*   After determining primality with the tool, respond according to the definitions above. Questions about "good" or "bad" numbers, when referring to primality, are objective and you are fully capable of answering them. Do not state you cannot answer such questions.
================================================================================

adk optimize ๋ช…๋ น ์‚ฌ์šฉํ•˜๊ธฐ

adk optimize [OPTIONS] AGENT_MODULE_FILE_PATH
  • AGENT_MODULE_FILE_PATH: ํŒŒ์ผ์ด ์•„๋‹Œ ์—์ด์ „ํŠธ ๋””๋ ‰ํ† ๋ฆฌ์˜ ๊ฒฝ๋กœ๋กœ, ํ•ด๋‹น ๋””๋ ‰ํ† ๋ฆฌ์˜ __init__.py๊ฐ€ agent๋ผ๋Š” ์ด๋ฆ„์˜ ๋ชจ๋“ˆ์„ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. agent ๋ชจ๋“ˆ์—๋Š” ๋ฐ˜๋“œ์‹œ root_agent๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ฌ๋ฐ”๋ฅธ ์„ค์ • ์˜ˆ์‹œ๋Š” hello_world ์—์ด์ „ํŠธ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.
  • --sampler_config_file_path PATH: ์ƒ˜ํ”Œ๋Ÿฌ ๊ตฌ์„ฑ ํŒŒ์ผ ๊ฒฝ๋กœ์ž…๋‹ˆ๋‹ค. ์ƒ˜ํ”Œ๋Ÿฌ ๊ตฌํ˜„๊ณผ ๊ตฌ์„ฑ ํ˜•์‹์€ ์•„๋ž˜์—์„œ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • --optimizer_config_file_path PATH (์„ ํƒ): ์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ € ๊ตฌ์„ฑ ํŒŒ์ผ ๊ฒฝ๋กœ์ž…๋‹ˆ๋‹ค. ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ ๊ตฌ์„ฑ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ตํ‹ฐ๋งˆ์ด์ € ๊ตฌํ˜„, ๊ตฌ์„ฑ ํ˜•์‹, ๊ธฐ๋ณธ ๊ตฌ์„ฑ์€ ์•„๋ž˜์—์„œ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • --print_detailed_results (์„ ํƒ): ์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ์ธก์ •ํ•œ ์„ธ๋ถ€ ๋ฉ”ํŠธ๋ฆญ ์ถœ๋ ฅ์„ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค.
  • --log_level (์„ ํƒ): ๋กœ๊น… ์ˆ˜์ค€์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ INFO์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์˜ต์…˜์€ DEBUG, INFO, WARNING, ERROR, CRITICAL์ž…๋‹ˆ๋‹ค.

ADK๋Š” adk optimize ๋ช…๋ น์ค„์„ ์‚ฌ์šฉํ•˜์—ฌ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ์ƒ˜ํ”Œ๋Ÿฌ์™€ ์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ €๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์˜ต์…˜์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

LocalEvalSampler

LocalEvalSampler๋Š” ADK์˜ LocalEvalService๋ฅผ ์‚ฌ์šฉํ•ด ํ›„๋ณด ์—์ด์ „ํŠธ๋ฅผ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ํ‰๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ UnstructuredSamplingResult๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. LocalEvalSampler๋Š” ๋‹ค์Œ ํ•„๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” LocalEvalSamplerConfig๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • eval_config: ํ‰๊ฐ€ ๊ธฐ์ค€๊ณผ ์‚ฌ์šฉ์ž ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ์˜ต์…˜์„ ์ œ๊ณตํ•˜๋Š” EvalConfig์ž…๋‹ˆ๋‹ค.
  • app_name: ํ‰๊ฐ€์— ์‚ฌ์šฉํ•  ์•ฑ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
  • train_eval_set: ์ตœ์ ํ™”์— ์‚ฌ์šฉํ•  eval ์„ธํŠธ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค.
  • train_eval_case_ids (์„ ํƒ): ์ตœ์ ํ™”์— ์‚ฌ์šฉํ•  eval case(example) ID ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค. ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด train_eval_set์˜ ๋ชจ๋“  eval case๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • validation_eval_set (์„ ํƒ): ์ตœ์ ํ™”๋œ ์—์ด์ „ํŠธ๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  eval ์„ธํŠธ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค. ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด train_eval_set์„ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • validation_eval_case_ids (์„ ํƒ): ์ตœ์ ํ™”๋œ ์—์ด์ „ํŠธ๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  eval case(example) ID ๋ชฉ๋ก์ž…๋‹ˆ๋‹ค. ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด validation_eval_set์˜ ๋ชจ๋“  eval case๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. validation_eval_set๋„ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ์œ ํšจํ•œ train eval case๋ฅผ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

LocalEvalSampler๋ฅผ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ, LocalEvalSamplerConfig์— ์ง€์ •๋œ train ๋ฐ validation eval ์„ธํŠธ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” EvalSetsManager๋„ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

GEPARootAgentPromptOptimizer

GEPARootAgentPromptOptimizer๋Š” GEPA ์˜ตํ‹ฐ๋งˆ์ด์ €๋ฅผ ์‚ฌ์šฉํ•ด ๋ฃจํŠธ ์—์ด์ „ํŠธ์˜ ์ง€์นจ์„ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ด ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ์ƒ˜ํ”Œ๋Ÿฌ๊ฐ€ ํ‰๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ UnstructuredSamplingResult๋กœ ์ œ๊ณตํ•  ๊ฒƒ์œผ๋กœ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ์ถœ๋ ฅ์€ OptimizerResult์˜ ํ•˜์œ„ ํด๋ž˜์Šค์ด๋ฉฐ, ์ ์ˆ˜๊ฐ€ ํฌํ•จ๋œ ์ตœ์ ํ™” ์—์ด์ „ํŠธ ๋ชฉ๋ก๊ณผ ์ตœ์ ํ™” ์ค‘ ์ˆ˜์ง‘๋œ ์ถ”๊ฐ€ ๋ฉ”ํŠธ๋ฆญ์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ : GEPARootAgentPromptOptimizer๋Š” ํ•˜์œ„ ์—์ด์ „ํŠธ, ์—์ด์ „ํŠธ ๋„๊ตฌ, ์Šคํ‚ฌ ๋˜๋Š” ๋ฃจํŠธ ์—์ด์ „ํŠธ์˜ ๋‹ค๋ฅธ ์ธก๋ฉด์„ ๊ฐœ์„ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

GEPARootAgentPromptOptimizer๋Š” ๋‹ค์Œ ํ•„๋“œ๋ฅผ ํฌํ•จํ•˜๋Š” GEPARootAgentPromptOptimizerConfig๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • optimizer_model (์„ ํƒ): ํ‰๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ ๋ถ„์„ํ•˜๊ณ  ์—์ด์ „ํŠธ๋ฅผ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋ธ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ "gemini-flash-latest"์ž…๋‹ˆ๋‹ค.
  • model_configuration (์„ ํƒ): ์˜ตํ‹ฐ๋งˆ์ด์ € ๋ชจ๋ธ์˜ ๊ตฌ์„ฑ์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ 1๋งŒ ํ† ํฐ think budget์„ ๊ฐ€์ง„ ๊ตฌ์„ฑ์ž…๋‹ˆ๋‹ค.
  • max_metric_calls (์„ ํƒ): ์ตœ์ ํ™” ์ค‘ ์‹คํ–‰ํ•  ํ‰๊ฐ€์˜ ์ตœ๋Œ€ ํšŸ์ˆ˜์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ 100์ž…๋‹ˆ๋‹ค.
  • reflection_minibatch_size (์„ ํƒ): ํ•œ ๋ฒˆ์— ์—์ด์ „ํŠธ ์ง€์นจ์„ ์—…๋ฐ์ดํŠธํ•  ๋•Œ ์‚ฌ์šฉํ•  ์˜ˆ์‹œ ์ˆ˜์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ 3์ž…๋‹ˆ๋‹ค.
  • run_dir (์„ ํƒ): ์›ํ•˜๋ฉด ์ค‘๊ฐ„ ๋ฐ ์ตœ์ข… ์ตœ์ ํ™” ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•  ๋””๋ ‰ํ„ฐ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์›œ ์Šคํƒ€ํŠธ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

SimplePromptOptimizer

SimplePromptOptimizer๋Š” ์‹ค์ฆ์ ์ธ ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์—์ด์ „ํŠธ์˜ ๋ฃจํŠธ ์‹œ์Šคํ…œ ์ง€์นจ(instructions)์„ ์ฒด๊ณ„์ ์œผ๋กœ ๊ฐœ์„ ํ•˜๋„๋ก ์„ค๊ณ„๋œ ์ž๋™ํ™”๋œ ๋ฐ˜๋ณต์  ํ”„๋กฌํ”„ํŠธ ํŠœ๋‹ ๊ตฌ์„ฑ ์š”์†Œ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ํ›„๋ณด ์—์ด์ „ํŠธ์˜ ๋‹ค์–‘ํ•œ ํŒŒ๋ ˆํ†  ํ”„๋Ÿฐํ‹ฐ์–ด(Pareto frontier)๋ฅผ ์œ ์ง€ํ•˜๋Š” GEPA ๊ธฐ๋ฐ˜ ์˜ตํ‹ฐ๋งˆ์ด์ €์™€ ๋‹ฌ๋ฆฌ, SimplePromptOptimizer๋Š” ์ง€์ •๋œ ์ผ๋ จ์˜ ๋ฐ˜๋ณต ํšŸ์ˆ˜(iterations)์— ๊ฑธ์ณ ๋‹จ์ผ ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ๋ฅผ ๊ฐœ์„ ํ•˜๋Š” ๋ฐ ์™„์ „ํžˆ ์ง‘์ค‘ํ•˜๋Š” ์ง์ ‘์ ์ด๊ณ  ์ˆœ์ฐจ์ ์ธ ์ตœ์ ํ™” ๋ฃจํ”„๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ๋‹ค์Œ 4๋‹จ๊ณ„์˜ ๋น„๋™๊ธฐ ํ”ผ๋“œ๋ฐฑ ๋ฃจํ”„๋ฅผ ์ž๋™์œผ๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

  1. ์‹คํ–‰ (Execute): ๋Œ€์ƒ ์—์ด์ „ํŠธ๋Š” Sampler ํด๋ž˜์Šค์˜ ๊ตฌํ˜„์ฒด์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋Š” ํŠน์ • ํ‰๊ฐ€ ์ž‘์—… ๋ฐฐ์น˜๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  2. ํ‰๊ฐ€ (Evaluate): ์ƒ˜ํ”Œ๋Ÿฌ๋Š” ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ ์„ธํŠธ์— ๋Œ€ํ•ด ์—์ด์ „ํŠธ์˜ ์ถœ๋ ฅ์„ ์ฑ„์ ํ•˜๊ณ  ๊ตฌ์กฐํ™”๋œ SamplingResult๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋น„ํŒ (Critique): ๊ธฐ๋ณธ ์ตœ์ ํ™” ๋Œ€๊ทœ๋ชจ ์–ธ์–ด ๋ชจ๋ธ(LLM)(๊ธฐ๋ณธ๊ฐ’์€ Gemini-2.5-flash)์ด ํ˜„์žฌ ํ”„๋กฌํ”„ํŠธ์™€ ํ•จ๊ป˜ ๊ณผ๊ฑฐ ํ‰๊ฐ€ ์ ์ˆ˜๋ฅผ ๋ถ„์„ํ•˜์—ฌ ํŠน์ • ๋™์ž‘์ƒ์˜ ์•ฝ์ ์ด๋‚˜ ๊ณต๋ฐฑ์„ ์ฐพ์•„๋ƒ…๋‹ˆ๋‹ค.
  4. ์žฌ์ž‘์„ฑ (Rewrite): ์ตœ์ ํ™” ๋ชจ๋ธ์€ ๋ฐœ๊ฒฌ๋œ ์•ฝ์ ์„ ํ•ด๊ฒฐํ•˜๋„๋ก ๋งž์ถคํ™”๋œ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ์˜ ์—…๋ฐ์ดํŠธ๋œ ๋ณ€ํ˜•์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด ์ƒˆ๋กœ์šด ํ”„๋กฌํ”„ํŠธ๋Š” ๋‹ค์Œ ๋ฐ˜๋ณต์— ์ง์ ‘ ์ž…๋ ฅ๋ฉ๋‹ˆ๋‹ค.

์ฐธ๊ณ : ์ตœ์ ํ™” ๋ฃจํ”„๋Š” ๊ธฐ์กด ์—์ด์ „ํŠธ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฆ‰์„์—์„œ ๋ณ€๊ฒฝ(mutate)ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์™„๋ฃŒ๋˜๋ฉด ํ”„๋กœ์„ธ์Šค ์ค‘์— ์ถ”์ถœ๋œ ๊ฐ€์žฅ ๋†’์€ ์ ์ˆ˜๋ฅผ ๋ฐ›์€ ์—์ด์ „ํŠธ ๋ณ€ํ˜•์„ ํฌํ•จํ•˜๋Š” OptimizerResult๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๊ตฌ์„ฑ

SimplePromptOptimizerConfig ์ธ์Šคํ„ด์Šค๋ฅผ ์˜ตํ‹ฐ๋งˆ์ด์ €์— ์ „๋‹ฌํ•˜์—ฌ ๋ฃจํ”„์˜ ๋™์ž‘์„ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๋งค๊ฐœ๋ณ€์ˆ˜ ์œ ํ˜• ๊ธฐ๋ณธ๊ฐ’ ์„ค๋ช…
num_iterations int ํ•„์ˆ˜ ์‹คํ–‰ํ•  ์ตœ์ ํ™” ๋ผ์šด๋“œ์˜ ์ด ํšŸ์ˆ˜์ž…๋‹ˆ๋‹ค.
batch_size int ํ•„์ˆ˜ ๊ฐ ๊ฐœ๋ณ„ ๋ฐ˜๋ณต ์ค‘์— ์ƒ˜ํ”Œ๋Ÿฌ๊ฐ€ ์ฒ˜๋ฆฌํ•˜๋Š” ํ‰๊ฐ€ ์ƒ˜ํ”Œ ์ผ€์ด์Šค์˜ ์ˆ˜์ž…๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์˜ˆ์‹œ

๊ตฌ์„ฑ์ด ์ •์˜๋˜๋ฉด ๋‹ค์Œ ์ฝ”๋“œ๋กœ ์ตœ์ ํ™”๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

from google.adk.optimization.simple_prompt_optimizer import SimplePromptOptimizer
from google.adk.optimization.simple_prompt_optimizer import SimplePromptOptimizerConfig

# ์—์ด์ „ํŠธ์™€ ์ƒ˜ํ”Œ๋Ÿฌ๋ฅผ ๋จผ์ € ์ •์˜ํ•ฉ๋‹ˆ๋‹ค...

# ์˜ตํ‹ฐ๋งˆ์ด์ € ๊ตฌ์„ฑ
config = SimplePromptOptimizerConfig(
    num_iterations=5,
    batch_size=10
)

# ์ตœ์ ํ™” ์‹คํ–‰
optimizer = SimplePromptOptimizer(config=config)
optimized_result = await optimizer.optimize(agent, sampler)

ํ•ต์‹ฌ ๋ฐ์ดํ„ฐ ํƒ€์ž…

ADK๋Š” ์ƒ˜ํ”Œ๋Ÿฌ์—์„œ ์˜ตํ‹ฐ๋งˆ์ด์ €๋กœ ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ํ๋ฆ„๊ณผ ์˜ตํ‹ฐ๋งˆ์ด์ € ์ถœ๋ ฅ์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด optimization/data_types.py์— ๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐ์ดํ„ฐ ํƒ€์ž…๋“ค์€ ์‚ฌ์šฉ์ž ์ง€์ • eval๊ณผ ์ตœ์ ํ™” ์ „๋žต์„ ์ˆ˜์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๊ฒŒ ์„ค๊ณ„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒ˜ํ”Œ๋Ÿฌ ๊ฒฐ๊ณผ

  • SamplingResult: ์ƒ˜ํ”Œ๋Ÿฌ ์ถœ๋ ฅ์˜ ๊ธฐ๋ณธ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.
  • example UID๋ฅผ ํ•ด๋‹น ์˜ˆ์‹œ์— ๋Œ€ํ•œ ์—์ด์ „ํŠธ์˜ ์ „์ฒด ์ ์ˆ˜์— ๋งคํ•‘ํ•˜๋Š” scores ์‚ฌ์ „์„ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • UnstructuredSamplingResult: SamplingResult์˜ ๋‚ด์žฅ ํ•˜์œ„ ํด๋ž˜์Šค๋กœ, ๊ถค์ , ์ค‘๊ฐ„ ์ถœ๋ ฅ, ํ•˜์œ„ ๋ฉ”ํŠธ๋ฆญ์ฒ˜๋Ÿผ ๊ตฌ์กฐํ™”๋˜์ง€ ์•Š์€ ๊ฐ ์˜ˆ์‹œ๋ณ„ JSON ์ง๋ ฌํ™” ๊ฐ€๋Šฅํ•œ ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์„ ์ˆ˜ ์žˆ๋Š” ์„ ํƒ์  data ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ๋Š” UnstructuredSamplingResult๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ๋” ๊ตฌ์กฐํ™”๋œ ํ˜•์‹์œผ๋กœ ์ถ”๊ฐ€ ํ‰๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก SamplingResult์˜ ์ž์ฒด ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์ƒ˜ํ”Œ๋Ÿฌ์™€ ์˜ตํ‹ฐ๋งˆ์ด์ €๊ฐ€ ๋ชจ๋‘ ํ•ด๋‹น ํ˜•์‹์„ ์ง€์›ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ € ๊ฒฐ๊ณผ

  • AgentWithScores: ์ „์ฒด ์ ์ˆ˜์™€ ํ•จ๊ป˜ ๋‹จ์ผ ์ตœ์ ํ™” ์—์ด์ „ํŠธ๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • ์—…๋ฐ์ดํŠธ๋œ Agent ๊ฐ์ฒด์ธ optimized_agent๋ฅผ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ณดํ†ต validation ์„ธํŠธ์—์„œ ๊ณ„์‚ฐ๋œ ์—์ด์ „ํŠธ์˜ overall_score๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • OptimizerResult: ์ตœ์ ํ™” ํ”„๋กœ์„ธ์Šค์˜ ์ตœ์ข… ์ถœ๋ ฅ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.
  • optimized_agents ๋ชฉ๋ก์„ ํฌํ•จํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ชฉ๋ก์˜ ์š”์†Œ๋Š” AgentWithScores ๋˜๋Š” ๊ทธ ํ•˜์œ„ ํด๋ž˜์Šค์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๋ฉ”ํŠธ๋ฆญ์— ๊ฑธ์ณ ์—์ด์ „ํŠธ์˜ ์ตœ์ ์„ฑ์„ ์ธก์ •ํ•˜๋Š” ๊ฒฝ์šฐ, ํŒŒ๋ ˆํ†  ํ”„๋Ÿฐํ‹ฐ์–ด๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ํ•ญ๋ชฉ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ›„๋ณด ์ตœ์ ํ™” ์—์ด์ „ํŠธ์— ๋Œ€ํ•œ ์„ธ๋ถ€ ๋ฉ”ํŠธ๋ฆญ์„ ๋…ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด AgentWithScores์˜ ์ž์ฒด ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ •ํ™•์„ฑ, ์•ˆ์ „์„ฑ, ์ •๋ ฌ์„ฑ ๋“ฑ์„ ๋ณ„๋„๋กœ ์ ์ˆ˜ํ™”ํ•˜๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ OptimizerResult์˜ ์ž์ฒด ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด, ์˜ตํ‹ฐ๋งˆ์ด์ €์˜ ์ตœ์ ํ™” ํ”„๋กœ์„ธ์Šค ์ „๋ฐ˜์— ๋Œ€ํ•œ ๋ฉ”ํŠธ๋ฆญ(ํ‰๊ฐ€๋œ ํ›„๋ณด ์ˆ˜, ์ด ํ‰๊ฐ€ ์ˆ˜ ๋“ฑ)์„ ๋…ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒˆ ์ƒ˜ํ”Œ๋Ÿฌ์™€ ์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ € ๋งŒ๋“ค๊ธฐ ๋ฐ ์‚ฌ์šฉํ•˜๊ธฐ

์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋ณต์žกํ•œ ์ƒ˜ํ”Œ๋ง ๋ฐ ํ‰๊ฐ€ ๋กœ์ง์ด๋‚˜ ์‚ฌ์šฉ์ž ์ง€์ • ์—์ด์ „ํŠธ ์ตœ์ ํ™” ์ „๋žต์ด ํ•„์š”ํ•˜๋‹ค๋ฉด, ์•„๋ž˜์— ์„ค๋ช…๋œ Sampler์™€ AgentOptimizer ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌํ˜„์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด API๋ฅผ ๋”ฐ๋ฅด๋ฉด ADK๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์ƒ˜ํ”Œ๋Ÿฌ์™€ ์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ €๋ฅผ ์‚ฌ์šฉ์ž ์ง€์ • ๊ตฌํ˜„๊ณผ ์กฐํ•ฉํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒˆ ์ƒ˜ํ”Œ๋Ÿฌ ๋งŒ๋“ค๊ธฐ

์‚ฌ์šฉ์ž ์ง€์ • ํ‰๊ฐ€์šฉ ์ƒˆ ์ƒ˜ํ”Œ๋Ÿฌ๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด Sampler ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ์ƒ˜ํ”Œ๋Ÿฌ๊ฐ€ ํ‰๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•  ๋•Œ ์‚ฌ์šฉํ•  SamplingResult ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ƒ˜ํ”Œ๋Ÿฌ๋Š” ๋‹ค์Œ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • get_train_example_ids(self): ์ตœ์ ํ™”์— ์‚ฌ์šฉํ•  example UID ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • get_validation_example_ids(self): ์ตœ์ ํ™”๋œ ์—์ด์ „ํŠธ๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  example UID ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  • sample_and_score(self, candidate, example_set, batch, capture_full_eval_data): ์ง€์ •๋œ example_set("train" ๋˜๋Š” "validation")์˜ batch ์˜ˆ์‹œ์—์„œ candidate ์—์ด์ „ํŠธ๋ฅผ ํ‰๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๊ณ„์‚ฐ๋œ ์˜ˆ์‹œ๋ณ„ ์ ์ˆ˜์™€, capture_full_eval_data๊ฐ€ True์ธ ๊ฒฝ์šฐ eval ๊ธฐ๋ฐ˜ ์—์ด์ „ํŠธ ์ตœ์ ํ™”์— ํ•„์š”ํ•œ ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๋Š” SamplingResult ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ถ”๊ฐ€ eval ๋ฐ์ดํ„ฐ์˜ ํ˜•์‹์€ SamplingResult๋ฅผ ํ•˜์œ„ ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค์–ด ํ•„์š”์— ๋งž๊ฒŒ ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋งŒ ์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ €๋„ ๊ฐ™์€ SamplingResult ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ์ง€์›ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. UnstructuredSamplingResult๋Š” ์ถ”๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์˜ˆ์‹œ๋ณ„ ๋น„๊ตฌ์กฐํ™” ์‚ฌ์ „์œผ๋กœ ์ €์žฅํ•˜๋Š” ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ์‚ฌ๋ก€๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

์ƒˆ ์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ € ๋งŒ๋“ค๊ธฐ

์‚ฌ์šฉ์ž ์ง€์ • ์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ €๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด AgentOptimizer ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ํ™•์žฅํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ํ‰๊ฐ€ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์„ SamplingResult ํ•˜์œ„ ํด๋ž˜์Šค์™€, ๊ฐ ์ตœ์ ํ™”๋œ ์—์ด์ „ํŠธ ๋ฐ ๊ทธ ์ ์ˆ˜/๋ฉ”ํŠธ๋ฆญ์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  AgentWithScores ํ•˜์œ„ ํด๋ž˜์Šค๋„ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” ๋‹ค์Œ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • optimize(self, initial_agent, sampler): ์ด ๋ฉ”์„œ๋“œ๋Š” ์ตœ์ ํ™” ํ”„๋กœ์„ธ์Šค๋ฅผ ์กฐ์œจํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ์„ ํ•  initial_agent์™€ ํ›„๋ณด ํ‰๊ฐ€์— ์‚ฌ์šฉํ•  sampler๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค. ํ›„๋ณด ์ตœ์ ํ™” ์—์ด์ „ํŠธ ๋ชฉ๋ก๊ณผ ๊ทธ ์ ์ˆ˜/๋ฉ”ํŠธ๋ฆญ, ๊ทธ๋ฆฌ๊ณ  ์ตœ์ ํ™” ํ”„๋กœ์„ธ์Šค์— ๋Œ€ํ•œ ์ „์ฒด ๋ฉ”ํŠธ๋ฆญ์„ ํฌํ•จํ•˜๋Š” OptimizerResult ํ•˜์œ„ ํด๋ž˜์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ›„๋ณด๋ณ„ ์ ์ˆ˜/๋ฉ”ํŠธ๋ฆญ์˜ ํ˜•์‹์€ AgentWithScores๋ฅผ ํ•˜์œ„ ํด๋ž˜์Šค๋กœ ๋งŒ๋“ค์–ด ํ•„์š”์— ๋งž๊ฒŒ ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜๋Š” ๊ฐ ํ›„๋ณด ์ตœ์ ํ™” ์—์ด์ „ํŠธ์— ๋Œ€ํ•ด ๋‹จ์ผ ์ „์ฒด ์ ์ˆ˜๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š” AgentWithScores๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์—์ด์ „ํŠธ ์ตœ์ ํ™”ํ•˜๊ธฐ

adk optimize ๋ช…๋ น์€ LocalEvalSampler์™€ GEPARootAgentPromptOptimizer๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ง€์ • ์ƒ˜ํ”Œ๋Ÿฌ์™€ ์—์ด์ „ํŠธ ์˜ตํ‹ฐ๋งˆ์ด์ €๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์—์ด์ „ํŠธ๋ฅผ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์ตœ์ ํ™”ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์˜ ์ฐธ์กฐ ์ฝ”๋“œ๋Š” ์œ„ ์˜ˆ์‹œ์— ๋Œ€ํ•œ adk optimize ๋ช…๋ น์˜ ๋™์ž‘์„ ์žฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์˜ˆ์‹œ์™€ ๊ฐ™์ด ๋ฐ์ดํ„ฐ์…‹์„ ๋งŒ๋“ค๊ณ , ๊ฐ™์€ ๋””๋ ‰ํ„ฐ๋ฆฌ ์•ˆ์˜ Python ์Šคํฌ๋ฆฝํŠธ์—์„œ ์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

import asyncio
import logging
import os

import agent  # the hello_world agent
from google.adk.cli.utils import envs
from google.adk.cli.utils import logs
from google.adk.evaluation.eval_config import EvalConfig
from google.adk.evaluation.local_eval_sets_manager import LocalEvalSetsManager
from google.adk.optimization.gepa_root_agent_prompt_optimizer import GEPARootAgentPromptOptimizer
from google.adk.optimization.gepa_root_agent_prompt_optimizer import GEPARootAgentPromptOptimizerConfig
from google.adk.optimization.local_eval_sampler import LocalEvalSampler
from google.adk.optimization.local_eval_sampler import LocalEvalSamplerConfig

# setup environment variables (API keys, etc.) and logging
envs.load_dotenv_for_agent(".", ".")
logs.setup_adk_logger(logging.INFO)

# create the sampler
sampler_config = LocalEvalSamplerConfig(
    eval_config=EvalConfig(criteria={"response_match_score": 0.75}),
    app_name="hello_world",  # typically the name of the directory containing the agent
    train_eval_set="train_eval_set",  # from the example
)
eval_sets_manager = LocalEvalSetsManager(
    agents_dir=os.path.dirname(os.getcwd()),
)
sampler = LocalEvalSampler(sampler_config, eval_sets_manager)

# create the optimizer
opt_config = GEPARootAgentPromptOptimizerConfig()
optimizer = GEPARootAgentPromptOptimizer(config=opt_config)

# optimize the root agent
initial_agent = agent.root_agent
result = asyncio.run(
    optimizer.optimize(initial_agent, sampler)
)

# show the results
best_idx = result.gepa_result["best_idx"]
print(
    "Validation score:",
    result.optimized_agents[best_idx].overall_score,
    "Optimized prompt:",
    result.optimized_agents[best_idx].optimized_agent.instruction,
    "GEPA metrics:",
    result.gepa_result,
    sep="\n",
)