iBetter Books
수정

기본 에이전트 만들기

LangChain으로 기본 에이전트를 만들어봅니다. 간단한 도구부터 시작해서 점점 기능을 추가합니다.

가장 간단한 에이전트

from langchain_ollama import OllamaLLMfrom langchain.agents import create_react_agent, AgentExecutorfrom langchain.tools import Toolfrom langchain.prompts import PromptTemplate# 1. LLM 준비llm = OllamaLLM(model="llama4")# 2. 도구 정의def greet(name: str) -> str:    """이름으로 인사합니다."""    return f"안녕하세요, {name}님!"tools = [    Tool(        name="greet",        func=greet,        description="이름을 받아 인사말을 생성합니다. 입력: 이름"    )]# 3. 프롬프트PROMPT = """Answer the following questions as best you can.You have access to the following tools:{tools}Use the following format:Question: the input question you must answerThought: you should always think about what to doAction: the action to take, should be one of [{tool_names}]Action Input: the input to the actionObservation: the result of the action... (this Thought/Action/Action Input/Observation can repeat N times)Thought: I now know the final answerFinal Answer: the final answer to the original input questionBegin!Question: {input}Thought: {agent_scratchpad}"""prompt = PromptTemplate.from_template(PROMPT)# 4. 에이전트 생성agent = create_react_agent(llm, tools, prompt)# 5. 실행기executor = AgentExecutor(    agent=agent,    tools=tools,    verbose=True)# 6. 실행result = executor.invoke({"input": "철수에게 인사해줘"})print(result["output"])

여러 도구 조합

from langchain_ollama import OllamaLLMfrom langchain.agents import create_react_agent, AgentExecutorfrom langchain.tools import Toolfrom langchain.prompts import PromptTemplate# 도구들def add(a_b: str) -> str:    """두 숫자를 더합니다. 입력 형식: '숫자1, 숫자2'"""    try:        a, b = map(float, a_b.split(","))        return str(a + b)    except:        return "올바른 형식: '숫자1, 숫자2'"def multiply(a_b: str) -> str:    """두 숫자를 곱합니다. 입력 형식: '숫자1, 숫자2'"""    try:        a, b = map(float, a_b.split(","))        return str(a * b)    except:        return "올바른 형식: '숫자1, 숫자2'"def get_length(text: str) -> str:    """텍스트의 길이를 반환합니다."""    return str(len(text))tools = [    Tool(name="add", func=add, description="두 숫자 덧셈. 입력: '숫자1, 숫자2'"),    Tool(name="multiply", func=multiply, description="두 숫자 곱셈. 입력: '숫자1, 숫자2'"),    Tool(name="length", func=get_length, description="텍스트 길이 계산. 입력: 텍스트")]# 에이전트 생성llm = OllamaLLM(model="llama4")prompt = PromptTemplate.from_template(PROMPT)  # 위와 동일agent = create_react_agent(llm, tools, prompt)executor = AgentExecutor(agent=agent, tools=tools, verbose=True)# 복합 질문result = executor.invoke({    "input": "'Hello World'의 글자 수에 10을 곱하면?"})print(result["output"])

실행 과정

> Entering new AgentExecutor chain...
Thought: 먼저 'Hello World'의 글자 수를 구해야 한다.
Action: length
Action Input: Hello World
Observation: 11

Thought: 글자 수는 11이다. 이제 10을 곱한다.
Action: multiply
Action Input: 11, 10
Observation: 110.0

Thought: 계산 완료.
Final Answer: 'Hello World'의 글자 수는 11이고, 10을 곱하면 110입니다.

> Finished chain.

@tool 데코레이터

더 간편하게 도구를 정의합니다.

from langchain.tools import tool@tooldef search_web(query: str) -> str:    """웹에서 정보를 검색합니다."""    # 실제로는 검색 API 호출    return f"'{query}'에 대한 검색 결과입니다."@tooldef get_current_time() -> str:    """현재 시간을 반환합니다."""    from datetime import datetime    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")@tooldef calculate(expression: str) -> str:    """수학 표현식을 계산합니다. 예: '2 + 3 * 4'"""    try:        result = eval(expression)        return str(result)    except Exception as e:        return f"계산 오류: {e}"# 도구 목록tools = [search_web, get_current_time, calculate]# 에이전트 생성agent = create_react_agent(llm, tools, prompt)executor = AgentExecutor(agent=agent, tools=tools, verbose=True)# 실행result = executor.invoke({"input": "현재 시간이 몇 시야?"})

도구 설명의 중요성

도구의 description이 에이전트의 도구 선택에 결정적입니다.

# 나쁜 예@tooldef func1(x: str) -> str:    """함수1"""  # 설명이 없어 언제 쓸지 모름    return x# 좋은 예@tooldef calculate_tax(income: str) -> str:    """    연소득을 입력받아 예상 세금을 계산합니다.    입력: 연소득 (원 단위, 숫자만)    출력: 예상 세금 (원)    예: '50000000' -> '5000000'    """    income_val = float(income)    tax = income_val * 0.1  # 단순화    return str(int(tax))

AgentExecutor 옵션

executor = AgentExecutor(    agent=agent,    tools=tools,    # 출력 옵션    verbose=True,           # 과정 출력    return_intermediate_steps=True,  # 중간 단계 반환    # 실행 제어    max_iterations=10,      # 최대 반복 횟수    max_execution_time=60,  # 최대 실행 시간 (초)    early_stopping_method="generate",  # 조기 종료 방식    # 오류 처리    handle_parsing_errors=True,  # 파싱 오류 처리)# 중간 단계 확인result = executor.invoke({"input": "10 + 20을 계산해줘"})print("최종 답변:", result["output"])print("중간 단계:", result.get("intermediate_steps", []))

오류 처리

executor = AgentExecutor(    agent=agent,    tools=tools,    verbose=True,    handle_parsing_errors=True  # 파싱 오류 자동 처리)# 또는 커스텀 오류 처리def handle_error(error):    return f"오류 발생: {error}. 다시 시도하세요."executor = AgentExecutor(    agent=agent,    tools=tools,    handle_parsing_errors=handle_error)

콜백으로 모니터링

from langchain.callbacks.base import BaseCallbackHandlerclass AgentMonitor(BaseCallbackHandler):    """에이전트 모니터링"""    def on_agent_action(self, action, **kwargs):        print(f"🔧 도구 사용: {action.tool}")        print(f"   입력: {action.tool_input}")    def on_agent_finish(self, finish, **kwargs):        print(f"✅ 완료: {finish.return_values}")    def on_tool_start(self, tool, input_str, **kwargs):        print(f"⚙️ 도구 시작: {tool}")    def on_tool_end(self, output, **kwargs):        print(f"📤 도구 결과: {output[:100]}...")# 콜백 적용executor = AgentExecutor(    agent=agent,    tools=tools,    callbacks=[AgentMonitor()],    verbose=False  # 기본 출력 끄기)result = executor.invoke({"input": "현재 시간 알려줘"})

전체 예제

from langchain_ollama import OllamaLLMfrom langchain.agents import create_react_agent, AgentExecutorfrom langchain.tools import toolfrom langchain.prompts import PromptTemplate# 도구 정의@tooldef search(query: str) -> str:    """인터넷에서 정보를 검색합니다."""    return f"'{query}' 검색 결과: Python은 프로그래밍 언어입니다."@tooldef calculator(expression: str) -> str:    """수학 계산을 수행합니다. 예: '2 + 3'"""    try:        return str(eval(expression))    except:        return "계산 오류"@tooldef translator(text: str) -> str:    """영어를 한국어로 번역합니다."""    # 실제로는 번역 API 사용    translations = {        "hello": "안녕하세요",        "world": "세계",        "python": "파이썬"    }    lower_text = text.lower()    return translations.get(lower_text, f"'{text}'의 번역")# 프롬프트PROMPT = """Answer the following questions as best you can. Use Korean for your final answer.You have access to the following tools:{tools}Use the following format:Question: the input question you must answerThought: you should always think about what to doAction: the action to take, should be one of [{tool_names}]Action Input: the input to the actionObservation: the result of the action... (this Thought/Action/Action Input/Observation can repeat N times)Thought: I now know the final answerFinal Answer: the final answer to the original input question (in Korean)Begin!Question: {input}Thought: {agent_scratchpad}"""prompt = PromptTemplate.from_template(PROMPT)# 에이전트 생성llm = OllamaLLM(model="llama4")tools = [search, calculator, translator]agent = create_react_agent(llm, tools, prompt)executor = AgentExecutor(    agent=agent,    tools=tools,    verbose=True,    max_iterations=5,    handle_parsing_errors=True)# 테스트questions = [    "100 나누기 4는?",    "Python이 뭐야?",    "Hello를 한국어로 번역해줘"]for q in questions:    print(f"\n질문: {q}")    result = executor.invoke({"input": q})    print(f"답변: {result['output']}")    print("-" * 50)

정리

구성 요소 역할
LLM 추론 엔진
Tool 외부 기능 실행
Prompt 에이전트 행동 지침
AgentExecutor 실행 및 관리

다음 단계

기본 에이전트를 만들었습니다. 다음 장에서는 LangChain 내장 도구를 활용합니다.