v3 이벤트 스트림이 조용히 누락하던 것들 — LangChain 1.4.8

langchain-core 1.4.8 + 1.3.10 (6월 18일): v3 미터링 공백, BaseTool 스키마 캐싱, gpt-5.x 라우팅 수정.

v3 이벤트 스트림이 조용히 누락하던 것들 — LangChain 1.4.8
Share

LangChain이 같은 날 오후 두 개의 연동 패치 릴리스를 배포했습니다. 가장 중요한 수정 사항은 마케팅 포스트가 아닌 내부 메커니즘 커밋 깊숙이 묻혀 있습니다. pip install -U를 실행하면 실제로 무엇이 바뀌는지 살펴봅니다.

langchain-core 1.4.8 과 langchain 1.3.10 의 변경 내용

2026년 6월 18일, LangChain 팀은 몇 분 간격으로 두 개의 연동 유지보수 릴리스를 배포했습니다. langchain-core는 1.4.7→1.4.8(UTC 19:23 병합), 메타 패키지 langchain은 1.3.9→1.3.10(UTC 19:40 병합)으로 올라갔으며, 최상위 GitHub 릴리스는 UTC 19:43에 게시됐습니다 . 두 릴리스 모두 1.0 이후 안정 라인 내의 패치 컷으로, 메이저·마이너 버전 변경은 없으며 양 패키지 모두 문서화된 Breaking Change가 없습니다. 두 패키지 모두 Python >=3.10,<4.0을 요구합니다 .

한줄 요약: langchain-core 1.4.8 과 langchain 1.3.10 은 2026년 6월 18일에 배포된 패치 릴리스로 Breaking Change가 없습니다. 주요 수정 사항: v3 stream-events 에서 캐시 토큰 사용량 세부 정보 보존, BaseTool 스키마 메모이제이션(~33 ms → ~0.33 ms), SummarizationMiddleware 의 멀티모달 URL 보존을 위한 XML 전환.

릴리스 PR 자체는 대부분 배관 작업 — version.py, pyproject.toml, 스냅샷, 락파일 갱신 — 이었으므로, 사용자에게 직접 영향을 주는 변경 사항은 해당 태그에 포함된 이전 PR들에서 비롯됩니다 . 코어에는 런타임 관련 변경 세 건, 메타 패키지에는 두 건이 반영됐습니다.

패키지변경 내용중요한 이유
langchain-core 1.4.8v3 stream-events 사용량 수정캐시 실행 시 input_token_details/output_token_details 복원
langchain-core 1.4.8BaseTool.tool_call_schema 메모이제이션에이전트 루프에서 단계별 툴 스키마 오버헤드 감소
langchain-core 1.4.8Python <3.11 의 coro_with_context컨텍스트 전파가 3.11+ 동작과 일치
langchain 1.3.10SummarizationMiddleware → XML 직렬화요약본에서 이미지/오디오/비디오 URL 참조 보존
langchain 1.3.10날짜 포함 OpenAI 스냅샷 감지gpt-5.2/gpt-5.4 스냅샷을 프로바이더 네이티브 구조화 출력으로 라우팅

이어지는 섹션에서는 각 변경 사항을 상세히 살펴봅니다 — 이전에 무엇이 문제였는지, 지금은 무엇이 수정됐는지, 그리고 업그레이드를 일정에 넣을 가치가 있는지 여부를 다룹니다 .

v3 이벤트 스트림의 공백: 캐시 호출 미터링 불완전 문제

What v3 event stream was silently losing — LangChain 1.4.8

langchain-core 1.4.8 의 가장 중요한 런타임 수정은 v3 스트리밍의 조용한 집계 오류를 해결합니다. 이번 릴리스 이전에는 stream_events(version="v3")astream_events(version="v3") 가 조립된 메시지나 on_llm_end 이벤트에 input_token_detailsoutput_token_details 를 전달하지 않았습니다 . 사용량 메타데이터는 입·출력 토큰 집계 수치를 여전히 보고했지만, 신규 토큰과 캐시 토큰을 구분하는 카테고리별 세부 정보는 전송되지 않았습니다. v3 이벤트로 비용을 측정하고 있었다면 불완전한 데이터를 기준으로 과금하고 있었던 셈입니다.

프롬프트 캐시 호출의 경우 이 공백은 직접적인 금전적 영향을 미쳤습니다. 캐시 토큰은 총 입력 토큰 수치에 포함됐지만, 해당 토큰이 더 저렴한 이유를 설명하는 cache_readcache_creation 필드가 누락됐습니다 . v3 이벤트를 소비하는 비용 귀속 레이어 — LangSmith 트레이서가 대표적 사례 — 는 캐시 읽기를 전액 입력으로 처리해 입력 비용을 과산정했습니다. 캐시 히트가 예외가 아닌 기본인 대형 재사용 시스템 프롬프트 기반 워크로드에서 이 과산정은 반올림 오차 수준이 아닙니다.

수정 사항은 세부 필드를 UsageInfo 와이어 타입을 통해 라우팅해 직렬화 전 구간에서 세부 정보가 유지되도록 하며, 새로운 하한을 도입합니다. langchain-core 1.4.8 은 이제 langchain-protocol>=0.0.17을 요구합니다 . 이 의존성 버전 상향이 실질적으로 확인해야 할 신호입니다 — 락파일이 구 프로토콜 패키지를 고정하고 있다면 코어를 업그레이드한 뒤에도 사용량 세부 정보가 흐르지 않으므로, 버전 범프만으로 충분하다고 가정하지 말고 전이 의존성 해석 결과를 직접 확인하십시오.

"v3 on_llm_end 사용량이 이제 v2와 일치하며, cache_readcache_creation 세부 정보를 온전히 유지합니다." — langchain-core 1.4.8 릴리스 노트, 실제 claude-sonnet-4-6 캐시 프롬프트로 검증됨 (source: PR #38255)

이 검증이 의미 있는 이유는 수정 사항을 합성 픽스처가 아닌 실제 프로바이더 응답에 고정하기 때문입니다. PR 작성자는 v3 경로가 실제 Claude 캐시 실행에서 v2 사용량 형태를 재현함을 확인했으며, 이는 이번 유지보수 컷이 제공하는 엔드투엔드 회귀 보장에 가장 가까운 근거입니다 . 한 가지 잔존 엣지 케이스는 직접 테스트할 가치가 있습니다. 다수의 스트리밍 청크에 걸쳐 중첩된 토큰 세부 키가 반복될 때의 정확한 처리 방식은 릴리스에서 상세히 문서화되지 않았습니다.

langchain-core 1.4.8의 메모이즈된 스키마: 33ms에서 0.33ms로

langchain-core 1.4.8의 두 번째 런타임 변경 사항은 도구 호출 성능 개선입니다. BaseTool.tool_call_schema가 이제 도구 인스턴스별로 생성된 Pydantic 서브셋 모델을 메모이즈하고, 프로퍼티에 접근할 때마다 모델을 새로 빌드하는 대신 기본 model_json_schema()/schema() 출력을 캐싱합니다 . 많은 도구를 바인딩하고 각 스텝마다 스키마를 변환하는 에이전트 루프에서는, 이 재빌드 비용이 스텝당 전체 비용을 조용히 잠식하고 있었습니다. 이번 수정으로 반복 연산이 일회성 연산으로 바뀝니다.

수정 전 상태가 핵심입니다. PR에 따르면, 기존 경로는 접근할 때마다 서브셋 모델을 재구성했으며 도구당 약 1.5ms가 소요됐습니다. 즉, 도구 23개를 한 번 순회하는 데 약 33ms가 걸렸고, 에이전트 스텝마다 이 변환을 반복 실행하는 미들웨어는 사이클당 수백 ms의 오버헤드를 누적시켰습니다 . 메모이제이션 적용 후, 동일한 23개 도구 순회는 워밍업된 경로에서 약 0.33ms로 측정됩니다 — 약 100배 단축 . 스키마 자체는 변경되지 않으며, 동일한 결과를 반복 계산하는 과정만 제거됩니다.

경로도구당 비용도구 23개 순회반복 루프
1.4.8 이전 (접근마다 콜드 재빌드)~1.5 ms~33 ms스텝당 미들웨어 오버헤드 수백 ms
1.4.8 (메모이즈, 워밍업 경로)~0.014 ms~0.33 ms최초 빌드 이후 무시 가능

업그레이드 전에 반드시 짚고 넘어가야 할 트레이드오프가 있습니다. 생성된 클래스와 기본 스키마 딕셔너리가 이제 접근 간에 재사용되므로, 반환된 객체를 제자리에서 변경하는 코드는 공유 상태 문제를 일으킵니다 — 다음 호출자는 이전 변경 내용이 적용된 객체를 받게 됩니다. PR은 반환된 스키마의 제자리 변경을 지원하지 않는 패턴으로 명시적으로 처리합니다 . tool_call_schema에서 받은 딕셔너리에 필드를 주입하는 미들웨어나 커스텀 도구 래퍼가 있다면 우회하세요. 먼저 복사한 뒤 변경하거나, 공유 스키마를 패치하는 대신 새 스키마를 빌드하세요.

대부분의 팀에게 실질적인 시사점은 단순합니다. 소수의 도구만 바인딩하는 에이전트라면 절약 효과는 실재하지만 절댓값은 작고, 스텝별 미들웨어를 통해 많은 도구를 처리한다면 바로 이 부분이 CPU 시간을 소모하던 지점이며 1.4.8이 대부분을 회수해줍니다. 벤치마크 수치는 독립적인 프로파일링이 아닌 PR 자체에서 나온 것이므로, 작성자가 측정한 수치로 받아들이고 자신의 도구 수와 호출 빈도에 맞춰 직접 확인하세요 .

날짜가 붙은 스냅샷 식별자가 프로바이더 네이티브 스키마 강제를 우회했던 방식

What v3 event stream was silently losing — LangChain 1.4.8

메타 패키지의 두 번째 기능 수정은 create_agent(..., response_format=<schema>)의 조용한 버그를 수정합니다. 이 함수는 모델 이름을 하드코딩된 허용 목록과 비교했기 때문에, gpt-5.2gpt-5.4 같은 기본 식별자는 프로바이더 네이티브 구조화 출력 모델로 인식된 반면, gpt-5.2-2025-12-01이나 gpt-5.4-2026-03-05 같은 날짜 스냅샷은 인식되지 않았습니다 . 문자열이 일치하지 않아 날짜가 붙은 핀이 탐지 로직을 통과하지 못하고 프로바이더 네이티브 경로에 도달하지 못한 것입니다.

이 문제가 주목할 만한 이유는 증상이 무음이었기 때문입니다. 탐지에 실패하면 create_agentProviderStrategy에서 ToolStrategy로 강등됐습니다 — OpenAI에 서버 측 JSON 스키마 강제를 요청하는 대신 도구 호출을 통해 구조화 출력을 시뮬레이션했습니다 . 이 전환은 세 가지를 동시에 바꿉니다. 트레이스 형태(네이티브 구조화 응답 대신 도구 호출 왕복), 토큰 집계(도구 호출 오버헤드가 사용량 메트릭에 반영), 그리고 가장 중요하게는 보장 수준입니다. ProviderStrategy는 OpenAI가 응답을 반환하기 전에 스키마에 대해 출력을 검증한다는 의미이고, ToolStrategy는 그 강제를 모델의 베스트 에포트에 맡깁니다. 예외는 발생하지 않았습니다 — 에이전트는 계속 동작했지만, 설정한 것보다 약한 제약 조건 아래에서였습니다.

재현 가능한 빌드와 엄격한 스키마 강제 모두를 위해 날짜 스냅샷을 정확히 고정했다면, 이번 릴리스 이전까지는 첫 번째만 얻고 있었던 셈입니다. 테스트 스위트를 통과하면서도 동작이 강등되고 있었습니다.

"gpt-5.2-2025-12-01이나 gpt-5.4-2026-03-05 같은 날짜 스냅샷은 프로바이더 네이티브 구조화 출력을 사용해야 하며, -pro 변형은 설계상 계속 제외됩니다." — langchain 1.3.10 수정에 문서화된 근거 (source: PR #38222)

이번 수정으로 날짜 접미사 패턴을 포함하도록 탐지 범위가 확장되어, gpt-5.2-2025-12-01 같은 스냅샷도 기본 식별자와 동일하게 ProviderStrategy로 라우팅됩니다 . -pro 변형은 의도적으로 제외 상태를 유지합니다 — 이는 동일한 실수가 아닌 기능 경계입니다. 실질적인 시사점: 프로덕션 에이전트에서 OpenAI 모델 버전을 고정하고 서버 측 스키마 검증에 의존한다면, langchain 1.3.10으로 업그레이드하면 원래 기대했던 강제가 복원됩니다. 업그레이드 전후로 샘플 트레이스를 비교해 전략이 실제로 되돌아왔는지 확인하는 것을 권장합니다.

SummarizationMiddleware, 멀티모달 콘텐츠 참조 보존을 위해 XML 직렬화로 전환

구조화 출력 라우팅을 수정하는 동일한 업그레이드에서 SummarizationMiddleware가 대화 기록을 요약기에 전달하는 방식도 바뀌었습니다. langchain 1.3.10부터는 기존 버퍼 문자열 형식 대신 XML로 직렬화합니다 . 이유는 멀티모달 보존입니다. 기존 버퍼 문자열 방식에서는 URL 기반 콘텐츠 블록이 조용히 누락될 수 있었습니다. 메시지에 첨부된 이미지·오디오·비디오 참조가 요약기에 도달하기 전에 평탄화되어 사라지고, 멀티모달 스레드로 만든 요약에서 해당 포인터가 완전히 유실되었습니다 .

XML 직렬화는 원시 바이너리 메타데이터를 프롬프트 예산에 추가하지 않으면서도 URL 참조를 요약기 컨텍스트에 그대로 유지합니다. 이 차이가 중요한 이유가 있습니다. 목표는 base64 페이로드나 전체 메타데이터를 요약 호출에 밀어 넣는 것이 아니라, 다운스트림 단계에서 이미지나 클립이 존재했는지, 어디서 찾을 수 있는지를 여전히 알 수 있도록 주소 지정 가능한 URL을 보존하는 것입니다. 이 변경 사항은 이미지 URL — https://example.com/shared-image.png — 이 이제 요약기 입력까지 종단 간 전달됨을 확인하는 테스트로 검증되었습니다 .

"기본 직렬화는 URL 기반 이미지·오디오·비디오 콘텐츠 블록을 누락시킬 수 있었으며, 요약 형식을 XML로 전환하면 토큰 예산을 원시 메타데이터에 소모하지 않으면서 해당 참조를 유지할 수 있습니다," LangChain 릴리스 노트 중 (source: docs.langchain.com release policy).

이 변경 사항은 텍스트 외 콘텐츠가 포함된 대화에 대해 장문 컨텍스트 요약을 실행하는 모든 체인이나 워크플로에 영향을 미칩니다.

  • 이미지가 포함된 스레드 — 기록에 스크린샷이나 다이어그램 참조가 있는 비전 에이전트는 이제 해당 URL을 압축된 요약에 그대로 유지합니다.
  • 오디오 및 비디오 — 전사 또는 미디어 분석 루프는 요약 경계에서 소스 링크를 버리지 않고 보존합니다.
  • 혼합 멀티모달 에이전트 — 컨텍스트 창 한도를 맞추기 위해 요약을 수행하는 파이프라인이 더 이상 미디어 포인터를 희생하지 않아도 됩니다.

에이전트가 텍스트 전용이라면 이 변경은 무관합니다. 그러나 멀티모달 기록을 요약하면서 이미지나 클립이 이후 턴에서 조용히 사라지는 현상을 경험했다면 1.3.10이 해결책입니다. 메타 패키지를 통해 배포되므로 langchain 버전을 올리기만 해도 자동으로 적용됩니다 .

이번 릴리스의 cryptography 46→48 버전 점프와 기타 정비 사항

What v3 event stream was silently losing — LangChain 1.4.8

주요 동작 수정 외에도, 두 릴리스 모두 의존성 버전 업그레이드와 타이핑 작업을 포함하고 있어 빠르게 지나치기 쉽지만 전이 의존성을 고정하고 있다면 살펴볼 가치가 있습니다. 메타 패키지 langchain==1.3.10은 cryptography를 46.0.7에서 48.0.1로 — 두 메이저 버전을 한 번에 — 올리고, aiohttp 3.14.0→3.14.1, pyjwt 2.12.0→2.13.0도 함께 업그레이드합니다 . 검증이 필요한 항목은 cryptography 업그레이드입니다. 대부분의 LangChain 사용자는 직접 이를 사용하지 않지만, cryptography 46.x를 하드 핀하거나 constraints 파일에서 지정한 경우 의존성 리졸버 충돌이 발생하며, 잠긴 빌더에서 소스 컴파일 방식을 사용하는 환경은 배포 전에 업그레이드를 테스트해야 합니다.

langchain-core==1.4.8도 보안 관련 업그레이드를 포함합니다: jupyter-server 2.18.0→2.20.0, tornado 6.5.6→6.5.7, bleach 6.3.0→6.4.0 . 이것들은 core의 개발/테스트 단계 의존성이므로 프로덕션 설치에는 거의 영향을 주지 않지만, 모노리포의 도구 환경을 최신 상태로 유지해 줍니다.

타이핑 작업은 호출자보다 유지 보수자에게 더 중요합니다. Core 1.4.8은 disallow_any_generics 문제를 해결하고 mypy warn_unreachable 설정을 활성화하여 이후 타입 체커가 허용하는 코드 범위를 더 엄격하게 만듭니다 . 실제 런타임에 영향을 주는 변경 사항도 하나 있습니다. Python <3.11에서 coro_with_context가 이제 제공된 컨텍스트를 통해 태스크를 생성하여 컨텍스트 전파 방식이 3.11+ 동작과 일치하도록 수정되었습니다. 기존 동작에 의존하는 경우 비동기 엣지 케이스가 달라질 수 있는 조용한 수정입니다 .

마지막으로, 역직렬화 허용 목록 테스트는 이제 "core"와 같이 명시적인 allowed_objects= 문자열을 사용합니다. 이는 암묵적 기본값에 의존하지 않고 라이브러리 전반에 걸쳐 더 엄격한 역직렬화 방식을 적용하겠다는 신호입니다 . 파괴적 변경은 없지만, 전체적으로 코드베이스를 더 엄격한 타이핑과 안전한 로딩 방향으로 이끌고 있습니다.

리졸버의 함정: langchain 1.3.10은 langchain-core 1.4.8을 강제하지 않는다

메타 패키지를 업그레이드해도 코어 수정사항이 자동으로 적용되지는 않습니다. langchain 1.3.10은 langchain-core>=1.4.7,<2.0.0을 선언합니다 — 하한선은 1.4.8이 아닌 1.4.7로 유지됩니다. 따라서 pip install이나 langchain 업그레이드를 실행해도, 락파일이나 제약 파일에서 1.4.8을 명시하지 않는 한 리졸버는 이미 조건을 충족하는 langchain-core==1.4.7을 굳이 올릴 이유가 없어 그대로 유지할 수 있습니다.

이 점이 중요한 이유는, 이번 릴리스에서 실질적으로 의미 있는 변경사항이 모두 코어 쪽에 있기 때문입니다: v3 스트리밍 사용량 세부 정보 수정, 도구별 스키마 메모이제이션, 그리고 Python 3.11 미만의 컨텍스트 전파 정리. 이 중 하나라도 필요하다면, 의존성 그래프가 자동으로 가져다주지 않습니다. 명시적으로 고정하세요:

langchain==1.3.10
langchain-core==1.4.8

그 전에, 1.4.8이 도입하는 전이적 하한선을 확인하세요. langchain-core 1.4.8은 langchain-protocol>=0.0.17langsmith>=0.3.45,<1.0.0을 요구합니다. 기존과 동일한 pydantic>=2.7.4,<3.0.0과 함께입니다. langchain-protocol 버전 상향은 v3 계량 수정과 연결되어 있습니다. 수정된 토큰 세부 정보가 이제 해당 패키지의 UsageInfo 와이어 타입을 통해 전달되기 때문입니다. 기존 고정 버전과 충돌하지 않는지 확인하세요 — 특히 특정 트레이서 통합을 위해 langsmith를 제약하고 있는 경우라면 더욱 그렇습니다.

핵심 요점: 1.3.10과 1.4.8을 하나의 결정이 아닌 별개의 두 결정으로 다루세요. 이 릴리스에는 문서화된 주요 변경사항이 없으므로 업그레이드 자체의 위험은 낮지만, 실제로 원하는 이점은 코어에 있습니다. langchain-core==1.4.8을 의도적으로 고정하고, 깨끗한 환경에서 의존성 리졸버를 실행해 langchain-protocol이나 langsmith 충돌을 확인하고, 배포 전에 락파일에서 해결된 버전을 검증하세요 — 그렇지 않으면 1.3.10을 배포하고도 여전히 구버전 1.4.7 경로로 캐시된 호출을 계량하게 될 수 있습니다.

자주 묻는 질문

pip install 'langchain==1.3.10'을 실행하면 langchain-core 1.4.8이 자동으로 설치되나요?

보장되지 않습니다. langchain 1.3.10은 langchain-core>=1.4.7,<2.0.0을 선언합니다 . 따라서 이미 1.4.7이 설치되어 조건을 충족하는 리졸버는 정당하게 그대로 유지할 수 있습니다. 코어 측 변경사항 — v3 사용량 세부 정보 수정 및 도구 스키마 메모이제이션 — 이 필요하다면 pip install 'langchain-core==1.4.8'을 명시적으로 실행하거나, 락파일에 고정하고 배포 전에 해결된 버전을 확인하세요.

v3 on_llm_end 사용량 세부 정보 누락에 실제로 영향받는 사람은 누구인가요?

astream_events(version="v3")(또는 stream_events)를 LangSmith 또는 커스텀 트레이서와 함께 호출하면서 input_token_detailsoutput_token_details를 읽는 모든 분이 해당됩니다. 1.4.8 이전에는 해당 세부 정보가 조합된 메시지와 on_llm_end 이벤트에서 누락되었습니다 . 특히 Claude 프롬프트 캐시 호출에서 영향이 두드러졌는데, cache_read/cache_creation 필드가 조용히 누락되면서도 캐시된 토큰은 총 입력량에 포함되어 보고되는 비용이 부풀려졌습니다. 작성자는 실제 claude-sonnet-4-6 캐시 프롬프트로 수정 사항을 검증해 v3 출력이 v2와 일치함을 확인했습니다 .

반환된 스키마 객체를 내 코드에서 수정할 경우 BaseTool 스키마 메모이제이션은 안전한가요?

아닙니다. langchain-core 1.4.8에서 tool_call_schema는 도구 인스턴스별로 생성된 Pydantic 서브셋 모델을 메모이즈하고 기본 스키마 딕셔너리를 캐싱합니다 . 반환된 객체는 이제 해당 도구의 모든 접근에서 공유되므로, 인플레이스 변경 — 예: tool.tool_call_schema['properties']['x'] = ... — 이 이후의 모든 읽기에 반영됩니다. 읽기 전용 접근은 안전합니다; 변경은 지원되지 않는 것으로 간주됩니다. 반환된 스키마에 쓰는 코드를 검토하고, 수정이 필요하다면 먼저 복사하세요.

langchain-core 1.4.8 또는 langchain 1.3.10에 주요 변경사항이 있나요?

문서화된 것은 없습니다. 둘 다 2026년 6월 18일에 출시된 1.0 이후 안정 라인 내 유지보수/패치 릴리스입니다 . 다만 세 가지 실질적인 주의사항이 있습니다. Python 3.11 미만에서 coro_with_context는 이제 제공된 컨텍스트를 통해 태스크 생성을 라우팅하므로, 비동기 컨텍스트 전파가 3.11+과 일치하며 이전 동작과 다를 수 있습니다 . 전이적으로 따라오는 cryptography 46→48 버전 상향도, 고정된 환경에서는 테스트할 가치가 있습니다. 그리고 SummarizationMiddleware는 이제 버퍼-문자열 형식 대신 XML을 출력합니다. 해당 출력을 파싱하는 코드가 있다면 직렬화 형태가 달라집니다 .

langchain-core 1.4.8이 langchain-protocol>=0.0.17을 요구하는 이유는 무엇인가요?

v3 스트리밍 계량 수정이 cache_read/cache_creation 세부 정보를 UsageInfo 와이어 타입을 통해 전달하는데, 0.0.17이 해당 필드를 와이어에 노출하는 langchain-protocol의 첫 번째 릴리스이기 때문입니다 . 이전 버전에는 스키마가 없어서, 세부 정보 필드가 직렬화 과정에서 유지됨을 보장하기 위해 하한선이 올라갔습니다. langchain-core 1.4.8은 langsmith>=0.3.45,<1.0.0pydantic>=2.7.4,<3.0.0도 요구합니다 . 그렇기 때문에 깨끗한 환경에서의 의존성 해결이 충돌을 발견하는 가장 안전한 방법입니다.