기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.
AgentCore 평가를 위한 LangGraph 원격 측정 설정
이 페이지에서는 LangGraph 에이전트를 계측하는 방법, 스팬을 식별하는 방법, 평가 필드를 추출하는 방법을 설명합니다. AgentCore Evaluations는 Python 및 TypeScript로 구축된 LangGraph 에이전트를 지원합니다.이 페이지에서는 Python 에이전트 지원 및 TypeScript 에이전트 지원에서 각 언어를 별도로 다룹니다. LangGraph 에이전트를 안정적으로 평가할 수 있도록 구성하는 모범 사례와 함께 종료됩니다.
주제
Python 에이전트 지원
Python LangGraph 에이전트는 범위 이름opentelemetry.instrumentation.langchain(OpenTelemetry) 또는 openinference.instrumentation.langchain (OpenInference)으로 스팬을 내보냅니다.
에이전트 계측
OpenTelemetry() 또는 OpenInferenceOpenInference()의 두 가지 계측 라이브러리 중 하나를 사용하여 LangGraph 에이전트를 계측할 수 있습니다openinference-instrumentation-langchain.opentelemetry-instrumentation-langchain Amazon Bedrock AgentCore Evaluations는 두 라이브러리를 모두 지원합니다. 라이브러리는 서로 다른 범위 이름을 내보내고 서로 다른 스팬 속성을 사용합니다. 평가 서비스는 각각에서 동일한 값을 추출합니다.
Amazon Bedrock AgentCore 런타임에서와 같이 에이전트가 AWS Distro for OpenTelemetry(ADOT)를 사용하여 실행되는 경우 명시적 계측 코드를 추가할 필요가 없습니다. 프로젝트의 종속성에 계측 라이브러리를 추가하면 충분합니다. ADOT는 시작 시 이를 검색하고 자동으로 활성화합니다.
종속성에 원하는 경로의 계측 라이브러리를 추가합니다. 다음 예제에서는 최소 버전을 고정하고 고정할 이유가 없는 한 사용 가능한 최신 버전을 사용합니다.
예
- OpenTelemetry
-
참고: 버전 0.55.0 이상을 사용합니다. 버전 0.55.0에는 평가 서비스가 의존하는 GitHub 웹 사이트의 최신 OpenTelemetry 생성형 AI 에이전트 스팬 규칙에 대한 지원이 추가되었습니다.
opentelemetry-instrumentation-langchain을 종속성에 추가합니다. 방출되는 범위 이름은 입니다opentelemetry.instrumentation.langchain.
requirements.txt:
opentelemetry-instrumentation-langchain>=0.55.0
pyproject.toml:
[project]
dependencies = [
"opentelemetry-instrumentation-langchain>=0.55.0",
]
- OpenInference
-
openinference-instrumentation-langchain을 종속성에 추가합니다. 방출되는 범위 이름은 입니다openinference.instrumentation.langchain.
requirements.txt:
openinference-instrumentation-langchain>=0.1.62
pyproject.toml:
[project]
dependencies = [
"openinference-instrumentation-langchain>=0.1.62",
]
계측은 관찰성을 설정하는 한 단계입니다. 평가를 위해 원격 측정을 내보내려면 관찰성 설정에서 전체 설정을 완료합니다.
스팬 식별 방법
스팬을 분류하는 데 사용되는 속성은 두 계측 라이브러리 간에 다릅니다.
예
- OpenTelemetry
-
OpenTelemetry 계측 라이브러리는 traceloop.span.kind 속성을 사용하여 스팬을 분류하고 최신 버전도를 설정합니다gen_ai.operation.name.
| 범위 유형 |
속성 식별 |
|
에이전트 호출
|
traceloop.span.kind = workflow (또한 gen_ai.operation.name = invoke_agent)
|
|
도구 실행
|
traceloop.span.kind = tool (또한 gen_ai.operation.name = execute_tool)
|
|
Inference
|
gen_ai.operation.name = chat
|
- OpenInference
-
OpenInference 계측 라이브러리는 openinference.span.kind 속성을 사용하여 스팬을 분류합니다.
| 범위 유형 |
속성 식별 |
|
에이전트 호출
|
openinference.span.kind = CHAIN 또는 AGENT
|
|
도구 실행
|
openinference.span.kind = TOOL
|
|
Inference
|
openinference.span.kind = LLM
|
호출 에이전트 범위의 경우 입력 및 출력에 메시지별 목록 정리가 포함되지 않습니다. 대신 콘텐츠는 직렬화된 LangChain 그래프 상태, 즉 전체 상태를 래핑하는 JSON 문자열입니다. 이 직렬화된 상태의 정확한 모양은 두 계측 라이브러리 간에 다릅니다. 두 경우 모두 서비스는 이를 구문 분석하여 사용자 프롬프트(사람 메시지)와 에이전트 응답(AI 메시지)을 찾습니다.
또한 LangGraph는 둘 이상의 형식으로 메시지 역할을 직렬화합니다. 역할은 소문자 값(human, ai, tool) 또는 LangChain 메시지 클래스 이름(HumanMessage, AIMessage, )으로 표시될 수 있습니다ToolMessage. 서비스는 두 양식을 모두 인식합니다.
이 콘텐츠의 위치는 원격 측정이 수집된 방식에 따라 달라집니다. 식별 속성(traceloop.span.kind 또는 openinference.span.kind)은 두 경우 모두 스팬에 있습니다. 자세한 내용은 원격 측정 설정 및 전송을 참조하세요.
분할 원격 측정을 사용하면 서비스는 각 범위와 상관관계가 있는 이벤트 레코드에서 콘텐츠를 읽습니다.
자세한 내용은 분할 원격 측정의 스팬 예제를 참조하세요.
통합 원격 측정을 사용하면 동일한 콘텐츠가 속성으로 스팬에 유지됩니다. 속성은 계측 라이브러리에 따라 다릅니다.
-
OpenTelemetry:
-
OpenInference:
자세한 내용은 통합 원격 측정의 스팬 예제를 참조하세요.
분할 원격 측정의 스팬 예제
분할 원격 측정을 사용하면 스팬은 식별 속성을 전달하고 콘텐츠는 상관관계가 있는 이벤트 레코드에 있습니다. 다음 예제는 Amazon Bedrock AgentCore 런타임에 배포된 Python LangGraph 여행 계획 에이전트에서 가져온 것입니다. 각 계측 라이브러리 아래에 동일한 에이전트가 표시됩니다.
이 예제는 완전한 범위가 아닙니다. 실제 에이전트 상호 작용의 대표 데이터를 표시하며, 일부 필드는 생략되고 긴 값은 가독성을 위해 잘립니다.
OpenTelemetry
예
- Invoke agent span
-
traceloop.span.kind 속성(workflow)은 이를 호출 에이전트 범위로 식별합니다. 최신 라이브러리 버전도 gen_ai.operation.name = 로 설정됩니다invoke_agent.
{
"traceId": "6a01eef11066751d68f90def0da1f80a",
"spanId": "ba1833fa7f097041",
"parentSpanId": "836a5ccf9a2186cc",
"name": "travel_agent.workflow",
"kind": "INTERNAL",
"scope": {
"name": "opentelemetry.instrumentation.langchain",
"version": "0.60.0"
},
"startTimeUnixNano": 1778511607308521744,
"endTimeUnixNano": 1778511610930280395,
"durationNano": 3621758651,
"attributes": {
"traceloop.span.kind": "workflow",
"gen_ai.operation.name": "invoke_agent",
"gen_ai.agent.name": "travel_agent",
"gen_ai.provider.name": "langgraph",
"traceloop.workflow.name": "travel_agent",
"session.id": "sea-nyc-trip-2-turns-adot_v17_opentelemetry_0_60_0"
},
"status": {
"code": "OK"
}
}
상관관계가 있는 이벤트 레코드에는 대화가 포함됩니다. 각 메시지의 content는 직렬화된 LangChain 그래프 상태입니다. 입력은 inputs 키 아래에 상태를 래핑합니다. 출력은 각 메시지를 LangChain 생성자 객체로 사용하여 outputs 키 아래에 이를 래핑합니다. 사용자 프롬프트는 인적 메시지이고 에이전트 응답은 직렬화된 상태 내의 AI 메시지입니다.
{
"spanId": "ba1833fa7f097041",
"traceId": "6a01eef11066751d68f90def0da1f80a",
"scope": {
"name": "opentelemetry.instrumentation.langchain"
},
"body": {
"input": {
"messages": [
{
"content": "{\"inputs\": {\"messages\": [{\"role\": \"user\", \"content\": \"Hey, how can you help me\"}]}, \"tags\": [], \"metadata\": {\"ls_integration\": \"langchain_create_agent\", \"lc_agent_name\": \"travel_agent\", \"thread_id\": \"sea-nyc-trip-2-turns-adot_v17_opentelemetry_0_60_0\"}, \"kwargs\": {\"name\": \"travel_agent\"}}",
"role": "user"
}
]
},
"output": {
"messages": [
{
"content": "{\"outputs\": {\"messages\": [{\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain\", \"schema\", \"messages\", \"HumanMessage\"], \"kwargs\": {\"content\": \"Hey, how can you help me\", \"type\": \"human\", \"id\": \"12345678-1234-1234-1234-123456789012\"}}, {\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain\", \"schema\", \"messages\", \"AIMessage\"], \"kwargs\": {\"content\": \"Hello! I'm your travel planning assistant ...\", \"type\": \"ai\"}}]}, \"kwargs\": {\"tags\": []}}",
"role": "assistant"
}
]
}
}
}
- Execute tool span
-
traceloop.span.kind 속성(tool)은 이를 실행 도구 범위로 식별합니다. 에는 도구 이름과 gen_ai.operation.name =가 gen_ai.tool.name 들어 있습니다execute_tool.
{
"traceId": "6a01eefa5c52f3d86a35038f35f5ba30",
"spanId": "5b332f3cd15ace04",
"parentSpanId": "922a21edc04eba29",
"name": "execute_tool search_flights",
"kind": "INTERNAL",
"scope": {
"name": "opentelemetry.instrumentation.langchain",
"version": "0.60.0"
},
"startTimeUnixNano": 1778511614892698232,
"endTimeUnixNano": 1778511614893399618,
"durationNano": 701386,
"attributes": {
"traceloop.span.kind": "tool",
"gen_ai.operation.name": "execute_tool",
"gen_ai.tool.name": "search_flights",
"gen_ai.tool.type": "function",
"gen_ai.tool.description": "Search for available flights between cities.",
"gen_ai.provider.name": "langgraph",
"traceloop.workflow.name": "travel_agent",
"session.id": "sea-nyc-trip-2-turns-adot_v17_opentelemetry_0_60_0"
},
"status": {
"code": "OK"
}
}
상관관계가 있는 이벤트 레코드에는 도구 입력( 인수) 및 출력(결과, LangChain으로 직렬화됨)이 포함됩니다ToolMessage.
{
"spanId": "5b332f3cd15ace04",
"traceId": "6a01eefa5c52f3d86a35038f35f5ba30",
"scope": {
"name": "opentelemetry.instrumentation.langchain"
},
"body": {
"input": {
"messages": [
{ "content": "{\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}" }
]
},
"output": {
"messages": [
{
"role": "tool",
"name": "search_flights",
"content": "{\"origin\": \"SEA\", \"destination\": \"NYC\", \"flights\": [ ... ]}"
}
]
}
}
}
OpenInference
OpenInference 라이브러리를 사용하면 스팬 유형이 openinference.span.kind 속성에 전달되고 에이전트 입력 및 출력이 상관관계가 있는 이벤트 레코드에 직렬화됩니다.
예
- Invoke agent span
-
openinference.span.kind 속성( CHAIN또는 그래프가 이름으로 컴파일된 AGENT 경우)은 이를 호출 에이전트 범위로 식별합니다.
{
"traceId": "6a387ee61078243c1cc455ed45c6c313",
"spanId": "0a7990d804132a9b",
"parentSpanId": "29ae22014173881c",
"name": "LangGraph",
"kind": "INTERNAL",
"scope": {
"name": "openinference.instrumentation.langchain",
"version": "0.1.66"
},
"startTimeUnixNano": 1782087405949310976,
"endTimeUnixNano": 1782087408945828864,
"durationNano": 2996517888,
"attributes": {
"openinference.span.kind": "CHAIN",
"input.mime_type": "application/json",
"output.mime_type": "application/json",
"llm.input_messages.0.message.role": "user",
"session.id": "sea-nyc-trip-2-turns-oi-0-1-66"
},
"status": {
"code": "OK"
}
}
상관관계가 있는 이벤트 레코드에는 대화가 포함됩니다. 사용자 프롬프트는 사람-역할 메시지이고 에이전트 응답은 직렬화된 메시지의 AI-역할 메시지입니다.
{
"spanId": "0a7990d804132a9b",
"traceId": "6a387ee61078243c1cc455ed45c6c313",
"scope": {
"name": "openinference.instrumentation.langchain"
},
"body": {
"input": {
"messages": [
{
"role": "user",
"content": "{\"messages\": [{\"role\": \"user\", \"content\": \"Hey, how can you help me\"}]}"
}
]
},
"output": {
"messages": [
{
"content": "{\"messages\": [{\"type\": \"human\", \"data\": {\"content\": \"Hey, how can you help me\", ...}}, {\"type\": \"ai\", \"data\": {\"content\": \"Hello! I'm your travel planning assistant ...\", ...}}]}",
"role": "assistant"
}
]
}
}
}
- Execute tool span
-
openinference.span.kind 속성(TOOL)은 이를 실행 도구 범위로 식별합니다.는 도구 이름을 tool.name 보유합니다.
{
"traceId": "6a387ef07b8f4f3732fab45d3c0b51ff",
"spanId": "ab105c12cc40048f",
"parentSpanId": "9b2d4e72760690b4",
"name": "search_flights",
"kind": "INTERNAL",
"scope": {
"name": "openinference.instrumentation.langchain",
"version": "0.1.66"
},
"startTimeUnixNano": 1782087411724620032,
"endTimeUnixNano": 1782087411725306880,
"durationNano": 686848,
"attributes": {
"openinference.span.kind": "TOOL",
"tool.name": "search_flights",
"tool.description": "Search for available flights between cities.",
"input.mime_type": "application/json",
"output.mime_type": "application/json",
"session.id": "sea-nyc-trip-2-turns-oi-0-1-66"
},
"status": {
"code": "OK"
}
}
상관관계가 있는 이벤트 레코드에는 도구 입력( 인수) 및 출력(결과, LangChain으로 직렬화됨)이 포함됩니다ToolMessage.
{
"spanId": "ab105c12cc40048f",
"traceId": "6a387ef07b8f4f3732fab45d3c0b51ff",
"scope": {
"name": "openinference.instrumentation.langchain"
},
"body": {
"input": {
"messages": [
{
"role": "user",
"content": "{\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}"
}
]
},
"output": {
"messages": [
{
"content": "{\"type\": \"tool\", \"data\": {\"content\": \"{\\\"origin\\\": \\\"SEA\\\", \\\"destination\\\": \\\"NYC\\\", \\\"flights\\\": [ ... ]}\", \"type\": \"tool\", \"name\": \"search_flights\", \"tool_call_id\": \"toolu_bdrk_01LzXXJCfpfuS7Bpf7e1qLMg\", \"status\": \"success\"}}",
"role": "assistant"
}
]
}
}
}
통합 원격 측정의 스팬 예제
통합 원격 측정을 사용하면 동일한 콘텐츠가 스팬 속성에 유지되고 별도의 이벤트 레코드가 생성되지 않습니다. 다음은 Python LangGraph 여행 계획 에이전트의 예입니다. 각 계측 라이브러리 아래에 동일한 에이전트가 표시됩니다.
이 예제는 완전한 범위가 아닙니다. 실제 에이전트 상호 작용의 대표 데이터를 표시하며, 일부 필드는 생략되고 긴 값은 가독성을 위해 잘립니다.
OpenTelemetry
예
- Invoke agent span
-
gen_ai.task.input 속성은 사용자 프롬프트를 유지하고 gen_ai.task.output 속성은 에이전트 응답과 함께 직렬화된 상태를 유지합니다. 둘 다 직렬화된 LangChain 그래프 상태입니다.
{
"traceId": "6a4de7b85e61747e6b568a1f4768e89d",
"spanId": "31ea3d5882dac680",
"name": "LangGraph.workflow",
"kind": "INTERNAL",
"scope": {
"name": "opentelemetry.instrumentation.langchain",
"version": "0.62.1"
},
"attributes": {
"traceloop.span.kind": "workflow",
"gen_ai.operation.name": "invoke_agent",
"gen_ai.agent.name": "LangGraph",
"gen_ai.task.input": "{\"inputs\": {\"messages\": [{\"role\": \"user\", \"content\": \"Hey, how can you help me\"}]}, \"tags\": [], \"metadata\": { ... }, \"kwargs\": {\"name\": \"LangGraph\"}}",
"gen_ai.task.output": "{\"outputs\": {\"messages\": [{\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain\", \"schema\", \"messages\", \"HumanMessage\"], \"kwargs\": {\"content\": \"Hey, how can you help me\", \"type\": \"human\"}}, {\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain\", \"schema\", \"messages\", \"AIMessage\"], \"kwargs\": {\"content\": \"Hello! I'm your travel planning assistant ...\", \"type\": \"ai\"}}]}, \"kwargs\": {\"tags\": []}}",
"session.id": "sea-nyc-trip-2-turns-unified"
},
"status": {
"code": "OK"
}
}
- Execute tool span
-
gen_ai.tool.call.arguments 속성에는 도구 인수가 있고 gen_ai.tool.call.result 속성에는 LangChain 로 직렬화된 도구 결과가 있습니다ToolMessage.
{
"traceId": "6a4de7c376913db82e6f0f336a16731d",
"spanId": "b64c37adefae74f0",
"name": "execute_tool search_flights",
"kind": "INTERNAL",
"scope": {
"name": "opentelemetry.instrumentation.langchain",
"version": "0.62.1"
},
"attributes": {
"traceloop.span.kind": "tool",
"gen_ai.operation.name": "execute_tool",
"gen_ai.tool.name": "search_flights",
"gen_ai.tool.description": "Search for available flights between cities.",
"gen_ai.tool.call.arguments": "{\"input_str\": \"{'origin': 'SEA', 'destination': 'NYC', 'date': '2025-03-15'}\", \"inputs\": {\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}, \"metadata\": { ... }}",
"gen_ai.tool.call.result": "{\"output\": {\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain\", \"schema\", \"messages\", \"ToolMessage\"], \"kwargs\": {\"content\": \"{\\\"origin\\\": \\\"SEA\\\", \\\"destination\\\": \\\"NYC\\\", \\\"flights\\\": [ ... ]}\", \"type\": \"tool\", \"name\": \"search_flights\", \"status\": \"success\"}}}",
"session.id": "sea-nyc-trip-2-turns-unified"
},
"status": {
"code": "OK"
}
}
OpenInference
예
- Invoke agent span
-
input.value 속성은 사용자 프롬프트를 유지하고 output.value 속성은 에이전트 응답과 함께 직렬화된 상태를 유지합니다.
{
"traceId": "6a387ee61078243c1cc455ed45c6c313",
"spanId": "b8c0b67876b78b91",
"name": "LangGraph",
"kind": "INTERNAL",
"scope": {
"name": "openinference.instrumentation.langchain",
"version": "0.1.66"
},
"attributes": {
"openinference.span.kind": "CHAIN",
"input.value": "{\"messages\": [{\"role\": \"user\", \"content\": \"Hey, how can you help me\"}]}",
"output.value": "{\"messages\": [{\"type\": \"human\", \"data\": {\"content\": \"Hey, how can you help me\"}}, {\"type\": \"ai\", \"data\": {\"content\": \"Hello! I'm your travel planning assistant ...\"}}]}",
"session.id": "sea-nyc-trip-2-turns-oi-0-1-66"
},
"status": {
"code": "OK"
}
}
- Execute tool span
-
input.value 속성에는 도구 인수가 있고 output.value 속성에는 LangChain 로 직렬화된 도구 결과가 있습니다ToolMessage.
{
"traceId": "6a387ef07b8f4f3732fab45d3c0b51ff",
"spanId": "58752612d9b22ae1",
"name": "search_flights",
"kind": "INTERNAL",
"scope": {
"name": "openinference.instrumentation.langchain",
"version": "0.1.66"
},
"attributes": {
"openinference.span.kind": "TOOL",
"tool.name": "search_flights",
"tool.description": "Search for available flights between cities.",
"input.value": "{\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}",
"output.value": "{\"type\": \"tool\", \"data\": {\"content\": \"{\\\"origin\\\": \\\"SEA\\\", \\\"destination\\\": \\\"NYC\\\", \\\"flights\\\": [ ... ]}\", \"name\": \"search_flights\"}}",
"session.id": "sea-nyc-trip-2-turns-oi-0-1-66"
},
"status": {
"code": "OK"
}
}
TypeScript 에이전트 지원
TypeScript LangGraph 에이전트는 Python 에이전트와 동일한 스팬 유형을 내보내므로 평가 서비스가 동일한 방식으로 읽습니다. 3개의 TypeScript 계측 라이브러리가 있으며, 각 라이브러리에는 고유한 범위 이름과 스팬 분류 규칙이 있습니다.
에이전트 계측
TypeScript 종속성에 원하는 경로의 계측 라이브러리를 추가합니다. 다음 예제에서는 최소 버전을 고정하고 고정할 이유가 없는 한 사용 가능한 최신 버전을 사용합니다.
예
- ADOT (OpenTelemetry)
-
ADOT의 TypeScript 에이전트의 경우 AWS Distro Node 자동 계측 패키지(@aws/aws-distro-opentelemetry-node-autoinstrumentation)를 종속성에 추가합니다. 여기에는 시작 시 활성화되고 범위 이름를 내보내는 기본 제공 LangChain 계측이 포함되어 있습니다@aws/aws-distro-opentelemetry-instrumentation-langchain.
package.json:
{
"dependencies": {
"@aws/aws-distro-opentelemetry-node-autoinstrumentation": "^0.12.0"
}
}
- Traceloop (OpenTelemetry)
-
종속성에 Traceloop LangChain 계측(@traceloop/instrumentation-langchain)을 추가합니다. 방출되는 범위 이름은 입니다@traceloop/instrumentation-langchain.
package.json:
{
"dependencies": {
"@traceloop/instrumentation-langchain": "^0.27.0"
}
}
- OpenInference
-
@arizeai/openinference-instrumentation-langchain을 종속성에 추가합니다. 방출되는 범위 이름은 입니다@arizeai/openinference-instrumentation-langchain.
package.json:
{
"dependencies": {
"@arizeai/openinference-instrumentation-langchain": "^4.0.14"
}
}
계측은 관찰성을 설정하는 한 단계입니다. 평가를 위해 원격 측정을 내보내려면 관찰성 설정에서 전체 설정을 완료합니다.
스팬 식별 방법
범위 식별은 계측 라이브러리에 따라 달라집니다.
-
ADOT(OpenTelemetry): 범위 이름을 내보내는 AWS Distro Node 자동 계측 패키지(@aws/aws-distro-opentelemetry-node-autoinstrumentation)는 다른 ADOT 네이티브 프레임워크와 동일한 gen_ai.operation.name (invoke_agent, execute_tool, chat)를 @aws/aws-distro-opentelemetry-instrumentation-langchain설정합니다.
-
Traceloop(OpenTelemetry): Traceloop(@traceloop/instrumentation-langchain) 세트의 OpenTelemetry JS 라이브러리traceloop.span.kind(workflow 호출 에이전트 스팬의 경우 , 도구 스팬의 task 경우 ), Python OpenTelemetry 라이브러리와 일치합니다. Python 에이전트 지원에서 스팬을 식별하는 방법을 참조하세요.
-
OpenInference: OpenInference JS 라이브러리(@arizeai/openinference-instrumentation-langchain)는 Python OpenInference 라이브러리와 동일한 openinference.span.kind (CHAIN 또는 AGENT, TOOL, LLM)를 설정합니다.
필드 추출은 계측 라이브러리에 따라 달라집니다.
-
ADOT(OpenTelemetry): 호출 에이전트 스팬은 구조적 컨테이너이며 대화 콘텐츠는 부분 형식 및 gen_ai.input.messages gen_ai.output.messages 속성의 추론(chat) 스팬에 있습니다.
-
Traceloop(OpenTelemetry): Traceloop의 OpenTelemetry JS 라이브러리를 사용하면 대화가 직렬화된 LangChain 상태로 traceloop.entity.input 및 traceloop.entity.output 속성에 있습니다. 이는 Python OpenTelemetry 라이브러리와 일치합니다. Python 에이전트 지원에서 평가 필드가 추출되는 방법을 참조하세요.
-
OpenInference: OpenInference JS 라이브러리를 사용하면 대화가 input.value 및 output.value 속성에 있고 추론 메시지가 인덱싱된 llm.input_messages.* 및 llm.output_messages.* 속성에도 나타납니다. 이는 Python OpenInference 라이브러리와 일치합니다.
TypeScript 에이전트의 범위 예
다음 예제는 통합 원격 측정을 사용하여 Amazon Bedrock AgentCore 런타임에 배포된 TypeScript LangGraph 여행 계획 에이전트에서 가져온 것입니다. 세 가지 TypeScript 계측 라이브러리 각각 아래에 동일한 에이전트가 표시됩니다.
이 예제는 완전한 범위가 아닙니다. 실제 에이전트 상호 작용의 대표 데이터를 표시하며, 일부 필드는 생략되고 긴 값은 가독성을 위해 잘립니다.
OpenTelemetry(ADOT 네이티브)
ADOT 네이티브 라이브러리( AWS Distro 노드 자동 계측 패키지에서 범위 이름 @aws/aws-distro-opentelemetry-node-autoinstrumentation를 내보냄@aws/aws-distro-opentelemetry-instrumentation-langchain)를 사용하면 간접 호출 에이전트 스팬은 구조적 컨테이너이고 대화 콘텐츠는 부분 형식 및 gen_ai.input.messages gen_ai.output.messages 속성의 추론(chat) 스팬에 있습니다.
예
- Invoke agent span
-
gen_ai.operation.name 속성(invoke_agent)은 이를 호출 에이전트 범위로 식별합니다. 스팬에는 에이전트 이름과 모델이 포함되지만 대화 콘텐츠는 포함되지 않습니다.
{
"traceId": "6a6bd0a1c8d91ed1e70a3906b551618",
"spanId": "ba1833fa7f097041",
"name": "invoke_agent LangGraph",
"kind": "INTERNAL",
"scope": {
"name": "@aws/aws-distro-opentelemetry-instrumentation-langchain",
"version": "0.12.0"
},
"attributes": {
"gen_ai.operation.name": "invoke_agent",
"gen_ai.agent.name": "LangGraph",
"gen_ai.provider.name": "openai",
"gen_ai.request.model": "gpt-4o-mini",
"session.id": "sea-nyc-trip-2-turns"
},
"status": {
"code": "OK"
}
}
- Execute tool span
-
gen_ai.operation.name 속성(execute_tool)은 이를 실행 도구 범위로 식별합니다.는 도구 이름을 gen_ai.tool.name 보유합니다. gen_ai.tool.call.arguments 및 gen_ai.tool.call.result 속성에는 도구 인수와 결과가 포함됩니다.
{
"traceId": "6a6bd0a25c52f3d86a35038f35f5ba30",
"spanId": "5b332f3cd15ace04",
"name": "execute_tool search_flights",
"kind": "INTERNAL",
"scope": {
"name": "@aws/aws-distro-opentelemetry-instrumentation-langchain",
"version": "0.12.0"
},
"attributes": {
"gen_ai.operation.name": "execute_tool",
"gen_ai.tool.name": "search_flights",
"gen_ai.tool.type": "function",
"gen_ai.tool.call.arguments": "{\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}",
"gen_ai.tool.call.result": "{\"origin\": \"SEA\", \"destination\": \"NYC\", \"flights\": [ ... ]}",
"session.id": "sea-nyc-trip-2-turns"
},
"status": {
"code": "OK"
}
}
- Inference span
-
gen_ai.operation.name 속성(chat)은 이를 추론 범위로 식별합니다. gen_ai.input.messages 및 gen_ai.output.messages 속성은 대화를 부분 형식으로 유지하고 시스템 프롬프트를 gen_ai.system_instructions 유지합니다.
{
"traceId": "6a6bd0a1c8d91ed1e70a3906b551618",
"spanId": "7c1f9a2b4d6e8a03",
"name": "chat gpt-4o-mini",
"kind": "INTERNAL",
"scope": {
"name": "@aws/aws-distro-opentelemetry-instrumentation-langchain",
"version": "0.12.0"
},
"attributes": {
"gen_ai.operation.name": "chat",
"gen_ai.provider.name": "openai",
"gen_ai.request.model": "gpt-4o-mini",
"gen_ai.input.messages": "[{\"role\": \"user\", \"parts\": [{\"type\": \"text\", \"content\": \"Hey, how can you help me\"}]}]",
"gen_ai.output.messages": "[{\"role\": \"assistant\", \"parts\": [{\"type\": \"text\", \"content\": \"I can assist you with planning your trip ...\"}]}]",
"gen_ai.system_instructions": "[{\"type\": \"text\", \"content\": \"You are a travel planning assistant ...\"}]",
"session.id": "sea-nyc-trip-2-turns"
},
"status": {
"code": "OK"
}
}
OpenTelemetry(Traceloop)
Traceloop(@traceloop/instrumentation-langchain)의 OpenTelemetry JS 라이브러리를 사용하면 스팬 유형이 traceloop.span.kind 속성(workflow 호출 에이전트 스팬의 경우 , 도구 스팬의 task 경우 )에 전달되고 =는 호출 에이전트 스팬gen_ai.operation.nameworkflow에 전달됩니다. 대화는 직렬화된 LangChain 상태로 traceloop.entity.input 및 traceloop.entity.output 속성에 있습니다.
예
- Invoke agent span
-
traceloop.span.kind 속성(workflow)은 이를 호출 에이전트 범위로 식별합니다. traceloop.entity.input 및 traceloop.entity.output 속성은 사용자 프롬프트(인간 메시지) 및 에이전트 응답(AI 메시지)이 구문 분석되는 직렬화된 LangChain 상태를 유지합니다.
{
"traceId": "6a6bd0b1c8d91ed1e70a3906b551618",
"spanId": "ba1833fa7f097041",
"name": "workflow RunnableSequence",
"kind": "INTERNAL",
"scope": {
"name": "@traceloop/instrumentation-langchain",
"version": "0.27.0"
},
"attributes": {
"traceloop.span.kind": "workflow",
"gen_ai.operation.name": "workflow",
"gen_ai.provider.name": "langchain",
"traceloop.workflow.name": "RunnableSequence",
"traceloop.entity.input": "{\"messages\": [{\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain_core\", \"messages\", \"HumanMessage\"], \"kwargs\": {\"content\": \"Hey, how can you help me\"}}]}",
"traceloop.entity.output": "{\"messages\": [{\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain_core\", \"messages\", \"AIMessage\"], \"kwargs\": {\"content\": \"I can assist you with planning your trip ...\"}}]}",
"session.id": "sea-nyc-trip-2-turns"
},
"status": {
"code": "OK"
}
}
- Execute tool span
-
traceloop.span.kind 속성(task)은 이를 실행 도구 범위로 식별합니다. traceloop.entity.input 및 traceloop.entity.output 속성에는 도구 인수와 결과가 포함됩니다.
{
"traceId": "6a6bd0b25c52f3d86a35038f35f5ba30",
"spanId": "5b332f3cd15ace04",
"name": "task search_flights",
"kind": "INTERNAL",
"scope": {
"name": "@traceloop/instrumentation-langchain",
"version": "0.27.0"
},
"attributes": {
"traceloop.span.kind": "task",
"traceloop.entity.name": "search_flights",
"traceloop.entity.input": "{\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}",
"traceloop.entity.output": "{\"output\": {\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain_core\", \"messages\", \"ToolMessage\"], \"kwargs\": {\"status\": \"success\", \"content\": \"{\\\"origin\\\": \\\"SEA\\\", \\\"destination\\\": \\\"NYC\\\", \\\"flights\\\": [ ... ]}\"}}}",
"session.id": "sea-nyc-trip-2-turns"
},
"status": {
"code": "OK"
}
}
OpenInference
OpenInference JS 라이브러리(@arizeai/openinference-instrumentation-langchain)를 사용하면 스팬 유형이 openinference.span.kind 속성에 전달됩니다. 대화 콘텐츠는 input.value 및 output.value 속성에 있으며 추론 메시지는 인덱싱된 llm.input_messages.* 및 llm.output_messages.* 속성에도 표시됩니다.
예
- Invoke agent span
-
openinference.span.kind 속성(CHAIN)은 이를 호출 에이전트 범위로 식별합니다. input.value 및 output.value 속성은 직렬화된 LangChain 상태를 유지합니다.
{
"traceId": "6a6bd0c1c8d91ed1e70a3906b551618",
"spanId": "0a7990d804132a9b",
"name": "LangGraph",
"kind": "INTERNAL",
"scope": {
"name": "@arizeai/openinference-instrumentation-langchain",
"version": "4.0.14"
},
"attributes": {
"openinference.span.kind": "CHAIN",
"input.value": "{\"messages\": [{\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain_core\", \"messages\", \"HumanMessage\"], \"kwargs\": {\"content\": \"Hey, how can you help me\"}}]}",
"output.value": "{\"messages\": [{\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain_core\", \"messages\", \"AIMessage\"], \"kwargs\": {\"content\": \"I can assist you with planning your trip ...\"}}]}",
"session.id": "sea-nyc-trip-2-turns"
},
"status": {
"code": "OK"
}
}
- Execute tool span
-
openinference.span.kind 속성(TOOL)은 이를 실행 도구 범위로 식별합니다.는 도구 이름을 tool.name 보유합니다. input.value 및 output.value 속성에는 도구 인수와 결과(LangChain으로 직렬화됨)가 포함됩니다ToolMessage.
{
"traceId": "6a6bd0c25c52f3d86a35038f35f5ba30",
"spanId": "ab105c12cc40048f",
"name": "search_flights",
"kind": "INTERNAL",
"scope": {
"name": "@arizeai/openinference-instrumentation-langchain",
"version": "4.0.14"
},
"attributes": {
"openinference.span.kind": "TOOL",
"tool.name": "search_flights",
"input.value": "{\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}",
"output.value": "{\"output\": {\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain_core\", \"messages\", \"ToolMessage\"], \"kwargs\": {\"status\": \"success\", \"content\": \"{\\\"origin\\\": \\\"SEA\\\", \\\"destination\\\": \\\"NYC\\\", \\\"flights\\\": [ ... ]}\"}}}",
"session.id": "sea-nyc-trip-2-turns"
},
"status": {
"code": "OK"
}
}
- Inference span
-
openinference.span.kind 속성(LLM)은 이를 추론 범위로 식별합니다. llm.input_messages.* 속성에는 시스템 프롬프트와 사용자 프롬프트가 저장되고 llm.output_messages.* 속성에는 에이전트 응답이 저장됩니다.
{
"traceId": "6a6bd0c1c8d91ed1e70a3906b551618",
"spanId": "1221a062c7f90a8e",
"name": "ChatOpenAI",
"kind": "INTERNAL",
"scope": {
"name": "@arizeai/openinference-instrumentation-langchain",
"version": "4.0.14"
},
"attributes": {
"openinference.span.kind": "LLM",
"llm.model_name": "gpt-4o-mini",
"llm.input_messages.0.message.role": "system",
"llm.input_messages.0.message.content": "You are a travel planning assistant ...",
"llm.input_messages.1.message.role": "user",
"llm.input_messages.1.message.content": "Hey, how can you help me",
"llm.output_messages.0.message.role": "assistant",
"llm.output_messages.0.message.content": "I can assist you with planning your trip ...",
"session.id": "sea-nyc-trip-2-turns"
},
"status": {
"code": "OK"
}
}
LangGraph 에이전트 모범 사례
LangGraph 에이전트를 빌드하고 호출하는 방법은 원격 측정에 표시되는 내용과 에이전트를 얼마나 안정적으로 평가할 수 있는지에 영향을 줍니다. 다음 방법은 사용자 프롬프트, 에이전트 응답 및 도구 활동을 복구할 수 있도록 하는 데 도움이 됩니다.
1. 에이전트 구성 패턴 선택
LangGraph 에이전트를 빌드하는 두 가지 일반적인 방법이 있습니다.
-
사전 구축create_agent: 시작하는 가장 빠른 방법입니다. LangGraph의 기본 제공 실행 루프를 통해 전달되는 대화를 통해 턴당 단일 호출 에이전트 스팬을 생성합니다. 사용자 지정 제어 흐름이 없는 표준 reason-act 에이전트를 원할 때 사용합니다.
from langchain.agents import create_agent
agent = create_agent(model=model, tools=[search_flights, book_flight])
-
사용자 지정 StateGraph : 노드, 엣지 및 조건부 라우팅을 완벽하게 제어할 수 있습니다. 각 노드 실행은 자체 범위가 되므로 추적이 더 세분화됩니다. 사용자 지정 오케스트레이션이 필요할 때 사용합니다.
from langgraph.graph import StateGraph, START, END
from typing_extensions import TypedDict
class State(TypedDict):
messages: list
graph = StateGraph(State)
graph.add_node("generate_response", generate_response)
graph.add_node("tools", run_tools)
graph.add_edge(START, "generate_response")
agent = graph.compile()
두 패턴 모두 동일한 방식으로 평가됩니다. 차이점은 트레이스의 세분성입니다.
2. messages 그래프 상태에서 사용(권장)
평가 서비스는 에이전트의 입력 및 출력 메시지에서 대화를 재구성합니다. messages 필드를 사용하는 것은 필수는 아니지만 가장 안정적인 추출이 가능합니다. 사용자 지정의 경우 상태의 messages 필드에 대화를 StateGraph유지합니다.
-
messages를 상태에 포함합니다(권장). 다른 사용자 지정 필드(예: user_id 또는 메타데이터)를 추가할 수 있습니다. messages이 있으면 표준 추출에서 사용자 프롬프트와 에이전트 응답을 직접 찾습니다. messages이 없는 경우 서비스는 개별 추론 범위에서 대화를 재구성하는 것으로 돌아가며, 이는 신뢰성이 떨어집니다.
-
대체하지 말고 추가하세요. 전체 대화 기록이 보존되도록 새 메시지를 덮어쓰지 않고 목록에 추가하는 LangGraph 규칙을 따릅니다.
-
표준 LangChain 메시지 유형(, , , )을 사용합니다.HumanMessage AIMessage ToolMessage SystemMessage 계측은 이를 올바르게 직렬화하고 서비스는 해당 역할을 인식합니다.
3. 지원되는 형식으로 사용자 메시지 전달
LangGraph 에이전트를 호출할 때 그래프의 messages 상태에 사용자 메시지를 추가합니다. LangGraph는 세 가지 교체 가능한 형식으로 메시지를 수락하며 AgentCore 평가는 모든 메시지를 지원합니다. 각는 서비스가 읽을 수 있는 스팬 및 이벤트 레코드를 생성합니다.
-
튜플: (role, content) 페어:
agent.invoke({"messages": [("user", user_message)]}, config=config)
-
LangChain 메시지 객체: aHumanMessage(또는 기타 메시지 클래스):
from langchain_core.messages import HumanMessage
agent.invoke({"messages": [HumanMessage(content=user_message)]}, config=config)
-
사전: {"role", "content"} 사전:
agent.invoke({"messages": [{"role": "user", "content": user_message}]}, config=config)
세 가지 형식 모두 동일한 messages 상태가 되므로 어떤 형식을 선택하든 사용자 프롬프트와 에이전트 응답이 동일하게 추출됩니다.