본문 바로가기

명사 美 비격식 (무리 중에서) 아주 뛰어난[눈에 띄는] 사람[것]

이론

Agent Loop과 ReAct 패턴 Trimming과 Conversation Summarization


Agent Loop

한번 묻고 끝나지 않는 일, 현업의 일은 보통 여러 단계이다. 행동 - 결과보고 - 다음행동 의 반복하는 구조가 Agent Loop.

one-shot 질문하나, 도구하나, 답하나 깔끔한 원샷은 복합적인 질문에서 한번에 끝나질못해 결과를 봐야 행동을 이어할 수가있다.  Agent Loop는 단계적 추론 CoT, 도구호출의 Function Calling, 여러도구중 선택하는 Tool 시스템, 결정 - 실행 - 결과전달의 수동루프가 모여있는것을 while루프로 묶는것. 

https://standout.tistory.com/1908

 

CoT란? Chain of Thought 프롬프트 방법 (" 단계적으로 생각하고 마지막에 최종 답을 제시해.")

Chain of Thought 생각의 사슬 CoTLM이 복잡한 문제를 해결할 때 단계적으로 추론하도록 유도하는 프롬프팅 기법" 단계적으로 생각하고 마지막에 최종 답을 제시해."https://standout.tistory.com/1875 프롬프트

standout.tistory.com

https://standout.tistory.com/1910

 

Function Calling이란? - 수동루프/자동실행 (feat.Docstring)

Function CallingFunction Calling은 LLM이 "이 함수를 호출하면 좋겠다"라고 판단하면 개발자가 만든 함수를 실행하는 기능 def get_weather(city): 함수를 개발했다면 사용자가 '서울날씨알려줘'라했을때 LLM이

standout.tistory.com

https://standout.tistory.com/1907

 

MCP란? Model Context Protocol: 사용자를 위한 서버가 아니라 AI를 위한 서버

MCP Model Context ProtocolLLM이 외부도구 Tool, 데이터 Data, 시스템 System 과 표준 방식으로 연결하기 위한 프로토콜.AI가 프로그램과 대화하기 위한 공통 언어. 기존의 서비스마다 연결 방식이 모두 달라

standout.tistory.com

https://standout.tistory.com/140

 

반복문 for와 while (feat. continue & break)

for문과 while모두 반복해서 돌리는 코드다. 그중 for문은 조건이 맞는것들만, while은 조건이 충족(참, true)일때 반복하는데 for문의 조건이 만약 비어있다면 사실 while(true)과 같다고 하겠다. for for(;;)

standout.tistory.com

 

 

 

사용자 요청
      ↓
Reasoning
(무엇을 해야 하지?)
      ↓
Tool 선택
      ↓
Function Calling
      ↓
결과 확인
      ↓
아직 해야 할 일이 있는가?
      ↓
Yes ───────────────┐
 ↓                 │
다음 Tool 호출      │
 ↓                 │
결과 확인───────────┘
 ↓
No
 ↓
최종 답변
while True:

    # 1. LLM이 다음 행동 결정
    action = llm(messages, tools)

    # 2. 더 이상 Tool이 필요 없으면 종료
    if action.type == "final_answer":
        print(action.content)
        break

    # 3. Tool 실행
    result = run_tool(action.name, action.arguments)

    # 4. 결과를 LLM에게 전달
    messages.append({
        "role": "tool",
        "content": result
    })

 

 

 

 

 

ReAct 패턴

Reason, Act의 합성어, 모델이 Thought, Action, Obervation을 거치고 관찰결과를 다음입력으로 되돌려 반복한다.

While True는 무한루프의 위험이있고 토큰을 끝없이 태움으로 while True 대신 MAX_STEPS, max_step을 둔다 .

보통 5~10을 두나 작업의 성격에 맞게 정한다. 재고확인 같은 2~3 스탭에는 6정도가 넉넉하다.

추가로 모델이 진전없이 도구명 인자를 여러번 수행하지않도록 중복 호출을 감지한다. 

MAX_STEPS = 6

messages = [{"role": "user", "content": user_question}]

# 중복 호출 감지용
visited = set()

for step in range(MAX_STEPS):

    # 1. LLM이 다음 행동 결정
    response = llm(messages, tools)

    # 2. 최종 답변이면 종료
    if response.type == "final_answer":
        print(response.content)
        break

    # 3. 같은 Tool + 같은 인자 반복 호출 방지
    tool_key = (
        response.tool_name,
        tuple(sorted(response.arguments.items()))
    )

    if tool_key in visited:
        print("동일한 Tool을 반복 호출하여 종료합니다.")
        break

    visited.add(tool_key)

    # 4. Tool 실행
    result = run_tool(
        response.tool_name,
        response.arguments
    )

    # 5. Observation 추가
    messages.append({
        "role": "tool",
        "content": result
    })

else:
    print("최대 반복 횟수를 초과했습니다.")

 

 

 

Trimming과 Conversation Summarization

ReAct루프는 매 스탭마다 관찰결과를 history에 덧붙임으로 메세지와 토큰이 게속 불어난다.

이는 비용, 지연이 됨으로 오래된 기록을 잘라내는 트리밍이 필요하다. 이때 첫 질문 즉 원래 목표는 반드시 보존해 모델이 목표를 잊지않도록 한다.  오래된 중간 기록은 대개 최종 판단에 덜 주요함으로 최근 몇개만 남기고 잘라낸다.

더 정교한 방법으로는 오래된 대화를 요약해서 압축하는 기법도 있다. 

MAX_STEPS = 6
MAX_HISTORY = 10      # 최근 10개 메시지만 유지

messages = [
    {"role": "user", "content": user_question}
]

for step in range(MAX_STEPS):

    # LLM 호출
    action = llm(messages)

    # 최종 답변이면 종료
    if action.type == "final_answer":
        print(action.content)
        break

    # Tool 실행
    result = run_tool(
        action.tool_name,
        action.arguments
    )

    # Observation 추가
    messages.append({
        "role": "tool",
        "content": result
    })

    # History Trimming
    if len(messages) > MAX_HISTORY:
        messages = [messages[0]] + messages[-9:]
MAX_HISTORY = 10

if len(messages) > MAX_HISTORY:

    # 오래된 대화
    old_messages = messages[:-5]

    # 최근 대화
    recent_messages = messages[-5:]

    # 오래된 내용을 LLM으로 요약
    summary = llm(
        "다음 대화를 핵심만 5줄 이내로 요약해줘.",
        old_messages
    )

    # 요약 + 최근 대화만 유지
    messages = [
        {
            "role": "system",
            "content": f"대화 요약:\n{summary}"
        }
    ] + recent_messages