대규모 언어 모델(LLM)과 이를 발전시킨 증강 언어 모델(ALM)은 현대 AI 시스템의 중추가 되었습니다. 강력한 언어 생성 기술에 검색 증강 생성(RAG) 같은 외부 지식 검색 기술을 결합하면 다양한 도메인에서 고급 추론, 질의 응답, 자동화가 가능해집니다. 이 모델들은 성능이 뛰어나지만 복잡한 작업을 처리할 때 시스템 전반에서 견고성이 일정하지 않고, 토큰 사용량이 많고, 응답 시간이 느리고, 프롬프트가 반복적이며 컨텍스트가 중복되는 비효율성 문제를 겪는 경우가 많습니다. 이러한 한계는 운영 비용을 증가시키고 확장성과 실시간 성능을 저해합니다.
ReWOO(관찰 없는 추론) 프레임워크는 이 문제를 극복하기 위해 추론으로부터 외부 지식 검색을 분리하는 새로운 방식을 취합니다. 단일 LLM을 통해 행동을 추론하고 인터리브 방식으로 관찰하는 대신, ReWOO는 이 우려를 별개의 모듈들로 분리합니다. 이 모듈들 각각은 LLM으로 구동될 수 있지만 특정한 역할이 주어집니다. 프로세스를 개별적인 계획, 증거 수집, 합성 단계로 모듈화함으로써 ReWOO는 토큰 효율성과 정확성을 향상시킵니다. 또한 시스템을 더 쉽게 디버깅할 수 있게 만들고, AI 워크플로가 좀 더 간소하게 효과적으로 작동하게 합니다.
ReWOO의 워크플로는 단계별 추론, 툴 호출, 요약이라는 세 가지 핵심 구성 요소를 중심으로 진행됩니다. 이 요소들은 플래너, 워커, 솔버의 세 부분으로 구성된 모듈식 구조로 구현됩니다.
플래너는 주요 작업을 일련의 집중적인 하위 질문들로 나누어 선명한 청사진을 만듭니다. LLM에 복잡한 질문에 한번에 대답해 달라고 하면 토큰이 과하게 사용되고, 답변은 모호해질 수 있기에, 플래너는 청사진이나 로드맵을 만듭니다. 이 단계적 분석은 워크플로를 안내하고 추론 프로세스를 구조화합니다.
워커는 검색 엔진이나 데이터베이스 같은 외부 툴을 호출해서 하위 질문에 답하기 위해 필요한 정보와 증거를 검색합니다. LLM을 사용하여 검색된 정보만을 기반으로 명확하고 간결한 답을 간단명료한 답을 생성합니다. 이 외부 관찰 단계는 불필요한 프롬프트 반복을 방지하고 토큰 소비를 줄이기 위해 추론 프로세스와 분리되어 있습니다.
솔버는 수집된 모든 인사이트를 종합해 신선하고 체계적인 최종 응답을 생성합니다. 이렇게 모듈별로 분리를 하면 대규모 언어 모델을 사용해 효율적이고 정확하며 확장 가능하게 추론을 할 수 있습니다.
LangChain과 LangGraph 같은 프레임워크는 OpenAI 모델, IBM Granite, Serper 및 Tavily 같은 전문 툴을 검색에 사용해서 ReWOO 아키텍처를 구현하기 위한 강력한 도구를 제공합니다.
이 튜토리얼에서는 콘텐츠 요약 작업을 수행하는 ReWOO 에이전트를 구축하는 방법을 살펴봅니다. 이 에이전트는 다음과 같은 기능을 합니다.
이 아키텍처의 용도:
이 단계별 튜토리얼에서 활용한 첨단 AI 기술:
이 튜토리얼에서는 Jupyter Notebook을 사용하여 ReWOO 스타일의 추론 파이프라인을 실행하도록 로컬 개발 환경을 설정하는 과정을 알아봅니다. 라이브 웹 검색에 IBM Granite 언어 모델과 Serper.dev를 사용합니다.
참고: GPU가 없어도 되지만 CPU 기반 시스템에서는 속도가 느려질 수 있습니다. 이 단계에서는 이 튜토리얼의 코드를 복사할 수 있는 Notebook 환경이 열립니다. 이 튜토리얼은 Github에서도 보실 수 있습니다.
이 라이브러리는 ReWOO 파이프라인을 실행하고 외부 툴과 상호 작용하는 데 필요합니다.
transformers: IBM Granite 대규모 언어 모델을 로드하고 실행합니다.
torch: 모델을 효율적으로 실행하는 데 필요한 딥 러닝 프레임워크입니다.
accelerate: 하드웨어 전반에 걸쳐 모델 성능을 최적화합니다(선택 사항).
requests: HTTP POST 요청을 외부 API(예: Serper)로 보냅니다.
이 단계에서는 ReWOO 파이프라인의 핵심 구성 요소를 빌드하는 데 필요한 Python 라이브러리를 가져옵니다.
transformers.AutoTokenizer: 텍스트를 언어 모델과 호환되는 토큰으로 변환하는 토크나이저를 로드합니다.
transformers.AutoModelForCausalLM: 응답을 생성하기 위해 사전 훈련된 IBM Granite 언어 모델을 로드합니다.
transformers.pipeline: 토크나이저와 모델을 사용하여 텍스트 생성 파이프라인을 빠르게 생성하는 고수준 인터페이스를 제공합니다.
이 단계에서는 IBM Granite 언어 모델을 로드하고 Hugging Face의 트랜스포머 라이브러리를 사용하여 텍스트 생성 파이프라인을 초기화합니다. Hugging Face에 사용되는 Granite 3.2 2B Instruct 모델을 여기에서 살펴보세요.
model_id = "ibm-granite/granite-3.2-2b-instruct": Hugging Face에서 호스팅되는 IBM Granite 모델 체크포인트의 이름을 지정합니다. 이 모델은 지침 준수 작업에 최적화되어 있습니다.
AutoTokenizer.from_pretrained(model_id): 지정된 모델과 연결된 토크나이저를 로드합니다. 인풋 텍스트를 토큰으로 변환하고 아웃풋 토큰을 텍스트로 디코딩하는 역할을 담당합니다.
AutoModelForCausallm.From_PreTrained (model_id): 질문에 답하거나 내용을 요약하는 등의 텍스트 생성 작업을 위해 언어 모델(Granite 3.2 2B 명령)을 로드합니다.
pipeline("text-generation", model=model, tokenizer=tokenizer): 모델과 토크나이저를 결합하는 고수준 텍스트 생성 파이프라인을 만들어서, 프롬프트에서 응답을 생성하기 쉽게 합니다.
이 단계에서는 ReWOO 아키텍처에서 워커 역할을 하는 함수를 정의합니다. 이 워커는 웹 검색 도구인 Serper.dev를 사용하여 인터넷에서 관련 최신 정보를 검색하여 추론과 답변 생성을 지원합니다. Serper.dev 는 Google 검색 결과를 구조화된 형식으로 제공하는 빠르고 가벼운 API로, AI 워크플로에서의 실시간 정보 검색에 이상적입니다.
이 설정을 통해 ReWOO 시스템은 LLM이 최종 결정을 내리기 전에 외부 지식 소스를 쿼리하여 현실 세계를 '관찰'할 수 있습니다.
ReWOO 파이프라인에서 Serper 사용하기:
SERPER_API_KEY = "<YOUR_API_KEY>" # 괄호 안에 실제 키 입력
참고: API 키를 공개된 저장소에 절대 업로드하지 마세요. 프로덕션 또는 팀 설정에는 보안을 위해 .env 파일이나 환경 변수를 사용합니다.
def query_serper(question, num_results=3): 검색 질문을 받고 상위 검색 결과에서 관련 스니펫을 반환하는 함수를 정의합니다.
payload = {"q": question, "num": num_results}: 검색어와 반환할 결과 수를 포함한 쿼리 페이로드를 준비합니다.
response = requests.post(...): 쿼리 및 헤더를 포함해 Serper API에 POST 요청을 보냅니다.
response.raise_for_status(): API 응답이 유효하지 않거나 실패하면 오류를 발생시킵니다.
snippets = [...]: 유기적 검색 결과에서 스니펫 텍스트를 추출합니다.
return "\n".join(snippets): 언어 모델에 대한 컨텍스트 역할을 하는 단일 문자열로서 스니펫을 연결하고 반환합니다.
참고: 이 함수는 ReWOO에서 추가 추론을 위해 외부 증거를 수집하는 '관찰' 단계의 중추를 이룹니다. 테스트할 때 API 키가 유효하고 속도 제한이 없어야 합니다.
이 단계에서는 ReWOO 아키텍처에서 솔버 역할을 하는 expert() 함수를 정의합니다. 솔버는 검색된 외부 증거를 종합하고 언어 모델을 사용해 최종 응답을 생성합니다.
def expert(question: str) -> str: expert() 함수는 질문(문자열)을 받아서, Granite 모델이 생성하는 답변(문자열)을 반환합니다. Serper.dev를 통해 웹을 검색하여 관련 정보를 수집하고, 이를 바탕으로 명확하고 완전한 응답을 생성하는 것입니다.
context = query_serper(question): Serper 웹 검색 도구를 사용하여 관련 정보(워커)를 검색합니다.
prompt = f"""...""": 모델이 검색된 컨텍스트만을 사용하여 응답하도록 지시하는 프롬프트를 작성합니다.
generator(...): Granite 모델을 호출해 입력된 프롬프트를 바탕으로 답변을 생성합니다.
for _ in range(5): 모델이 최대 5회에 걸친 청크 단위로 답변을 생성하게 하는 루프입니다. 답변이 길어서 한 번에 완료할 수 없는 경우 도움이 됩니다.
generated_text += new_text: 각각의 새 텍스트 청크를 추가하여 전체 답변을 형성합니다.
if new_text.endswith(...): 답변이 완전해 보이고(문장 맨 끝에 마침표, 물음표, 느낌표) 단어가 충분하면(50개 이상) 루프가 중지됩니다.
return generated_text.strip(): 정리된 최종 답변을 반환합니다.
참고: 프롬프트 형식은 모델이 '할루시네이션'에 빠지거나 주제에서 벗어나지 않게 하는 중요한 역할을 하며 컨텍스트를 이루는 내용에 충실해야 합니다. 우리는 아웃풋 길이를 제어하고 리소스 사용을 효율적으로 관리하는 동시에 과도한 토큰 사용을 방지하기 위해, 생성 청크 각각을 토큰 120개로 제한합니다.
이 단계에서는 광범위한 인풋 작업을 더 잘고 명확하게 정의된 하위 질문으로 나누는 플래너 함수를 정의합니다. 이는 ReWOO 단계적 추론의 핵심 원칙입니다.
def planner(task: str): 이는 단일 인수 작업(수행할 작업을 설명하는 문자열)을 허용하는 플래너라는 함수를 정의합니다.
topic = task.replace("요약", "").replace("소설", "").strip(): 작업에서 주제(예: 제목이나 테마)를 추출합니다. '요약'과 '소설' 같은 일반적인 프롬프트 문구를 제거하여 인풋을 정리한 다음, 선행 및 후행 공백을 잘라서 핵심 주제를 분리합니다.
return [ ... ]: 워커 모듈을 안내하는 특정한 질문 목록을 반환합니다.
참고: 인풋 주제의 깊이와 성격에 따라 더 구체적인 하위 질문으로 목록을 확장할 수 있습니다.
이 단계에서는 ReWOO 파이프라인에서 솔버 역할을 하는 final_summarizer 함수를 정의합니다. 이 함수는 워커가 제공한 하위 답변(증거)을 가져와 언어 모델을 사용하여, 일관성 있는 요약을 새로 작성합니다.
def final_summarizer(task: str, sub_answers: dict) -> str: 원래 작업과 하위 답변을 수신하는 함수를 정의하고 간결한 요약을 반환합니다.
insights = "\n".join(sub_answers.values()): 모든 답변을 결합해서 단일 문자열로 바꾸고 줄 바꿈으로 구분해서 프롬프트에 포함시킵니다.
base_prompt = f"""...""": 모델이 제공된 인사이트를 요약하도록 지시하는 기본 프롬프트를 구성합니다. 하위 답변만을 바탕으로 새로운 요약을 생성하도록 모델을 안내합니다.
max_total_tokens = 400: 아웃풋이 너무 길어지지 않도록 생성되는 토큰 수의 상한선을 설정합니다.
max_loops = 5: 생성 과정을 최대 5회 반복해서 요약문을 점진적으로 작성합니다.
for in range(maxloops): 언어 모델을 사용하여 텍스트 청크를 생성하는 루프입니다.
response = generator(..., max_new_tokens=100, ...): 생성기(파이프라인 객체)를 사용하여 각 루프에서 새 토큰을 최대 100개 생성합니다. 샘플링 모드(do_sample=True)를 사용하면 응답을 더 다채롭고 창의적이게 만들 수 있습니다.
if summary.endswith(...) or total_tokens_used >= max_total_tokens: 요약문이 적절한 문장 부호로 끝나거나 토큰 한도에 도달하면 루프를 종료합니다.
return summary.strip(): 후행 공백 없이 유려한 최종 요약문을 반환합니다.
이 단계에서는 ReWOO 파이프라인의 마지막 단계를 나타내는 솔버 함수를 정의합니다. 플래너를 사용하고, 전문가(워커)를 호출하고, final_summarizer(솔버)을 사용하여 요약문을 생성하고 전체 프로세스를 조정합니다. ReWOO 아키텍처는 플래너를 사용해 주요 작업을 하위 질문들로 세분화하는 방법으로 다단계 추론을 합니다. 각 하위 질문을 전문가 모듈이 개별적으로 처리하며, 최종 요약 담당이 모든 답변을 종합해 일관된 응답을 합성합니다. 이러한 모듈 방식을 취하면 시스템이 복잡한 작업을 좀 더 효과적으로 처리할 수 있습니다.
def solver(task: str): ReWOO 워크플로 전체를 실행하기 위한 메인 컨트롤러 함수를 정의합니다.
subquestions = planner(task): 플래너를 사용하여 인풋 작업을 집중된 하위 질문들로 세분화합니다.
ans = expert(q): 각 하위 질문에 대해 전문가 함수를 호출하여 웹 기반 증거를 가져오고 관련 답변을 생성합니다. 플래너가 생성한 하위 질문 각각이 툴 인풋으로서 전문가에게 전달됩니다. 전문가 모듈은 언어 모델을 사용하여 이 인풋을 처리합니다. 이는 특정한 하위 작업을 위해 툴을 실행하는 것이라고 볼 수 있습니다.
answers[q] = ans: 답변 각각을, 해당 질문을 키로 지정해서 저장합니다. 이는 추후 요약을 하기 위함입니다.
final_summary = final_summarizer(task, answers): 수집된 모든 답변을 final_summarizer에 입력해 깔끔하고 조리있는 요약문을 생성합니다.
print(final_summary) and return final_summary: 원 작업에 대한 요약문 완성본을 표시하고 반환합니다.
참고: solver() 함수에 소요되는 총 시간은 시스템마다 다를 수 있습니다. 이는 CPU 속도, 가용 RAM, 다양한 하드웨어 설정에서 실행되는 모델의 효율성이 저마다 다르기 때문입니다. 코드는 루프 생성 전략과 언어 모델을 함께 사용하기 때문에 처리 능력이나 메모리가 낮은 시스템에서는 시간이 훨씬 오래 걸릴 수 있습니다. 검색이 네트워크 기반으로 이루어지고 프롬프트 크기가 큰 것도 지연 원인일 수 있습니다. 성능을 개선하려면 더 작거나 양자화된 모델을 사용하거나, 토크나이저와 생성기 파이프라인을 최적화하거나, Google Colab이나 Kaggle Notebooks처럼 GPU 지원 환경에서 코드를 실행하여 max_loops을 줄이는 것이 좋습니다.
참고: ReWOO 파이프라인의 성능과 안정성을 향상시키려면 요약문 품질, 일관성, 생성 지연과 같은 평가 성능을 개선하는 것이 중요합니다. 이 지표들은 다양한 작업과 하드웨어 설정에서 시스템이 얼마나 잘 작동하는지 평가하는 데 도움이 됩니다. 아키텍처는 지능형 알고리즘을 통합하여 큰 질문을 작은 질문 여러 개로 나누고 가장 유용한 답변을 분류하는 방법으로 확장할 수 있습니다. 이런 개선 작업을 거치면 추론의 정확도와 효율성이 올라가고, 생성 시간이 줄어들고, 최종 아웃풋의 품질 전반이 향상됩니다.
생성형 AI로 워크플로와 프로세스를 자동화하는 강력한 AI 어시스턴트 및 에이전트를 구축, 배포, 관리하세요.
믿을 수 있는 AI 솔루션으로 비즈니스의 미래를 설계하세요.
IBM Consulting AI 서비스는 기업이 AI 활용 방식을 재구상하여 혁신을 달성하도록 지원합니다.