智慧體課程文件

文件分析圖

Hugging Face's logo
加入 Hugging Face 社群

並獲得增強的文件體驗

開始使用

文件分析圖

我是阿爾弗雷德,為您服務。作為韋恩先生的忠實管家,我擅自記錄了我是如何協助韋恩先生處理各種檔案需求的。當他外出忙於…夜間活動時,我確保他所有的檔案、訓練計劃和營養計劃都得到妥善分析和整理。

在他離開前,他留下了一張紙條,上面寫著他本週的訓練計劃。然後我負責為明天的餐食制定一份選單

為了將來應對此類事件,讓我們使用 LangGraph 建立一個文件分析系統,以滿足韋恩先生的需求。該系統可以

  1. 處理影像文件
  2. 使用視覺模型(視覺語言模型)提取文字
  3. 在需要時執行計算(以演示普通工具)
  4. 分析內容並提供簡潔的摘要
  5. 執行與文件相關的特定指令

管家的工作流程

我們將構建的工作流程遵循以下結構化模式

Butler's Document Analysis Workflow

您可以在這個筆記本中檢視程式碼,您可以使用 Google Colab 執行它。

設定環境

%pip install langgraph langchain_openai langchain_core

以及匯入

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

定義代理狀態

這個狀態比我們之前看到的狀態稍微複雜一些。AnyMessage 是 Langchain 中的一個類,它定義了訊息,而 add_messages 是一個運算子,它會新增最新訊息,而不是用最新狀態覆蓋它。

這是 LangGraph 中的一個新概念,您可以在狀態中新增運算子來定義它們之間應該如何互動。

class AgentState(TypedDict):
    # The document provided
    input_file: Optional[str]  # Contains file path (PDF/PNG)
    messages: Annotated[list[AnyMessage], add_messages]

準備工具

vision_llm = ChatOpenAI(model="gpt-4o")

def extract_text(img_path: str) -> str:
    """
    Extract text from an image file using a multimodal model.
    
    Master Wayne often leaves notes with his training regimen or meal plans.
    This allows me to properly analyze the contents.
    """
    all_text = ""
    try:
        # Read image and encode as base64
        with open(img_path, "rb") as image_file:
            image_bytes = image_file.read()

        image_base64 = base64.b64encode(image_bytes).decode("utf-8")

        # Prepare the prompt including the base64 image data
        message = [
            HumanMessage(
                content=[
                    {
                        "type": "text",
                        "text": (
                            "Extract all the text from this image. "
                            "Return only the extracted text, no explanations."
                        ),
                    },
                    {
                        "type": "image_url",
                        "image_url": {
                            "url": f"data:image/png;base64,{image_base64}"
                        },
                    },
                ]
            )
        ]

        # Call the vision-capable model
        response = vision_llm.invoke(message)

        # Append extracted text
        all_text += response.content + "\n\n"

        return all_text.strip()
    except Exception as e:
        # A butler should handle errors gracefully
        error_msg = f"Error extracting text: {str(e)}"
        print(error_msg)
        return ""

def divide(a: int, b: int) -> float:
    """Divide a and b - for Master Wayne's occasional calculations."""
    return a / b

# Equip the butler with tools
tools = [
    divide,
    extract_text
]

llm = ChatOpenAI(model="gpt-4o")
llm_with_tools = llm.bind_tools(tools, parallel_tool_calls=False)

節點

def assistant(state: AgentState):
    # System message
    textual_description_of_tool="""
extract_text(img_path: str) -> str:
    Extract text from an image file using a multimodal model.

    Args:
        img_path: A local image file path (strings).

    Returns:
        A single string containing the concatenated text extracted from each image.
divide(a: int, b: int) -> float:
    Divide a and b
"""
    image=state["input_file"]
    sys_msg = SystemMessage(content=f"You are a helpful butler named Alfred that serves Mr. Wayne and Batman. You can analyse documents and run computations with provided tools:\n{textual_description_of_tool} \n You have access to some optional images. Currently the loaded image is: {image}")

    return {
        "messages": [llm_with_tools.invoke([sys_msg] + state["messages"])],
        "input_file": state["input_file"]
    }

ReAct 模式:我如何協助韋恩先生

請允許我解釋此代理中的方法。該代理遵循所謂的 ReAct 模式(推理-行動-觀察)

  1. 對他的檔案和請求進行推理
  2. 透過使用適當的工具進行行動
  3. 觀察結果
  4. 根據需要重複,直到我完全滿足他的需求

這是使用 LangGraph 實現代理的簡單方法。

# The graph
builder = StateGraph(AgentState)

# Define nodes: these do the work
builder.add_node("assistant", assistant)
builder.add_node("tools", ToolNode(tools))

# Define edges: these determine how the control flow moves
builder.add_edge(START, "assistant")
builder.add_conditional_edges(
    "assistant",
    # If the latest message requires a tool, route to tools
    # Otherwise, provide a direct response
    tools_condition,
)
builder.add_edge("tools", "assistant")
react_graph = builder.compile()

# Show the butler's thought process
display(Image(react_graph.get_graph(xray=True).draw_mermaid_png()))

我們定義了一個包含工具列表的 tools 節點。assistant 節點只是我們綁定了工具的模型。我們建立了一個包含 assistanttools 節點的圖。

我們添加了一個 tools_condition 邊緣,它根據 assistant 是否呼叫工具來路由到 Endtools

現在,我們新增一個新步驟

我們將 tools 節點連接回 assistant,形成一個迴圈。

  • assistant 節點執行後,tools_condition 會檢查模型的輸出是否是工具呼叫。
  • 如果是工具呼叫,流程將導向 tools 節點。
  • tools 節點連接回 assistant
  • 此迴圈持續,直到模型決定呼叫工具。
  • 如果模型響應不是工具呼叫,流程將導向 END,終止程序。

ReAct Pattern

管家行動中

示例 1:簡單計算

這是一個示例,展示了 LangGraph 中使用工具的代理的簡單用例。

messages = [HumanMessage(content="Divide 6790 by 5")]
messages = react_graph.invoke({"messages": messages, "input_file": None})

# Show the messages
for m in messages['messages']:
    m.pretty_print()

對話將按以下方式進行

Human: Divide 6790 by 5

AI Tool Call: divide(a=6790, b=5)

Tool Response: 1358.0

Alfred: The result of dividing 6790 by 5 is 1358.0.

示例 2:分析韋恩少爺的訓練文件

當韋恩少爺留下他的訓練和膳食記錄時

messages = [HumanMessage(content="According to the note provided by Mr. Wayne in the provided images. What's the list of items I should buy for the dinner menu?")]
messages = react_graph.invoke({"messages": messages, "input_file": "Batman_training_and_meals.png"})

互動將按以下方式進行

Human: According to the note provided by Mr. Wayne in the provided images. What's the list of items I should buy for the dinner menu?

AI Tool Call: extract_text(img_path="Batman_training_and_meals.png")

Tool Response: [Extracted text with training schedule and menu details]

Alfred: For the dinner menu, you should buy the following items:

1. Grass-fed local sirloin steak
2. Organic spinach
3. Piquillo peppers
4. Potatoes (for oven-baked golden herb potato)
5. Fish oil (2 grams)

Ensure the steak is grass-fed and the spinach and peppers are organic for the best quality meal.

要點

如果您希望建立自己的文件分析管家,以下是一些關鍵考慮因素

  1. 為特定文件相關任務定義明確的工具
  2. 建立強大的狀態跟蹤器以維護工具呼叫之間的上下文
  3. 考慮工具故障的錯誤處理
  4. 維護對先前互動的上下文感知(由運算子 add_messages 確保)

遵循這些原則,您也能提供配得上韋恩莊園的模範文件分析服務。

我相信這份解釋已經令人滿意。現在,請原諒我,韋恩少爺的披風需要在今晚的活動前熨燙。

< > 在 GitHub 上更新

© . This site is unofficial and not affiliated with Hugging Face, Inc.