Agent Server 런에 대한 사용자 피드백 수집하기

Agent Server 런에 대한 사용자 피드백 수집하기

이 튜토리얼은 Agent Server 런에 대한 사용자 피드백을 수집하고, 이를 LangSmith의 트레이스에 자동으로 연결하는 방법을 보여줘요. 런을 만들 때 요청 본문의 feedback_keys 필드에 키들을 포함하면, 각 키에 대한 사전 서명된 URL이 응답으로 돌아와서 클라이언트가 그 URL로 Agent Server 런에 대한 사용자 피드백을 수집할 수 있답니다.

출처: 문서

본문

이 튜토리얼에서는 Agent Server 런에 대한 사용자 피드백을 수집하고, 이를 LangSmith의 트레이스에 자동으로 연결하는 방법을 보여줍니다. 런을 만들 때 요청 본문의 feedback_keys 필드에 키들을 포함하세요. 응답은 각 키에 대한 사전 서명된 URL을 반환하며, 클라이언트가 이 URL을 사용해 Agent Server 런에 대한 사용자 피드백을 수집할 수 있습니다.

LangSmith는 피드백을 사용해 에이전트 구현을 지속적으로 개선합니다. LangSmith에서 피드백이 어떻게 작동하는지 더 자세히 알아보려면 LangSmith 피드백을 참고하세요.

작동 방식

  1. 런을 만들고 요청 본문에 feedback_keys를 포함합니다. 예를 들어 POST /threads/{thread_id}/runs/stream을 호출할 때 요청 본문의 feedback_keys를 다음과 같이 설정합니다:
    ["user_liked", "user_disliked"]
    
  2. 응답의 feedback 객체에는 각 키에 대한 사전 서명된 URL이 포함되어 있습니다. 예를 들어 feedback 객체는 다음과 같습니다:
    {
        "user_liked": "https://api.smith.langchain.com/api/v1/feedback/tokens/ef19fedf-dcac-4cbb-a59c-00661efd6425",
        "user_disliked": "https://api.smith.langchain.com/api/v1/feedback/tokens/e952734e-c0a0-417b-a04d-fc2209691ed5"
    }
    
  3. 반환된 URL에 요청합니다 (예: POST /api/v1/feedback/tokens/{token_id}). 그러면 피드백 키가 Agent Server 런에서 생성된 트레이스와 연결됩니다. 자세한 내용은 LangSmith API 레퍼런스를 참고하세요.
  4. LangSmith는 선택한 피드백 키(예: user_liked 또는 user_disliked)를 사용해 제출된 피드백을 런과 연결합니다.

feedback_keys로 스트리밍 런 API 호출하기

런을 만들고 응답에서 feedback 객체를 파싱합니다.

Python SDK

from langgraph_sdk import get_client

client = get_client(url="<DEPLOYMENT_URL>", api_key="<API_KEY>")

thread = await client.threads.create()
thread_id = thread["thread_id"]

feedback_urls = {}

async for event in client.runs.stream(
    thread_id,
    "agent",
    input={
        "messages": [
            {"role": "user", "content": "Tell me a joke about databases."}
        ]
    },
    stream_mode="updates",
    feedback_keys=["user_liked", "user_disliked"],
):
    if event.event == "feedback":
        # Example: {"user_liked": ".../feedback/tokens/<id>", "user_disliked": "..."}
        feedback_urls = event.data
        print("Feedback URLs:", feedback_urls)
    elif event.event == "updates":
        print(event.data)

JavaScript SDK

import { Client } from "@langchain/langgraph-sdk";

const client = new Client({ apiUrl: "<DEPLOYMENT_URL>", apiKey: *** });

const thread = await client.threads.create();
const threadId = thread.thread_id;

let feedbackUrls = {};

const streamResponse = client.runs.stream(threadId, "agent", {
  input: {
    messages: [{ role: "user", content: "Tell me a joke about databases." }],
  },
  streamMode: "updates",
  feedbackKeys: ["user_liked", "user_disliked"],
});

for await (const event of streamResponse) {
  if (event.event === "feedback") {
    // Example: { user_liked: ".../feedback/tokens/<id>", user_disliked: "..." }
    feedbackUrls = event.data;
    console.log("Feedback URLs:", feedbackUrls);
  } else if (event.event === "updates") {
    console.log(event.data);
  }
}

cURL

curl --request POST \
  --url "<DEPLOYMENT_URL>/threads/<THREAD_ID>/runs/stream" \
  --header "Content-Type: application/json" \
  --header "x-api-key: *** \
  --data '{
    "assistant_id": "agent",
    "input": {
      "messages": [
        {
          "role": "user",
          "content": "Tell me a joke about databases."
        }
      ]
    },
    "stream_mode": "updates",
    "feedback_keys": ["user_liked", "user_disliked"]
  }'

스트리밍된 feedback 이벤트 처리하기

스트림은 다음과 같은 feedback 이벤트를 방출합니다:

event: feedback
data: {"user_liked":"https://api.smith.langchain.com/api/v1/feedback/tokens/ef19fedf-dcac-4cbb-a59c-00661efd6425", "user_disliked": "https://api.smith.langchain.com/api/v1/feedback/tokens/e952734e-c0a0-417b-a04d-fc2209691ed5"}

data의 각 키는 feedback_keys에 전달한 값 중 하나와 일치합니다. 각 값은 클라이언트가 해당 런에 대한 피드백을 제출하기 위해 호출할 수 있는 생성된 URL입니다.

생성된 URL로 피드백 제출하기

사용자가 피드백 옵션을 선택하면 해당 URL로 POST 요청을 보냅니다. GET도 지원됩니다. 자세한 내용은 LangSmith API 레퍼런스를 참고하세요.

예를 들어 사용자가 엄지 내리기 버튼을 클릭하면 user_disliked URL을 호출합니다:

POST

curl --request POST \
  --url "https://api.smith.langchain.com/api/v1/feedback/tokens/e952734e-c0a0-417b-a04d-fc2209691ed5" \
  --header "Content-Type: application/json" \
  --data '{
    "score": 1,
    "value": 0,
    "comment": "I didn't like this joke because it didn't make me laugh.",
    "correction": {},
    "metadata": {}
  }'

GET

metadataGET에서 지원되지 않습니다.

curl --request GET \
  --url "https://api.smith.langchain.com/api/v1/feedback/tokens/e952734e-c0a0-417b-a04d-fc2209691ed5?score=1&value=0&comment=I%20didn%27t%20like%20this%20joke%20because%20it%20didn%27t%20make%20me%20laugh.&correction=%7B%7D"

이 요청이 성공하면 LangSmith는 user_disliked 키를 사용해 트레이스에 피드백을 기록합니다.

피드백 데이터 모델 최적화하기

user_likeduser_disliked 키는 user_score 같은 단일 키 아래로 모델링할 수도 있습니다.

예를 들어:

  • user_liked에는 key="user_score"score=1을 사용
  • user_disliked에는 key="user_score"score=-1을 사용

이렇게 하면 모든 사용자 선호 신호가 하나의 피드백 키 아래에 그룹화되어 분석이 단순해집니다.

피드백 데이터 모델은 유연하며 사용 사례에 맞게 설계되어야 합니다. 예를 들어 어떤 애플리케이션은 별도의 불리언 스타일 키(user_liked, user_disliked)를 선호하는 반면, 다른 애플리케이션은 단일 숫자 점수(user_score) 또는 여러 피드백 키를 가진 더 풍부한 루브릭을 선호할 수 있습니다.

클라이언트 UI에서 프로덕션화하기

프로덕션화된 솔루션은 피드백 URL을 수동으로 호출하는 대신 프론트엔드를 통해 노출합니다.

구현의 높은 수준 예시:

  1. 백엔드 또는 프론트엔드에서 런을 만듭니다.
  2. feedback 객체를 캡처하고 반환된 URL을 저장합니다.
  3. 엄지 위/아래 버튼과 피드백 폼 같은 피드백 컨트롤을 렌더링합니다.
  4. 피드백 제출 시 사용자의 피드백 의도에 따라 피드백 URL에 POST 또는 GET을 보냅니다.
  5. 선택적으로 제출 후 피드백 컨트롤을 비활성화하고 사용자에게 확인을 표시합니다.

더 알아보기