콘텐츠로 이동

핑거프린팅 (Fingerprinting)

CrewAI에서 Agent, Crew, Task 같은 컴포넌트가 여러 개 얽혀 있는 시스템을 만들다 보면, "이 컴포넌트가 정말 내가 만든 그 컴포넌트가 맞을까?" 같은 궁금증이 생기기 마련이에요. 특히 실행 단계나 로그를 추적해야 할 때는요. CrewAI는 이 고민을 핑거프린트(Fingerprint) 라는 개념으로 풀어냅니다. 컴포넌트마다 생애주기 전체에 걸쳐 고유한 식별자를 자동으로 부여해서, 이 컴포넌트를 추적하고 검증할 수 있게 해주는 기능이죠.

개념: 핑거프린트가 뭔가요?

핑거프린트는 crewai.security 모듈의 Fingerprint 클래스의 인스턴스입니다. Agent, Crew, Task를 만들 때마다 자동으로 하나씩 생기고, 각각 다음과 같은 정보를 담고 있어요.

  • UUID 문자열: 컴포넌트를 식별하는 고유 식별자. 자동 생성되며 수동으로 설정할 수 없어요.
  • 생성 시각(creation timestamp): 핑거프린트가 생성된 시점. 자동으로 기록되며 수동으로 바꿀 수 없어요.
  • 메타데이터: 추가 정보를 담는 딕셔너리. 이건 원하는 대로 커스터마이즈할 수 있어요.

핑거프린트는 컴포넌트가 생성되는 순간 자동으로 만들어지고 할당됩니다. 그리고 각 컴포넌트는 자신의 핑거프린트를 읽기 전용 프로퍼티로 노출해요. 즉 값을 마음대로 바꿀 수 없고, 조회만 할 수 있는 구조입니다.

이 핑거프린트는 크게 네 가지 용도로 쓸 수 있어요.

  • 컴포넌트 사용을 감사하고 추적하기
  • 컴포넌트의 정체성 무결성 보장하기
  • 컴포넌트에 메타데이터 붙이기
  • 추적 가능한 작업 체인 만들기

핑거프린트 접근하기

컴포넌트를 만들기만 하면 핑거프린트는 자동으로 생성돼요. fingerprint 프로퍼티로 접근하면 되고, UUID 문자열은 uuid_str로 확인합니다.

from crewai import Agent, Crew, Task

# 컴포넌트 생성 - 핑거프린트는 자동으로 만들어진다
agent = Agent(
    role="Data Scientist",
    goal="Analyze data",
    backstory="Expert in data analysis"
)

crew = Crew(
    agents=[agent],
    tasks=[]
)

task = Task(
    description="Analyze customer data",
    expected_output="Insights from data analysis",
    agent=agent
)

# 핑거프린트 접근하기
agent_fingerprint = agent.fingerprint
crew_fingerprint = crew.fingerprint
task_fingerprint = task.fingerprint

# UUID 문자열 출력하기
print(f"Agent fingerprint: {agent_fingerprint.uuid_str}")
print(f"Crew fingerprint: {crew_fingerprint.uuid_str}")
print(f"Task fingerprint: {task_fingerprint.uuid_str}")

메타데이터로 추가 맥락 담기

핑거프린트의 메타데이터는 자유롭게 바꿀 수 있는 부분이에요. 버전이라던가 담당 부서 같은 관리 정보를 붙여서 나중에 추적할 때 활용할 수 있죠.

# 에이전트 핑거프린트에 메타데이터 추가
agent.security_config.fingerprint.metadata = {
    "version": "1.0",
    "department": "Data Science",
    "project": "Customer Analysis"
}

# 메타데이터 접근하기
print(f"Agent metadata: {agent.fingerprint.metadata}")

여기서 눈여겨볼 점이 하나 있어요. 메타데이터를 설정할 때는 agent.security_config.fingerprint.metadata로 가지만, 읽을 때는 agent.fingerprint.metadata로 접근한다는 점이에요. 설정 경로와 조회 경로가 다르다는 걸 기억해 두면 헷갈리지 않아요.

핑거프린트는 변하지 않는다

핑거프린트는 컴포넌트의 생애주기 동안 그대로 유지되도록 설계되어 있어요. 컴포넌트의 내용을 수정해도 핑거프린트는 그대로입니다. 아래 코드처럼 에이전트의 goal을 바꿔도 원래 핑거프린트가 유지되는 걸 확인할 수 있어요.

original_fingerprint = agent.fingerprint.uuid_str

# 에이전트 수정
agent.goal = "New goal for analysis"

# 핑거프린트는 그대로 유지된다
assert agent.fingerprint.uuid_str == original_fingerprint

이런 특성 덕분에 "이 컴포넌트는 처음 만들어진 그 컴포넌트다"라는 정체성을 안정적으로 보장할 수 있어요.

결정론적 핑거프린트 만들기

UUID와 생성 시각은 직접 설정할 수 없지만, generate 메서드에 시드(seed) 를 넘기면 결정론적(deterministic)인 핑거프린트를 만들 수 있어요. 같은 시드를 쓰면 항상 같은 핑거프린트가 나오는 구조죠.

from crewai.security import Fingerprint

# 시드 문자열로 결정론적 핑거프린트 만들기
deterministic_fingerprint = Fingerprint.generate(seed="my-agent-id")

# 같은 시드는 항상 같은 핑거프린트를 만든다
same_fingerprint = Fingerprint.generate(seed="my-agent-id")
assert deterministic_fingerprint.uuid_str == same_fingerprint.uuid_str

# 메타데이터도 함께 설정할 수 있다
custom_fingerprint = Fingerprint.generate(
    seed="my-agent-id",
    metadata={"version": "1.0"}
)

예를 들어 에이전트마다 고정된 ID를 부여해서 언제 실행해도 동일하게 식별되도록 하고 싶다면, 이 방식을 쓰면 됩니다.

핑거프린트 구조 살펴보기

핑거프린트가 실제로 어떤 필드를 갖는지 정리하면 이렇습니다.

from crewai.security import Fingerprint

fingerprint = agent.fingerprint

# UUID 문자열 - 고유 식별자 (자동 생성)
uuid_str = fingerprint.uuid_str  # 예: "123e4567-e89b-12d3-a456-426614174000"

# 생성 시각 (자동 생성)
created_at = fingerprint.created_at  # datetime 객체

# 메타데이터 - 추가 정보 (자유롭게 커스터마이즈 가능)
metadata = fingerprint.metadata  # 딕셔너리, 기본값은 {}

더 알아보기

핑거프린트는 컴포넌트의 정체성을 추적하고 검증하는 데 유용하지만, 이 기능과 연결된 개념들이 더 있어요. 컴포넌트를 더 안전하게 다루고 싶다면 CrewAI의 보안(security) 관련 문서를, 시스템 전체의 동작 흐름을 추적하고 싶다면 관찰성(observability) 이나 로깅 관련 가이드를 함께 살펴보는 걸 추천해요. 컴포넌트의 조합과 실행 방식을 더 알고 싶다면 에이전트, 크루, 태스크 기본 문서도 도움이 됩니다.