Langchain의 agents를 사용하면 보다 간단히 agnet를 만들 수 있다.

 

1. Tool 및 llm 정의

from langchain.agents import Tool
from langchain.agents.agent_types import AgentType

def add_tool(input_str : str) -> str:
    # print(input_str)
    try:
        arr = list(map(int, input_str.split()))
        return str(sum(arr))
    except Exception as e:
        return f"에러: {str(e)}"
        
def chat_tool(input_st: str):
    return llm.invoke(input_st)




api_key = ''
model = 'gpt-4o-mini'

llm = ChatOpenAI(api_key=api_key, model=model)

# description은 툴의 설명을 적으며 어떤 상황에서 툴을 사용하게 될지, 입력은 어떻게 정의할지 작성한다.
# func는 해당 툴을 사용할 때 어떤 함수를 사용할지 정의한다.
tools = [
    Tool( name= 'AddTool', func=add_tool, description="두 숫자를 더합니다. 입력은 두 숫자를 공백으로 구분한 문자열로 입력합니다. 입력 형식: '3 5'"),
    Tool( name= 'ChatTool', func=chat_tool
         , description="일반적인 질문이나 대화에 답변합니다. 계산, 검색, 도구 실행이 필요하지 않은 경우 사용하세요. 입력 예시: '오늘 기분이 어때?' 또는 'AI는 어떻게 작동해?'")
]

 

2. agent 작성

from langchain_community.chat_models import ChatOpenAI
from langchain.agents import initialize_agent

# llm 기반의 agent트 생성
# agentType은 분류되지 않은 추론형
# verbose agent의 동작 과정 확인
agent = initialize_agent(
    tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)

 

Agent 타입에 대한 설명

https://api.python.langchain.com/en/latest/agents/langchain.agents.agent_types.AgentType.html

 

3. agent 실행

response = agent.run("3하고 7을 더해줘.")
print(response)

 

결과

툴을 잘 선택했지만 input Type에 대한 에러가 발생했다. 

확인해보니 "'3 5'" 와 같이 입력이 들어가서 description을 수정해주니 정상 동작했다.
before : .....입력 형식: '3 5'"

after : 입력 형식: 3 5"

또한 아래와 같이 Exception 발생 시 Exception을 추론하여 재시도하며 이후 마지막에는 다른 Tool(ChatTool)을 사용하여 결과를 만들어내는 것을 확인  할 수 있다.


> Entering new AgentExecutor chain...
3하고 7을 더하는 계산이 필요하다.  
Action: AddTool  
Action Input: '3 7'  
Observation: 에러: invalid literal for int() with base 10: "'3"
Thought:입력 형식이 잘못된 것 같다. 숫자들에 불필요한 따옴표가 포함되어 있는 것 같다. 따옴표 없이 다시 시도해 보아야겠다.  
Action: AddTool  
Action Input: '3 7'  
Observation: 에러: invalid literal for int() with base 10: "'3"
Thought:입력 형식이 여전히 잘못된 것 같다. 따옴표가 여전히 포함되어 있는 것 같지 않지만, 정확한 문제는 확인해봐야겠다.  
Action: AddTool  
Action Input: '3 7'  
Observation: 에러: invalid literal for int() with base 10: "'3"
Thought:입력 형식에 문제가 있는 것 같다. 두 숫자를 더하는 방법을 다시 살펴봐야겠다.  
Action: AddTool  
Action Input: '3 7'  
Observation: 에러: invalid literal for int() with base 10: "'3"
Thought:입력 형식에 문제가 발생하고 있다. 숫자를 더하기 위해 입력을 정확하게 조정해야 할 것 같다.  
Action: AddTool  
Action Input: '3 7'  
Observation: 에러: invalid literal for int() with base 10: "'3"
Thought:입력 형식이 계속해서 잘못된 결과를 초래하고 있다. 문제를 해결하기 위해 입력을 다시 확인하고 수정해야 할 것 같다.  
Action: AddTool  
Action Input: '3 7'  
Observation: 에러: invalid literal for int() with base 10: "'3"
Thought:입력 형식에 문제가 발생하고 있는 것 같다. 계속해서 같은 오류가 발생하고 있으므로, 다른 방법을 통해 질문에 답변해야 할 것 같다.  
Action: ChatTool  
Action Input: '3하고 7을 더해줘.'  
Observation: content='3과 7을 더하면 10입니다.' additional_kwargs={} response_metadata={'token_usage': {'completion_tokens': 12, 'prompt_tokens': 17, 'total_tokens': 29, 'completion_tokens_details': {'accepted_prediction_tokens': 0, 'audio_tokens': 0, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 0}, 'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-mini', 'system_fingerprint': 'fp_80cf447eee', 'finish_reason': 'stop', 'logprobs': None} id='run-3c1360fb-0f39-4f8c-9932-95fe87de0518-0'
Thought:I now know the final answer.  
Final Answer: 3과 7을 더하면 10입니다.

> Finished chain.
3과 7을 더하면 10입니다.

 

 

https://github.com/Kmmanki/RAG_inflearn/blob/main/Codes/2-3AI_Agent_langchain.ipynb

 

RAG_inflearn/Codes/2-3AI_Agent_langchain.ipynb at main · Kmmanki/RAG_inflearn

인프런 RAG를 활용한 LLM Application. Contribute to Kmmanki/RAG_inflearn development by creating an account on GitHub.

github.com

 

 

 todo:

  • Agent들의 타입과 동작 방식 찾아보기
  • 제공하고 있는 통합 Tool들이 무엇이 있는지 확인하고 테스트 해보기

AI Agent

AI 에이전트는 사람의 개입 없이 특정 작업을 수행하는 자율 지능형 시스템

 


TOOL

AI Agent가 사용하게 되는 도구 Ex) 날씨 API, google 캘린더 API 등


Python을 사용한 AI Agent

 

1. 툴 작성

2. 툴 선택을 위한 prompt 작성

3. 툴 선택 prompt를 사용 llm 결과 반환

4. 툴의 사용

5. 4번의 결과로 답변 llm 생성

 

1. 툴 작성

# 입력 받는 타입으 str, 그 외 값을 받는가면 str로 casting
def add_too(input_str : str) -> str:
    try:
        arr = list(input_str.split())
        return str(sum(arr))
    except Exception as e:
        return f"에러: {str(e)}"

 

2. 툴 선택을 위한 Prompt 작성

# 일반대화와 두 수를 더하는 2가지의 TOOL 정의
TOOL_PROMPT_DISC="""
당신은 다음 도구를 사용할 수 있습니다:

도구 이름: AddTool
기능: 두 숫자를 더합니다.
입력 예시: "3 5"


도구 이름: ChatTool
기능: 일반적인 질문이나 대화에 답변합니다. 계산, 검색, 도구 실행이 필요하지 않은 경우 사용하세요.
입력 예시: "오늘 기분이 어때?" 또는 "AI는 어떻게 작동해?"

사용자가 질문하면, 어떤 도구를 사용할지 판단하고 다음 형식으로 대답하세요:

사용할 도구: <도구 이름>
입력값: <도구에 줄 입력값>

사용자의 질문: "{question}"
"""

 

3. 툴 선택 Prompt를 사용한 LLM 결과 출력

from langchain_community.chat_models import ChatOpenAI

api_key = 'api_key'
model = 'gpt-4o-mini'
llm = ChatOpenAI(api_key=api_key, model=model)
query = "3더하기 5의 값은 뭐지?"

TOOL_PROMPT = TOOL_PROMPT_DISC.format(question=query)
TOOL_RESULT = llm.invoke(TOOL_PROMPT)

 

4. 툴의 사용

import re
match = re.search(r"사용할 도구:\s*(\w+)\s*입력값:\s*[\"']?(.+?)[\"']?$", TOOL_RESULT.content.strip(), re.DOTALL)

tool = match.group(1)
tool_input = match.group(2)
print(tool)
print(tool_input)

if tool == 'AddTool':
    tool_result = add_tool(tool_input)
    print(tool_result)
elif tool == 'ChatTool':
    llm.invoke(tool_input)

 

 

5. 툴의 결과로 답변생성

import re
match = re.search(r"사용할 도구:\s*(\w+)\s*입력값:\s*[\"']?(.+?)[\"']?$", TOOL_RESULT.content.strip(), re.DOTALL)

tool = match.group(1)
tool_input = match.group(2)
print(tool)
print(tool_input)

if tool == 'AddTool':
    tool_result = add_tool(tool_input)
    print(tool_result)
    FINAL_PROMPT_DISC = """
        사용자의 질문: "{question}"
        도구 실행 결과: {result}
        이제 사용자에게 자연어로 대답하세요.
    """
    FINAL_PROMPT = FINAL_PROMPT_DISC.format(question = query, result=tool_result)
    print(llm.invoke(FINAL_PROMPT))
elif tool == 'ChatTool':
    llm.invoke(tool_input)

 

 

 

 

.py로 만든 파일

from langchain_community.chat_models import ChatOpenAI
import re

api_key = ''
model = 'gpt-4o-mini'
llm = ChatOpenAI(api_key=api_key, model=model)



######## prompt
# 도구 선택 프롬프트
tool_prompt_disc="""
당신은 다음 도구를 사용할 수 있습니다:

도구 이름: AddTool
기능: 두 숫자를 더합니다.
입력 예시: "3 5"


도구 이름: ChatTool
기능: 일반적인 질문이나 대화에 답변합니다. 계산, 검색, 도구 실행이 필요하지 않은 경우 사용하세요.
입력 예시: "오늘 기분이 어때?" 또는 "AI는 어떻게 작동해?"

사용자가 질문하면, 어떤 도구를 사용할지 판단하고 다음 형식으로 대답하세요:

사용할 도구: <도구 이름>
입력값: <도구에 줄 입력값>

사용자의 질문: "{question}"
"""

final_prompt_disc="""
사용자의 질문: "{question}"
도구 실행 결과: {result}
이제 사용자에게 자연어로 대답하세요.
"""

########

def add_tool(input_str : str) -> str:
    try:
        arr = list(map(int, input_str.split()))
        return str(sum(arr))
    except Exception as e:
        return f"에러: {str(e)}"
    
def run_agent(query: str):
    tool_prompt = tool_prompt_disc.format(question=query)
    tool_result = llm.invoke(tool_prompt)

    match = re.search(r"사용할 도구:\s*(\w+)\s*입력값:\s*[\"']?(.+?)[\"']?$", tool_result.content.strip(), re.DOTALL)
    tool = match.group(1)
    tool_input = match.group(2)
    print(tool_result.content)
    if tool == "AddTool":
        add_result = add_tool(tool_input)
        final_prompt = final_prompt_disc.format(question = query, result=add_result)
        return llm.invoke(final_prompt).content
    elif tool == "ChatTool":
        final_prompt = final_prompt_disc.format(question = query, result=tool_input)
        return llm.invoke(final_prompt).content
    
if __name__ == '__main__':
    query="3 더하기 5는 ?"
    # query="오늘 저녁메뉴는 뭘 먹는게 좋을까?
    print("사용자 질문 :", query)
    result = run_agent(query)
    print("llm 답변: ",result)

 

addTool을 사용할만한 질문
chatTool을 사용할만한 질문

 

https://github.com/Kmmanki/RAG_inflearn/blob/main/Codes/2-1AI_Agent_python.ipynb

 

RAG_inflearn/Codes/2-1AI_Agent_python.ipynb at main · Kmmanki/RAG_inflearn

인프런 RAG를 활용한 LLM Application. Contribute to Kmmanki/RAG_inflearn development by creating an account on GitHub.

github.com

 

'AI????, LLM???' 카테고리의 다른 글

AI Agent와 Tool 2 (langchain을 사용한)  (0) 2025.04.15
LangChain을 사용한 RAG 구성 1  (0) 2025.04.15

LangChain

언어모델을 보다 간편하게 사용할 수 있게해주는 프레임워크.

 

공식 사이트

https://python.langchain.com/docs/introduction/

 

Introduction | 🦜️🔗 LangChain

LangChain is a framework for developing applications powered by large language models (LLMs).

python.langchain.com

 

RAG( Retrieval-Augmented Generation )

한글로 검색 증강 생성으로 RAG를 사용하지 않는 LLM은 오답(할루시네이션)을 만들어낼 확률이 높으며 이를 해결하기위해 RAG를 사용 

RAG는 답변을 생성할 시 답변 생성에 도움이 되는 소스 데이터를 함께 LLM에 전달함으로써 할루시네이션을 줄인다.


RAG의 순서

1. 검색할 데이터를 추출한다.

증강 검색할 데이터를 워드파일로부터 추출한다.

 

2. 데이터를 파싱한다.

해당 데이터를 chunk 단위로 분할한다. 이는 LLM이 토큰 단위로 데이터를 처리하며 입력가능한 토큰의 개수는 정해져 있고 불필요한 데이터를 너무 많이 넘기게 되면 RAG 성능이 낮아짐

 

3. 데이터를 임베딩 한다.

데이터를 벡터의 형태로 변환한다. 벡터로 변환하므로서 각 단어들간의 유사도를 유추 할 수 있으므로 입력한 단어와 높은 유사도를 가지는 데이터를 검색한다.

 

4. DB에 적재한다.

 

5. 검색 시 유사도가 높은 데이터를 추출한다.

질문을 임베딩 하여 벡터화 하고 해당 벡터와 유사도가 높은 데이터를 찾는다.

 

6. 해당 데이터와 질문을 프롬프트로 만들어 LLM에 질문한다.

유사도가 높은 데이터를 사용하여 문장 답변을 생성한다.


LangChain 및 필요 라이브러리 설치

%pip install --upgrade pip
%pip install langchain-community docx2txt langchain_text_splitters python-dotenv langchain-openai langchain-chroma

 

 

langchain-community: LangChain의 인터페이스

langchain-openai: 인터페이스로 사용할 내부 코어

docx2txt : 워드 추출 라이브러리

langchain-text-splitters: 문장 파서 

 

 

openAI, Ollama anthropic 등 다양한 LLM을 사용할수 있다. 


 

Langchain을 사용하여 문장 생성

from langchain.chat_models import ChatOpenAI

api_key='api 키'
model = 'gpt-4o-mini'

llm = ChatOpenAI(api_key=api_key, model=model)
llm.invoke("안녕 반가워")

 

 

 

Docx2txt를 사용한 워드 파일 데이터 추출

from langchain_community.document_loaders import Docx2txtLoader
loader = Docx2txtLoader('../tax_with_table.docx')
document = loader.load()
document

 

TextSplitter를 사용한 워드 파일 분할

파일을 분할하는 이유

  • 입력할 수 있는 토큰의 수가 정해져 있기 때문에 무한정 큰 데이터를 입력 할 수 없음
  • 유사도 검색으로 검색 된 결과가 너무 크다면 불필요한 정보까지 함께 입력 되기 때문에 정확성이 낮아 질 수 있음
  • overlap: 이전 문장의 문맥을 이해하기 위해 이전 청크의 일부분을 가져오는 크기
from langchain_text_splitters import RecursiveCharacterTextSplitter
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000
    , chunk_overlap = 100
)
loader.load_and_split(text_splitter=text_splitter)

 

RecursiveCharacterTextSplitter 외에도 여러 splitter가 존재한다.


임베딩

문자를 vector화 하는 과정

from langchain_community.embeddings import OpenAIEmbeddings
embedding =  OpenAIEmbeddings(model='text-embedding-3-small')
embedding_document = embedding.embed_documents(["안녕하세요", "반가워요"])


데이터 적재

VectorDB는 Chroma, Pinecone등이 존재하며 해당 DB마다 사용하고 있는 검색 알고리즘이 다르다.

 

이번 테스트에서는 Chroma를 사용한다.

Chroma는 메모리 DB로 간단히 사용할수 있으며 파일로 데이터를 저장할 수 있다.

from langchain_community.embeddings import OpenAIEmbeddings
from dotenv import load_dotenv
from langchain_community.vectorstores import Chroma

#.env 파일에 OPENAI_API_KEY=api key 추가
load_dotenv()
embedding = OpenAIEmbeddings(model="text-embedding-3-small")

store = Chroma.from_documents(collection_name="tax_document", persist_directory="../Chroma", documents=splitted_document, embedding=embedding)
# 파일에서 받아 올 때 
# store = Chroma(collection_name="tax_document", persist_directory="../Chroma", embedding_function=embedding)

 

 

VectorStore에 쿼리 전송

query ="연봉 3000만원의 소득세"
# 유사도 높은 3개의 결과 반환
result = store.similarity_search_with_score(query=query, k=3)

 

Prompt생성

https://smith.langchain.com/hub/

 

LangSmith

 

smith.langchain.com

langchaing hub에는 다른 사용자들이 만들어둔 prompt들이 존재한다.

직접 prompt를 만들지 않아도 다양한 prompt를 사용할 수 있다. 다만 API로 pull을 사용할 시 API_KEY를 발급 받아야한다. 간단하게 검색하여 template으로 사용하기로 한다.

from langchain_community.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate

# API KEY를 받아서 사용할 시 
# from langchain import hub
# prompt = hub.pull("rlm/rag-prompt")

prompt_text =""""
"You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise.
Question: {question} 
Context: {context} 
Answer:"""

prompt = PromptTemplate.from_template(prompt_text)

 

 

Chain

위의 Prompt, llm, VectorStore를 합친 인터페이스로 Chain이 없다면 로직은 아래와 같아진다.

1. 질문들 받는다 

2. 질문을 retriver(Store)로부터 유사도 높은 Context(문서)를 추출한다.
3. prompt에 context와 질문을 을 매핑한다.

4. llm에 질문한다.

 

Chain의 생성자로 prompt, llm, VectorStore를 전달하기 때문에 신규 질문이 들어오면 chain.invoke("질문")만 사용하면된다.

 

Chain은 종류

이번에는 RerivalQA라는 chain을 사용한다.

이 체인은 먼저 관련 문서를 가져오기 위한 검색 단계를 수행한 다음, 해당 문서를 LLM에 전달하여 응답을 생성한다.

 

그외 키워드 추출 등 다양한 chain들이 존재한다.

https://python.langchain.com/v0.1/docs/modules/chains/

 

How to migrate from v0.0 chains | 🦜️🔗 LangChain

LangChain has evolved since its initial release, and many of the original "Chain" classes

python.langchain.com

 

 

from langchain.chains import RetrievalQA
from langchain_community.chat_models import ChatOpenAI

api_key='api key'
model = 'gpt-4o-mini'

llm = ChatOpenAI(api_key=api_key, model=model)


chain = RetrievalQA.from_chain_type(
    llm, 
    retriever=store.as_retriever(),
    chain_type_kwargs={"prompt": prompt}
)

chain.invoke(query)

 

+ Recent posts