LLM을 사용할 때 다양한 API로부터 얻은 결과를 사용하여 더 정확한 결과를 얻고 싶을 때에 Agent을 사용합니다. 어떤 상황에 어떤 API를 쓸지를 판단하기 위해서는 상황 인식(Context-Aware)에 기반한 Reasoning(추론: 상황에 대한 인식을 바탕으로 새로운 사실을 유도)이 필요합니다. 여기에서는 Agent를 이용하여 여러개의 API를 선택적으로 사용하는 한국어 Chatbot을 구현합니다. 이를 위한 Architecture는 아래와 같습니다.
- 사용자가 채팅창에서 질문을 입력하면 WebSocket 방식으로 Lambda(chat)에 전달됩니다.
- Lambda(chat)은 Agent 동작을 수행하는데, Action - Observation - Thought - Final Answer의 동작을 수행합니다. 만약 Thought에서 Final Answer를 얻지 못하면 Action부터 다시 수행합니다.
- Agent의 Action은 API를 이용해 필요한 정보를 얻어옵니다. 이때 사용하는 API에는 도서 추천, 날씨정보, 검색엔진이 있을 수 있습니다. 또한 시스템 시간을 가져오는 동작은 별도 API가 아닌 내부 함수를 이용해 구현할 수 있습니다.
- 만약 RAG의 정보가 필요한 경우에는 Action의 하나로 RAG을 이용하여 필요한 정보를 조회합니다.
- Observation/Thought/Final Answer를 위해 Agent는 prompt를 이용해 LLM에 요청을 보내고 응답을 받습니다.
- Agent가 Final Answer을 구하면 사용자에게 전달합니다.
아래에서 구현한 Agent는 zero-shot agent로 사용자의 질문에 따라 tools 리스트로부터 적절한 tool을 선택하여 활용합니다. tool은 함수 또는 API로 구현됩니다. 선택된 tool로 원하는 작업을 완료하지 못하면 다른 tool을 추가로 활용합니다.
Agent란 주변 환경을 탐지하여 자율적으로 동작하는 장치 또는 프로그램을 의미합니다. 인공지능을 이용한 지능형 에이전트는 센서를 이용하여 주변 환경을 자각하여 Actuator를 이용하여 적절한 행동을 합니다. agent의 라틴어 어원인 agere의 뜻은 to do 또는 to act의 의미를 가지고 있습니다.
Agent를 이용하면 LLM 결과를 향상시킬 수 있습니다.
-
Andrew Ng: What's next for AI agentic workflows ft. Andrew Ng of AI Fund
-
AI Pioneer Shows The Power of AI AGENTS - "The Future Is Agentic"
- Robust technology: Reflection, Tool use
- Reflection: coder agent가 생성한 코드를 critic agent가 확인하면서 코드를 개선하는 방법
- Tool use
- Emerging technology: Planning, Multi-agent collaboration
- Planning
- Multi-agent collaboration
An Introduction to LLM Agents | From OpenAI Function Calling to LangChain Agents 참조
- Thinking: What to do + planning (order, priority...)
- Acting: used tools, search, browser, etc...
- What is an Agent? LLM + Tools
- LLM: predicts next word/sentence
- Tool: perform actions in the real world
LangChain의 Agent Type와 같이, Agent는 Tool Calling, OpenAI tools, ReAct와 같은 방법을 이용해 구현할 수 있습니다.
- ReAct의 경우에 직관적이고 이해가 쉬운 반면에 Multi-Input Tools, Parallel Function Calling과 같은 기능을 제공하지 않고 있습니다.
- OpenAI tools는 가장 많이 사용되고 있고, 다양한 사례를 가지고 있습니다.
- Tool Calling은 OpenAI tools와 유사한 방식으로 Anthropic, Gemini등을 지원하고 있습니다.
LangChain의 ReAct를 이용하여 Agent를 정의합니다. ReAct에 대한 자세한 내용은 ReAct.md을 참조합니다. Agent의 동작은 Action, Observation, Thought와 같은 동작을 반복적으로 수행하여 Final Answer를 얻습니다. Agent에 대한 자세한 내용은 agent.md을 참조합니다.
최종 답변에 한 번에 도달하는 대신에 여러 단계의 thought(사고)-action(행동)-observation(관찰) 과정을 통해 과제를 해결할 수 있고, 환각도 줄일 수 있습니다. 이때의 한 예는 아래와 같습니다.
Thought -> Action (Search) -> Observation -> Thought - Action (Search) -> Observation -> Thought -> Final Result
- LLM으로 Tool들로 부터 하나의 Action을 선택합니다. 이때에는 tool의 description을 이용합니다.
- Action을 수행합니다.
- Action결과를 관찰(Observation)합니다.
- 결과가 만족스러운지 확인(Thought) 합니다. 만족하지 않으면 반복합니다.
ReAct를 위한 Prompt 에제는 prompt.md을 참조합니다. 한글화한 ReAct prompt는 아래와 같습니다.
PromptTemplate.from_template("""다음은 Human과 Assistant의 친근한 대화입니다. Assistant은 상황에 맞는 구체적인 세부 정보를 충분히 제공합니다. Assistant의 이름은 서연이고, 모르는 질문을 받으면 솔직히 모른다고 말합니다.
사용할 수 있는 tools은 아래와 같습니다:
{tools}
다음의 format을 사용하세요.:
Question: 답변하여야 할 input question
Thought: you should always think about what to do.
Action: 해야 할 action로서 [{tool_names}]에서 tool의 name만을 가져옵니다.
Action Input: action의 input
Observation: action의 result
... (Thought/Action/Action Input/Observation을 5번 반복 할 수 있습니다.)
Thought: 나는 이제 Final Answer를 알고 있습니다.
Final Answer: original input에 대한 Final Answer
너는 Human에게 해줄 응답이 있거나, Tool을 사용하지 않아도 되는 경우에, 다음 format을 사용하세요.:
'''
Thought: Tool을 사용해야 하나요? No
Final Answer: [your response here]
'''
Begin!
Question: {input}
Thought:{agent_scratchpad}
""")
apis.md에서는 도서 검색, 날씨, 시간과 같은 유용한 검색 API에 대해 설명하고 있습니다.
- get_book_list: 도서 정보 검색 (교보)
- get_current_time: 시스템 날짜와 시간
- get_weather_info: 현재의 날씨 정보
- search_by_tavily: 가벼운 인터넷 검색
- search_by_opensearch: RAG에서 기술적인 자료 검색
LangChain의 Prebuilt component인 create_react_agent을 이용합니다.
def run_agent_react(connectionId, requestId, chat, query):
prompt_template = get_react_prompt_template(agentLangMode)
# create agent
isTyping(connectionId, requestId)
agent = create_react_agent(chat, tools, prompt_template)
agent_executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True,
handle_parsing_errors=True,
max_iterations = 5
)
# run agent
response = agent_executor.invoke({"input": query})
msg = readStreamMsg(connectionId, requestId, response['output'])
msg = response['output']
return msg
langsmith.md은 LangSmith에서 발급한 api key를 설정하여, agent의 동작을 디버깅할 수 있도록 해줍니다.
Agent 사용시 Tool을 선택하고, Observation과 Thought을 통해 Action으로 얻어진 결과가 만족스러운지 확인하는 과정이 필요합니다. 따라서 LLM의 성능은 Agent의 결과와 밀접한 관계가 있습니다. Claude Sonnet으로 Agent를 만든 결과가 일반적으로 Claude Haiku보다 우수하여, Sonnet을 추천합니다.
LangChain의 Tool calling agent은 Multi-Input Tools, Parallel Function Calling와 같은 다양한 기능을 제공하고 있습니다. 상세한 내용은 toolcalling.md을 참조합니다.
- Chat models에 따르면, BedrockChat은 Tool calling agent을 지원하고 있지 않습니다.
- ChatBedrock API는 Agent를 선언할 수 있으나, 아래의 LangSmith 결과와 같이 Tool Calling에 대한 응답을 얻지 못하고 있습니다.
- Tool calling은 ReAct에서 지원하지 못하고 있는 Multi-Input Tools, Parallel Function Calling등을 지원하고 있으므로, 향후 지원을 기대해 봅니다.
LangGraph는 agent를 생성하고 여러개의 Agent가 있을때의 흐름을 관리하기 위한 LangChain의 Extention입니다. 이를 통해 cycle flow를 생성할 수 있으며, 메모리가 내장되어 Agent를 생성에 도움을 줍니다. 상세한 내용은 LangGraph guide을 참조합니다.
LangChain과 LangGraph Agent를 비교하면 아래와 같습니다.
- LangChain Agent는 Resoning/Action을 효과적으로 수행하고 매우 powerful 합니다.
- LLM의 성능이 매우 중요하므로 LLM 모델을 잘 선택하여야 합니다. 성능이 더 좋은 모델은 일반적으로 더 많은 연산시간을 필요로 합니다. (예 지연시간: Opus > Sonnet > Haiku)
- 각 Tool의 invocation을 위해서 매번 LLM을 호출하여야 합니다. Tool을 연속적으로 실행(Observation 없이)할 때에는 불필요한 시간이 될 수 있습니다.
- 한번에 한개의 step을 수행하고 parallel call을 지원하지 않습니다.
- LangGraph를 이용한 Agent는 복잡한 process를 State Machine을 이용해 구현할 수 있으며, Multi-Agent 구조에 적합합니다.
Agent는 아래와 같은 Components를 가지고 있습니다.
- Memory: Shared state across the graph
- Tools: Nodes can call tools and modify state
- Planning: Edges can route control flow based on LLM decisions
참조: Building and Testing Reliable Agents: chain/agent 비교하여 개념 설명
Introduction to LangGraph은 Agent 종류별로 설명하고 있습니다. 또한, agent-executor.md에서는 LangGraph를 이용하여 Tool을 실행하는 Agent Executor에 대해 설명하고 있습니다. 자세한 구현한 코드는 agent-executor.ipynb와 lambda-chat를 참조합니다.
Agent를 위한 Class인 AgentState와 tool을 비롯한 각 노드를 정의합니다.
class ChatAgentState(TypedDict):
messages: Annotated[list, add_messages]
tool_node = ToolNode(tools)
def should_continue(state: ChatAgentState) -> Literal["continue", "end"]:
messages = state["messages"]
last_message = messages[-1]
if not last_message.tool_calls:
return "end"
else:
return "continue"
def call_model(state: ChatAgentState):
prompt = ChatPromptTemplate.from_messages(
[
("system",
"다음의 Human과 Assistant의 친근한 이전 대화입니다."
"Assistant은 상황에 맞는 구체적인 세부 정보를 충분히 제공합니다."
"Assistant의 이름은 서연이고, 모르는 질문을 받으면 솔직히 모른다고 말합니다."
"최종 답변에는 조사한 내용을 반드시 포함하여야 하고, <result> tag를 붙여주세요.",
),
MessagesPlaceholder(variable_name="messages"),
]
)
chain = prompt | model
response = chain.invoke(state["messages"])
return {"messages": [response]}
각 Node state를 정의합니다.
workflow = StateGraph(AgentState)
workflow.add_node("agent", call_model)
workflow.add_node("action", tool_node)
workflow.add_edge(START, "agent")
workflow.add_conditional_edges(
"agent",
should_continue,
{
"continue": "action",
"end": END,
},
)
workflow.add_edge("action", "agent")
app = workflow.compile()
Graph로 Agent를 정의하고 아래와 같이 실행합니다.
from langchain_core.messages import HumanMessage
inputs = [HumanMessage(content="강남역 맛집 알려줘")]
for event in app.stream({"messages": inputs}, stream_mode="values"):
event["messages"][-1].pretty_print()
생성된 Graph는 아래와 같습니다.
langgraph-agent.md에서는 LangGraph를 이용해 Agent를 생성하는 방법을 설명합니다.
Reflection: reflection-agent.md에서는 LangGraph를 이용해 Reflection을 반영하는 Agent를 생성하는 방법을 설명하고 있습니다.
이 솔루션을 사용하기 위해서는 사전에 아래와 같은 준비가 되어야 합니다.
- AWS Account 생성에 따라 계정을 준비합니다.
본 실습에서는 Oregon 리전 (us-west-2)을 사용합니다. 인프라 설치에 따라 CDK로 인프라 설치를 진행합니다.
실행한 결과는 아래와 같습니다.
- "안녕"이라고 입력하고, 동작하는것을 LangSmith로 확인합니다.
Tools에 여러개의 API를 등록해 놓았지만, LLM이 Tool을 사용할 필요가 없다고 생각하면 LLM이 답변을 수행합니다.
이때의 로그는 아래와 같습니다.
Thought: Tool을 사용해야 하나요? No
Final Answer: 안녕하세요! 무엇을 도와드릴까요?
- "서울 날씨는?"를 입력하면 현재의 날씨 정보를 조회하여 알려줍니다.
- "오늘 날짜 알려줘"를 하면 시스템 날짜를 확인하여 알려줍니다.
- "서울 여행에 대한 책을 추천해줘"를 입력하면 교보문고의 검색 API를 이용하여 관련책을 검색하여 추천합니다.
- 오늘 날짜를 알수 있으므로 "올해 크리스마스까지 몇일이 남아 있어?"와 같은 질문에 정확히 답변할 수 있습니다.
- "서울과 부산의 날씨를 알려줘"와 같이 서울과 부산의 결과를 각각 검색한 후에 아래와 같은 결과를 얻습니다.
이때의 LangSmith의 로그를 확인하면 서울과 부산과 대한 검색후 결과를 생성하였습니다. (get_weather_info를 서울과 부산에 대해 각각 호출함)
- "미국 여행을 하려고 해. 추천해줘 어떻게 여행하는게 좋아?"로 질문을 하면 아래와 같이 로스웬젤레스를 추천해주는데 날씨정보도 같이 전달하고 있습니다.
상세한 내부 동작은 아래와 같습니다.
- 질문에 필요한 정보를 찾습니다. 여기에서는 여행일정, 방문도시, 관심사에 선택했습니다.
- 현재 가지고 있는 api중에 관련된 것을 찾았는데, 도서정보를 찾는 API(get_product_list)가 선택되었습니다.
- "미국 여행 가이드 북"을 검색해서 도서 정보를 얻었습니다.
- 가이드된 도서 목록에서 미국 서부 지역, 뉴욕을 선택하고 추가 정보를 찾으려고 합니다.
- API중에 get_weather_info을 선택해서, Los Angeles 를 검색합니다.
- 가이드 북과 날씨 정보를 조합하여 Final Answer로 여행 계획을 추천합니다.
아래는 LangSmith에서 추출한 로그 입니다.
Question: 미국 여행을 하려고 해. 추천해줘 어떻게 여행하는게 좋아?
Thought:Thought: 미국 여행에 대한 구체적인 정보가 필요할 것 같습니다. 여행 일정, 방문 도시, 관심사 등에 대해 더 자세히 알아보는 것이 좋겠습니다.
Action: get_product_list
Action Input: 미국 여행 가이드북
Observation: 추천 도서는 아래와 같습니다.
[국내도서]미국 서부 셀프트래블(2022-2023), URL: https://product.kyobobook.co.kr/detail/S000060626443
[eBook]미국 서부 셀프트래블(2022-2023), URL: https://ebook-product.kyobobook.co.kr/dig/epd/ebook/E000002960164
[국내도서]버킷리스트 미국 서부, URL: https://product.kyobobook.co.kr/detail/S000001981279
[eBook]살아보고 싶다면, 포틀랜드, URL: https://ebook-product.kyobobook.co.kr/dig/epd/ebook/E000003234513
[국내도서]뉴욕 영화 가이드북, URL: https://product.kyobobook.co.kr/detail/S000001913689
Thought: Thought: 여행 가이드북 목록을 보니 미국 서부 지역과 뉴욕에 대한 정보가 있습니다. 하지만 구체적인 여행 계획을 세우기 위해서는 더 자세한 정보가 필요할 것 같습니다.
Action: get_weather_info
Action Input: Los Angeles
Observation: 로스앤젤레스의 현재 날씨의 특징은 Clouds이며, 현재 온도는 13.85도 이고, 최저온도는 11.85도, 최고 온도는 15.6도 입니다. 현재 습도는 85% 이고, 바람은 초당 2.06 미터 입니다. 구름은 100% 입니다.
Thought: 미국 여행에 대한 구체적인 정보를 모으기 위해 여러 도구를 사용해 보았습니다. 가이드북 목록을 통해 인기 여행지와 관심 분야를 파악할 수 있었고, 날씨 정보를 통해 여행 시기와 준비물을 고려할 수 있었습니다. 이제 이 정보들을 종합하여 여행 계획을 세울 수 있을 것 같습니다.
Final Answer: 미국 여행을 계획할 때는 다음 사항들을 고려하는 것이 좋습니다.
1. 여행 지역 선정: 가이드북 목록에서 보았듯이 서부 지역(로스앤젤레스, 포틀랜드 등)과 뉴욕이 인기 여행지입니다. 관심사와 일정에 맞춰 방문 도시를 정하세요.
2. 계절 및 날씨: 로스앤젤레스 날씨 정보를 보니 현재 구름이 많고 온도는 10도 중반입니다. 여행 시기에 따라 날씨가 다르므로 이에 맞춰 옷차림과 활동을 계획하는 것이 좋습니다.
3. 교통 및 숙박: 렌터카 이용이 편리할 수 있습니다. 도시 간 이동 시에는 기차나 항공편을 이용할 수 있습니다. 숙박 시설은 호텔, 모텔, 에어비앤비 등 다양한 선택지가 있습니다.
4. 관광명소 및 활동: 뉴욕 영화 가이드북에서 보듯 영화 촬영지 방문, 미술관 관람 등 취향에 맞는 활동을 계획하세요.
이때의 결과는 아래와 같습니다.
- "서울 여행에 대한 책을 추천해줘"로 입력후 결과를 확인합니다.
아래와 같이 get_book_list를 이용해 얻어온 도서 정보와 search_by_tavily로 얻어진 정보를 통합하였음을 알 수 있습니다.
-
다양한 API사용해 보기 위하여 "서울에서 부산으로 여행하려고 하고 있어. 서울과 부산의 온도를 비교해줘. 그리고 부산가면서 읽을 책 추천해주고, 부산가서 먹을 맛집도 찾아줘."로 입력 후 결과를 확인합니다.
LangSmith의 로그를 보면 아래와 같이 get_weather_info로 서울/부산의 날씨를 검색하고, get_book_list을 이용해 도서 목록을 가져오고, search_by_tavily로 맛집 검색한 결과를 보여주고 있습니다.
- error_code.pdf를 다운로드 한 후에 채팅창의 파일 아이콘을 선택하여 업로드 합니다. 이후 "보일러 에러코드에 대해 설명해줘."라고 입력하몬 RAG에서 얻어진 결과를 이용해 아래와 같이 답변합니다.
LangSmith의 로그를 보면 아래와 같이 search_by_opensearch(RAG)를 호출하여 얻은 정보로 답변을 생성했음을 알 수 있습니다.
더이상 인프라를 사용하지 않는 경우에 아래처럼 모든 리소스를 삭제할 수 있습니다.
-
API Gateway Console로 접속하여 "rest-api-for-llm-agent", "ws-api-for-llm-agent"을 삭제합니다.
-
Cloud9 Console에 접속하여 아래의 명령어로 전체 삭제를 합니다.
cd ~/environment/llm-agent/cdk-llm-agent/ && cdk destroy --all
LangChain과 LangGraph를 이용해 한국어 Chatbot Agent을 만들었습니다. Agent를 사용함으로써 다양한 API를 문맥(Context)에 따라 활용할 수 있었습니다. 다만 API를 여러번 호출함으로 인한 지연시간이 증가하고, prompt에 넣을 수 있는 Context 길이 제한으로 검색이나 RAG 결과를 일부만 넣게 되는 제한이 있습니다.
Building Context-Aware Reasoning Applications with LangChain and LangSmith
Using LangChain ReAct Agents for Answering Multi-hop Questions in RAG Systems
Intro to LLM Agents with Langchain: When RAG is Not Enough
LangChain 🦜️🔗 Tool Calling and Tool Calling Agent 🤖 with Anthropic
Automating tasks using Amazon Bedrock Agents and AI