이 가이드에서는 에이전트 애플리케이션을 최적화하고 확장하기 위한 검증된 권장사항과 디자인 패턴을 공유합니다. 이 콘텐츠는 설계 시간 비용을 줄이고, 런타임 비용을 줄이고, 에이전트 안정성을 개선하는 데 도움이 됩니다.
일반
이 섹션에서는 에이전트 개발 및 요청 사항 작성을 시작하기 위한 일반적인 권장사항을 제공합니다.
단순하게 시작하기
에이전트 애플리케이션을 처음 빌드할 때는 간단한 사용 사례부터 시작해야 합니다. 간단한 사용 사례가 작동하면 더 복잡한 사용 사례를 계속 빌드합니다.
요청 사항은 구체적이어야 합니다.
상담사 안내는 구체적이고 명확해야 합니다. 지침은 잘 정리되어 있고 주제별로 그룹화되어야 합니다. 특정 주제에 관한 안내를 무작위로 흩뿌리지 마세요. 사람이 쉽게 따를 수 있는 안내여야 합니다.
구조화된 요청 사항 사용
지침 작성을 완료한 후에는 지침 재구성 기능을 사용하여 지침의 형식을 지정해야 합니다. 이 형식을 사용하면 에이전트의 신뢰성이 높아집니다.
여러 모달리티와 채널의 모듈식 구성요소 사용
에이전트가 다양한 모달리티 (텍스트 또는 음성) 또는 채널 (API, 전화 통신, 웹)에 대해 서로 다른 방식으로 응답해야 하는 경우 모듈식 구성요소와 Python 도구 및 콜백에서 채널 및 모달리티 확인을 사용해야 합니다.
도구
이 섹션에서는 외부 API 래핑, 도구 호출 연결 등 도구를 정의하고 사용하는 권장사항을 제공합니다.
Python 도구로 API 래핑
외부 API 스키마는 에이전트와 관련이 없는 많은 입력 및 출력 매개변수를 정의할 수 있습니다. 이러한 경우에 OpenAPI 도구를 사용하면 모델에 불필요한 컨텍스트를 제공하여 신뢰성이 떨어질 수 있습니다. 예를 들어 OpenAPI 사양 도구가 3개의 매개변수를 입력으로 사용하고 100개의 키/값 쌍이 있는 큰 JSON 객체를 반환한다고 가정해 보겠습니다. 에이전트는 이 도구의 입력 인수 3개를 예측하고, 반환될 때 100개의 키/값 쌍이 모두 포함된 전체 JSON 페이로드를 확인합니다. 이러한 쌍 중 3개만 실제로 대화와 관련이 있다면 나머지 97개 쌍은 대화 기록에 토큰을 추가하는 관련 없는 데이터입니다. 무해해 보일 수 있지만 에이전트에게 불필요한 혼란을 야기하고 추론 시간을 늘리며 지연 시간을 늘릴 수 있습니다.
Python 도구를 사용하여 API 호출을 래핑하는 것이 좋습니다. 래핑을 사용하면 에이전트와 컨텍스트 기록에서 불필요한 데이터를 난독화할 수 있습니다. 특정 시점에 상담사와 관련된 데이터만 반환하여 상담사에게 표시되는 정확한 컨텍스트를 제어할 수 있습니다. 이를 통해 모델과 공유되는 도구에서 정의한 입력 및 출력 파라미터를 완전히 제어할 수 있습니다. 이 방법은 도구를 사용한 컨텍스트 엔지니어링의 한 형태입니다.
샘플 코드:
def python_wrapper(arg_a: str, arg_b: str) -> dict:
"""
Call the scheduling service to schedule an appointment,
returning only relevant fields.
"""
res = complicated_external_api_call(...)
# Process result to extract only relevant key-value pairs.
processed_res = {
"appointment_time": res.json()["appointment_time"],
"appointment_location": res.json()["appointment_location"],
"confirmation_id": res.json()["confirmation_id"],
}
return processed_res
결정론적 동작을 위한 도구 및 콜백 사용
특정 대화 시나리오에서는 에이전트 애플리케이션의 더 결정적인 동작이 필요할 수 있습니다. 이 경우 도구나 콜백을 사용해야 합니다.
콜백은 일반적으로 완전한 결정론적 제어를 위한 최적의 옵션입니다. 콜백은 에이전트의 권한 밖에서 발생하므로 에이전트는 콜백 실행에 관여하지 않습니다.
도구의 내부 구조는 완전히 결정적이지만 에이전트가 오케스트레이션한 도구 호출은 결정적이지 않습니다. 에이전트가 도구를 호출하기로 결정하고, 도구 입력 인수를 준비하고, 도구 결과를 해석합니다. 에이전트가 이 오케스트레이션을 환각할 수 있습니다.
도구 호출 연결
도구로 API 호출을 래핑하는 것과 마찬가지로 대화 턴 중에 여러 도구를 실행해야 하는 경우 에이전트가 하나의 도구를 호출하도록 지시하고 해당 도구가 다른 도구를 호출하도록 구현해야 합니다.
또는 에이전트가 첫 번째 도구를 호출하도록 지시하고 나머지 도구를 호출하는 after_tool_callback 콜백을 정의할 수 있습니다.
도구 호출을 연결하는 잘못된 패턴
일반적인 목표를 달성하기 위해 대화 차례 중에 여러 도구를 호출하도록 에이전트에게 지시하는 것은 좋지 않은 패턴으로 간주됩니다.
모델은 모든 도구 호출과 해당 도구 호출의 모든 매개변수를 예측해야 합니다. 그런 다음 도구 호출을 순서대로 예측하는지 확인해야 합니다. 이는 결정론적 작업을 수행하기 위해 본질적으로 비결정적인 모델에 크게 의존하고 있음을 의미합니다.
예를 들어 다음 도구 시퀀스를 고려해 보세요.
tool_1(arg_a, arg_b)-> outputctool_2(arg_c)-> outputdtool_3(arg_d)-> outpute
이러한 세 가지 도구 호출에 대한 명령어를 정의하면 다음과 같은 런타임 이벤트 시퀀스가 생성됩니다.
- 사용자 입력
- 모델 -> 에이전트가
tool_1(arg_a, arg_b)를 예측합니다. tool_1_response.json()이 반환됩니다.- 에이전트가
tool_1_response.json()를 해석하고arg_c를 추출합니다. - 모델 -> 에이전트가
tool_2(arg_c)를 예측합니다. tool_2_response.json()이 반환됩니다.- 에이전트가
tool_2_response.json()를 해석하고arg_d를 추출합니다. - 모델 -> 에이전트가
tool_3(arg_d)를 예측합니다. tool_3_response.json()이 반환됩니다.- 모델 -> 에이전트가 최종 대답 제공
모델 호출이 4개, 도구 예측이 3개, 입력 인수가 4개 있습니다.
도구 호출을 연결하기에 적합한 패턴
여러 도구를 호출해야 하는 경우 에이전트가 단일 도구를 호출하도록 지시하고 해당 도구가 다른 도구를 호출하도록 구현하는 것이 좋은 패턴으로 간주됩니다.
다음 도구는 다른 세 가지 도구를 호출합니다.
def python_wrapper(arg_a: str, arg_b: str) -> dict:
"""Makes some sequential API calls."""
res1 = tools.tool_1({"arg_a": arg_a, "arg_b": arg_b})
res2 = tools.tool_2(res1.json())
res3 = tools.tool_3(res2.json())
return res3.json()
단일 도구 호출의 이벤트 시퀀스를 고려해 보세요.
- 사용자 입력
- 모델 -> 에이전트가
python_wrapper(arg_a, arg_b)를 예측합니다. python_wrapper_response.json()이 반환됩니다.- 모델 -> 에이전트가 최종 대답 제공
이 접근 방식을 사용하면 토큰이 줄어들고 할루시네이션 발생 가능성이 줄어듭니다.
명확하고 고유한 도구 정의
도구 정의에는 다음 권장사항을 적용해야 합니다.
- 도구의 이름이 서로 비슷해서는 안 됩니다. 도구 이름이 서로 눈에 띄게 달라야 합니다.
- 사용하지 않는 도구는 에이전트 노드에서 삭제해야 합니다.
매개변수 이름에는 스네이크 케이스를 사용하고, 설명이 포함된 이름을 사용하며, 흔하지 않은 약어는 피하세요.
좋은 예:
first_name,phone_number,url나쁜 예:
i,arg1,fn,pnum,rqst매개변수는 중첩된 구조가 아닌 평면화된 구조를 사용해야 합니다. 구조가 더 많이 중첩될수록 모델이 키/값 쌍과 적절한 타이핑을 예측하는 데 더 많이 의존하게 됩니다.
개발 워크플로
이 섹션에서는 에이전트 개발 중 팀 공동작업, 버전 제어, 테스트를 위한 권장사항을 제공합니다.
에이전트 공동작업을 위한 개발 프로세스 정의
팀과 협력하여 에이전트 애플리케이션을 개발할 때는 개발 프로세스를 정의해야 합니다. 다음은 가능한 공동작업 사례의 예입니다.
- 서드 파티 버전 제어 사용: 가져오기 및 복원을 사용하여 변경사항을 서드 파티 버전 제어 시스템과 동기화합니다. 동기화, 검토, 병합 프로세스에 동의합니다. 변경사항을 수락하기 위한 명확한 소유자와 명확한 단계(예: 평가 결과가 있음)를 정의합니다.
- 기본 제공 버전 제어 사용: 기본 제공 버전 제어를 사용하는 프로세스를 설정합니다. 버전 관리에 스냅샷을 사용하는 방법에 동의합니다. 예를 들어 마일스톤에 도달했을 때(평가 세트가 통과됨) 또는 새 기능 개발이 완료되기 전에 스냅샷을 요구할 수 있습니다. 변경사항을 동기화, 검토, 병합하는 프로세스에 동의합니다.
버전을 사용하여 에이전트 상태 저장
버전을 사용하면 에이전트 애플리케이션 내에서 완료한 작업이나 변경사항을 기념할 수 있습니다. 안내, 도구, 변수 및 기타 항목을 변경한 후 다른 변경사항을 적용하기 전에 해당 상태를 저장할 수 있습니다. 버전은 에이전트의 변경할 수 없는 스냅샷입니다. 일부 변경사항에 만족하고 에이전트 애플리케이션이 설계한 대로 작동하는 경우, 특히 평가를 통해 변경사항을 검증한 후 버전을 만들어야 합니다. 버전을 만든 후에는 언제든지 해당 버전으로 롤백할 수 있습니다.
10~15개의 주요 변경사항이 있을 때마다 버전을 만드는 것이 좋습니다.
버전의 이름을 시맨틱하게 지정하는 것도 도움이 되며, 개발팀과 함께 사용할 이름 지정 규칙을 결정해야 합니다. 예를 들어 pre-prod-instruction-changes 또는 prod-ready-for-testing과 같은 설명적인 이름이 있습니다. v1.0.0, v1.0.1 등의 이름을 사용하여 시맨틱 버전 관리와 같은 표준을 사용할 수도 있습니다. 버전에는 커밋 메시지 본문과 유사한 세부정보를 추가할 수 있는 설명 필드도 있습니다. 해당 버전으로 롤백해야 하는 경우를 대비하여 버전 이름과 설명은 짧고 의미가 있으며 이해하기 쉬워야 합니다.
엔드 투 엔드 테스트 실행
에이전트 애플리케이션 개발 프로세스에는 외부 시스템과의 통합을 확인하기 위한 엔드 투 엔드 테스트가 포함되어야 합니다.
평가
이 섹션에서는 평가를 사용하여 상담사 신뢰성을 보장하기 위한 권장사항을 제공합니다.
평가 사용
평가는 에이전트의 안정성을 유지하는 데 도움이 됩니다. 이를 사용하여 에이전트와 에이전트가 호출하는 API에 대한 기대치를 설정합니다.
세션 처리
이 섹션에서는 세션 수명 주기를 관리하는 패턴을 제공합니다.
정적 응답을 통한 결정론적 인사말 및 지연 시간 감소
세션이 시작될 때 결정론적 응답을 말하도록 에이전트를 구성할 수 있습니다. 이 접근 방식을 사용하면 모델 호출과 토큰을 절약하고 지연 시간을 줄일 수 있습니다.
before_model_callback을 사용하면 수신되는 입력을 가로채고 정적 인사말 메시지로 응답할 수 있습니다.
def before_model_callback(
callback_context: CallbackContext,
llm_request: LlmRequest
) -> Optional[LlmResponse]:
for part in callback_context.get_last_user_input():
# Or other events or texts
if part.text == "<event>session start</event>":
return LlmResponse.from_parts(parts=[
Part.from_text(text="Hello how can I help you today?")
])
return None
모델이 작동하는 동안 접두사 메시지로 빠르게 응답
세션이 시작되면 사용자가 모델 생성을 기다리도록 강요하지 마세요. 대답에 접두사를 붙여 에이전트가 친근한 브랜드 인사말('안녕하세요. 저는 개인 어시스턴트인 Gemini입니다')을 빠르게 전달할 수 있으며, 모델은 백그라운드에서 사용자의 기본 요청을 동시에 처리합니다.
이 기능은 partial = True 설정에 따라 달라집니다.
일반적으로 FuctionCall이 아닌 응답은 종료 응답으로 간주됩니다.
partial = True를 사용하면 에이전트가 응답 후 처리를 계속하도록 강제합니다.
다음 예에서 에이전트 애플리케이션은 환영 메시지를 빠르게 전달한 후 기본 요청 처리를 계속합니다. 이렇게 하면 어색한 입력 일시중지가 없어 상담사가 응답성이 좋다고 느낍니다.
def before_model_callback(callback_context: CallbackContext, llm_request: LlmRequest) -> Optional[LlmResponse]:
for part in callback_context.get_last_user_input():
if part.text == "<event>session start</event>":
response = LlmResponse.from_parts([Part.from_text("Hello, I'm Gemini, your personal AI assistant.")])
response.partial = True
return response
return None
필수 콘텐츠 확인 및 시행
경우에 따라 상담사에게 특정 필수 콘텐츠 (예: 법적 면책 조항)를 제공하도록 지시하고 상담사가 실제로 이를 포함했는지 확인해야 할 수 있습니다. 이 패턴을 사용하면 모델이 작동할 때는 모델의 자연스러운 생성을 활용하고, 실패할 때는 콘텐츠를 결정론적으로 적용할 수 있습니다.
after_model_callback를 사용하여 모델의 출력을 확인할 수 있습니다. 필수 콘텐츠가 있으면 콜백은 None를 반환하여 모델의 대답이 통과하도록 합니다. 누락된 경우 콜백은 필수 콘텐츠가 포함된 새 응답을 구성합니다.
샘플 변수:
| 변수 이름 | 기본값 |
|---|---|
| first_turn | 참 |
DISCLAIMER = "THIS CONVERSATION MAY BE RECORDED FOR LEGAL PURPOSES."
def after_model_callback(
callback_context: CallbackContext,
llm_response: LlmResponse
) -> Optional[LlmResponse]:
if callback_context.variables.get("first_turn"):
callback_context.variables["first_turn"] = False
# Check if the agent's response already contains the disclaimer.
# The agent might have produced it based on instructions.
for part in callback_context.get_last_agent_output():
if part.text and DISCLAIMER in part.text:
return None
# If the agent failed to produce the disclaimer, force it.
return LlmResponse.from_parts(parts=[
Part.from_text(DISCLAIMER),
*llm_response.content.parts
])
return None
세션 종료 시 맞춤 도구 호출
세션이 종료될 때 특정 도구를 호출하도록 에이전트를 구성할 수 있습니다. 이는 종료 시 데이터 동기화, 외부 API로 데이터 전송, 백엔드 작업 완료, 통화 메타데이터 로깅과 같은 통화 후 마무리 이벤트에 유용할 수 있습니다.
예를 들어 세션이 종료되기 직전에 호출하려는 post_call_logging와 같은 기존 도구가 있다고 가정해 보겠습니다.
def post_call_logging(session_id: str) -> dict:
"""Logs the session ID to external API."""
API_URL = "https://api.example.com"
response = ces_requests.post(
url=API_URL,
data={"session_id": session_id}
)
return response.json()
after_model_callback을 사용하여 다음 순서를 실행할 수 있습니다.
- 에이전트의 대답에서
end_session도구 호출을 확인합니다. post_call_logging도구 파트를 만듭니다.end_session도구 호출 앞에post_call_logging도구 호출을 삽입합니다.
이렇게 하면 에이전트가 세션을 종료하기 전에 로깅 도구를 실행합니다.
def after_model_callback(
callback_context: CallbackContext,
llm_response: LlmResponse
) -> Optional[LlmResponse]:
for index, part in enumerate(llm_response.content.parts):
if part.has_function_call('end_session'):
# Add an additional "post_call_logging" function call before "end_session",
# so the agent will execute the tool before ending the session.
tool_call = Part.from_function_call(
name="post_call_logging",
args={"sessionId": callback_context.session_id}
)
return LlmResponse.from_parts(
parts=llm_response.content.parts[:index] + [tool_call] + llm_response.content.parts[index:]
)
return None
실시간 사용자 인터페이스 업데이트를 위해 부분 응답 사용
상담사가 주문 상태 업데이트와 같은 작업을 실행하면 모델이 최종 응답을 처리하는 동안 지연이 발생할 수 있습니다. 부분 응답을 사용하면 도구가 실행을 완료할 때 클라이언트 사용자 인터페이스에 알림을 보내 시각적 업데이트를 모델의 텍스트 생성과 분리할 수 있습니다.
사용자 인터페이스는 상태 표시줄, 추적기 또는 영수증을 실시간으로 새로고침할 수 있습니다.
이 기능은 partial = True 설정에 따라 달라집니다.
일반적으로 FuctionCall이 아닌 응답은 종료 응답으로 간주됩니다.
partial = True를 사용하면 에이전트가 응답 후 처리를 계속하도록 강제합니다.
JSON 페이로드가 모델에 전송되지 않습니다. 따라서 에이전트는 대답 생성 중에 페이로드의 존재를 알지 못합니다.
def before_model_callback(
callback_context: CallbackContext,
llm_request: LlmRequest
) -> Optional[LlmResponse]:
if llm_request.contents[-1].parts[-1].has_function_response('update_order'):
order_state = llm_request.contents[-1].parts[-1].function_response.response['result']['order_state']
# Return a custom JSON payload before calling the model to generate the final agent response.
response = LlmResponse.from_parts([Part.from_json(data=json.dumps(order_state))])
response.partial = True
return response
return None
클라이언트 측 통합
이 섹션에서는 클라이언트 측 애플리케이션과 통합하기 위한 패턴을 제공합니다.
맞춤 페이로드를 사용하여 사용자 인터페이스를 구동하는 방법
사용자는 동적이고 대화형 인터페이스를 기대합니다. 맞춤 페이로드를 사용하여 클라이언트 측 렌더링을 유도하고 에이전트와 세련된 애플리케이션 간의 격차를 해소할 수 있습니다. 일반 텍스트 옵션을 제공하는 대신, 대답에서 특정 패턴(예: 선택사항 목록)을 감지하고 클릭 가능한 칩이나 버튼과 같은 전환율이 높은 대화형 사용자 인터페이스 요소로 변환하도록 에이전트를 구성하세요.
after_model_callback를 사용하여 특정 트리거에 대한 에이전트 응답을 스캔합니다.
예를 들어 모델 출력이 '사용 가능한 옵션은 환불, 주문 추적, 상담사와의 대화입니다'인 경우 다음 콜백은 이러한 옵션을 JSON 페이로드로 가로채고 추출하여 사용자 인터페이스 렌더링에 사용할 수 있습니다.
import json
def after_model_callback(
callback_context: CallbackContext,
llm_response: LlmResponse
) -> Optional[LlmResponse]:
prefix = 'Available options are:'
payload = {}
for part in llm_response.content.parts:
if part.text is not None and part.text.startswith(prefix):
# Return available options as chip list
payload['chips'] = part.text[len(prefix):].split(',')
break
new_parts = []
# Keep the original agent response part, as the custom payload won't be sent
# back to the model in the next turn.
new_parts.extend(llm_response.content.parts)
new_parts.append(Part.from_json(data=json.dumps(payload)))
return LlmResponse.from_parts(parts=new_parts)
마크다운 및 HTML 표시
대화형 인터페이스가 에이전트 응답에 마크다운과 HTML을 지원하는 경우 시뮬레이터도 마크다운과 HTML을 지원하므로 시뮬레이터를 사용하여 이러한 응답을 테스트할 수 있습니다.
예시 안내:
<role>
You are a "Markdown Display Assistant," an AI agent designed to demonstrate
various rich content formatting options like images, videos, and deep links
using HTML-style markdown. Your purpose is to generate and display this
content directly to the user based on their requests.
</role>
<persona>
Your primary goal is to showcase the rich content rendering capabilities of
the platform by generating HTML markdown for elements like images, videos,
and hyperlinks. You are a helpful and direct assistant. When asked to show
something, you generate the markdown for it and present it.
You should not engage in conversations outside the scope of generating and
displaying markdown. If the user asks for something unrelated, politely
state that you can only help with displaying rich content. Adhere strictly
to the defined constraints and task flow.
</persona>
<constraints>
1. **Scope Limitation:** Only handle requests related to displaying
markdown content (images, videos, links, etc.). Do not answer general
knowledge questions or perform other tasks.
2. **Tool Interaction Protocol:** You must use the \`display_markdown\`
tool to generate the formatted content string.
3. **Direct Output:** Your final response to the user must be the raw
markdown string returned by the \`display_markdown\` tool. Do not add
any conversational text around it unless the tool returns an error.
For example, if the tool returns \`"<img src='...'>"\`, your response
should be exactly \`"<img src='...'>"\`.
4. **Clarity and Defaults:** If a user's request is vague (e.g., "show me
an image"), use the tool's default values to generate a response. There
is no need to ask for clarification.
5. **Error Handling:** If the tool call fails or returns an error, inform
the user about the issue in a conversational manner.
</constraints>
<taskflow>
These define the conversational subtasks that you can take. Each subtask
has a sequence of steps that should be taken in order.
<subtask name="Generate and Display Markdown">
<step name="Parse Request and Call Tool">
<trigger>
User initiates a request to see any form of rich content (image,
video, link, etc.).
</trigger>
<action>
1. Identify the types of content the user wants to see (e.g.,
image, video, deep link).
2. Call the \`display_markdown\` tool. Set the corresponding
boolean arguments to \`True\` based on the user's request.
For example, if the user asks for a video and a link, call
\`display_markdown(show_video=True, show_deep_link=True)\`.
3. If the user makes a general request like "show me something
cool", you can enable all flags.
</action>
</step>
<step name="Output Tool Response">
<trigger>
The \`display_markdown\` tool returns a successful response
containing a \`markdown_string\`.
</trigger>
<action>
1. Extract the value of the \`markdown_string\` key from the
tool's output.
2. Use this value as your direct and final response to the
user, without any additional text or formatting.
</action>
</step>
</subtask>
</taskflow>
샘플 Python 도구:
from typing import Any
def display_markdown(show_image: bool, show_video: bool, show_deep_link: bool) -> dict[str, Any]:
"""
Constructs a markdown string containing HTML for various rich media elements.
This function generates an HTML-formatted string based on the boolean flags provided.
It can include an image, a video, and a hyperlink (deep link). The content for
these elements is pre-defined.
Args:
show_image (bool): If True, an <img> tag will be included in the output.
show_video (bool): If True, a <video> tag will be included in the output.
show_deep_link (bool): If True, an <a> tag will be included in the output.
Returns:
dict[str, Any]: A dictionary with a single key 'markdown_string' containing the
generated HTML markdown. If no flags are set, it returns a
message indicating nothing was requested.
"""
# MOCK: This is a mock implementation. It does not fetch any dynamic content.
# It assembles a markdown string from hardcoded HTML snippets to demonstrate
# the agent's ability to render rich content.
markdown_parts = []
if show_image:
image_html = "This is a sample image:\n<img src='https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png' alt='Google Logo' width='272' height='92' />"
markdown_parts.append(image_html)
if show_video:
video_html = "This is a sample video:\n<video controls width='320' height='240'><source src='https://www.w3schools.com/html/mov_bbb.mp4' type='video/mp4'>Sorry, your browser does not support embedded videos.</video>"
markdown_parts.append(video_html)
if show_deep_link:
link_html = "This is a sample deep link:\n<a href='https://www.google.com'>Click here to go to Google</a>"
markdown_parts.append(link_html)
if not markdown_parts:
return {"markdown_string": "You did not request any content to be displayed. Please specify if you want to see an image, video, or link."}
return {"markdown_string": "\n\n".join(markdown_parts)}
음성 및 오디오 채널 컨트롤
이 섹션에서는 사전 녹음된 오디오, 대기 음악, 끼어들기 설정 등 음성 및 오디오 채널을 제어하는 패턴을 제공합니다.
참고:
- Linear16, mulaw, alaw 오디오 인코딩이 오디오 파일로 지원됩니다.
- 다른 클라우드 프로젝트에 속한 Cloud Storage 버킷을 사용하는 경우 Customer Engagement Suite 서비스 계정
service-<PROJECT-NUMBER>@gcp-sa-ces.iam.gserviceaccount.com에 대상 Cloud Storage 버킷에 대한storage.objects.get권한을 명시적으로 부여해야 합니다. interruptable입력 인수를 사용하여 사전 녹음된 오디오가 최종 사용자에 의해 중단될 수 있는지 여부를 구성할 수 있습니다.- 음악 재생의 경우
cancellable입력 인수를 사용하여 에이전트가 새 응답을 생성할 때 음악 재생을 중지해야 함을 나타낼 수 있습니다.
브랜드별 사전 녹음된 오디오 재생
사용자 요청을 처리하기 전에 미리 녹음된 오디오 파일을 재생하도록 에이전트를 구성할 수 있습니다. 세션 시작 시 브랜드 승인 인사말이나 필수 법적 공개에 사용할 수 있습니다.
"transcript": "yyy"를 사용하여 에이전트에게 오디오 재생 텍스트를 제공하여 후속 응답을 생성하는 데 필요한 컨텍스트가 있는지 확인합니다.
"interrupable": false를 사용하면 사용자가 오디오 재생을 중단할 수 없습니다.
def before_model_callback(
callback_context: CallbackContext,
llm_request: LlmRequest
) -> Optional[LlmResponse]:
for part in callback_context.get_last_user_input():
if part.text == "<event>session start</event>":
return LlmResponse.from_parts(parts=[
Part.from_json(data='{"audioUri": "gs://path/to/audio/file", "transcript": "transcript for the audio file", "interruptable": false}')
])
return None
느린 도구를 실행할 때 사전 녹음된 음악 재생 (끼어들기 없음)
느리고 '차단' 도구(예: 계정 유효성 검사 및 활성화)가 실행되는 동안 음악을 재생하도록 에이전트를 구성할 수 있습니다. 도구 실행이 완료되면 음악이 자동으로 중지됩니다. 음악이 재생되는 동안 사용자는 에이전트와 상호작용할 수 없습니다.
def after_model_callback(
callback_context: CallbackContext,
llm_response: LlmResponse
) -> Optional[LlmResponse]:
for index, part in enumerate(llm_response.content.parts):
if part.has_function_call("slow_tool"):
play_music = Part.from_json(
data='{"audioUri": "gs://path/to/music/file", "cancellable": true}'
)
return LlmResponse.from_parts(
parts=llm_response.content.parts[:index] +
[play_music] + llm_response.content.parts[index:]
)
return None
비동기 도구 실행 시 사전 녹음된 음악 재생 (끼어들기 허용)
사용자 계정 확인 및 활성화와 같이 도구를 비동기적으로 실행하는 동안 음악을 재생하도록 에이전트를 구성할 수 있습니다. 사용자가 이미 음악을 중단하지 않은 경우 비동기 도구가 완료되면 음악이 자동으로 종료됩니다. 최종 사용자는 언제든지 음악을 중단하고 에이전트와의 상호작용을 계속할 수 있습니다.
def before_model_callback(
callback_context: CallbackContext,
llm_request: LlmRequest
) -> Optional[LlmResponse]:
for part in llm_request.contents[-1].parts:
if part.has_function_response("async_tool"):
text = Part.from_text(text="I'm submitting your order, it may take a while.")
music = Part.from_json(
data='{"audioUri": "gs://path/to/music/file", "cancellable": true}'
)
return LlmResponse.from_parts(parts=[text, music])
return None
특정 대답에 대한 사용자 끼어들기 허용 안 함
상담사가 법적 면책 조항과 같은 중요한 정보를 읽어줄 때는 사용자가 상담사를 방해하지 못하도록 허용하지 않지만, 상담사 응답의 나머지 부분에 대해서는 끼어들기를 허용할 수 있습니다.
customize_response 시스템 도구를 사용합니다.
결과가 결정적인지 여부에 따라 다음 두 가지 방법으로 이 동작을 구현할 수 있습니다.
- 콜백 (결정적): 샘플에 표시된 대로 콜백에서 응답을 강제합니다.
- 요청 사항 (에이전트 주도): 요청 사항에서 에이전트가
customize_response도구를 사용하도록 유도합니다.
def before_model_callback(
callback_context: CallbackContext,
llm_request: LlmRequest
) -> Optional[LlmResponse]:
for part in callback_context.get_last_user_input():
if part.text == "<event>session start</event>":
return LlmResponse.from_parts(parts=[
Part.from_customized_response(
content=("Hello, I'm Gemini. Please listen to the following legal "
"disclaimer: <LEGAL_DISCLAIMER>"),
disable_barge_in=True
),
Part.from_text("How can I help you today?")
])
return None
입력이 없는 경우의 맞춤 응답
에이전트가 입력을 기다리다가 시간 초과되면(에이전트 애플리케이션 설정의 무음 제한 시간 참고) 기본적으로 생성형 응답이 사용됩니다. 하지만 모델 콜백 전에 사용자가 입력을 수신했는지 확인하고 조건부로 응답을 제공할 수 있습니다.
def before_model_callback(
callback_context: CallbackContext,
llm_request: LlmRequest
) -> Optional[LlmResponse]:
for part in callback_context.get_last_user_input():
if part.text:
if "no user activity detected" in part.text:
return LlmResponse.from_parts(parts=[
Part.from_text(text="Hi, are you still there?")
])
return None
오류 처리
이 섹션에서는 도구 오류 처리 패턴을 제공합니다.
도구 실패 시 다른 상담사에게 트랜스퍼
특정 도구 실행이 실패하면 대화를 처리할 다른 에이전트에게 확실하게 인계할 수 있습니다. 이는 런타임 오류 중에 사용자 환경을 보호하는 데 중요한 안전 장치입니다.
def before_model_callback(
callback_context: CallbackContext,
llm_request: LlmRequest
) -> Optional[LlmResponse]:
for part in llm_request.contents[-1].parts:
if (part.has_function_response('authentication') and
'error' in part.function_response.response['result']):
return LlmResponse.from_parts(parts=[
Part.from_text('Sorry something went wrong, let me transfer you to another agent.'),
Part.from_agent_transfer(agent='escalation agent')
])
return None
도구 실패 시 세션을 적절하게 종료
특정 도구 실행이 실패하면 세션을 정상적으로 종료할 수 있습니다. 이렇게 하면 중요한 도구 오류가 발생할 때 무한 루프와 혼란스러운 응답을 방지할 수 있습니다.
샘플 콜백:
def before_model_callback(
callback_context: CallbackContext,
llm_request: LlmRequest
) -> Optional[LlmResponse]:
for part in llm_request.contents[-1].parts:
if (part.has_function_response('authentication') and
'error' in part.function_response.response['result']):
return LlmResponse.from_parts(parts=[
Part.from_text('Sorry something went wrong, please call back later.'),
Part.from_end_session(reason='Failure during user authentication.')
])
return None
컨텍스트 및 변수
이 섹션에서는 컨텍스트 변수 사용 패턴을 제공합니다.
OpenAPI 도구에 컨텍스트 변수 전달
맞춤형 AI는 사용자 세션 데이터에 액세스하는 도구가 필요합니다.
모델이 세션 ID나 사용자 변수와 같은 중요한 세부정보를 수동으로 기억하고 전달하도록 하는 것은 본질적으로 신뢰할 수 없고 느립니다.
대신 에이전트가 특정 컨텍스트 변수를 OpenAPI 도구에 전달할 수 있습니다.
x-ces-session-context을 사용하여 값이 모델에서 생성될 필요가 없고 (모델에 스키마가 표시되지 않음) 컨텍스트 변수에서 가져온 것임을 나타낼 수 있습니다.
다음 표에는 사용 가능한 값이 나와 있습니다.
| 값 | 설명 |
|---|---|
$context.project_id |
Google Cloud 프로젝트 ID입니다. |
$context.project_number |
Google Cloud 프로젝트 번호입니다. |
$context.location |
에이전트의 위치 (리전)입니다. |
$context.app_id |
에이전트 애플리케이션 ID입니다. |
$context.session_id |
세션의 고유 식별자입니다. |
$context.variables |
모든 컨텍스트 변수 값을 객체로 나타냅니다. |
$context.variables.variable_name |
특정 컨텍스트 변수의 값입니다. variable_name을 변수 이름으로 바꿉니다. |
openapi: 3.0.0
info:
title: test-title
description: test-description
version: 1.0.0
paths:
/test-path/{session_id}:
post:
parameters:
- name: session_id
in: path
description: The session ID.
required: true
schema:
type: string
x-ces-session-context: $context.session_id
- name: test_variable
in: query
description: Specific session variable.
required: true
schema:
type: string
x-ces-session-context: $context.variables.test_variable
requestBody:
description: test-description
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SessionParams'
responses:
'200':
description: test-response-description
content:
application/json:
schema:
type: object
properties:
result:
type: string
components:
schemas:
SessionParams:
type: object
description: all context variables
x-ces-session-context: $context.variables
동적 프롬프트
다음 항목을 사용하여 모델에 전송되는 동적 프롬프트가 있는 에이전트를 빌드할 수 있습니다.
- 프롬프트 변형을 제어하는 데 사용할 수 있는 변수
- 변수 참조가 포함된 명령어
- 대화 세부정보를 기반으로 변수를 업데이트할 수 있는 도구
- before_model_callback
예를 들어 사용자가 변호사인지 해적인지에 따라 에이전트 안내를 변경할 수 있습니다.
변수:
| 변수 이름 | 기본값 |
|---|---|
| current_instructions | 나는 Gemini이며 Google에서 일해. |
| lawyer_instructions | 너는 변호사이고 아재 개그 스타일의 농담을 하지만 변호사다운 면모를 보여야 해. |
| pirate_instructions | 너는 해적이고 네 임무는 해적으로서 농담을 하는 거야. |
| 사용자 이름 | 알 수 없음 |
안내:
The current user is: {username}
You can use {@TOOL: update_username} to update the user's name if they provide
it.
Follow the current instruction set below exactly.
{current_instructions}
Python 도구:
from typing import Optional
def update_username(username: str) -> Optional[str]:
"""Updates the current user's name."""
set_variable("username", username)
콜백:
def before_model_callback(
callback_context: CallbackContext,
llm_request: LlmRequest
) -> Optional[LlmResponse]:
username = callback_context.get_variable("username", None)
if username == "Jenn":
new_instructions = callback_context.get_variable("pirate_instructions")
elif username == "Gary":
new_instructions = callback_context.get_variable("lawyer_instructions")
callback_context.set_variable("current_instructions", new_instructions)