TL;DR
Claude는 텍스트에 숨은 문자를 넣는 대신 단어 선택의 무작위성을 조정해 통계적 워터마크를 만들고, 지원 파일에는 서명된 C2PA 콘텐츠 자격 증명을 메타데이터로 붙인다. 텍스트는 복사나 파일 이동으로 신호가 사라지지 않으므로 문장 구조를 크게 다시 쓰거나 다른 LLM으로 바꿔써야 하며, 완전한 제거 여부는 탐지기로 확인해야 한다. 코드는 Python AST를 이용해 식별자와 독스트링을 바꿀 수 있지만 변환 후 실행 검사가 필요하다. 파일은 c2pa-python으로 매니페스트를 먼저 확인한 뒤 새 파생물을 만들고 결과를 검증하는 방식으로 처리하며, 문서에 명시되지 않은 PDF 지원 범위까지 일반화해서는 안 된다.
섹션별 상세

import os
from openai import OpenAI
def rewrite_text(text: str) -> str:
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
prompt = f"""
Rewrite the following text completely in new wording.
Rules:
- Preserve the facts and meaning.
- Preserve technical accuracy.
- Change sentence structure throughout.
- Do not merely replace a few words with synonyms.
- Rebuild paragraphs where useful.
- Return only the rewritten text.
TEXT:
{text}
"""
response = client.responses.create(
model=os.getenv("REWRITE_MODEL", "gpt-5"),
input=prompt,
)
return response.output_text
if __name__ == "__main__":
original = open("input.txt", "r", encoding="utf-8").read()
rewritten = rewrite_text(original)
with open("output.txt", "w", encoding="utf-8") as f:
f.write(rewritten)Claude가 만든 텍스트를 다른 LLM의 OpenAI-compatible endpoint로 다시 작성해 문장 선택 패턴을 바꾼다.


import ast
import keyword
import random
import string
from pathlib import Path
class IdentifierRenamer(ast.NodeTransformer):
def __init__(self, seed: int = 42):
self.rng = random.Random(seed)
self.mapping = {}
def _new_name(self, old_name: str) -> str:
if old_name in self.mapping:
return self.mapping[old_name]
prefix = random.choice(["tmp", "value", "item", "obj", "data"])
suffix = "".join(
self.rng.choice(string.ascii_lowercase) for _ in range(5)
)
candidate = f"{prefix}_{suffix}"
while keyword.iskeyword(candidate):
suffix = "".join(
self.rng.choice(string.ascii_lowercase) for _ in range(6)
)
candidate = f"{prefix}_{suffix}"
self.mapping[old_name] = candidate
return candidate
def visit_Name(self, node):
node.id = self._new_name(node.id)
return self.generic_visit(node)
def visit_arg(self, node):
node.arg = self._new_name(node.arg)
return self.generic_visit(node)
def visit_alias(self, node):
if node.asname:
node.asname = self._new_name(node.asname)
return self.generic_visit(node)
def remove_docstrings(tree: ast.AST) -> None:
for node in ast.walk(tree):
if not isinstance(node, (ast.Module, ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
continue
if not node.body:
continue
first = node.body[0]
if (
isinstance(first, ast.Expr)
and isinstance(first.value, ast.Constant)
and isinstance(first.value.value, str)
):
node.body.pop(0)
def rewrite_python(source: str) -> str:
tree = ast.parse(source)
remove_docstrings(tree)
transformer = IdentifierRenamer()
tree = transformer.visit(tree)
ast.fix_missing_locations(tree)
return ast.unparse(tree)
def rewrite_file(input_path: str, output_path: str) -> None:
source = Path(input_path).read_text(encoding="utf-8")
rewritten = rewrite_python(source)
Path(output_path).write_text(
rewritten,
encoding="utf-8",
)
if __name__ == "__main__":
rewrite_file(
"input.py",
"rewritten.py",
)Python AST로 코드의 식별자와 독스트링을 바꾸고 재생성해 실행 구조를 보존하면서 소스 표현을 변환한다.
pip install c2pa-pythonC2PA 매니페스트를 읽고 검증하는 Python 라이브러리를 설치한다.
import json
from c2pa import Context, Reader
def inspect_c2pa(path: str) -> dict | None:
try:
with Context() as context:
with Reader(path, context=context) as reader:
data = reader.json()
return json.loads(data)
except Exception as exc:
print(f"No readable C2PA manifest: {exc}")
return None
if __name__ == "__main__":
manifest = inspect_c2pa("image.png")
if manifest:
print(json.dumps(manifest, indent=2))파일을 열어 C2PA 매니페스트가 있는지 확인하고, 읽을 수 있는 경우 JSON 형태로 출력한다.

용어 해설
- SynthID-Text
- — SynthID-Text는 텍스트에 별도 문자나 파일 메타데이터를 삽입하지 않고, 언어 모델이 다음 단어를 선택할 때 사용하는 무작위성의 방향을 조정하는 방식이다. 충분히 긴 문장에 통계적 패턴이 누적되면 탐지기가 이를 근거로 생성 출처를 판별할 수 있다.
- C2PA 콘텐츠 자격 증명(C2PA)
- — C2PA는 이미지와 같은 파일에 콘텐츠의 출처와 처리 이력을 기록하는 서명된 자격 증명 표준이다. Claude가 지원하는 파일에서는 이 정보가 픽셀 자체가 아니라 파일 메타데이터에 저장되므로, 새 파생 파일을 만들면 기존 매니페스트와의 연결이 끊길 수 있다.
- 추상 구문 트리(Abstract Syntax Tree)
- — Abstract Syntax Tree는 소스 코드를 문법 구조에 따라 트리 형태로 표현한 자료 구조다. Python 코드를 AST로 읽은 뒤 식별자와 주석, 독스트링을 바꾸고 다시 소스 코드로 생성하면 실행 구조를 유지하면서 원래 텍스트의 표면 패턴을 크게 바꿀 수 있다.
- 바꿔쓰기(Paraphrasing)
- — Paraphrasing은 원문의 사실과 의미를 유지하면서 문장 구조와 표현을 다시 구성하는 작업이다. Claude의 텍스트 워터마크처럼 여러 단어 선택에 분산된 통계 패턴은 단순 복사나 파일 이동으로 사라지지 않지만, 상당한 바꿔쓰기로 패턴을 약화할 수 있다.
- 워터마킹(Watermarking)
- — 워터마킹은 생성물에 출처를 식별할 수 있는 신호를 넣는 기술이다. 이 글에서 텍스트는 단어 선택의 통계 패턴을, 지원 파일은 서명된 C2PA 메타데이터를 사용하며, 코드에서는 문법 제약 때문에 일반 문장보다 선택 가능한 지점이 적다.
기술
- Claude
- SynthID-Text
- C2PA
- Python
- OpenAI-compatible endpoint
- gpt-5
- c2pa-python
- Python AST
- Quillbot
활용 사례
- Claude가 생성한 텍스트의 출처 패턴을 다른 표현으로 재작성하는 작업
- Python 코드의 식별자·주석·독스트링을 AST 기반으로 변환하는 작업
- 이미지 파일의 C2PA 매니페스트 존재 여부를 검사하는 작업
- 파일을 재저장하거나 변환한 뒤 C2PA 자격 증명을 다시 검증하는 작업
AI 요약 · 북마크 · 개인 피드 설정 — 무료
출처 · 인용 안내
인용 시 "요약 출처: AI Trends (aitrends.kr)"를 표기하고, 사실 확인은 원문 보기 기준으로 진행해 주세요. 자세한 기준은 운영 정책을 참고해 주세요.
