Buckets:
| # 문서 분석 그래프[[document-analysis-graph]] | |
| 저 알프레드는 Mr.웨인님의 신뢰받는 집사로서, 그분의 다양한 문서 업무를 어떻게 지원할지 기록해두었습니다. 그가 밤 활동을 하러 나간 동안, 저는 모든 서류, 훈련 일정, 영양 계획을 분석하고 정리합니다. | |
| 그분이 외출하기 전, 이번 주 훈련 프로그램이 적힌 쪽지를 남기셨습니다. 그 쪽지를 보고 저는 내일 식사를 위한 **메뉴**를 직접 짜기로 했죠. | |
| 앞으로도 이런 일이 있을 때를 대비해, LangGraph를 활용해 웨인님을 위한 문서 분석 시스템을 만들어봅시다. 이 시스템은 다음을 수행 할 수 있습니다: | |
| 1. 이미지 문서 처리 | |
| 2. 비전 모델(비전 언어 모델)로 텍스트 추출 | |
| 3. 필요시 계산 수행(일반 툴 시연) | |
| 4. 내용 분석 및 요약 제공 | |
| 5. 문서 관련 특정 지시 실행 | |
| ## 집사의 워크플로우[[the-butlers-workflow]] | |
| 만들 워크플로우의 구조는 다음과 같습니다: | |
|  | |
| 이 노트북을 따라가며 Google Colab에서 코드를 실행해볼 수 있습니다. | |
| ## 환경 설정[[setting-up-the-environment]] | |
| ```python | |
| %pip install langgraph langchain_openai langchain_core | |
| ``` | |
| 임포트 : | |
| ```python | |
| import base64 | |
| from typing import List, TypedDict, Annotated, Optional | |
| from langchain_openai import ChatOpenAI | |
| from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage | |
| from langgraph.graph.message import add_messages | |
| from langgraph.graph import START, StateGraph | |
| from langgraph.prebuilt import ToolNode, tools_condition | |
| from IPython.display import Image, display | |
| ``` | |
| ## 에이전트 상태 정의[[defining-agent's-state]] | |
| 이 상태는 앞서 본 것보다 조금 더 복잡합니다. | |
| `AnyMessage`는 Langchain의 메시지 클래스이고, `add_messages`는 최신 메시지를 누적하는 연산자입니다. | |
| LangGraph에서는 상태에 연산자를 추가해 상호작용 방식을 정의할 수 있습니다. | |
| ```python | |
| class AgentState(TypedDict): | |
| # 제공된 문서 | |
| input_file: Optional[str] # 파일 경로(PDF/PNG) | |
| messages: Annotated[list[AnyMessage], add_messages] | |
| ``` | |
| ## 툴 준비하기[[preparing-tools]] | |
| ```python | |
| vision_llm = ChatOpenAI(model="gpt-4o") | |
| def extract_text(img_path: str) -> str: | |
| """ | |
| 멀티모달 모델로 이미지 파일에서 텍스트 추출 | |
| Wayne 주인님은 종종 훈련 일정이나 식단이 적힌 쪽지를 남깁니다. | |
| 이 기능으로 내용을 제대로 분석할 수 있습니다. | |
| """ | |
| all_text = "" | |
| try: | |
| # 이미지를 읽고 base64로 인코딩 | |
| with open(img_path, "rb") as image_file: | |
| image_bytes = image_file.read() | |
| image_base64 = base64.b64encode(image_bytes).decode("utf-8") | |
| # base64 이미지 데이터를 포함한 프롬프트 준비 | |
| message = [ | |
| HumanMessage( | |
| content=[ | |
| { | |
| "type": "text", | |
| "text": ( | |
| "이 이미지에서 모든 텍스트를 추출하세요. 설명 없이 추출된 텍스트만 반환하세요." | |
| ), | |
| }, | |
| { | |
| "type": "image_url", | |
| "image_url": { | |
| "url": f"data:image/png;base64,{image_base64}" | |
| }, | |
| }, | |
| ] | |
| ) | |
| ] | |
| # 비전 모델 호출 | |
| response = vision_llm.invoke(message) | |
| # 추출된 텍스트 추가 | |
| all_text += response.content + "\n\n" | |
| return all_text.strip() | |
| except Exception as e: | |
| # 집사는 오류도 우아하게 처리해야 합니다 | |
| error_msg = f"텍스트 추출 오류: {str(e)}" | |
| print(error_msg) | |
| return "" | |
| def divide(a: int, b: int) -> float: | |
| """주인님의 계산 요청을 위한 나눗셈 함수""" | |
| return a / b | |
| # 집사, 도구(tool) 장착 | |
| tools = [ | |
| divide, | |
| extract_text | |
| ] | |
| llm = ChatOpenAI(model="gpt-4o") | |
| llm_with_tools = llm.bind_tools(tools, parallel_tool_calls=False) | |
| ``` | |
| ## 노드[[the-nodes]] | |
| ```python | |
| def assistant(state: AgentState): | |
| # 시스템 메시지 | |
| textual_description_of_tool=""" | |
| extract_text(img_path: str) -> str: | |
| 멀티모달 모델로 이미지 파일에서 텍스트 추출 | |
| Args: | |
| img_path: 로컬 이미지 파일 경로(문자열) | |
| Returns: | |
| 각 이미지에서 추출된 텍스트를 합친 문자열 | |
| divide(a: int, b: int) -> float: | |
| a를 b로 나눔 | |
| """ | |
| image=state["input_file"] | |
| sys_msg = SystemMessage(content=f"당신은 Mr. Wayne과 배트맨을 섬기는 친절한 집사 알프레드입니다. 아래 도구로 문서를 분석하고 계산을 수행할 수 있습니다:\n{textual_description_of_tool} \n 현재 로드된 이미지는: {image}") | |
| return { | |
| "messages": [llm_with_tools.invoke([sys_msg] + state["messages"])], | |
| "input_file": state["input_file"] | |
| } | |
| ``` | |
| ## ReAct 패턴: 집사의 지원 방식[[the-react-pattern-how-i-assist-mr-wayne]] | |
| 이 에이전트는 ReAct 패턴(Reason-Act-Observe)을 따릅니다. | |
| 1. 문서와 요청을 **이해(Reason)** | |
| 2. 적절한 도구를 **실행(Act)** | |
| 3. 결과를 **관찰(Observe)** | |
| 4. 필요시 반복 | |
| 아주 간단한 LangGraph 에이전트 구현 예시입니다. | |
| ```python | |
| # 그래프 생성 | |
| builder = StateGraph(AgentState) | |
| # 노드 정의: 실제 작업을 수행 | |
| builder.add_node("assistant", assistant) | |
| builder.add_node("tools", ToolNode(tools)) | |
| # 엣지 정의: 제어 흐름 결정 | |
| builder.add_edge(START, "assistant") | |
| builder.add_conditional_edges( | |
| "assistant", | |
| # 최신 메시지가 도구를 필요로 하면 tools로 라우팅 | |
| # 아니면 직접 응답 | |
| tools_condition, | |
| ) | |
| builder.add_edge("tools", "assistant") | |
| react_graph = builder.compile() | |
| # 집사의 사고 과정을 시각화 | |
| display(Image(react_graph.get_graph(xray=True).draw_mermaid_png())) | |
| ``` | |
| `tools` 노드는 도구 리스트를, `assistant` 노드는 도구가 바인딩된 모델을 의미합니다. | |
| 그래프에는 `assistant`와 `tools` 노드가 있습니다. | |
| `tools_condition` 엣지는 모델이 도구를 호출하면 tools로, 아니면 End로 흐름을 보냅니다. | |
| 이제 한 단계 더 추가합니다: | |
| `tools` 노드를 다시 `assistant`로 연결해 루프를 만듭니다. | |
| - `assistant` 노드 실행 후, `tools_condition`이 모델 출력이 도구 호출인지 확인합니다. | |
| - 도구 호출이면 흐름이 `tools` 노드로 이동합니다. | |
| - `tools` 노드는 다시 `assistant`로 연결됩니다. | |
| - 이 루프는 모델이 도구 호출을 결정하는 한 계속됩니다. | |
| - 모델 응답이 도구 호출이 아니면 흐름이 END로 이동해 프로세스가 종료됩니다. | |
|  | |
| ## 집사의 실제 활용 예시[[the-butler-in-action]] | |
| ### 예시 1: 간단한 계산[[example-1-simple-calculations]] | |
| 아래는 LangGraph에서 도구를 사용하는 간단한 예시입니다. | |
| ```python | |
| messages = [HumanMessage(content="6790을 5로 나눠줘")] | |
| messages = react_graph.invoke({"messages": messages, "input_file": None}) | |
| # 메시지 출력 | |
| for m in messages['messages']: | |
| m.pretty_print() | |
| ``` | |
| 대화 예시: | |
| ``` | |
| Human: 6790을 5로 나눠줘 | |
| AI Tool Call: divide(a=6790, b=5) | |
| Tool Response: 1358.0 | |
| Alfred: 6790을 5로 나누면 1358.0입니다. | |
| ``` | |
| ### 예시 2: Wayne 주인님의 훈련 문서 분석[[example-2-analyzing-master-waynes-training-documents]] | |
| 주인님이 훈련 및 식단 쪽지를 남겼을 때: | |
| ```python | |
| messages = [HumanMessage(content="제공된 이미지에 있는 Wayne 주인님의 쪽지에 따라 저녁 메뉴에 필요한 재료 목록을 알려줘.")] | |
| messages = react_graph.invoke({"messages": messages, "input_file": "Batman_training_and_meals.png"}) | |
| ``` | |
| 대화 예시: | |
| ``` | |
| Human: 제공된 이미지에 있는 Wayne 주인님의 쪽지에 따라 저녁 메뉴에 필요한 재료 목록을 알려줘. | |
| AI Tool Call: extract_text(img_path="Batman_training_and_meals.png") | |
| Tool Response: [훈련 일정 및 메뉴 세부 정보가 추출됨] | |
| Alfred: 저녁 메뉴를 위해 다음 재료를 구입하세요: | |
| 1. 목초 사육 소고기 등심 스테이크 | |
| 2. 유기농 시금치 | |
| 3. 피키요 고추 | |
| 4. 감자(오븐에 구울 허브 감자용) | |
| 5. 피쉬 오일(2그램) | |
| 스테이크는 목초 사육, 시금치와 고추는 유기농으로 준비하면 최고의 식사가 됩니다. | |
| ``` | |
| ## 핵심 요약[[key-takeaways]] | |
| 나만의 문서 분석 집사를 만들고 싶다면 다음을 고려하세요: | |
| 1. **문서 관련 작업별로 명확한 도구 정의** | |
| 2. **도구 호출 간 맥락 유지를 위한 견고한 상태 추적기** | |
| 3. **도구 실패 시 오류 처리 고려** | |
| 4. **이전 상호작용 맥락 유지(add_messages 연산자 활용)** | |
| 이 원칙을 따르면 Wayne 저택에 어울리는 문서 분석 서비스를 제공할 수 있습니다. | |
| *이 설명이 도움이 되었길 바랍니다. 이제 주인님의 망토를 다림질하러 가보겠습니다.* | |
Xet Storage Details
- Size:
- 9.42 kB
- Xet hash:
- c404a752870a6a593ae670a1b80e67942e5f689619806269aafa9506bb3a2c06
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.