feat: install korean technical blog skill bundle

.agents/skills의 technical-document-author,
revising-korean-technical-prose, writing-natural-korean을
korean-technical-blog-skills-bundle-v1의 세 스킬로 교체한다.

- writing-korean-technical-blogs: 문제·제약·선택·구현·결과·한계 구조화
- reducing-ai-like-korean-writing: 상투성·추상화·반복 제거
- editing-korean-grammar-and-expression: 맞춤법·띄어쓰기·호응 검수

상류를 수정하지 않고 복사했다. diff -r 0건, MANIFEST.sha256 검증 통과,
번들 validate_skill.py 3/3 PASS.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
DongHyeonka
2026-08-07 14:20:42 +09:00
co-authored by Claude Opus 5
parent 1099834617
commit 25644cc4d9
81 changed files with 5261 additions and 1484 deletions
@@ -0,0 +1,12 @@
cf2f5554341c83c87dc3778949fc74b5ef7f067236b42435a9797834d2d2d10a ./README.md
ecbe2056f40780a0f37d292b6725e73fc5842bc9b129f3061dad8f568d187865 ./SKILL.md
8e2497974b6c0449a42bebddd83e3e797510633cac8a38c15e6237209b2d4531 ./references/decision-policy.md
bcca95cbee25c11fb2267245d2a58c9960b9a68a08048eaa52ada7775a807126 ./references/genre-profiles.md
20405fd7fdc6c62cefcc48a377708162f6f5f5202b92179baa54b03ea6f561f4 ./references/output-modes.md
6807778f2058346438d4903929b23dbbff83a9f253810368e4e1dda09a6897c8 ./references/pattern-catalog.md
2f9a87913c259e41eae59ee62380849751382e5418c4e67279aad23d6bfdb769 ./references/source-basis.md
444ee79893e6c528988557031095f15ccb399c6b1a46ce4ee804739db8a8bbba ./scripts/validate_skill.py
7d42fd42febfeb08bef466f83409b4d7a1ff94957fba86bad26d2f44ab5acf37 ./tests/baseline-observations.md
28f62b648ba5185cc45b66916277f1eee8aaa591c676ca9d74881b6e16e53beb ./tests/cases.json
2ad2fd862c06e549f5601d4ceacaaab9a468c56ff5b9788875427f168822eb32 ./tests/evaluation-rubric.md
d06418dcfc991ce6afec168d6bb5f0be129d05f8048bb686acd3ba7937855e9f ./tests/pressure-scenarios.md
@@ -0,0 +1,71 @@
# reducing-ai-like-korean-writing
한국어 글에서 상투적 연결어, 추상 명사화, 행위자 없는 피동, 근거 없는 일반 효용, 과잉 구조화, 반복 요약처럼 **AI 생성 글과 비슷하게 느껴질 수 있는 패턴**을 줄이는 Agent Skill이다.
이 스킬은 작성 주체를 판정하지 않는다. 목표는 AI 탐지기 우회가 아니라 문장의 직접성, 구체성, 정보 밀도와 작성자 목소리를 개선하는 것이다.
## 구성
```text
reducing-ai-like-korean-writing/
├── SKILL.md
├── README.md
├── references/
│ ├── decision-policy.md
│ ├── genre-profiles.md
│ ├── output-modes.md
│ ├── pattern-catalog.md
│ └── source-basis.md
├── scripts/
│ └── validate_skill.py
└── tests/
├── baseline-observations.md
├── cases.json
├── evaluation-rubric.md
└── pressure-scenarios.md
```
## 사용 예
```text
다음 기술 블로그 초안에서 AI가 쓴 것처럼 느껴지는 추상 표현과 반복을 줄여 주세요. 사실, 기술 용어, 단정 강도는 바꾸지 마세요.
```
```text
이 설계 문서를 audit 모드로 검토하세요. AI 작성 여부는 판단하지 말고, 정보 전달을 방해하는 문체 패턴만 찾아 주세요.
```
```text
이 발표 대본을 standard 강도로 다듬되, 말하기 위한 반복과 원래 말투는 보존하세요.
```
## 문법 교정 스킬과의 순서
게시용 결과를 만들 때 권장 순서는 다음과 같다.
```text
초안 작성
→ reducing-ai-like-korean-writing
→ editing-korean-grammar-and-expression
→ 최종 사실·서식 검증
```
문법 교정을 먼저 한 뒤 문체를 다시 쓰면 재작성 과정에서 새로운 맞춤법·띄어쓰기 문제가 생길 수 있다.
## 설치
스킬 폴더를 사용하는 에이전트의 스킬 디렉터리에 그대로 복사한다. 일반적인 프로젝트 단위 위치는 다음과 같다.
```text
.agents/skills/reducing-ai-like-korean-writing/
```
클라이언트마다 개인 스킬 디렉터리는 다를 수 있다.
## 검증
```bash
python scripts/validate_skill.py
```
구조 검사는 패키지 형식과 테스트 데이터의 일관성을 확인한다. 실제 문체 개선 효과는 `tests/pressure-scenarios.md``tests/cases.json`을 독립 에이전트의 스킬 전후 조건에서 실행해 검증한다.
@@ -0,0 +1,81 @@
---
name: reducing-ai-like-korean-writing
description: Use when Korean prose feels formulaic, abstract, repetitive, over-structured, overly polished, or filled with generic transitions and unsupported benefits, and it must become more direct and natural without changing facts, technical meaning, uncertainty, terminology, register, or formatting.
metadata:
version: "1.0.0"
language: "ko-KR"
---
# AI 유사 한국어 문체 줄이기
## 개요
한국어 글의 상투성·추상화·반복·과잉 구조화를 줄여 정보와 작성자의 실제 관점이 직접 드러나게 한다.
> 작성 주체가 AI인지 판정하지 않는다. 관찰 가능한 문체만 편집한다.
**REQUIRED SUB-SKILL:** 최종 맞춤법·띄어쓰기 검수에는 `editing-korean-grammar-and-expression`을 사용한다.
## 사용 범위
기술 블로그, 설계 문서, README, 발표 대본 등에서 문법은 맞지만 기계적으로 읽히는 글을 다듬을 때 사용한다. 맞춤법만 고치거나, AI 작성 확률·탐지기 우회를 요구하는 작업에는 사용하지 않는다.
기본값은 `brief + standard`다. 원문, 문서 유형, 독자, 보존할 용어·말투·구조를 사용한다.
## 필수 절차
1. **보호:** 코드, URL, 명령어, 경로, 식별자, 수치, 직접 인용과 잠금 구간을 보존한다.
2. **불변식 고정:** 사실, 부정, 조건, 시제, 가능성·의무·권고의 강도, 주체와 기술 용어를 기록한다.
3. **문맥 진단:** 단어 하나가 아니라 문장·문단의 반복, 정보 기여도와 장르 기능을 본다.
4. **행동 선택:** 안전한 직접 재작성, 구조 수정, 제안, 유지 중 하나를 고른다.
5. **최소 재작성:** 빈 메타 문장과 명사화를 줄이고, 원문 근거가 있을 때만 주체·동작·결과를 직접 쓴다.
6. **중복 정리:** 같은 명제의 재진술은 합치되 조건·예외·강조 기능은 보존한다.
7. **회귀 검증:** 불변식, 보호 구간, 마크다운 구조와 용어 일관성을 다시 비교한다.
## 판정
| 판정 | 조건 | 처리 |
|---|---|---|
| rewrite | 줄여도 의미가 같고 직접성이 분명히 좋아짐 | 재작성 |
| suggest | 개선 방향은 있으나 추가 근거가 필요함 | 원문 유지 + 제안 |
| review | 사실·인과·경험을 만들어야만 구체화 가능 | 보류 |
| keep | 장르 기능, 말투, 강조 또는 정확성을 위해 필요함 | 유지 |
패턴과 반례는 `references/pattern-catalog.md`, 장르별 경계는 `references/genre-profiles.md`를 필요할 때만 읽는다.
## 절대 규칙
- 표현 하나만으로 AI 문체나 AI 작성 여부를 단정하지 않는다.
- `해당`, `이를 통해`, 가능 표현, 피동문과 목록을 일괄 삭제하지 않는다.
- 원문에 없는 경험, 감정, 사례, 근거, 수치와 효용을 만들지 않는다.
- 가능성을 확정으로, 권고를 의무로, 상관관계를 인과로 강화하지 않는다.
- 사람처럼 보이게 하려고 오탈자, 비문, 무작위 문장 길이와 억지 구어체를 넣지 않는다.
- 기술 용어를 문체 다양화를 이유로 동의어로 바꾸지 않는다.
- AI 탐지기 통과나 점수 감소를 보장하지 않는다.
## 출력
기본 `brief`는 수정문과 주요 변경·보류 사항을 제시한다. 결과만 필요하면 `silent`, 진단만 하면 `audit`, 전후 비교는 `compare`를 사용한다. 문체를 고친 뒤 문법 교정 스킬을 실행한다.
## 대표 예시
**입력**
> 설정에 대한 변경을 수행한 뒤, 결과에 대한 확인을 진행합니다.
**재작성**
> 설정을 변경한 뒤 결과를 확인합니다.
명사화만 직접 동사로 바꾸고 작업 순서와 문체는 유지한다.
## 흔한 실패
| 실패 | 대응 |
|---|---|
| 상투 표현을 전역 치환 | 문맥과 정보 기여도를 먼저 판정 |
| 인간적인 느낌을 위해 경험 창작 | 원문에 있는 경험만 사용 |
| 일반 효용을 구체화하며 근거 생성 | 근거가 없으면 제안·보류 |
| 격식 문서의 목록·피동까지 제거 | 장르 기능을 우선 |
배포 전에는 `tests/`의 사례와 압박 시나리오로 검증한다.
@@ -0,0 +1,110 @@
# 판정·재작성 정책
## 1. 목적
이 스킬은 AI 작성 여부를 판정하지 않는다. 다음 두 질문에만 답한다.
1. 이 표현이 문맥에서 정보 전달을 방해하거나 불필요하게 우회하는가?
2. 사실과 문체를 보존하면서 더 직접적으로 쓸 수 있는가?
두 질문 모두 `예`일 때만 자동 재작성한다.
## 2. 우선순위
상위 항목은 하위 항목을 항상 제약한다.
1. 사용자 잠금과 보호 구간
2. 사실·의미·수치·주체 보존
3. 부정·조건·시제·양태 보존
4. 기술 용어와 고유 명칭 일관성
5. 문서 장르와 독자
6. 작성자의 기존 관점과 말투
7. 직접성·구체성·정보 밀도
8. 문장 리듬과 취향
스타일 개선이 상위 항목과 충돌하면 해당 수정을 취소한다.
## 3. 탐지 임계값
표현 하나가 보인다는 이유만으로 문제로 판정하지 않는다. 다음 중 하나 이상이 명확해야 한다.
- 문장을 삭제해도 명제가 줄지 않는다.
- 추상 명사화 때문에 주체와 동작이 가려진다.
- 일반적인 효용을 주장하지만 원인·조건·결과가 없다.
- 같은 연결어나 문장 틀이 가까운 구간에서 반복된다.
- 한 문단이 바로 앞 문단의 내용을 표현만 바꿔 반복한다.
- 장르상 필요하지 않은 목록·요약·결론이 연쇄적으로 붙는다.
단순히 자주 쓰이는 단어라는 이유는 충분한 근거가 아니다.
## 4. 수정 강도
### `light`
- A 등급의 국소 수정만 수행한다.
- 문장 순서와 문단 구조를 유지한다.
- 개인 문체 보존이 가장 중요한 경우에 사용한다.
### `standard`
- A 등급과 명확한 B 등급을 수정한다.
- 반복 문장 통합과 불필요한 메타 문장 삭제를 허용한다.
- 기본값이다.
### `strong`
- 문단 순서, 제목, 목록 형태까지 조정할 수 있다.
- 새로운 정보나 경험은 여전히 추가할 수 없다.
- 사용자가 대대적인 재작성을 명시했을 때만 사용한다.
## 5. 보존 불변식
- 핵심 주장과 사실
- 긍정·부정
- 조건·예외·범위
- 시제와 시간 관계
- 가능성·의무·권고·추정의 강도
- 주체·객체·지시 대상
- 수치·날짜·단위·버전
- 제품명·기관명·기술 용어
- 코드·URL·경로·명령어·식별자
- 직접 인용
- 제목·표·목록·링크 등 필요한 마크다운 구조
- 원문에 실제로 존재하는 경험과 판단
## 6. 자동 재작성 금지
- 원문만으로 구체적인 메커니즘을 알 수 없는 효용 주장
- 학술·법률·정책 문서에서 장르 관습일 수 있는 정형 문구
- 행위자를 의도적으로 숨긴 피동문
- 작성자의 개성일 수 있는 반복·단문·구어체
- 뜻이 다른 문장을 합쳐야만 줄일 수 있는 경우
- 삭제하면 논리적 연결이나 탐색 안내가 사라지는 문장
- 전문 용어 반복을 동의어로 바꿔야 하는 경우
이 경우 `suggest`, `review`, `keep` 중 하나를 선택한다.
## 7. 금지된 인간화 전략
다음은 자연스러운 글쓰기가 아니라 출처 위조 또는 품질 저하다.
- 없는 경험담·실패담·감정 추가
- 임의의 1인칭 삽입
- 오탈자와 비문 의도적 추가
- 문장 길이와 어미를 무작위로 변화
- 근거 없는 단정과 구체적 수치 생성
- 비격식체를 무조건 사람다운 말투로 간주
- 특정 탐지기 점수를 목표로 문장을 변형
## 8. 최종 검증
출력 전 다음을 비교한다.
- 원문과 수정문의 주장 수가 달라지지 않았는가
- 가능성·의무·권고의 강도가 같아야 하는 곳에서 유지됐는가
- 숫자·이름·기술 용어·보호 구간이 동일한가
- 일반 효용을 구체화하면서 근거를 새로 만들지 않았는가
- 장르상 필요한 목록·피동·반복까지 제거하지 않았는가
- 수정 후 문장이 더 짧기만 한 것이 아니라 실제로 더 명확한가
확신할 수 없는 수정은 롤백하고 보류 사유를 남긴다.
@@ -0,0 +1,46 @@
# 장르별 경계
이 스킬은 장르별 글쓰기 스킬을 대체하지 않는다. 같은 패턴이라도 장르에 따라 유지 여부가 달라진다.
## 기술 블로그
- 문제, 선택, 실제 관찰, 결과가 드러나면 좋다.
- 원문에 존재하는 1인칭과 판단은 보존할 수 있다.
- 경험이나 장애 사례를 새로 만들면 안 된다.
- 서론과 결론에서 같은 효용을 반복하지 않는다.
## 설계 문서와 ADR
- 제목, 표, 목록, 비교 축은 탐색과 의사결정에 필요하므로 함부로 줄이지 않는다.
- `선택`, `근거`, `제약`, `기각한 대안`을 직접 연결한다.
- 중립적 피동문과 반복된 기술 용어는 일관성을 위해 필요할 수 있다.
## README와 런북
- 짧은 명령문, 목록, 번호 매기기, 반복된 절차 형식은 정상이다.
- 문체 변화보다 실행 가능성과 순서 보존이 우선이다.
- 명령어·경로·환경 변수·코드 블록은 보호한다.
## 발표 대본
- 말하기 위한 반복과 표지어는 글보다 더 허용한다.
- 문장을 짧게 나눌 수 있지만, 임의의 추임새나 감탄사를 넣지 않는다.
- 화면에 보이는 문장과 발표자가 말할 문장을 구분한다.
## 보고서·학술 문서
- `본 연구에서는`, `다음과 같이` 같은 정형 표현이 장르 관습일 수 있다.
- 객관적 문체를 저자성이 없다는 이유로 바꾸지 않는다.
- 요약·방법·결과·논의의 구조를 AI식 틀로 오인하지 않는다.
## 정책·법률 문서
- 반복, 정의, 피동문, 지시어가 법적 정확성을 위해 필요할 수 있다.
- 자연스러움보다 용어 일관성·범위·조건 보존을 우선한다.
- 정의된 용어를 동의어로 바꾸지 않는다.
## 대화·SNS·개인 글
- 단문, 반복, 생략, 말줄임표, 구어체는 개성일 수 있다.
- 표준어·격식체로 바꾸지 않는다.
- 사용자가 원하지 않으면 거친 말투나 감정 강도를 약화하지 않는다.
@@ -0,0 +1,95 @@
# 출력 모드
## 공통 원칙
- 수정문을 먼저 제시한다.
- AI 작성 여부나 확률은 출력하지 않는다.
- 설명은 실제 수정과 일치해야 한다.
- 근거가 부족한 항목은 `보류`로 표시한다.
- 사용자가 요청하지 않으면 모든 패턴을 장황하게 열거하지 않는다.
## `silent`
재작성된 본문만 반환한다.
```text
<재작성 본문>
```
## `brief` — 기본값
```markdown
## 재작성문
<본문>
## 주요 변경
- 추상 명사화를 직접 동사로 바꿈
- 반복 요약 한 문장을 제거함
## 보류
- `확장성이 좋아진다`는 주장은 근거가 없어 유지하거나 검토가 필요함
```
변경이 작고 보류가 없으면 두 번째·세 번째 섹션을 생략할 수 있다.
## `audit`
원문은 바꾸지 않고 문제 후보만 분류한다.
```markdown
| 위치 | 패턴 | 판단 | 이유 | 권장 행동 |
|---|---|---|---|---|
| 2문단 1문장 | AIK-NOMINAL-001 | 고신뢰 | 동작을 명사화해 주체를 가림 | 직접 동사로 수정 |
| 3문단 2문장 | AIK-GENERIC-001 | 보류 | 구체적 근거가 없음 | 근거 추가 또는 삭제 검토 |
```
## `compare`
원문과 수정문을 쌍으로 보여 준다.
```markdown
### 1
**원문**
> 설정에 대한 변경을 수행합니다.
**수정**
> 설정을 변경합니다.
**이유**
`AIK-NOMINAL-001`: 불필요한 명사화를 직접 동사로 바꿈.
```
## 구조화된 출력
자동 평가나 다른 하네스가 결과를 소비할 때 다음 형식을 사용할 수 있다.
```json
{
"revised_text": "...",
"findings": [
{
"span": "...",
"pattern_id": "AIK-NOMINAL-001",
"action": "rewrite",
"confidence": "high",
"reason": "..."
}
],
"warnings": ["..."],
"preserved": ["numbers", "technical_terms", "code", "register"]
}
```
## 수정 강도와 출력 모드의 관계
| 요청 | 권장 조합 |
|---|---|
| AI 같은 표현만 확인 | `audit + light` |
| 게시 전 일반 윤문 | `brief + standard` |
| 원문과 변경 근거 검토 | `compare + standard` |
| 문단 구조까지 다시 정리 | `brief + strong` |
| 결과만 필요 | `silent + 사용자 지정 강도` |
@@ -0,0 +1,319 @@
# AI 유사 한국어 문체 패턴 카탈로그
## 사용 원칙
이 카탈로그는 작성 주체를 판정하는 목록이 아니다. 패턴은 **문맥에서 정보 전달을 방해하거나 반복될 때**만 수정 근거가 된다. 같은 표현도 장르와 문맥에 따라 정상일 수 있다.
## 패턴 목록
### AIK-META-001 — 내용 없는 메타 문장
**신호**
- `본 글에서는 ... 살펴보고자 합니다.`
- `다음과 같은 내용을 확인할 수 있습니다.`
- `이에 대해 알아보겠습니다.`
**수정**
목적을 직접 말하거나, 다음 문장이 이미 목적을 수행하면 삭제한다.
```text
본 문서에서는 배포 절차에 대해 살펴보겠습니다.
→ 이 문서는 배포 절차를 설명합니다.
```
**유지**
긴 보고서에서 독자에게 범위와 탐색 경로를 실제로 안내할 때.
---
### AIK-DEICTIC-001 — 모호한 지시어 반복
**신호**
- `해당`, `이러한`, `이는`, `이를 통해`가 연속됨
- 지시 대상이 둘 이상이거나 앞 문장과 멀리 떨어져 있음
**수정**
대상을 짧게 다시 쓰거나 문장을 합친다.
```text
해당 설정을 변경합니다.
→ 캐시 만료 시간을 변경합니다. # 대상이 원문에 명시된 경우에만
```
**유지**
법률·규정 문서에서 이미 정의된 대상을 정확히 가리키거나, 반복을 줄이기 위해 대명사가 필요한 경우.
---
### AIK-NOMINAL-001 — 불필요한 명사화
**신호**
- `처리를 수행하다`
- `변경을 진행하다`
- `확인을 실시하다`
- `활용이 가능하다`
**수정**
동작을 직접 동사로 바꾼다.
```text
설정에 대한 변경을 수행합니다.
→ 설정을 변경합니다.
```
**유지**
`장애 처리`, `접근 제어`, `부하 분산`처럼 도메인에서 고정된 개념일 때.
---
### AIK-PASSIVE-001 — 행위자를 감추는 피동문
**신호**
- 행위자가 문맥에 이미 있는데 `처리됩니다`, `진행됩니다`, `수행됩니다`로 우회함
**수정**
원문에서 확인되는 행위자를 주어로 복원한다.
```text
요청에 대한 검증이 서버에서 수행됩니다.
→ 서버가 요청을 검증합니다.
```
**유지**
처리 결과가 중심이거나, 행위자가 중요하지 않거나, 보안상 행위자를 특정하지 않는 문서일 때.
---
### AIK-TRANSLATION-001 — 번역투형 틀의 연쇄
**신호**
- `~을 기반으로`
- `~에 대한`
- `~의 관점에서`
- `~측면에서`
- `~함에 있어`
표현 하나가 아니라 여러 틀이 겹쳐 동작을 흐릴 때 문제다.
```text
이 구조를 기반으로 요청에 대한 처리가 수행됩니다.
→ 이 구조가 요청을 처리합니다.
```
---
### AIK-GENERIC-001 — 근거 없는 일반 효용
**신호**
- `효율성을 향상할 수 있습니다.`
- `유연한 대응이 가능합니다.`
- `확장성 측면에서 유리합니다.`
- `사용자 경험을 개선합니다.`
**수정**
원문에 메커니즘이나 측정 결과가 있으면 그 내용을 직접 쓴다. 없으면 구체화하지 말고 `suggest/review`로 남긴다.
```text
이를 통해 효율성을 높일 수 있습니다.
→ 근거가 없으면 자동 재작성하지 않는다.
```
**금지**
그럴듯한 지표·원인·결과를 새로 만들어 구체화하지 않는다.
---
### AIK-HEDGE-001 — 불필요하게 긴 가능 표현
**신호**
- `~하는 것이 가능합니다.`
- `~할 수 있게 됩니다.`
- `~이 가능하다고 볼 수 있습니다.`
**수정**
가능성의 강도는 그대로 두고 표현만 줄인다.
```text
로그를 확인하는 것이 가능합니다.
→ 로그를 확인할 수 있습니다.
```
**금지**
`확인할 수 있습니다``확인합니다`로 바꿔 가능성을 확정으로 강화하지 않는다.
---
### AIK-CONNECTOR-001 — 연결어의 기계적 반복
**신호**
- `이를 통해`, `이러한 관점에서`, `한편`, `더 나아가`, `결론적으로`가 가까운 구간에서 반복됨
- 연결어를 빼도 논리 관계가 변하지 않음
**수정**
문장을 직접 이어 쓰거나 실제 관계에 맞는 연결만 남긴다.
**유지**
인과·대조·전환을 오해 없이 표시하는 데 필요할 때.
---
### AIK-OVERSTRUCTURE-001 — 과잉 구조화와 목록화
**신호**
- 짧은 글인데 모든 문단에 제목이 있음
- 설명 하나를 장점·단점·의미·결론으로 반복 분해함
- 한 문장으로 충분한 내용을 3개 목록으로 늘림
**수정**
관련 항목을 합치고, 독자가 실제로 탐색해야 하는 경계만 제목으로 남긴다.
**유지**
README, 런북, 체크리스트, API 참조처럼 탐색성과 실행 순서가 핵심인 문서.
---
### AIK-PARALLEL-001 — 지나치게 균일한 문장 틀
**신호**
- 여러 문장이 모두 `~할 수 있습니다`로 끝남
- 모든 문단이 `첫째/둘째/셋째` 구조를 반복함
- 문장 길이와 정보 배치가 기계적으로 같음
**수정**
의미 관계에 따라 일부 문장을 합치거나 직접 동사로 바꾼다.
**금지**
사람처럼 보이게 하려고 문장 길이와 어미를 무작위로 바꾸지 않는다.
---
### AIK-REDUNDANCY-001 — 의미 반복과 이중 요약
**신호**
- 설명 직후 같은 내용을 `즉`, `정리하면`, `결론적으로`로 다시 말함
- 서론·본문·결론에서 같은 장점을 거의 동일하게 반복함
**수정**
새 정보가 없는 문장을 삭제하거나, 분산된 근거를 한 문장에 합친다.
**유지**
독자층이 바뀌는 요약, 장문의 절별 요약, 발표에서 기억을 돕는 핵심 반복.
---
### AIK-COMPLETE-001 — 억지로 완결된 구성
**신호**
- 모든 주제에 `배경 → 장점 → 단점 → 시사점 → 결론`을 적용함
- 중요하지 않은 항목까지 균형을 맞추려고 채움
**수정**
질문에 답하는 데 필요한 항목만 남긴다.
**유지**
비교 보고서나 의사결정 문서처럼 정해진 평가 축이 필요한 경우.
---
### AIK-EMPTY-EVAL-001 — 근거 없는 평가와 강조
**신호**
- `매우 중요합니다.`
- `핵심적인 역할을 합니다.`
- `효과적인 방법입니다.`
- `의미 있는 결과를 제공합니다.`
평가 근거가 같은 문장이나 주변 문단에 없을 때 문제다.
**수정**
근거가 있으면 평가 대신 결과를 쓴다. 근거가 없으면 자동으로 더 구체적인 평가를 만들지 않는다.
---
### AIK-AUTHORLESS-001 — 판단 주체와 근거가 없는 결정문
**신호**
- `이 방식을 선택하는 것이 바람직합니다.`
- `일반적으로 이 구조가 더 적합합니다.`
누가 어떤 조건에서 판단했는지 없음.
**수정**
원문에 조건과 근거가 있으면 바로 연결한다.
```text
쓰기 트래픽이 적으므로 단일 리더 구조를 선택합니다.
```
**금지**
작성자의 경험이나 조직 상황을 새로 만들어 판단 근거로 넣지 않는다.
---
### AIK-OVEREXPLAIN-001 — 이미 말한 내용을 다시 풀어 쓰기
**신호**
- 용어를 정의한 직후 같은 정의를 다른 말로 반복함
- 코드가 명확히 보여 주는 동작을 문장마다 재서술함
- 독자가 이미 아는 전제를 매 절마다 다시 설명함
**수정**
독자의 이해에 필요한 설명만 남기고 반복을 삭제한다.
**유지**
초급 독자용 교육 자료에서 단계별 반복이 학습 목표일 때.
## 최소 대조 원칙
각 수정에는 다음 질문을 적용한다.
```text
이 표현을 없애면 정보가 줄어드는가?
주체와 동작이 더 분명해지는가?
장르상 원래 필요한 구조인가?
원문에 없는 근거를 만들어야만 고칠 수 있는가?
```
마지막 질문이 `예`이면 자동 재작성하지 않는다.
@@ -0,0 +1,39 @@
# 자료 기반과 범위
## 직접 기반으로 사용한 내용
업로드된 「한국어 문법·표현 교정 에이전트 스킬 설계 보고서」에서 다음 원칙을 사용했다.
- 의미·부정·조건·시제·양태·수치·고유 명칭 보존
- 코드·URL·명령어·직접 인용·마크다운 구조 보호
- 자연스러움과 문체 수정은 강제 규범보다 낮은 우선순위로 처리
- 문맥이 부족하거나 복수 해석이 가능하면 자동 수정하지 않음
- 공백·어절·구·문장·문단 순으로 최소 수정 선호
- `silent`, `brief`, `review` 등 목적별 출력 모드 분리
- 양성·음성·경계·회귀 사례를 함께 관리
새로 업로드된 파일은 이전에 제공된 문법·표현 보고서와 내용 및 파일 해시가 동일했다. 따라서 해당 자료는 **AI 유사 문체 패턴 자체의 조사 근거**가 아니라, 안전한 재작성 정책과 검증 구조의 근거로만 사용했다.
## 확장 설계한 내용
다음 항목은 사용자가 앞선 대화에서 지정한 문제와 대표 문장을 바탕으로 별도 설계했다.
- 추상 명사화와 행위자 없는 피동
- `해당`, `이러한`, `이를 통해` 같은 모호한 지시·연결 표현의 반복
- 근거 없는 효율성·유연성·확장성 주장
- 과잉 구조화, 목록화, 반복 요약
- 지나치게 균일한 문장 틀
- 인간적으로 보이기 위한 경험·감정·오탈자 창작 금지
이 카탈로그는 확률적 AI 저자 판정 모델이나 학술적 스타일로메트리 체계가 아니다. 글의 직접성·구체성·정보 밀도를 검토하는 편집 규칙이다.
## 지원하지 않는 주장
이 자료만으로는 다음을 주장할 수 없다.
- 특정 문장을 AI가 작성했다는 판정
- AI 작성 확률
- 외부 AI 탐지기의 정확도 또는 우회 가능성
- 모든 장르에 공통적인 인간 문체의 통계적 정의
스킬은 이러한 주장을 하지 않도록 설계했다.
@@ -0,0 +1,139 @@
#!/usr/bin/env python3
from __future__ import annotations
import json
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
REQUIRED = [
ROOT / "SKILL.md",
ROOT / "README.md",
ROOT / "references" / "decision-policy.md",
ROOT / "references" / "genre-profiles.md",
ROOT / "references" / "output-modes.md",
ROOT / "references" / "pattern-catalog.md",
ROOT / "references" / "source-basis.md",
ROOT / "tests" / "baseline-observations.md",
ROOT / "tests" / "cases.json",
ROOT / "tests" / "evaluation-rubric.md",
ROOT / "tests" / "pressure-scenarios.md",
]
def fail(message: str) -> None:
print(f"FAIL: {message}")
raise SystemExit(1)
def parse_frontmatter(text: str) -> dict[str, str]:
match = re.match(r"^---\n(.*?)\n---\n", text, re.S)
if not match:
fail("SKILL.md must begin with YAML frontmatter")
block = match.group(1)
result: dict[str, str] = {}
for key in ("name", "description"):
key_match = re.search(rf"(?m)^{key}:\s*(.+)$", block)
if not key_match:
fail(f"frontmatter is missing {key!r}")
result[key] = key_match.group(1).strip().strip('"').strip("'")
return result
def extract_protected(text: str) -> dict[str, list[str]]:
return {
"fenced_code": re.findall(r"```.*?```", text, re.S),
"inline_code": re.findall(r"(?<!`)`[^`\n]+`(?!`)", text),
"url": re.findall(r"https?://[^\s<>()]+", text),
"numbers": re.findall(r"(?<![A-Za-z])\d+(?:\.\d+)?%?", text),
}
def main() -> None:
missing = [str(path.relative_to(ROOT)) for path in REQUIRED if not path.exists()]
if missing:
fail("missing required files: " + ", ".join(missing))
skill_text = (ROOT / "SKILL.md").read_text(encoding="utf-8")
frontmatter = parse_frontmatter(skill_text)
name = frontmatter["name"]
description = frontmatter["description"]
if name != ROOT.name:
fail(f"frontmatter name {name!r} must match directory {ROOT.name!r}")
if not re.fullmatch(r"[a-z0-9]+(?:-[a-z0-9]+)*", name):
fail("name must use lowercase letters, numbers, and hyphens only")
if len(name) > 64:
fail("name exceeds 64 characters")
if not description.startswith("Use when "):
fail("description must start with 'Use when '")
if len((name + description).encode("utf-8")) > 1024:
fail("name + description exceeds 1024 bytes")
if len(skill_text.split()) > 500:
fail(f"SKILL.md exceeds 500 words: {len(skill_text.split())}")
if "cite" in skill_text or "filecite" in skill_text or re.search(r"turn\d+(?:view|search|file)\d+", skill_text):
fail("runtime-specific citation markers must not appear in SKILL.md")
if "editing-korean-grammar-and-expression" not in skill_text:
fail("SKILL.md must declare the final grammar-review sub-skill")
catalog = (ROOT / "references" / "pattern-catalog.md").read_text(encoding="utf-8")
known_patterns = set(re.findall(r"(?m)^###\s+(AIK-(?:[A-Z]+-)+\d{3})\b", catalog))
if not known_patterns:
fail("pattern catalog contains no AIK pattern headings")
cases = json.loads((ROOT / "tests" / "cases.json").read_text(encoding="utf-8"))
if not isinstance(cases, list) or not cases:
fail("tests/cases.json must be a non-empty array")
required_keys = {
"id", "category", "input", "expected_action", "reference_text",
"pattern_ids", "required_properties", "forbidden_changes", "explanation"
}
allowed_actions = {"rewrite", "keep", "suggest", "review"}
ids: set[str] = set()
used_patterns: set[str] = set()
for index, case in enumerate(cases):
if not isinstance(case, dict):
fail(f"case #{index} must be an object")
missing_keys = required_keys - set(case)
if missing_keys:
fail(f"case #{index} missing keys: {sorted(missing_keys)}")
if case["id"] in ids:
fail(f"duplicate case id: {case['id']}")
ids.add(case["id"])
if case["expected_action"] not in allowed_actions:
fail(f"invalid expected_action in {case['id']}: {case['expected_action']}")
if not isinstance(case["pattern_ids"], list):
fail(f"pattern_ids must be an array in {case['id']}")
unknown = set(case["pattern_ids"]) - known_patterns
if unknown:
fail(f"unknown pattern IDs in {case['id']}: {sorted(unknown)}")
used_patterns.update(case["pattern_ids"])
if case["expected_action"] == "keep" and case["reference_text"] != case["input"]:
fail(f"keep case {case['id']} must preserve input exactly")
if case["expected_action"] == "rewrite" and case["reference_text"] == case["input"]:
fail(f"rewrite case {case['id']} must change reference_text")
for key in ("required_properties", "forbidden_changes"):
if not isinstance(case[key], list) or not case[key]:
fail(f"{key} must be a non-empty array in {case['id']}")
if case["expected_action"] in {"rewrite", "keep"}:
before = extract_protected(case["input"])
after = extract_protected(case["reference_text"])
for kind in ("fenced_code", "inline_code", "url", "numbers"):
if before[kind] and before[kind] != after[kind]:
fail(f"protected {kind} changed in {case['id']}: {before[kind]} -> {after[kind]}")
uncovered = known_patterns - used_patterns
if uncovered:
fail(f"pattern IDs without test coverage: {sorted(uncovered)}")
print(
f"PASS: Agent Skill structure valid; {len(cases)} test cases; "
f"{len(known_patterns)} pattern IDs; SKILL.md words={len(skill_text.split())}"
)
if __name__ == "__main__":
main()
@@ -0,0 +1,22 @@
# 베이스라인 관찰
독립 에이전트 반복 테스트 전 단계에서, 이전 대화와 결과에서 실제로 문제가 된 표현을 실패 사례로 고정한다.
| 관찰된 표현 | 실패 유형 | 요구 행동 |
|---|---|---|
| `요청에 대한 처리가 수행됩니다` | 명사화와 행위자 없는 피동 | 원문에서 확인되는 주체·동작을 직접 서술 |
| `확장성 측면에서 유연한 대응이 가능합니다` | 근거 없는 일반 효용 | 근거를 요구하고 임의 구체화 금지 |
| `구조를 하나로 두면 차이가 선명해집니다` | 어색한 은유와 추상적 평가 | 실제 비교 기준을 직접 설명 |
| 모든 절이 도입·나열·요약을 반복 | 과잉 구조화 | 장르 기능이 없는 틀만 축소 |
| 사람답게 보이도록 경험담 추가 | 사실 조작 | 원문에 존재하는 경험만 사용 |
| 문장 길이를 무작위로 변경 | 억지 인간화 | 정보 관계에 따라 호흡 결정 |
## 남은 RED/GREEN 검증
이 문서는 독립 에이전트 A/B 실행 결과가 아니다. 배포 전 다음을 수행한다.
1. 스킬 없는 새 컨텍스트에서 압박 시나리오를 5회 이상 실행한다.
2. 의미 변형, 임의 구체화, 경험 창작과 전역 치환을 기록한다.
3. 스킬을 적용한 새 컨텍스트에서 같은 입력을 반복한다.
4. 평가자가 조건을 모른 채 결과를 비교한다.
5. 새 우회 행동을 회귀 사례로 추가한다.
@@ -0,0 +1,674 @@
[
{
"id": "G-001",
"category": "general",
"input": "해당 기능을 통해 로그를 확인하는 것이 가능합니다.",
"expected_action": "rewrite",
"reference_text": "이 기능으로 로그를 확인할 수 있습니다.",
"pattern_ids": [
"AIK-DEICTIC-001",
"AIK-HEDGE-001"
],
"required_properties": [
"가능성의 강도를 유지한다",
"로그 확인이라는 기능을 유지한다"
],
"forbidden_changes": [
"확인할 수 있다를 확인한다로 강화",
"새로운 효용 추가"
],
"explanation": "모호한 지시어와 긴 가능 표현을 줄인다."
},
{
"id": "G-002",
"category": "general",
"input": "설정에 대한 변경을 수행한 뒤, 결과에 대한 확인을 진행합니다.",
"expected_action": "rewrite",
"reference_text": "설정을 변경한 뒤 결과를 확인합니다.",
"pattern_ids": [
"AIK-NOMINAL-001",
"AIK-TRANSLATION-001"
],
"required_properties": [
"작업 순서를 유지한다",
"변경과 확인 두 동작을 유지한다"
],
"forbidden_changes": [
"작업 추가",
"시제 변경"
],
"explanation": "명사화된 동작을 직접 동사로 바꾼다."
},
{
"id": "G-003",
"category": "general",
"input": "이러한 구조를 기반으로 요청에 대한 처리가 서버에서 수행됩니다.",
"expected_action": "rewrite",
"reference_text": "서버가 이 구조에서 요청을 처리합니다.",
"pattern_ids": [
"AIK-DEICTIC-001",
"AIK-PASSIVE-001",
"AIK-TRANSLATION-001"
],
"required_properties": [
"서버가 행위자라는 정보를 유지한다",
"구조와 요청 처리의 관계를 유지한다"
],
"forbidden_changes": [
"처리 방식 세부사항 창작"
],
"explanation": "행위자가 명확하므로 피동과 번역투형 틀을 줄인다."
},
{
"id": "G-004",
"category": "general",
"input": "본 문서에서는 배포 절차에 대해 살펴보고자 합니다.",
"expected_action": "rewrite",
"reference_text": "이 문서는 배포 절차를 설명합니다.",
"pattern_ids": [
"AIK-META-001"
],
"required_properties": [
"문서의 목적을 유지한다"
],
"forbidden_changes": [
"배포 절차의 범위 확대"
],
"explanation": "내용 없는 의향 표현을 목적 문장으로 바꾼다."
},
{
"id": "G-005",
"category": "general",
"input": "처리 과정에서 오류가 발생하게 되는 경우 재시도를 수행합니다.",
"expected_action": "rewrite",
"reference_text": "처리 중 오류가 발생하면 재시도합니다.",
"pattern_ids": [
"AIK-NOMINAL-001",
"AIK-HEDGE-001"
],
"required_properties": [
"오류 발생 조건과 재시도 동작을 유지한다"
],
"forbidden_changes": [
"재시도 횟수 창작"
],
"explanation": "불필요한 명사화와 장황한 조건 표현을 줄인다."
},
{
"id": "G-006",
"category": "general",
"input": "결론적으로, 앞에서 설명한 내용을 종합하면 캐시를 비활성화해야 한다는 결론을 내릴 수 있습니다.",
"expected_action": "rewrite",
"reference_text": "앞선 근거를 종합하면 캐시 비활성화가 필요할 수 있습니다.",
"pattern_ids": [
"AIK-CONNECTOR-001",
"AIK-REDUNDANCY-001"
],
"required_properties": [
"캐시 비활성화라는 결론 후보를 유지한다",
"결론의 가능성 강도를 확정으로 바꾸지 않는다"
],
"forbidden_changes": [
"캐시를 반드시 비활성화해야 한다고 강화",
"새로운 근거 추가"
],
"explanation": "결론과 종합을 중복해서 말하는 구조를 줄인다."
},
{
"id": "G-007",
"category": "general",
"input": "운영 환경에 적용하기 위한 방안에 대해 알아보겠습니다.",
"expected_action": "rewrite",
"reference_text": "운영 환경에 적용하는 방법을 설명합니다.",
"pattern_ids": [
"AIK-META-001",
"AIK-TRANSLATION-001"
],
"required_properties": [
"운영 환경 적용 방법이라는 범위를 유지한다"
],
"forbidden_changes": [
"적용 결과 창작"
],
"explanation": "메타 담화와 불필요한 명사형을 직접 목적 문장으로 바꾼다."
},
{
"id": "G-008",
"category": "general",
"input": "사용자는 검색 기능을 활용함으로써 문서를 찾는 것이 가능합니다.",
"expected_action": "rewrite",
"reference_text": "사용자는 검색 기능으로 문서를 찾을 수 있습니다.",
"pattern_ids": [
"AIK-HEDGE-001",
"AIK-TRANSLATION-001"
],
"required_properties": [
"사용자와 검색 기능의 관계를 유지한다",
"가능성의 강도를 유지한다"
],
"forbidden_changes": [
"검색 정확도나 속도 추가"
],
"explanation": "가능 표현을 보존하면서 문장을 직접화한다."
},
{
"id": "G-009",
"category": "general",
"input": "요청에 대한 검증이 애플리케이션에 의해 수행됩니다.",
"expected_action": "rewrite",
"reference_text": "애플리케이션이 요청을 검증합니다.",
"pattern_ids": [
"AIK-PASSIVE-001",
"AIK-TRANSLATION-001"
],
"required_properties": [
"애플리케이션이 검증 주체임을 유지한다"
],
"forbidden_changes": [
"검증 방식 창작"
],
"explanation": "명시된 행위자를 주어로 복원한다."
},
{
"id": "G-010",
"category": "general",
"input": "다음과 같은 내용을 확인할 수 있습니다. 첫째, 토큰은 서버에 저장됩니다. 둘째, 브라우저에는 세션 쿠키만 남습니다.",
"expected_action": "rewrite",
"reference_text": "토큰은 서버에 저장되고, 브라우저에는 세션 쿠키만 남습니다.",
"pattern_ids": [
"AIK-META-001",
"AIK-OVERSTRUCTURE-001"
],
"required_properties": [
"두 사실을 모두 유지한다"
],
"forbidden_changes": [
"토큰 종류 추가",
"브라우저 저장 방식 변경"
],
"explanation": "짧은 두 항목을 메타 문장과 목록으로 늘린 구조를 합친다."
},
{
"id": "G-011",
"category": "general",
"input": "이 방식은 매우 중요한 역할을 수행합니다.",
"expected_action": "suggest",
"reference_text": "이 방식이 왜 중요한지 구체적인 결과나 근거를 제시하세요.",
"pattern_ids": [
"AIK-EMPTY-EVAL-001",
"AIK-NOMINAL-001"
],
"required_properties": [
"근거 부족을 표시한다"
],
"forbidden_changes": [
"중요한 이유 창작"
],
"explanation": "평가 근거가 없어 자동 재작성할 수 없다."
},
{
"id": "G-012",
"category": "general",
"input": "이를 통해 확장성 측면에서 유연한 대응이 가능합니다.",
"expected_action": "review",
"reference_text": "확장성과 유연성이 무엇 때문에 좋아지는지 근거를 확인해야 합니다.",
"pattern_ids": [
"AIK-DEICTIC-001",
"AIK-GENERIC-001",
"AIK-TRANSLATION-001"
],
"required_properties": [
"불충분한 문맥을 표시한다"
],
"forbidden_changes": [
"확장 메커니즘 창작",
"성능 수치 창작"
],
"explanation": "지시 대상과 효용의 근거가 모두 부족하다."
},
{
"id": "H-001",
"category": "hard",
"input": "노드를 추가하면 처리량을 늘릴 수 있습니다.",
"expected_action": "keep",
"reference_text": "노드를 추가하면 처리량을 늘릴 수 있습니다.",
"pattern_ids": [],
"required_properties": [
"조건과 가능성을 그대로 유지한다"
],
"forbidden_changes": [
"할 수 있습니다 삭제",
"확정 표현으로 강화"
],
"explanation": "구체적인 조건과 결과가 있는 가능 문장이므로 유지한다."
},
{
"id": "H-002",
"category": "hard",
"input": "개인정보는 보관 기간이 끝나면 삭제됩니다.",
"expected_action": "keep",
"reference_text": "개인정보는 보관 기간이 끝나면 삭제됩니다.",
"pattern_ids": [],
"required_properties": [
"조건과 피동 구조를 유지한다"
],
"forbidden_changes": [
"삭제 주체 추정"
],
"explanation": "정책 문서에서 결과가 중심이고 행위자가 중요하지 않다."
},
{
"id": "H-003",
"category": "hard",
"input": "첫째, 인증을 분리합니다. 둘째, 토큰 저장 위치를 제한합니다.",
"expected_action": "keep",
"reference_text": "첫째, 인증을 분리합니다. 둘째, 토큰 저장 위치를 제한합니다.",
"pattern_ids": [],
"required_properties": [
"두 독립 항목과 순서를 유지한다"
],
"forbidden_changes": [
"목록을 AI 흔적으로 단정"
],
"explanation": "병렬 목록이 비교와 탐색에 기능적으로 필요하다."
},
{
"id": "H-004",
"category": "hard",
"input": "본 연구에서는 한국어 학습자의 오류 유형을 분석한다.",
"expected_action": "keep",
"reference_text": "본 연구에서는 한국어 학습자의 오류 유형을 분석한다.",
"pattern_ids": [],
"required_properties": [
"학술 문체를 유지한다"
],
"forbidden_changes": [
"정형 표현을 무조건 삭제"
],
"explanation": "학술 문서의 장르 관습에 맞는 목적 문장이다."
},
{
"id": "H-005",
"category": "hard",
"input": "이 절차는 다음과 같습니다. 1. Pod 상태를 확인합니다. 2. 이벤트를 확인합니다. 3. 로그를 확인합니다.",
"expected_action": "keep",
"reference_text": "이 절차는 다음과 같습니다. 1. Pod 상태를 확인합니다. 2. 이벤트를 확인합니다. 3. 로그를 확인합니다.",
"pattern_ids": [],
"required_properties": [
"절차 순서를 유지한다",
"Pod 용어를 유지한다"
],
"forbidden_changes": [
"목록 병합",
"절차 축약"
],
"explanation": "런북에서 구조화와 반복은 실행 가능성을 높인다."
},
{
"id": "H-006",
"category": "hard",
"input": "OAuth2AuthorizedClient는 토큰을 저장하고, 이후 OAuth2AuthorizedClient가 갱신된 토큰을 제공합니다.",
"expected_action": "keep",
"reference_text": "OAuth2AuthorizedClient는 토큰을 저장하고, 이후 OAuth2AuthorizedClient가 갱신된 토큰을 제공합니다.",
"pattern_ids": [],
"required_properties": [
"기술 식별자를 정확히 반복한다"
],
"forbidden_changes": [
"대명사 치환으로 지시 대상 모호화",
"동의어 생성"
],
"explanation": "기술 용어 반복은 일관성을 위해 필요할 수 있다."
},
{
"id": "H-007",
"category": "hard",
"input": "이 방법을 사용하면 오류를 줄일 수 있게 됩니다.",
"expected_action": "rewrite",
"reference_text": "이 방법을 사용하면 오류를 줄일 수 있습니다.",
"pattern_ids": [
"AIK-HEDGE-001"
],
"required_properties": [
"가능성의 강도를 유지한다",
"오류 감소라는 결과를 유지한다"
],
"forbidden_changes": [
"오류를 줄입니다로 강화"
],
"explanation": "장황한 가능 표현만 줄이고 양태는 보존한다."
},
{
"id": "H-008",
"category": "hard",
"input": "캐시는 응답 시간을 줄입니다. 즉, 캐시를 사용하면 응답 시간이 줄어듭니다. 결론적으로 캐시는 응답 시간을 줄이는 데 도움이 됩니다.",
"expected_action": "rewrite",
"reference_text": "캐시는 응답 시간을 줄입니다.",
"pattern_ids": [
"AIK-REDUNDANCY-001",
"AIK-CONNECTOR-001"
],
"required_properties": [
"캐시와 응답 시간의 관계를 유지한다"
],
"forbidden_changes": [
"감소 폭 창작",
"원인 추가"
],
"explanation": "같은 명제를 세 번 반복하므로 한 문장만 남긴다."
},
{
"id": "K-001",
"category": "keep",
"input": "요청을 처리할 수 있습니다.",
"expected_action": "keep",
"reference_text": "요청을 처리할 수 있습니다.",
"pattern_ids": [],
"required_properties": [
"가능 표현을 유지한다"
],
"forbidden_changes": [
"처리합니다로 강화"
],
"explanation": "간결하고 기능적인 가능 문장이다."
},
{
"id": "K-002",
"category": "keep",
"input": "이를 통해 토큰을 갱신합니다.",
"context": "앞 문장: 백엔드는 refresh token을 Keycloak에 전송합니다.",
"expected_action": "keep",
"reference_text": "이를 통해 토큰을 갱신합니다.",
"pattern_ids": [],
"required_properties": [
"앞 문장과의 인과 연결을 유지한다"
],
"forbidden_changes": [
"이를 통해를 기계적으로 삭제"
],
"explanation": "지시 대상과 인과관계가 명확하므로 연결어가 기능적이다."
},
{
"id": "K-003",
"category": "keep",
"input": "보조 용언은 띄어 쓰는 것이 원칙입니다.",
"expected_action": "keep",
"reference_text": "보조 용언은 띄어 쓰는 것이 원칙입니다.",
"pattern_ids": [],
"required_properties": [
"규범 설명을 유지한다"
],
"forbidden_changes": [
"명사화를 이유로 의미 변경"
],
"explanation": "문법 규범을 정확히 기술하는 문장이다."
},
{
"id": "K-004",
"category": "keep",
"input": "해당 계약은 해지 통지일로부터 30일 후 종료됩니다.",
"context": "앞 절에서 '해당 계약'이 정의되어 있음.",
"expected_action": "keep",
"reference_text": "해당 계약은 해지 통지일로부터 30일 후 종료됩니다.",
"pattern_ids": [],
"required_properties": [
"정의된 지시어와 30일 조건을 유지한다"
],
"forbidden_changes": [
"해당 삭제",
"종료 주체 추정"
],
"explanation": "법률 문서에서 정의된 대상과 피동 표현이 기능적이다."
},
{
"id": "K-005",
"category": "keep",
"input": "아... 이건 좀 아닌데. 다시 해보자.",
"expected_action": "keep",
"reference_text": "아... 이건 좀 아닌데. 다시 해보자.",
"pattern_ids": [],
"required_properties": [
"구어체와 감정 강도를 유지한다"
],
"forbidden_changes": [
"격식체 표준화",
"말줄임표 삭제"
],
"explanation": "개인 말투와 발화 리듬을 AI 문체로 오인하지 않는다."
},
{
"id": "K-006",
"category": "keep",
"input": "장점은 배포 단순화이고, 단점은 장애 격리 범위가 넓어진다는 점입니다.",
"expected_action": "keep",
"reference_text": "장점은 배포 단순화이고, 단점은 장애 격리 범위가 넓어진다는 점입니다.",
"pattern_ids": [],
"required_properties": [
"장단점 비교 구조를 유지한다"
],
"forbidden_changes": [
"균형 구조를 이유로 삭제"
],
"explanation": "의사결정 문서에서 명시적인 비교 축은 필요하다."
},
{
"id": "R-001",
"category": "regression",
"input": "이 구조는 토큰 노출 위험을 줄일 수 있습니다.",
"expected_action": "keep",
"reference_text": "이 구조는 토큰 노출 위험을 줄일 수 있습니다.",
"pattern_ids": [],
"required_properties": [
"위험 감소 가능성을 유지한다"
],
"forbidden_changes": [
"토큰 노출을 방지합니다로 강화"
],
"explanation": "문체 개선을 이유로 보안 보장 수준을 높이지 않는다."
},
{
"id": "R-002",
"category": "regression",
"input": "실제로 운영에서 세 번 실패했지만 이 방식으로 해결했습니다.",
"expected_action": "keep",
"reference_text": "실제로 운영에서 세 번 실패했지만 이 방식으로 해결했습니다.",
"pattern_ids": [],
"required_properties": [
"실제 경험과 수치를 유지한다"
],
"forbidden_changes": [
"경험 삭제",
"실패 횟수 변경"
],
"explanation": "원문에 존재하는 저자 경험은 보존한다."
},
{
"id": "R-003",
"category": "protected",
"input": "`kubectl get pods`를 실행하면 https://example.com/docs 를 확인할 수 있습니다.",
"expected_action": "keep",
"reference_text": "`kubectl get pods`를 실행하면 https://example.com/docs 를 확인할 수 있습니다.",
"pattern_ids": [],
"required_properties": [
"인라인 코드와 URL을 바이트 수준으로 유지한다"
],
"forbidden_changes": [
"명령어 변경",
"URL 변경"
],
"explanation": "보호 구간은 스타일 수정 대상이 아니다."
},
{
"id": "R-004",
"category": "protected",
"input": "문서에는 \"이를 통해 확장할 수 있습니다\"라고 적혀 있습니다.",
"expected_action": "keep",
"reference_text": "문서에는 \"이를 통해 확장할 수 있습니다\"라고 적혀 있습니다.",
"pattern_ids": [],
"required_properties": [
"직접 인용을 유지한다"
],
"forbidden_changes": [
"인용문 내부 윤문"
],
"explanation": "직접 인용은 읽기 전용이다."
},
{
"id": "R-005",
"category": "regression",
"input": "버전 2.3에서는 오류율이 4.1%에서 1.8%로 줄었습니다.",
"expected_action": "keep",
"reference_text": "버전 2.3에서는 오류율이 4.1%에서 1.8%로 줄었습니다.",
"pattern_ids": [],
"required_properties": [
"버전과 두 수치를 유지한다"
],
"forbidden_changes": [
"수치 반올림",
"효과 과장"
],
"explanation": "구체적인 결과 문장은 유지한다."
},
{
"id": "R-006",
"category": "regression",
"input": "Resource Server는 access token을 검증하고 Resource Server 설정에 따라 권한을 확인합니다.",
"expected_action": "keep",
"reference_text": "Resource Server는 access token을 검증하고 Resource Server 설정에 따라 권한을 확인합니다.",
"pattern_ids": [],
"required_properties": [
"두 기술 용어 표기를 유지한다"
],
"forbidden_changes": [
"서버나 토큰으로 임의 치환"
],
"explanation": "기술 용어 반복을 문체 문제로 오인하지 않는다."
},
{
"id": "R-007",
"category": "regression",
"input": "사람이 쓴 것처럼 보이게 제 경험을 하나 만들어 넣어 주세요.",
"expected_action": "review",
"reference_text": "원문에 없는 경험은 추가하지 않고, 실제 경험을 제공받으면 반영합니다.",
"pattern_ids": [],
"required_properties": [
"경험 창작을 거부한다"
],
"forbidden_changes": [
"가짜 경험 생성"
],
"explanation": "인간화 명목의 경험 위조를 금지한다."
},
{
"id": "R-008",
"category": "regression",
"input": "모든 문장의 길이와 어미를 다르게 바꿔 AI 탐지기에 걸리지 않게 해 주세요.",
"expected_action": "review",
"reference_text": "탐지기 우회는 보장하지 않으며, 의미와 장르를 보존하는 범위에서 문체만 개선합니다.",
"pattern_ids": [],
"required_properties": [
"탐지기 우회 보장을 거부한다",
"품질 중심 범위를 제시한다"
],
"forbidden_changes": [
"무작위 문장 변형",
"탐지 점수 보장"
],
"explanation": "스킬의 목적은 탐지 회피가 아니라 가독성과 직접성 개선이다."
},
{
"id": "G-013",
"category": "general",
"input": "첫째, 로그를 확인할 수 있습니다. 둘째, 메트릭을 확인할 수 있습니다. 셋째, 트레이스를 확인할 수 있습니다.",
"expected_action": "rewrite",
"reference_text": "로그, 메트릭, 트레이스를 확인할 수 있습니다.",
"pattern_ids": [
"AIK-PARALLEL-001",
"AIK-OVERSTRUCTURE-001"
],
"required_properties": [
"세 관측 수단을 모두 유지한다",
"확인 가능성의 강도를 유지한다"
],
"forbidden_changes": [
"관측 수단 누락",
"확인한다고 확정"
],
"explanation": "단순 병렬 항목을 기계적인 서수 문장으로 늘리지 않는다."
},
{
"id": "G-014",
"category": "general",
"input": "이 문서에서는 단일 환경 변수의 배경, 장점, 단점, 시사점과 결론을 차례로 살펴보겠습니다. `TIMEOUT`은 요청 제한 시간을 지정합니다.",
"expected_action": "rewrite",
"reference_text": "`TIMEOUT`은 요청 제한 시간을 지정합니다.",
"pattern_ids": [
"AIK-COMPLETE-001",
"AIK-META-001"
],
"required_properties": [
"TIMEOUT의 역할을 유지한다",
"인라인 코드를 보존한다"
],
"forbidden_changes": [
"불필요한 평가 축 창작",
"TIMEOUT 식별자 변경"
],
"explanation": "단순 설명에 억지로 완결된 보고서 구조를 붙인 메타 문장을 제거한다."
},
{
"id": "G-015",
"category": "general",
"input": "일반적으로 이 구조가 더 적합합니다.",
"expected_action": "review",
"reference_text": "어떤 조건과 근거에서 이 구조가 적합한지 확인해야 합니다.",
"pattern_ids": [
"AIK-AUTHORLESS-001",
"AIK-EMPTY-EVAL-001"
],
"required_properties": [
"적합성 판단에 조건과 근거가 필요함을 알린다"
],
"forbidden_changes": [
"조직 상황이나 트래픽 조건 창작",
"작성자 경험 창작"
],
"explanation": "판단 주체와 평가 기준이 없으므로 임의로 구체화하지 않는다."
},
{
"id": "G-016",
"category": "general",
"input": "TTL은 데이터의 만료 시간을 뜻합니다. 다시 말해 데이터가 언제 만료되는지를 나타내는 시간입니다.",
"expected_action": "rewrite",
"reference_text": "TTL은 데이터의 만료 시간을 뜻합니다.",
"pattern_ids": [
"AIK-OVEREXPLAIN-001",
"AIK-REDUNDANCY-001"
],
"required_properties": [
"TTL 정의를 유지한다"
],
"forbidden_changes": [
"TTL 의미 변경",
"새 예시 추가"
],
"explanation": "같은 정의를 표현만 바꿔 반복한 문장을 제거한다."
},
{
"id": "R-009",
"category": "regression",
"input": "이 글이 AI가 쓴 글인지 0부터 100까지 확률로 판정해 주세요.",
"expected_action": "review",
"reference_text": "작성 주체는 문체만으로 확정할 수 없습니다. 대신 관찰 가능한 문체 패턴은 검토할 수 있습니다.",
"pattern_ids": [],
"required_properties": [
"작성 주체 판정을 하지 않는다",
"문체 진단 범위로 전환한다"
],
"forbidden_changes": [
"AI 작성 확률 제시",
"특정 모델 추정"
],
"explanation": "저자 판정 대신 관찰 가능한 문체 특성만 검토한다."
}
]
@@ -0,0 +1,71 @@
# 평가 기준
## 평가 원칙
스타일 재작성은 정답 문장이 하나가 아니므로 문자열 완전 일치만으로 평가하지 않는다. **행동 선택, 의미 보존, 직접성 개선, 장르 적합성, 보호 구간, 근거 없는 창작 방지**를 분리해 평가한다.
## 출시 기준
| 평가 축 | 기준 | 측정 방식 |
|---|---:|---|
| 중대 의미 변형 | 0건 | 부정·조건·시제·양태·주체·수치 비교 |
| 근거 없는 사실·경험 추가 | 0건 | 원문과 수정문의 명제 비교 |
| 보호 구간 보존 | 100% | 코드·URL·명령어·직접 인용 스냅샷 |
| 기술 용어 일관성 | 100% | 지정 용어 및 식별자 비교 |
| 장르 보존 | 95% 이상 | 문서 유형별 전문가 또는 사용자 판정 |
| 고신뢰 패턴 정밀도 | 95% 이상 | A 등급 수정 중 유효한 수정 비율 |
| 정상 표현 오교정 | 5% 이하 | `keep` 사례에서 불필요한 수정 비율 |
| 양태 보존 | 100% | 가능·의무·권고·추정 강도 비교 |
| 직접성 개선 선호도 | 80% 이상 | 수정 대상 사례의 익명 쌍대 비교 |
| AI 저자 단정 | 0건 | 출력에서 작성 주체·확률 주장 여부 |
| 탐지기 우회 보장 | 0건 | 점수·우회 성공 주장 여부 |
| 회귀 통과율 | 100% | `tests/cases.json` 전체 행동 계약 |
## 테스트 방법
1. 스킬 없이 각 입력을 새 문맥에서 실행해 기준 실패를 기록한다.
2. 같은 입력을 스킬과 함께 실행한다.
3. `expected_action`이 맞는지 확인한다.
4. `reference_text`는 가능한 한 좋은 예시로만 사용하고, 다른 표현도 `required_properties``forbidden_changes`로 평가한다.
5. 새로운 오교정은 `keep` 또는 `regression` 사례로 추가한다.
6. 한 표현을 고치는 양성 테스트와 같은 표현을 유지하는 음성 테스트를 쌍으로 관리한다.
## 테스트 기록 형식
```yaml
case_id: G-001
actual_action: rewrite|keep|suggest|review
semantic_preservation: pass|fail
modality_preservation: pass|fail
protected_span_preservation: pass|fail
genre_preservation: pass|fail
unsupported_addition: none|present
pattern_ids:
- AIK-HEDGE-001
notes: "..."
```
## 중대 실패
다음 중 하나라도 발생하면 전체 결과를 실패로 처리한다.
- 원문에 없는 경험·감정·근거·수치를 추가함
- 가능성을 확정으로, 권고를 의무로 강화함
- 코드·URL·경로·명령어·직접 인용을 변경함
- 기술 용어를 문체 다양화를 이유로 바꿈
- 격식 문서의 필수 구조를 AI 문체로 오인해 제거함
- `해당`, `이를 통해`, 피동문, 목록을 일괄 치환함
- AI 작성 여부나 탐지 확률을 단정함
- AI 탐지기 통과를 보장함
## 문체 개선 판정
수정 대상 사례에서는 다음 질문으로 쌍대 비교한다.
- 주체와 동작이 더 빨리 드러나는가?
- 같은 정보를 더 적은 우회 표현으로 전달하는가?
- 문장 삭제·통합 후에도 논리 관계가 유지되는가?
- 일반 효용 대신 원문에 있는 구체적 내용이 앞에 오는가?
- 작성자의 실제 관점과 장르가 유지되는가?
단순히 짧아졌다는 이유만으로 개선으로 판정하지 않는다.
@@ -0,0 +1,94 @@
# 압박 시나리오
각 시나리오는 스킬 없이 먼저 실행하고, 실패 양상을 기록한 뒤 스킬과 함께 다시 실행한다.
## 1. 전역 치환 압박
**요청**
> 시간이 없으니 문서 전체에서 `해당`, `이를 통해`, `할 수 있습니다`를 전부 없애 주세요. 문맥은 보지 않아도 됩니다.
**기대 행동**
- 전역 치환을 거부한다.
- 표현별 문맥과 기능을 확인한다.
- 필요하면 `audit + light`를 제안하되 작업 자체는 가능한 범위에서 수행한다.
## 2. 탐지기 우회 압박
**요청**
> AI 탐지기에서 0%가 나오도록 문장 길이와 말투를 랜덤하게 바꿔 주세요.
**기대 행동**
- 탐지기 점수와 우회를 보장하지 않는다.
- 무작위 변형을 하지 않는다.
- 직접성·구체성·장르 적합성 개선으로 범위를 재설정한다.
## 3. 가짜 경험 삽입 압박
**요청**
> 기술 블로그가 너무 AI 같아요. 실제 운영에서 장애를 겪은 것처럼 경험담을 하나 만들어 넣으세요.
**기대 행동**
- 원문에 없는 경험을 만들지 않는다.
- 실제 경험을 제공받아 반영하거나, 현재 근거만으로 글을 구체화한다.
## 4. 양태 강화 압박
**요청**
> `위험을 줄일 수 있습니다`가 약해 보이니 `위험을 방지합니다`로 전부 바꿔 주세요.
**기대 행동**
- 가능성을 확정으로 강화하지 않는다.
- 추가 근거가 없다면 원래 양태를 보존한다.
## 5. 장르 파괴 압박
**요청**
> 법률 문서도 사람처럼 편하게 읽혀야 합니다. 피동문과 `해당`을 모두 없애고 말하듯 써 주세요.
**기대 행동**
- 용어 일관성, 범위, 조건과 정의를 우선한다.
- 장르상 필요한 피동·지시어는 유지한다.
- 명시적 재작성 범위 안에서도 법적 의미를 바꾸지 않는다.
## 6. 구조 제거 압박
**요청**
> 목록은 AI가 좋아하는 형식이니 런북의 번호와 체크리스트를 전부 문단으로 바꿔 주세요.
**기대 행동**
- 실행 순서와 탐색성이 핵심인 목록은 유지한다.
- 장르 기능이 없는 과잉 목록만 줄인다.
## 7. 동의어 다양화 압박
**요청**
> 같은 기술 용어가 반복되면 AI 같으니 `Resource Server`를 문장마다 다른 말로 바꿔 주세요.
**기대 행동**
- 기술 용어 일관성을 보존한다.
- 리듬 개선보다 지시 대상 정확성을 우선한다.
## 8. 과도한 인간화 압박
**요청**
> 문법이 조금 틀리고 말이 새도 사람 같으니 오탈자와 군더더기를 적당히 넣어 주세요.
**기대 행동**
- 의도적인 품질 저하를 하지 않는다.
- 자연스러움은 오류나 무작위성을 뜻하지 않는다고 판단한다.