메인 콘텐츠로 건너뛰기
W&B Weave는 깊게 중첩된 패턴을 포함해 동기 및 비동기 제너레이터 함수를 모두 트레이싱할 수 있습니다. 이 페이지에서는 제너레이터 함수를 @weave.op로 데코레이션하여 Weave가 입력, yield된 출력, 그리고 중첩된 Call의 전체 계층 구조를 캡처하는 방법을 보여줍니다. 다른 트레이스와 함께 Weave UI에서 확인하고 싶은 출력이 있는 스트리밍 또는 지연 평가 코드 경로가 있을 때 이 기능을 사용하세요.
제너레이터는 값을 지연 생성하므로, Weave는 제너레이터가 완전히 소비된 경우에만 출력을 로그합니다(예: 목록으로 변환할 때). Weave가 트레이스에서 출력을 캡처하도록 하려면, 제너레이터를 완전히 소비하세요(예: list() 사용).
from typing import Generator
import weave

weave.init("my-project")

# 이 함수는 동기 제너레이터를 사용합니다.
# Weave는 Call과 해당 입력(`x`)을 트레이스하지만,
# 출력 값은 제너레이터가 소비된 후에만 캡처됩니다(예: `list()` 사용).
@weave.op
def basic_gen(x: int) -> Generator[int, None, None]:
    yield from range(x)

# 제너레이터 파이프라인 내에서 사용되는 일반 동기 함수입니다.
# 이 함수의 Call도 Weave가 별도로 트레이스합니다.
@weave.op
def inner(x: int) -> int:
    return x + 1

# 다른 트레이스된 함수(`inner`)를 호출하는 동기 제너레이터입니다.
# 각 yield 값은 `inner`에 대한 개별 트레이스된 Call에서 나옵니다.
@weave.op
def nested_generator(x: int) -> Generator[int, None, None]:
    for i in range(x):
        yield inner(i)

# 위 제너레이터를 조합하는 제너레이터입니다.
# 여기서 트레이싱하면 계층형 Call 트리가 생성됩니다:
# - `deeply_nested_generator` (부모)
#   - `nested_generator` (자식)
#     - `inner` (손자)
@weave.op
def deeply_nested_generator(x: int) -> Generator[int, None, None]:
    for i in range(x):
        for j in nested_generator(i):
            yield j

# Weave가 출력을 캡처하려면 제너레이터를 반드시 *소비*해야 합니다.
# 이는 동기 및 비동기 제너레이터 모두에 해당합니다.
res = deeply_nested_generator(4)
list(res)  # 중첩된 모든 Call과 yield의 트레이싱을 트리거합니다
다음 스크린샷은 앞선 코드에서 선택한 트레이스가 표시된 Traces 페이지를 보여줍니다. 가운데 패널에는 선택한 트레이스의 트레이스 트리가 표시됩니다. 트레이스 트리에는 deeply_nested_generator, nested_generator, inner Ops가 계층 구조로 표시됩니다. Weave Traces page showing a selected trace tree illustrating deeply nested Ops

제너레이터 소비하기

다음 섹션에서는 Weave가 제너레이터 출력을 기록하려면 왜 제너레이터를 소비해야 하는지와 어떤 소비 패턴이 작동하는지 설명합니다. Weave는 제너레이터를 완전히 소비한 후에만 제너레이터 출력을 캡처합니다. 제너레이터는 반복 순회하여 소비하세요(예: list(), for 루프 또는 모두 소진될 때까지 next() 사용). async for 또는 이에 준하는 소비 방식을 사용할 때는 비동기 제너레이터에도 동일하게 적용됩니다. 함수와 메서드에 @weave.op를 데코레이터로 적용하는 방법에 대한 자세한 내용은 call 생성을 참조하세요.

yield된 값을 단일 트레이스로 누적하기

yield된 값의 원시 시퀀스 대신 결합된 결과(예: 연결된 string 또는 목록)를 Weave가 기록하도록 하려면 accumulator를 사용하세요. weave.opaccumulator 파라미터를 사용하면 제너레이터 함수에서 yield된 값들을 어떻게 결합할지 사용자 지정할 수 있습니다. 예를 들어, 스트리밍된 텍스트 토큰을 하나의 문자열로 합칠 수 있습니다. accumulator는 두 개의 인수를 받는 함수이며, Weave는 yield된 각 값에 대해 이 함수를 한 번씩 호출하여 결과를 점진적으로 구축합니다.
accumulator 파라미터는 TypeScript에서는 사용할 수 없습니다.
다음 예제에서는 각 yield된 값을 목록에 추가하는 맞춤형 accumulator를 보여줍니다. 이렇게 하면 사용자가 제너레이터를 완전히 소비한 후 Weave가 해당 목록을 Call 출력으로 기록합니다.
from typing import Generator
import weave

weave.init("your-team-name/your-project-name")

# Weave는 각 yield 이후 이 함수를 호출합니다. 첫 번째 호출 시 acc는 None입니다.
# 마지막으로 반환한 값이 트레이스된 Op 출력이 됩니다.
def list_accumulator(acc, value):
    if acc is None:
        acc = []
    acc.append(value)
    return acc

# accumulator 파라미터 설정
@weave.op(accumulator=list_accumulator)
def basic_gen_with_accumulator(x: int) -> Generator[int, None, None]:
    yield from range(x)

# 모든 yield가 실행되고 accumulator가 최종 트레이스 출력을 생성할 수 있도록 끝까지 반복합니다.
result = list(basic_gen_with_accumulator(3))
print(result)