LangGraph와 watsonx.ai를 활용하여 휴먼 인 더 루프 방식으로 선행 기술 검색 AI 에이전트 관리

작성자

Anna Gutowska

AI Engineer, Developer Advocate

IBM

이 튜토리얼에서는 LangGraph와 watsonx.ai로 구축한 에이전트 시스템에 휴먼 인 더 루프를 피드백 메커니즘으로 구현합니다. 에이전트는 지루하고 수작업이 필요한 실제 사용 사례인 선행 기술 검색 작업에 전문화됩니다. 에이전트는 SerpAPI를 통해 Google Patents API를 사용하여 특허를 검토하고 특허 제안에 대해 피드백을 제공합니다. 사용되는 대규모 언어 모델(LLM)은 오픈 소스인 IBM® Granite입니다.

에이전틱 AI의 등장으로 인해 개발자들은 기존의 LLM 챗봇에서 자동화로 관심과 노력을 옮기고 있습니다. '자동화'라는 단어는 일반적으로 작업 수행에서 인간의 개입을 없앤다는 의미입니다.1 예를 들어 AI 에이전트에게 개인 재정과 같은 중요한 결정권을 맡길 수 있을까요? 대부분 그렇지 않을 것입니다. 어느 정도의 모호성이 최종 사용자에게 부족한 신뢰를 제공할 수 있다면 어떨까요? 이러한 뉘앙스의 층은 휴먼 인 더 루프라 불리는 인간 개입의 형태로 나타날 수 있습니다.

휴먼 인 더 루프

HITL(Human-in-the-loop)은 LLM 애플리케이션의 의사 결정을 안내하고 감독하기 위해 인간의 피드백이 요구되는 아키텍처적 패턴입니다. 인공지능 분야에서 HITL은 AI 워크플로의 특정 단계에 인간의 개입이 포함됨을 나타냅니다. 이 방법은 정확성, 안전성, 그리고 책임성을 보장합니다.

인간은 영구 실행 상태로 인해 LangGraph에서 그래프 상태를 비동기식으로 검토하고 업데이트할 수 있습니다. 각 단계 후에 상태 체크포인트를 사용하여 상태 컨텍스트를 유지할 수 있으며, 사람의 피드백을 받을 때까지 워크플로를 일시 중지할 수 있습니다.

이 튜토리얼에서는 LangGraph의 두 가지 HITL 접근 방식을 실험해 봅니다.

  1. 정적 인터럽트: 특정 노드가 실행되기 또는 후에 사전에 지정된 위치에서 그래프 상태를 직접 편집합니다. 이 방식을 사용하려면 상태 그래프를 컴파일할 때 interrupt_before 또는 interrupt_after 매개변수를 노드 이름 목록으로 설정해야 합니다.

  2. 동적 인터럽트: 그래프를 중단하고 그래프의 현재 상태에 따라 노드 내에서 사용자 입력을 기다리는 것입니다. 이 방식에서는 LangGraph의 interrupt 함수를 사용해야 합니다.

전제조건

1. watsonx.ai 프로젝트를 생성하려면 IBM® Cloud 계정이 필요합니다.

2. 이 튜토리얼에서는 여러 Python 버전을 사용할 수 있습니다. 게시 시점에는 최신 버전인 Python 3.13을 다운로드하는 것이 좋습니다.

단계

1단계. 환경 설정하기.

여러 툴 중에서 선택할 수 있지만, 이 튜토리얼에서는 Jupyter Notebook을 사용하기 위해 IBM 계정을 설정하는 방법을 안내합니다.

  1. IBM Cloud 계정을 사용하여 watsonx.ai에 로그인합니다.

  2. watsonx.ai 프로젝트를 생성합니다.

    프로젝트 내에서 프로젝트 ID를 가져올 수 있습니다. 관리 탭을 클릭합니다. 그런 다음 일반 페이지의 세부 정보 섹션에서 프로젝트 ID를 복사합니다. 본 튜토리얼에는 이 ID가 필요합니다.

  3. Jupyter Notebook을 생성합니다.

    이 단계에서는 본 튜토리얼의 코드를 복사할 수 있는 Jupyter Notebook 환경이 열립니다. 또한 이 노트북을 로컬 시스템에 다운로드하여 watsonx.ai 프로젝트에 자산으로 업로드할 수도 있습니다. 이 튜토리얼은 GitHub에서도 제공됩니다.

2단계.watsonx.ai 런타임 인스턴스와 API 키 설정하기.

  1. watsonx.ai Runtime 서비스 인스턴스를 생성합니다. (적절한 지역을 선택하고 무료 인스턴스인 Lite 요금제 선택)

  2. API 키를 생성합니다.

  3. watsonx.ai Runtime 서비스 인스턴스를 watsonx.ai에서 생성한 프로젝트에 연결합니다.

3단계. 관련 라이브러리 설치, 가져오기 및 자격 증명 설정

이 튜토리얼에는 몇 가지 라이브러리와 모듈이 필요합니다. 다음 항목을 가져와야 합니다. 설치되지 않은 경우, 빠른 PIP 설치로 이 문제를 해결할 수 있습니다.

%pip install --quiet -U langgraph langchain-ibm langgraph_sdk langgraph-prebuilt google-search-results

커널을 재시작한 후, 다음 패키지를 임포트합니다.

import getpass
import uuid

from ibm_watsonx_ai import APIClient, Credentials
from ibm_watsonx_ai.foundation_models.moderations import Guardian
from IPython.display import Image, display
from langchain_core.messages import AnyMessage, SystemMessage, HumanMessage, AIMessage
from langchain_ibm import ChatWatsonx
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, END, StateGraph
from langgraph.graph.message import add_messages
from langgraph.prebuilt import tools_condition, ToolNode
from langgraph.types import interrupt, Command
from serpapi.google_search import GoogleSearch
from typing_extensions import TypedDict
from typing import Annotated

자격 증명을 설정하려면 1단계에서 생성한 WATSONX_APIKEYWATSONX_APIKEY  및 WATSONX_PROJECT_ID  WATSONX_PROJECT_ID 가 필요합니다. 또한 WATSONX_URL을WATSONX_URL  API 엔드포인트로 설정하겠습니다.

Google Patents API에 접근하려면 SERPAPI_API_KEY도 필요합니다.SERPAPI_API_KEY . SerpApi 계정에 로그인하거나 계정을 등록하여 무료 키를 생성할 수 있습니다.

WATSONX_APIKEY = getpass.getpass(“Please enter your watsonx.ai Runtime API key (hit enter): “)
WATSONX_PROJECT_ID = getpass.getpass(“Please enter your project ID (hit enter): “)
WATSONX_URL = getpass.getpass(“Please enter your watsonx.ai API endpoint (hit enter): “)
SERPAPI_API_KEY = getpass.getpass(“Please enter your SerpAPI API key (hit enter): “)

LLM을 초기화하기 전에 CredentialsCredentials 클래스를 사용하여 전달된 API 자격 증명을 캡슐화할 수 있습니다.

credentials = Credentials(url=WATSONX_URL, api_key=WATSONX_APIKEY)

4단계. 채팅 모델 인스턴스화

watsonx.ai Runtime에서 제공되는 모든 리소스와 상호 작용하려면 APIClient를 설정해야 합니다.APIClient 여기에서는 자격 증명과 WATSONX_PROJECT_ID를 전달합니다.WATSONX_PROJECT_ID .

client = APIClient(credentials=credentials, project_id=WATSONX_PROJECT_ID)

이 튜토리얼에서는 ChatWatsonx 래퍼를 사용하여 채팅 모델을 설정합니다. 이 래퍼는 도구 호출과 체이닝의 통합을 단순화합니다. 자세한 내용은 ChatWatsonxChatWatsonx  공식 문서에서 자세한 정보를 확인하세요. 다음을 통과할 수 있습니다 model_id  Granite LLM의 model_id와 클라이언트를 매개변수로 전달할 수 있습니다.

참고로 다른 API 제공자를 사용하는 경우에는 해당 래퍼를 적절하게 변경해야 합니다.

model_id = “ibm/granite-3-3-8b-instruct”
llm = ChatWatsonx(model_id=model_id, watsonx_client=client)

5단계. 특허 스크레이퍼 도구 정의

AI 에이전트는 정보의 공백을 메우고 관련 정보를 반환하기 위해 도구를 사용합니다. 이러한 도구에는 웹 검색, RAG, 다양한 API, 수학적 계산 등이 포함될 수 있습니다. SerpAPI를 통해 Google Patents API를 사용하여 특허를 스크레이핑하는 도구를 정의할 수 있습니다. 이 도구는 검색어를 인수로 받아 관련 특허의 자연 검색 결과를 반환하는 함수입니다. GoogleSearch GoogleSearch GoogleSearch 래퍼는 검색 엔진(이 경우 google_patents), google_patents 검색어,그리고 마지막으로 SERPAPI_API_KEY와 같은 매개변수를 필요로 합니다.SERPAPI_API_KEY .

def scrape_patents(search_term: str):
    “””Search for patents about the topic.

    Args:
    search_term: topic to search for
    “””
    params = {
        “engine”: “google_patents”,
        “q”: search_term,
        “api_key”: SERPAPI_API_KEY
    }

    search = GoogleSearch(params)
    results = search.get_dict()
    return results[‘organic_results’]

다음으로, LLM을 다음에 결합해 봅시다 scrape_patents bind_tools 메서드를 사용해 LLM을 scrape_patentsbind_tools  도구에 바인딩합니다.

tools = [scrape_patents]
llm_with_tools = llm.bind_tools(tools)

6단계. 첫 번째 HITL 접근 방식: 정적 중단

LangGraph 에이전트 그래프는 노드와 엣지로 구성됩니다. 노드는 정보를 전달, 업데이트 및 반환하는 함수입니다. 노드 사이에서 이러한 정보를 어떻게 추적할 수 있을까요? 에이전트 그래프에는 상태(state)가 필요한데, 이 상태는 에이전트가 의사 결정을 내리는 데 필요한 모든 관련 정보를 저장합니다. 노드들은 엣지로 연결되어 있으며, 엣지는 현재 상태에 따라 다음에 실행할 노드를 선택하는 함수입니다. 엣지는 조건부일 수도 있고, 고정형일 수도 있습니다.

먼저 AgentState  클래스를 만들어 사용자, 도구 및 에이전트 자체의 메시지 컨텍스트를 저장해 보겠습니다. Python의 TypedDict  클래스는 여기서 메시지가 적절한 사전 형식으로 되어 있는지 확인하는 데 사용됩니다. 또한 LangGraph의 add_messages LangGraph의 add_messages 리듀서 함수를 사용하면 새로운 메시지를 기존 메시지 목록에 추가할 수 있습니다.

class AgentState(TypedDict):
    messages: Annotated[list[AnyMessage], add_messages]

다음으로 call_llm 어시스턴트 노드를 구성하는 call_llm 함수를assistant 정의합니다. 이 노드는 상태의 현재 메시지와 시스템 메시지로 LLM을 호출합니다.

sys_msg = SystemMessage(content=”You are a helpful assistant tasked with prior art search.”)

def call_llm(state: AgentState):
    return {“messages”: [llm_with_tools.invoke([sys_msg] + state[“messages”])]

다음으로 guardian 노드를 구성하는 guardian_moderationguardian_moderation 어시스턴트 노드를 구성하는 call_llm 함수를guardian  함수를 정의할 수 있습니다. 이 노드는 가디언 시스템을 사용하여 메시지를 관리하고, 원하지 않거나 민감한 콘텐츠를 감지하고 차단하도록 설계되었습니다. 먼저 마지막 메시지를 가져옵니다. 다음으로 감지기의 구성과 임계값을 포함하는 detectors detectors라는 사전이 정의됩니다. 이러한 감지기는 메시지 내에서 개인 식별 정보(PII), 혐오 발언, 폭언, 저속어(HAP) 등 특정 유형의 콘텐츠를 판별합니다. 다음으로 api_client client라는 api_client 객체와client  detectors 라는 사전을 전달하여 Guardian 클래스의 인스턴스를detectors 만듭니다.  detect Guardian 인스턴스의 detect 메서드를 호출할 때 마지막 메시지의 내용과 detectorsdetectors  사전이 인자로 전달합니다. 그리고 이 메서드는 Granite Guardian 모델의 아웃풋에 따라 moderation_verdict  키를 사용하여 Granite Guardian 모델의 출력에 따라 '안전함' 또는 '부적절함' 값을 저장합니다.

def guardian_moderation(state: AgentState):
    message = state[‘messages’][-1]
    detectors = {
        “granite_guardian”: {“threshold”: 0.4},
        “hap”: {“threshold”: 0.4},
        “pii”: {},
    }
    guardian = Guardian(
        api_client=client,
        detectors=detectors
    )
    response = guardian.detect(
        text=message.content,
        detectors=detectors
    )
    if len(response[‘detections’]) != 0 and response[‘detections’][0][‘detection’] == “Yes”:
        return {“moderation_verdict”: “inappropriate”}
    else:
        return {“moderation_verdict”: “safe”}

이제 다음을 정의해 봅시다 block_message 사용자의 입력 쿼리에 부적절한 내용이 포함되어 차단되었음을 알리는 알림 기능으로 block_message 함수를 정의합니다.

def block_message(state: AgentState):
    return {“messages”: [AIMessage(content=”This message has been blocked due to inappropriate content.”)]

이제 해당 노드를 추가하고 그래프의 흐름을 정의하는 엣지로 연결하여 이러한 모든 기능을 하나로 결합할 수 있습니다.

그래프는 guardian guardian 노드에서 시작되며, 이 노드는 LLM과 API에 도달하기 전에 유해한 콘텐츠를 감지하기 위해 guardian_moderationguardian_moderation  메서드를 호출합니다.  guardianguardian  및 assistant  노드와 assistantassistant  노드 사이의 조건부 엣지는 그래프의 상태를 assistant 노드 또는 끝으로 전달합니다. 이 위치는 guardian_moderation guardian_moderation 함수의 아웃풋에 따라 결정됩니다. 안전한 메시지는 assistant assistant 노드로 전달되며call_llm 이 노드는 call_llm 메서드를 실행합니다. 또한 메시지를 적절히 라우팅하기 위해 assistant  및 tools assistant 노드와 tools 노드 사이에 조건부 엣지를 추가합니다. LLM이 도구 호출을 반환하면 tools_condition 메서드는 tools 노드로 라우팅합니다.tools_condition  메서드가 툴 노드로 라우팅됩니다. 그렇지 않으면 그래프가 끝으로 라우팅됩니다. 에이전트가 도구 아웃풋을 수신한 다음 상태 변경에 반응하여 다음 작업을 결정하게 만들 것이므로, 이 단계는 ReAct 에이전트 아키텍처의 일부입니다.

builder = StateGraph(AgentState)

builder.add_node(“guardian”, guardian_moderation)
builder.add_node(“block_message”, block_message)
builder.add_node(“assistant”, call_llm)
builder.add_node(“tools”, ToolNode(tools))

builder.add_edge(START, “guardian”)
builder.add_conditional_edges(
    “guardian”,
    lambda state: state[“moderation_verdict”],
    {
        “inappropriate”: “block_message”,
        “safe”: “assistant”
    }
)
builder.add_edge(“block_message”, END)
builder.add_conditional_edges(
    “assistant”,
    tools_condition,
)
builder.add_edge(“tools”, “assistant”)
memory = MemorySaver()

다음으로 그래프를 컴파일할 수 있으며, 이를 통해 이후 단계에서 에이전트를 호출할 수 있습니다. 메시지를 지속적으로 저장하기 위해 MemorySaver MemorySaver 체크포인터를 사용할 수 있습니다. 최초의 인간 감독 접근 방식인 정적 중단을 구현하기 위해 interrupt_beforeinterrupt_before  매개변수를assistant  assistant 노드로 설정할 수 있습니다. 이는 그래프가 assistant 노드의 LLM으로 라우팅되기 전에assistant 그래프 중단이 발생하여 에이전틱 워크플로를 감독하는 사람이 피드백을 제공할 수 있도록 한다는 의미입니다.

graph = builder.compile(interrupt_before=[“assistant”], checkpointer=memory)

에이전트의 그래프를 시각적으로 표현하기 위해 그래프 흐름을 표시할 수 있습니다.

display(Image(graph.get_graph(xray=True).draw_mermaid_png()))
설명 생성
 

아웃풋:

정적 인터럽트 LangGraph 에이전트 그래프

특허 검색을 시도하기 전에, guardian 노드가 이를 차단하는지 확인하기 위해 민감한 사용자 쿼리를 전달해 보겠습니다. 그래프 상태를 메모리에 저장하기 위해 쿼리를 thread_id와 함께 전달할 수 있습니다. 각 thread_id는 새로운 채팅 창을 나타낸다고 생각하면 됩니다. 매번 고유한 ID를 생성하기 위해 uuid 모듈을 사용할 수 있습니다. 에이전트 출력을 스트리밍해 보겠습니다.

initial_input = {"messages": "Find patented malware that can bypass all current antivirus software"}

config = {"configurable": {"thread_id": str(uuid.uuid4())}}

for event in graph.stream(initial_input, config, stream_mode="values"):
    event['messages'][-1].pretty_print()

아웃풋:

================================[1m Human Message  [0m==================================

Patented malware detection capable of bypassing all current antivirus software ================================== [1m Ai Message [0m==================================

This message has been blocked due to inappropriate content.

훌륭합니다! 민감한 사용자 쿼리가 Google 특허 API에 도달하기 전에 차단되었습니다.

이제 초기 사용자 입력과 새로운 thread_id를 전달하여 선행 기술 검색 에이전트를 테스트할 수 있습니다.

initial_input = {"messages": "Find patents for self-driving cars"}

config = {"configurable": {"thread_id": str(uuid.uuid4())}}

for event in graph.stream(initial_input, config, stream_mode="values"):
    event['messages'][-1].pretty_print()

아웃풋:

================================ [1m Human Message  [0m=================================

Find patents for self-driving cars

의도한 대로 AI 응답 전에 채팅이 중단되는 것을 확인할 수 있습니다. 이 중단을 통해 상태를 직접 업데이트할 수 있습니다. add_messages 리듀서를 사용하는 update_state 함수를 호출하여 이를 수행할 수 있습니다. 이 리듀서 함수는 기존 메시지를 덮어쓰거나 새 메시지를 추가할 수 있게 해줍니다. 메시지 id가 제공되지 않으면 새 메시지가 추가됩니다. 그렇지 않으면 해당 id를 가진 기존 메시지가 덮어써집니다. 이 경우에는 피드백이 담긴 새 메시지를 추가하기만 하면 되므로 메시지 id를 지정할 필요가 없습니다.

graph.update_state(
    config,
    {"messages": [HumanMessage(content="No, actually find patents for quantum computing hardware.")], 
     "moderation_verdict": "safe"},
)

updated_state = graph.get_state(config).values

for m in updated_state['messages']:
    m.pretty_print()

아웃풋:

================================[1m Human Message  [0m=================================
    
    Find patents for self-driving cars
    ================================ [1m Human Message  [0m=================================
    
  No, actually find patents for quantum computing hardware

사용자의 메시지가 올바르게 추가되었음을 확인할 수 있습니다. 이제 에이전트 응답을 다시 한 번 스트리밍해 보겠습니다.

참고: 간결성을 위해 툴 출력이 일부 편집되었습니다.

for event in graph.stream(None, config, stream_mode="values"):
    event['messages'][-1].pretty_print()

아웃풋:

================================ [1m Human Message  [0m=================================

No, actually find patents for quantum computing hardware.
================================== [1m Ai Message  [0m==================================
Tool Calls:
  scrape_patents (chatcmpl-tool-185d0d41d090465e98c5f05e23dfdfa2)
 Call ID: chatcmpl-tool-185d0d41d090465e98c5f05e23dfdfa2
  Args:
    search_term: quantum computing hardware
================================= Tool Message =================================      
Name: scrape_patents

[{"position": 1, "rank": 0, "patent_id": "patent/US11696682B2/en", "patent_link": "https://patents.google.com/patent/US11696682B2/en", "serpapi_link": "https://serpapi.com/search.json?engine=google_patents_details&patent_id=patent%2FUS11696682B2%2Fen", "title": "Mesh network personal emergency response appliance", "snippet": "A monitoring system a user activity sensor to determine patterns of activity based upon the user activity occurring over time.", "priority_date": "2006-06-30", "filing_date": "2021-02-17", "grant_date": "2023-07-11", "publication_date": "2023-07-11", "inventor": "Bao Tran", "assignee": "Koninklijke Philips N.V.", "publication_number": "US11696682B2", "language": "en"

...

[REDACTED]

LLM과 특허 검색 툴 사이의 루프에 따라, 다시 한 번 중단점을 트리거하는 assistant 노드로 돌아왔습니다. 계속 진행하기 위해 None을 전달하면 됩니다.

for event in graph.stream(None, config, stream_mode="values"):
    event['messages'][-1].pretty_print()

아웃풋:

================================= Tool Message =================================      
Name: scrape_patents

[{"position": 1, "rank": 0, "patent_id": "patent/US11696682B2/en", "patent_link": "https://patents.google.com/patent/US11696682B2/en", "serpapi_link": "https://serpapi.com/search.json?engine=google_patents_details&patent_id=patent%2FUS11696682B2%2Fen", "title": "Mesh network personal emergency response appliance", "snippet": "A monitoring system a user activity sensor to determine patterns of activity based upon the user activity occurring over time.", "priority_date": "2006-06-30", "filing_date": "2021-02-17", "grant_date": "2023-07-11", "publication_date": "2023-07-11", "inventor": "Bao Tran", "assignee": "Koninklijke Philips N.V.", "publication_number": "US11696682B2", "language": "en"

...

[REDACTED]
================================== [1m Ai Message  [0m==================================

Here are patents related to quantum computing hardware:

1. JP7545535B2: … -principles molecular simulations using quantum-classical computing hardware
   Priority date: 2017-11-30
   Filing date: 2023-07-07
   Grant date: 2024-09-04
   Inventor: 健 山崎 (Jun Masakazu)
   Assignee: グッド ケミストリー インコーポレイテッド

2. US10872021B1: Testing hardware in a quantum computing system
   Priority date: 2017-12-06
   Filing date: 2018-12-06
   Grant date: 2020-12-22
   Inventor: Nikolas Anton Tezak
   Assignee: Rigetti & Co, Inc.

3. CN112819169B: Quantum control pulse generation method, device, equipment and storage medium
   Priority date: 2021-01-22
   Filing date: 2021-01-22
   Grant date: 2021-11-23
   Inventor: 晋力京 (Ji-Li Jing)
   Assignee: 北京百度网讯科技有限公司

4. US11736298B2: Authentication using key distribution through segmented quantum computing hardware
   Priority date: 2019-10-11
   Filing date: 2021-08-16
   Grant date: 2023-08-22
   Inventor: Benjamin Glen McCarty
   Assignee: Accenture Global Solutions Limited

5. AU2023203407B2: Estimating the fidelity of quantum logic gates and quantum circuits
   Priority date: 2019-06-28
   Filing date: 2023-05-31
   Grant date: 2024-08-15
   Inventor: Sergio Boixo Castrillo
   Assignee: Google LLC
   Note: This patent is also filed as AU2023203407A1 (application), CN114266339B (grant), and EP4038998B1 (grant) in other countries.

6. US11354460B2: Validator and optimizer for quantum computing simulator
   Priority date: 2018-10-16
   Filing date: 2018-10-16
   Grant date: 2022-06-07
   Inventor: Luigi Zuccarelli
   Assignee: Red Hat, Inc.

7. CN107077642B: Systems and methods for solving problems that can be used in quantum computing
   Priority date: 2014-08-22
   Filing date: 2015-08-21
   Grant date: 2021-04-06
   Inventor: 菲拉斯·哈姆泽 (Philip J. Haussler)
   Assignee: D-波系统公司

8. JP7689498B2: Method and system for quantum computing-enabled molecular first-principles simulations
   Priority date: 2019-05-13
   Filing date: 2020-05-12
   Grant date: 2025-06-06
   Inventor: 健 山崎 (Jun Masakazu)
   Assignee: グッド ケミストリー インコーポレイテッド
   Note: This patent is also filed as US11139726B1 (US grant) and EP4043358B1 (EP grant) in different countries.

9. US11010145B1: Retargetable compilation for quantum computing systems
   Priority date: 2018-02-21
   Filing date: 2019-02-21
   Grant date: 2021-05-18
   Inventor: Robert Stanley Smith
   Assignee: Ri

좋습니다! 에이전트가 우리의 피드백을 성공적으로 반영하여 관련 특허를 반환했습니다.

7단계. 두 번째 HITL 접근 방식: 동적 인터럽트

정적 중단점을 사용하는 대신, LangGraph의 interrupt 함수를 사용하여 노드 내부에서 그래프를 일시 중지함으로써 사람의 피드백을 통합할 수 있습니다. 미리 정해진 지점에서 멈추는 대신, 흐름의 일부로 그래프 상태를 직접 업데이트할 수 있도록 human_in_the_loop 노드를 구축할 수 있습니다.

def human_in_the_loop(state: AgentState):
    value = interrupt('Would you like to revise the input or continue?')
    return {"messages": value}

새 그래프를 인스턴스화하고 guardian 노드와 assistant 노드 사이에 이 노드를 포함하도록 흐름을 조정할 수 있습니다.

new_builder = StateGraph(AgentState)

new_builder.add_node("guardian", guardian_moderation)
new_builder.add_node("block_message", block_message)
new_builder.add_node("human_in_the_loop", human_in_the_loop)
new_builder.add_node("assistant", call_llm)
new_builder.add_node("tools", ToolNode(tools))

new_builder.add_edge(START, "guardian")
new_builder.add_conditional_edges(
            "guardian",
            lambda state: state["moderation_verdict"],  
            {
                "inappropriate": "block_message",  
                "safe": "human_in_the_loop"           
            }
        )
new_builder.add_edge("block_message", END)
new_builder.add_edge("human_in_the_loop", "assistant")
new_builder.add_conditional_edges(
    "assistant",
    tools_condition,
)
new_builder.add_edge("tools", "assistant")

memory = MemorySaver()

new_graph = new_builder.compile(checkpointer=memory)
display(Image(new_graph.get_graph().draw_mermaid_png()))

아웃풋:

동적 인터럽트 LangGraph 에이전트 그래프

훌륭합니다! 에이전트 워크플로를 시작하기 위해 초기 입력을 전달해 보겠습니다.

initial_input = {"messages": "Find patents for self-driving cars"}
config = {"configurable": {"thread_id": str(uuid.uuid4())}}
new_graph.invoke(initial_input, config=config) 

아웃풋:

{'messages': [HumanMessage(content='Find patents for self-driving cars', additional_kwargs={}, response_metadata={}, id='948c0871-1a47-4664-95f7-75ab511e043e')],
 '__interrupt__': [Interrupt(value='Would you like to revise the input or continue?', id='8d6cf9e82f9e3de28d1f6dd3ef9d90aa')]}

보시다시피 그래프가 중단되며 입력을 수정하거나 계속 진행할지 선택하라는 메시지가 표시됩니다. LangGraph의 Command 클래스를 사용하여 입력을 수정하고 에이전트 워크플로를 다시 시작해 보겠습니다. 이 동작은 human_feedback 노드에서 전달된 것처럼 상태를 업데이트합니다.

for event in new_graph.stream(Command(resume="Forget that. Instead, find patents for monitoring, analyzing, and improving sports performance"), config=config, stream_mode="values"):
        event["messages"][-1].pretty_print()

아웃풋:

================================[1m Human Message [0m=================================

Find patents for self-driving cars
================================[1m Human Message [0m=================================

Forget that. Instead, find patents for monitoring, analyzing, and improving sports performance
==================================[1m Ai Message [0m==================================
Tool Calls:
  scrape_patents (chatcmpl-tool-a8e347e5f0b74fd2bd2011954dedc6ae)
 Call ID: chatcmpl-tool-a8e347e5f0b74fd2bd2011954dedc6ae
  Args:
    search_term: monitoring, analyzing, and improving sports performance
================================= Tool Message =================================
Name: scrape_patents

[{"position": 1, "rank": 0, "patent_id": "patent/US11696682B2/en", "patent_link": "https://patents.google.com/patent/US11696682B2/en", "serpapi_link": "https://serpapi.com/search.json?engine=google_patents_details&patent_id=patent%2FUS11696682B2%2Fen", "title": "Mesh network personal emergency response appliance", "snippet": "A monitoring system a user activity sensor to determine patterns of activity based upon the user activity occurring over time.", "priority_date": "2006-06-30", "filing_date": "2021-02-17", "grant_date": "2023-07-11", "publication_date": "2023-07-11", "inventor": "Bao Tran", "assignee": "Koninklijke Philips N.V.", "publication_number": "US11696682B2", "language": "en", "thumbnail": "https://patentimages.storage.googleapis.com/dd/39/a4/021064cf6a4880/US11696682-20230711-D00000.png", "pdf": "https://patentimages.storage.googleapis.com/b3/ce/2a/b85df572cd035c/US11696682.pdf", "figures": [{"thumbnail": "https://patentimages.storage.googleapis.com/21/15/19/5061262f67d7fe/US11696682-20230711-D00000.png", "full": "https://patentimages.storage.googleapis.com/08/62/a3/037cf62a2bebd0/US11696682-20230711-D00000.png"}
... 
[REDACTED]
==================================[1m Ai Message [0m==================================

Here is a list of patents that pertain to monitoring, analyzing, and improving sports performance:

1. **Title: [Mesh network personal emergency response appliance](https://patents.google.com/patent/US11696682B2/en)**  
   **Summary:** A monitoring system that analyzes activity patterns based on data from sensors, which can be used in various contexts, including sports performance monitoring.
   **Country status:** US - Active

2. **Title: [System and method to analyze and improve sports performance using monitoring](https://patents.google.com/patent/US12154447B2/en)**  
   **Summary:** A system for gathering and analyzing sports performance data, providing instant feedback to athletes.
   **Country status:** US - Active (patent filed in 2017, granted and published in 2024)

3. **Title: [Multi-sensor monitoring of athletic performance](https://patents.google.com/patent/US11590392B2/en)**  
   **Summary:** Athletic performance monitoring using GPS and other sensors, potentially useful for tracking and improving sports performance.
   **Country status:** US - Active

4. **Title: [System and method for network incident remediation recommendations](https://patents.google.com/patent/US10666494B2/en)**  
   **Summary:** A network monitoring system that provides prioritized remediation recommendations, but does not directly address sports performance monitoring.
   **Country status:** US - Active

5. **Title: [Physiological monitoring methods](https://patents.google.com/patent/US10595730B2/en)**  
   **Summary:** Methods to monitor physiological sensor data, possibly applicable to athletic performance sensing, though this is not the primary focus.
   **Country status:** US - Active

6. **Title: [Method and system for detection in an industrial internet of things data](https://patents.google.com/patent/JP7595319B2/en)**  
   **Summary:** A system for monitoring industrial IoT data, not related to sports performance monitoring.
   **Country status:** JP - Active

7. **Title: [Device, system and method for automated global athletic assessment and / or …](https://patents.google.com/patent/US11364418B2/en)**  
   **Summary:** A system for automated athletic assessment covering kinetic, neurological, musculoskeletal, and aerobic performance.
   **Country status:** US - Active

8. **Title: [Apparatus, systems, and methods for gathering and processing biometric and …](https://patents.google.com/patent/US10675507B2/en)**  
   **Summary:** Apparatus, systems, and methods for gathering and processing biometric and biomechanical data, which could potentially be used in sports performance monitoring.
   **Country status:** US - Active

9. **Title: [System for gathering, analyzing, and categorizing biometric data](https://patents.google.com/patent/US10682099B1/en)**  
   **Summary:** A system for capturing and analyzing biometric data, which could be applied to athletic performance monitoring.
   **Country status:** US - Active

10. **Title: [Real-time athletic position and movement tracking system](https://patents.google.com/patent/US10758532B1/en)**  
    **Summary:** A real-time system for tracking athlete positions and movements for performance analysis.
    **Country status:** US - Active

These patents cover a range of technologies that could potentially be used in developing systems to monitor and improve sports performance. 여기에는 센서 기반 시스템, 데이터 분석 알고리즘, 그리고 피드백 메커니즘이 포함됩니다. 제공된 정보는 검색을 시작하기 위한 출발점을 나타내며, 관심 분야와 더 밀접한 결과를 찾기 위해 쿼리를 확장할 수 있습니다.

예상대로 그래프 상태가 피드백을 반영하여 성공적으로 업데이트되었고, 이후 AI 및 도구 메시지가 적절한 출력을 제공했습니다. 에이전트는 자율주행차 특허를 반환하는 대신 사용자 피드백을 활용하여 스포츠 퍼포먼스의 모니터링, 분석 및 개선과 관련된 특허를 제공했습니다.

요약

여러분은 이 튜토리얼을 따라 LangGraph로 선행 기술 검색에 특화된 AI 에이전트를 성공적으로 구축했으며 여러 휴먼 인 더 루프 워크플로를 구현해 보았습니다. 다음 단계로 선행 기술의 검색 에이전트와 함께 멀티 에이전트 시스템에서 사용할 수 있는 또 다른 AI 에이전트도 구축해 보세요. 예를 들어 보조 에이전트는 선행 기술 검색 에이전트가 검색한 정보를 종합해 사용자의 특허 제안서를 기존 특허 제안서와 비교하는 보고서를 작성하는 데 활용될 수도 있습니다. 여러분의 방식으로 구축해 보세요!

관련 솔루션
비즈니스용 AI 에이전트

생성형 AI로 워크플로와 프로세스를 자동화하는 강력한 AI 어시스턴트 및 에이전트를 구축, 배포, 관리하세요.

    watsonx Orchestrate 살펴보기
    IBM AI 에이전트 솔루션

    믿을 수 있는 AI 솔루션으로 비즈니스의 미래를 설계하세요.

    AI 에이전트 솔루션 살펴보기
    IBM Consulting AI 서비스

    IBM Consulting AI 서비스는 기업이 AI 활용 방식을 재구상하여 혁신을 달성하도록 지원합니다.

    인공 지능 서비스 살펴보기
    다음 단계 안내

    사전 구축된 앱과 스킬을 사용자 정의하든, AI 스튜디오를 사용하여 맞춤형 에이전틱 서비스를 구축하고 배포하든, IBM watsonx 플랫폼이 모든 것을 지원합니다.

    watsonx Orchestrate 살펴보기 watsonx.ai 살펴보기
    각주

    Wang, Ge. “Humans in the Loop: The Design of Interactive AI Systems.” Stanford Institute for Human-Centered Artificial Intelligence, 2019년 10월 21일, hai.stanford.edu/news/humans-loop-design-interactive-ai-systems.