냥냠
[교육] LangChain & LangGraph 실습 - AI agent 만들기 - (2) 본문

실습 - 문서 기반 AI 챗봇 만들기
(1) LangChain 활용
1. LLM 모델 설정:
- ChatOpenAI 등 사용할 대규모 언어 모델을 초기화합니다. (API 키 연동 포함)
llm = ChatOpenAI(model_name="gpt-4o-mini",
temperature=0.,
api_key=openai_key
)
2. 문서 로딩 및 전처리:
- 파일 로더 (PDFLoader 등): .pdf, .txt, .docx 등 외부 문서 파일을 불러옵니다.
- 텍스트 스플리터 (RecursiveCharacterTextSplitter 등): 로드된 긴 문서를 LLM이 처리하기 적합한 작은 단위(청크)로 분할합니다.
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
dir = "./files/"
file_list = os.listdir(dir) #폴더 내의 모든 파일 목록 가져오기
loader = PyPDFLoader(dir+file_list[0])
splitter = RecursiveCharacterTextSplitter(chunk_size=300,
chunk_overlap=50, # 앞뒤로 50자씩 겹치게
separators=["\n\n"])
split_docs = loader.load_and_split(text_splitter=splitter)
3. 정보 색인화 (임베딩 및 저장):
- 임베딩 모델 (OpenAIEmbeddings 등): 분할된 텍스트 청크들을 벡터(숫자 배열)로 변환합니다.
- 벡터 스토어 (FAISS, Chroma 등): 임베딩된 벡터들을 저장하고 관리하여 효율적인 의미 기반 검색을 가능하게 합니다.
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
embeddings = OpenAIEmbeddings()
vector_store = FAISS.from_documents(embedding=embeddings, documents=split_docs)
4. 검색기 구성:
- 리트리버 (as_retriever() 등): 벡터 저장소에서 질의와 유사한 문서를 찾아 반환하는 검색기 객체를 생성합니다.
# 리트리버 생성
retriever = vector_store.as_retriever()
5. 프롬프트 및 체인 구성:
- 프롬프트 템플릿 (PromptTemplate, ChatPromptTemplate): 사용자 질문과 검색된 문서를 조합하여 LLM에 전달할 최종 프롬프트 양식을 정의합니다. (이때, 검색된 문서를 프롬프트에 삽입하는 문서 포맷팅 과정이 포함될 수 있습니다.)
- 체인 생성 (LLMChain, RetrievalQA 또는 LCEL): 리트리버로 문서를 검색하고, 그 결과를 프롬프트에 넣어 LLM에 전달한 후 응답을 받는 전체 흐름을 연결하는 체인을 구축합니다.
*LangChain은 LangChain Expression Language (LCEL)이라는 문법을 사용하여 구성요소를 유연하게 연결함
from langchain_core.prompts import ChatPromptTemplate
# 프롬프트 템플릿
prompt = ChatPromptTemplate([
("system", "문서 : {context}\n\n"
"당신은 문서에서 원하는 정보를 찾는 10년차 데이터 전문가입니다. 항상 문서를 기반하여 응답해주세요\n"
"문서에서 응답을 찾을 수 없는 경우 '문서에서 응답을 찾을 수 없습니다.' 라고 답변하세요."),
("user", "{query}")
])
# 문서 포맷팅
# 검색기(retriever)로부터 반환된 여러 개의 문서 객체(Document 리스트)를 LLM 프롬프트에 삽입하기 적합한 하나의 문자열 형태로 변환하는 함수
def format_docs(docs):
return "\n\n".join(doc.page_content for doc in docs)
# 체인 생성
# retriever -> prompt -> llm
# RunnableLambda는 일반 파이썬 함수를 LangChain의 Runnable 객체로 만들어 체인에 연결할 수 있게 함
# RunnablePassthrough(): 사용자로부터 받은 query를 그대로 다음 단계로 전달
chain = {"context": retriever | RunnableLambda(format_docs),
"query": RunnablePassthrough()} | prompt | llm
6. 질문 & 답변:
- 사용자 질문을 체인에 invoke()하여 문서 기반의 답변을 받습니다.
query = "2025년엔 어떤 부분을 준비해야할까?"
result = chain.invoke(query)
print(result.content)

(2) LangGraph 활용
LangGraph 요소 : State, Node, Edge
- State : 에이전트가 현재 어떤 단계에 있는지를 나타내는 정보
- Node : 하나의 독립적인 작업 단위
- Edge : 노드 간의 흐름을 정의하는 연결선
1. 기본 컴포넌트 설정:
- LLM 모델 생성: ChatOpenAI와 같은 대규모 언어 모델을 초기화합니다.
- 데이터 준비 및 검색 도구 설정: 파일 로더 (예: PDF), 텍스트 스플리터, 임베딩 모델, 벡터 저장소, 리트리버 등을 설정합니다. 이들은 그래프의 노드에서 사용될 외부 도구 역할을 합니다.
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
from langchain.document_loaders import PyPDFLoader
llm = ChatOpenAI(model="gpt-4o-mini",
temperature=0.,
api_key = openai_key)
file_path = "./files/"
def embedding_file(file_path):
splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
chunk_size=300,
chunk_overlap=50,
separators=["\n\n"],
)
loader = PyPDFLoader(file_path)
docs = loader.load_and_split(text_splitter=splitter)
embeddings = OpenAIEmbeddings()
vector_store = FAISS.from_documents(docs, embeddings)
retriever = vector_store.as_retriever()
return retriever
retriever = embedding_file(file_path+file_list[1])
2. 그래프 상태 정의:
- 그래프의 각 노드 간에 전달될 정보(예: 사용자 질문, 검색된 문서, LLM 답변, 대화 기록 등)를 담을 상태(State) 스키마를 정의합니다.
# 그래프 상태 정의
class State(TypedDict):
messages : Annotated[list, add_messages]
document : Annotated[Document, "Retrieve Response"]
- 노드 정의 및 내부 체인 구성:
- 프롬프트 및 LLM 체인 정의: 각 노드(예: "문서 검색" 노드, "답변 생성" 노드)에서 수행할 구체적인 작업(예: retriever를 실행하거나 프롬프트와 LLM을 연결하는 체인)을 정의합니다.
- 적제된 메세지 객체에 [-1] 호출 시 최신의 메세지를 가져올 수 있다.
# 그래프 내의 특정 "노드"에서 실행될 작업을 정의하는 부분
# 사용자 질문을 받아 리트리버를 통해 문서를 검색하고,
# 그 문서를 LLM이 활용할 수 있도록 포맷팅하여 그래프의 상태(state)에 저장하는 역할
def create_document(state:State):
docs = retriever.invoke(state["messages"][-1].content)
docs = "\n\n".join(doc.page_content for doc in docs)
return {"document":docs}
# 체인 활성화 (+프롬프트 작성)
def response(state:State):
prompt = ChatPromptTemplate.from_messages([
("system",
"""
context : {context}
당신은 언제나 고객에게 최선을 다해 답변을 하며 말투는 굉장히 친근합니다. 직업은 전문 상담원입니다. 답변 시, 아래의 규칙을 지켜야만 합니다.
---
### 규칙 ###
1. 주어진 context만을 이용하여 답변해야합니다.
2. 주어진 context에서 답변을 할 수 없다면 "해당 문의는 010-2255-3366으로 연락주시면 도와드리겠습니다. 영업 시간은 오전 10시-오후 6시입니다." 라고 대답하세요.
3. 문자열에 A1, A2, A11, A22 등 필요 없는 문자는 제거한 뒤 출력합니다.
4. 항상 친절한 말투로 응대합니다.
5. 하이퍼 링크를 그대로 출력합니다. 대소문자를 명확하게 구분하세요. 아래 예시를 참고하여 서식을 맞추세요.
**하이퍼 링크 예시**
5-1. [스타벅스 구역삼사거리점](https://naver.me/FV7K6xTM) 입니다.
5-2. [화목순대국](https://naver.me/FQVGK6TZ) 입니다.
5-3. [모두의연구소 역삼캠퍼스](https://naver.me/GMvc9Hv5) 입니다.
---
"""),
("human", "{query}")
])
chain = prompt | llm
return {"messages": chain.invoke({"context" : state["document"],
"query": state["messages"][-1]})}
- 그래프 빌더 생성 및 노드/엣지 추가:
- Graph 또는 StateGraph 빌더를 생성합니다.
- 노드 추가: 정의된 각 작업 단계를 노드로 추가합니다.
- 엣지 추가: 각 노드 간의 전환 조건(어떤 노드에서 다음 어떤 노드로 이동할지)을 엣지(Edge)로 연결하여 워크플로우를 정의합니다.
# 그래프 빌더 생성
graph_builder = StateGraph(State)
# 노드 및 엣지 추가
graph_builder.add_node("create_document", create_document);
graph_builder.add_node("response", response);
graph_builder.add_edge(START, "create_document");
graph_builder.add_edge("create_document", "response");
graph_builder.add_edge("response", END);
- 그래프 컴파일 및 실행:
- 정의된 노드와 엣지를 바탕으로 그래프를 컴파일하여 실행 가능한 워크플로우로 만듭니다.
- invoke() 또는 stream() 등으로 컴파일된 그래프에 메시지를 입력하여 실행하고, 최종 답변을 받습니다. (예: input = {"messages": [("user", "질문 내용")]})
# 그래프 컴파일
graph = graph_builder.compile()
# 질문 & 답변
# -1 값에 답변, -2 값에 질문이 담겨있다.
result = graph.invoke({'messages':("user", "언제 개강하나요?")})
result["messages"][-1].content


프롬프트 규칙에 문서에 없는 정보를 질문하면 대답을 정해주었기 때문에 근거 없는 정보에 대해서는 답을 해주지 않는다는 점에서
RAG를 사용함으로써 할루시네이션을 감소하고 답변의 신뢰성을 높일 수 있다.
https://conference.etnews.com/conf_info.html?uid=398
LangChain + LangGraph Bootcamp: AI 에이전트를 만드는 하루
AI 에이전트는 챗봇, 문서 요약, 데이터 정리 등 일상과 업무에서 큰 도움을 줄 수 있는 기술입니다. 이 워크숍은 프 로그래밍과 AI에 처음 도전하는 초급자를 위해 설계되었으며, 복잡한 이론 대
conference.etnews.com
'AI' 카테고리의 다른 글
| n8n(엔팔엔, 엔에잇엔, 네이튼, ,,.,.)으로 간단한 워크플로우 만들기 (0) | 2025.12.12 |
|---|---|
| Streamlit을 이용한 LangChain RAG AI Agent 웹 서비스 구축 (0) | 2025.07.04 |
| [교육] LangChain & LangGraph 실습 - AI agent 만들기 - (3) (0) | 2025.07.01 |
| [교육] LangChain & LangGraph 실습 - AI agent 만들기 - (1) (0) | 2025.06.28 |
| 2025 AI 컨퍼런스 참석 후기 ( AI Work Summit, SOTEC, AI EXPO ... ) (3) | 2025.06.17 |