제대로 작동하는 에이전트를 구축하는 것과 그렇지 않은 에이전트를 구축하는 것에는 엄청난 차이가 있습니다. 후자의 범주에 속하는 에이전트를 구축하려면 어떻게 해야 할까요? 이 가이드에서는 에이전트 구축을 위한 모범 사례를 살펴보겠습니다.
상담원 구축이 처음인 경우에는 먼저 소개 상담원에게 및 smolagent 가이드 투어.
최고의 에이전트 시스템은 가장 단순합니다: 워크플로를 최대한 단순화하세요. #
워크플로에서 LLM에게 일부 권한을 부여하면 오류가 발생할 위험이 있습니다.
잘 프로그래밍된 에이전트 시스템에는 오류 로깅 및 재시도 메커니즘이 잘 갖춰져 있으므로 LLM 엔진이 실수를 스스로 수정할 수 있습니다. 하지만 LLM 오류의 위험을 최대한 줄이려면 워크플로를 단순화해야 합니다!
서핑 여행 회사를 위해 사용자 쿼리에 응답하는 봇인 [intro_agents]의 예를 다시 살펴봅시다. 상담원이 새로운 서핑 명소에 대한 질문을 받을 때마다 "이동 거리 API"와 "날씨 API"를 각각 두 번씩 호출하는 대신 두 API를 한 번에 호출하고 연결된 출력을 사용자에게 반환하는 하나의 통합 도구인 "return_spot_information" 함수를 만들 수 있습니다.
이렇게 하면 비용, 지연 시간, 오류 위험을 줄일 수 있습니다!
주요 지침은 다음과 같습니다: LLM 호출 횟수를 최대한 줄이세요.
이를 통해 몇 가지 시사점을 얻을 수 있습니다:
- 가능하면 두 개의 API를 예로 든 것처럼 두 개의 도구를 하나로 그룹화하세요.
- 가능하면 로직은 에이전트 결정이 아닌 결정론적 함수를 기반으로 해야 합니다.
LLM 엔진으로의 정보 흐름 개선 #
LLM 엔진은 외부 세계와의 유일한 통신은 문 아래로 전달되는 메모뿐인 방 안에 갇혀 있는 ~지능적인~ 로봇과 같다는 것을 기억하세요.
프롬프트에 명시적으로 입력하지 않으면 어떤 일이 발생했는지 알 수 없습니다.
그러니 먼저 작업을 매우 명확하게 만드는 것부터 시작하세요! 에이전트는 LLM에 의해 구동되기 때문에 작업 구성에 약간의 변화를 주면 완전히 다른 결과가 나올 수 있습니다.
그런 다음 도구 사용 시 상담원에게 전달되는 정보 흐름을 개선하세요.
따라야 할 구체적인 지침:
- 각 도구는 다음을 사용하여
인쇄
명령문을 도구의앞으로
메서드)에 유용할 수 있는 모든 것을 제공합니다.- 특히 도구 실행 오류에 대한 세부 정보를 기록하면 많은 도움이 될 것입니다!
예를 들어 위치와 날짜 시간을 기준으로 날씨 데이터를 검색하는 도구가 있습니다:
먼저, 형편없는 버전입니다:
복사됨
날짜/시간 가져오기 smolagent 가져오기 도구에서 def get_weather_report_at_coordinates(좌표, 날짜_시간): # 더미 함수, [온도(°C), 0-1 스케일의 비 위험도, 파도 높이(m)]의 목록을 반환합니다. 반환 [28.0, 0.35, 0.85] def get_coordinates_from_location(location): # 더미 좌표를 반환합니다. 반환 [3.3, -42.0] @tool def get_weather_api(location: str, date_time: str) -> str: """ 일기 예보를 반환합니다. Args: location: 날씨를 원하는 장소의 이름입니다. date_time: 보고서를 원하는 날짜와 시간입니다. """ 경도, 위도 = convert_location_to_coordinates(위치) 날짜_시간 = datetime.strptime(날짜_시간) 반환 str(get_weather_report_at_coordinates((경도, 위도), 날짜_시간))
왜 나쁜가요?
- 에 사용해야 하는 형식의 정밀도가 없습니다.
날짜_시간
- 위치를 지정하는 방법에 대한 자세한 내용은 없습니다.
- 위치가 올바른 형식이 아니거나 날짜_시간이 올바른 형식이 아닌 경우와 같은 명시적인 실패 사례와 관련된 로깅 메커니즘이 없습니다.
- 출력 형식을 이해하기 어려운 경우
도구 호출이 실패하면 메모리에 기록된 오류 추적을 통해 LLM이 도구를 리버스 엔지니어링하여 오류를 수정하는 데 도움이 될 수 있습니다. 하지만 왜 그렇게 많은 작업을 해야 할까요?
이 도구를 구축하는 더 좋은 방법은 다음과 같습니다:
복사됨
@tool def get_weather_api(location: str, date_time: str) -> str: """ 일기 예보를 반환합니다. Args: location: 날씨를 원하는 장소의 이름입니다. '앵커 포인트, 타가주트, 모로코'와 같이 장소 이름, 도시 이름, 국가가 뒤따라야 합니다. 날짜_시간: 보고서를 받고자 하는 날짜와 시간으로, '%m/%d/%y %H:%M:%S'와 같은 형식입니다. """ 경도, 위도 = convert_location_to_coordinates(location) try: 날짜_시간 = datetime.strptime(날짜_시간) 예외는 e로 제외합니다: ValueError("`date_time`을 날짜/시간 형식으로 변환하지 못했습니다. '%m/%d/%y %H:%M:%S' 형식의 문자열을 제공해야 합니다.")가 발생합니다. 전체 추적:" + str(e)) temperature_celsius, risk_of_rain, wave_height = get_weather_report_at_coordinates((lon, lat), date_time) 반환 f"{위치}, {날짜_시간}에 대한 일기 예보입니다: 온도는 {온도_씨씨}°C, 비 위험도는 {위험도*100:.0f}%, 파도 높이는 {파도_높이}m입니다."
일반적으로 LLM의 부담을 덜기 위해 스스로에게 물어볼 좋은 질문은 "내가 이 도구를 처음 사용하는 멍청한 사람이라면 이 도구로 프로그래밍하고 내 오류를 수정하는 것이 얼마나 쉬울까?"입니다.
상담원에게 더 많은 인수 제공 #
작업을 설명하는 단순한 문자열 외에 몇 가지 추가 개체를 상담원에게 전달하려면 다음을 사용하면 됩니다. 추가_args
인수를 사용하여 모든 유형의 객체를 전달할 수 있습니다:
복사됨
smolagent에서 CodeAgent, HfApiModel을 가져옵니다. model_id = "meta-llama/Llama-3.3-70B-Instruct" agent = CodeAgent(tools=[], model=HfApiModel(model_id=model_id), add_base_tools=True) agent.run( "마이크는 왜 뉴욕에 아는 사람이 많지 않나요?", additional_args={"mp3_sound_file_url":'https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/recording.mp3'} )
예를 들어 다음과 같이 사용할 수 있습니다. 추가_args
인수를 사용하여 에이전트가 활용할 이미지나 문자열을 전달할 수 있습니다.
상담원 디버깅 방법 #
1. 더 강력한 LLM 사용 #
에이전트 워크플로에서 오류 중 일부는 실제 오류이고, 다른 일부는 LLM 엔진이 제대로 추론하지 못한 오류입니다. 예를 들어 다음과 같은 추적을 생각해 보세요. 코드 에이전트
자동차 사진을 만들어 달라고 요청했습니다:
복사됨
==================================================================================================== New task ==================================================================================================== 멋진 자동차 사진 만들기 ──────────────────────────────────────────────────────────────────────────────────────────────────── 새 단계 ──────────────────────────────────────────────────────────────────────────────────────────────────── 에이전트가 아래 코드를 실행 중입니다: ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── image_generator(prompt="LED 헤드라이트, 공기역학적 디자인, 생생한 색상, 고해상도, 실사 같은 멋진 미래형 스포츠카") ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 코드 스니펫의 마지막 출력입니다: ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── /var/folders/6m/9b1tts6d5w960j80wbw9tx3m0000gn/T/tmpx09qfsdd/652f0007-3ee9-44e2-94ac-90dae6bb89a4.png 1단계 - 소요 시간 16.35초 - 입력 토큰: 1,383 - 출력 토큰: 77 ──────────────────────────────────────────────────────────────────────────────────────────────────── 새 단계 ──────────────────────────────────────────────────────────────────────────────────────────────────── 에이전트가 아래 코드를 실행 중입니다: ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── final_answer("/var/folders/6m/9b1tts6d5w960j80wbw9tx3m0000gn/T/tmpx09qfsdd/652f0007-3ee9-44e2-94ac-90dae6bb89a4.png") ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── 출력물을 인쇄합니다: 코드 스니펫의 마지막 출력입니다: ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── /var/folders/6m/9b1tts6d5w960j80wbw9tx3m0000gn/T/tmpx09qfsdd/652f0007-3ee9-44e2-94ac-90dae6bb89a4.png 최종 답변 /var/folders/6m/9b1tts6d5w960j80wbw9tx3m0000gn/T/tmpx09qfsdd/652f0007-3ee9-44e2-94ac-90dae6bb89a4.png
사용자는 이미지가 반환되는 대신 경로가 반환되는 것을 보게 됩니다. 이는 시스템의 버그처럼 보일 수 있지만 실제로는 에이전트 시스템이 오류를 일으킨 것이 아니라 LLM의 두뇌가 이미지 출력을 변수에 저장하지 않는 실수를 저질렀을 뿐입니다. 따라서 이미지를 저장할 때 기록된 경로를 활용하는 방법 외에는 이미지에 다시 액세스할 수 없으므로 이미지 대신 경로를 반환합니다.
따라서 에이전트 디버깅의 첫 번째 단계는 "더 강력한 LLM 사용"입니다. 다음과 같은 대안이 있습니다. Qwen2/5-72B-Instruct
였다면 이런 실수를 하지 않았을 것입니다.
2. 추가 안내 / 추가 정보 제공 #
더 효과적으로 안내한다면 덜 강력한 모델을 사용할 수도 있습니다.
모델의 입장이 되어 보세요: 여러분이 작업을 해결하는 모델이라면 시스템 프롬프트 + 작업 공식화 + 도구 설명에서 제공되는 정보로 인해 어려움을 겪으시겠습니까?
추가 설명이 필요하신가요?
추가 정보를 제공하기 위해 시스템 프롬프트를 바로 변경하지 않는 것이 좋습니다. 기본 시스템 프롬프트에는 프롬프트를 잘 이해하는 경우를 제외하고는 엉망으로 만들고 싶지 않은 조정 사항이 많기 때문입니다. LLM 엔진을 안내하는 더 좋은 방법은 다음과 같습니다:
- 해결해야 할 과제에 관한 내용이라면 이 모든 세부 사항을 과제에 추가하세요. 작업의 길이가 100페이지에 달할 수도 있습니다.
- 도구 사용 방법에 관한 내용인 경우: 도구의 설명 속성입니다.
3. 시스템 프롬프트 변경(일반적으로 권장하지 않음) #
위의 설명으로 충분하지 않은 경우 시스템 프롬프트를 변경할 수 있습니다.
어떻게 작동하는지 살펴봅시다. 예를 들어, 기본 시스템 프롬프트에서 코드 에이전트 (아래 버전은 제로샷 예제를 생략하여 단축한 것입니다.)
복사됨
인쇄(에이전트.시스템_프롬프트_템플릿)
결과는 다음과 같습니다:
복사됨
귀하는 코드 블롭을 사용하여 모든 작업을 해결할 수 있는 전문 조수입니다. 최선을 다해 해결해야 하는 과제가 주어집니다. 이를 위해 여러분에게는 도구 목록에 대한 액세스 권한이 주어집니다. 이러한 도구는 기본적으로 코드로 호출할 수 있는 Python 함수입니다. 과제를 해결하려면 '생각:', '코드:', '관찰:'의 순서로 일련의 단계를 진행하도록 계획을 세워야 합니다. 각 단계의 '생각:' 순서에서는 먼저 과제를 해결하기 위한 추론과 사용하려는 도구를 설명해야 합니다. 그런 다음 '코드:' 순서에서 간단한 Python으로 코드를 작성해야 합니다. 코드 시퀀스는 '' 시퀀스로 끝나야 합니다. 각 중간 단계에서 'print()'를 사용하여 나중에 필요한 중요한 정보를 저장할 수 있습니다. 그러면 이러한 인쇄 출력은 '관찰:' 필드에 나타나며, 다음 단계의 입력으로 사용할 수 있습니다. 마지막에는 'final_answer' 도구를 사용하여 최종 답을 반환해야 합니다. 다음은 개념 도구를 사용한 몇 가지 예입니다: --- {examples} 위의 예는 존재하지 않을 수도 있는 개념적 도구를 사용한 것입니다. 생성한 Python 코드 스니펫에서 계산을 수행하는 것 외에도 이러한 도구에 대한 액세스 권한만 있습니다: {{tool_descriptions}} {관리되는_에이전트_설명}} 다음은 작업을 해결하기 위해 항상 지켜야 할 규칙입니다: 1. 항상 '생각:' 시퀀스와 '```' 시퀀스로 끝나는 'Code:\n```py' 시퀀스를 제공해야 하며, 그렇지 않으면 실패합니다. 2. 정의한 변수만 사용하세요! 3. 항상 도구에 올바른 인수를 사용하세요. 'answer = wiki({'query': "제임스 본드가 사는 곳은 어디인가요?"})'와 같이 인수를 딕셔너리로 전달하지 말고 'answer = wiki(query="제임스 본드가 사는 곳은 어디인가요?")'와 같이 인수를 직접 사용하세요. 4. 특히 출력 형식을 예측할 수 없는 경우 같은 코드 블록에 너무 많은 순차적 도구 호출을 연결하지 않도록 주의하세요. 예를 들어, 검색 호출의 반환 형식이 예측할 수 없는 경우 같은 블록에 출력에 의존하는 다른 도구 호출을 두지 말고 print()로 결과를 출력하여 다음 블록에서 사용하세요. 5. 필요할 때만 도구를 호출하고, 이전에 정확히 동일한 매개변수로 수행한 도구 호출을 다시 수행하지 마세요. 6. 새 변수의 이름을 도구와 같은 이름으로 지정하지 마세요. 예를 들어 'final_answer'라는 변수의 이름을 지정하지 마세요. 7. 코드에 개념 변수를 만들지 마세요. 로그에 개념 변수가 있으면 실제 변수와 혼동될 수 있으므로 절대 만들지 마세요. 8. 코드에서 임포트를 사용할 수 있지만 다음 모듈 목록에서만 사용할 수 있습니다: {{authorized_imports}} 9. 상태는 코드 실행 간에 지속되므로 한 단계에서 변수를 만들거나 모듈을 가져온 경우 모두 지속됩니다. 10. 포기하지 마세요! 여러분은 과제를 해결하는 것이지 해결 방법을 제시하는 것이 아닙니다. 이제 시작하세요! 과제를 올바르게 풀면 $1,000,000의 보상을 받게 됩니다.
보시다시피 다음과 같은 자리 표시자가 있습니다. "{{tool_descriptions}}"
상담원 초기화 시 자동으로 생성된 특정 도구 또는 관리되는 상담원에 대한 설명을 삽입하는 데 사용됩니다.
따라서 사용자 정의 프롬프트를 인수로 전달하여 이 시스템 프롬프트 템플릿을 덮어쓸 수는 있지만 시스템_프롬프트
매개변수를 사용하려면 새 시스템 프롬프트에 다음과 같은 자리 표시자가 포함되어야 합니다:
"{{tool_descriptions}}"
를 클릭하여 도구 설명을 삽입합니다."{{관리되는_에이전트_설명}}"
를 클릭하여 관리되는 상담원에 대한 설명이 있는 경우 이를 삽입합니다.- For
코드 에이전트
만 해당됩니다:"{{authorized_imports}}"
를 클릭하여 승인된 가져오기 목록을 삽입합니다.
그런 다음 다음과 같이 시스템 프롬프트를 변경할 수 있습니다:
복사됨
smolagents.prompts에서 CODE_SYSTEM_PROMPT를 가져옵니다. 수정된_시스템_프롬프트 = CODE_SYSTEM_PROMPT + "\n자, 여기 있습니다!" # 여기에서 시스템 프롬프트 변경 에이전트 = 코드에이전트( tools=[], model=HfApiModel(), 시스템_프롬프트=수정된_시스템_프롬프트 )
이는 도구 호출 에이전트.
4. 추가 계획 #
저희는 에이전트가 일반 작업 단계 사이에 정기적으로 실행할 수 있는 보충 계획 단계에 대한 모델을 제공합니다. 이 단계에서는 툴 호출이 없으며, LLM은 단순히 알고 있는 사실 목록을 업데이트하고 이러한 사실에 따라 다음에 수행해야 할 단계를 반영하도록 요청받습니다.
복사됨
smolagent에서 load_tool, CodeAgent, HfApiModel, DuckDuckGoSearchTool을 가져옵니다. 닷텐브이에서 load_dotenv를 가져옵니다. load_dotenv() # 허브에서 가져오기 도구 image_생성_도구 = load_tool("m-ric/text-to-image", trust_remote_code=True) search_tool = DuckDuckGoSearchTool() 에이전트 = 코드에이전트( tools=[search_tool], model=HfApiModel("Qwen/Qwen2.5-72B-Instruct"), planning_interval=3 # 기획을 활성화하는 곳입니다! ) # 실행! result = agent.run( "최고 속도로 치타가 퐁 알렉상드르 3세의 길이를 달리는 데 얼마나 걸릴까요?"), )