더더더, 자동화에 도전

재정지원 사업 제안서 작성 AI 파이프라인 구축기

---

소개

정부 재정지원 사업 제안서를 써본 분이라면 아실 겁니다. 공고문 분석, 타기관 사례 조사, 우리 기관 역량 정리, 전략 수립, 섹션별 집필, 검토… 한 사이클에 보통 2~3주가 걸리고, 그 과정에서 담당자는 수십 개의 문서를 열었다 닫았다 반복합니다.

처음엔 단순한 목표였습니다.

▎ "타기관 선정보고서를 AI가 읽고 패턴을 찾아줬으면 좋겠다."

그런데 하나를 자동화하다 보니 욕심이 생겼습니다. RFP 분석도, 역량 매핑도, 갭 분석도, 집필도, 검토도… 결국 "담당자가 파일만 올리면 초안까지 나오는 시스템" 을 목표로 잡게 됐습니다.

이 글은 그 과정에서 시도한 것들, 막힌 것들, 그리고 실제로 돌아가게 된 것들의 기록입니다.

---

진행 방법

사용 도구

- Claude Code (CLI) — 파이프라인 오케스트레이터 + 집필 AI

- Python (pdfplumber, python-docx, lxml) — 파일 파싱 및 출력 생성

- Google Drive + MCP Filesystem — 파일 입출력 연동

- HWPX (한글 파일 포맷) — 한국 공공기관 문서 표준

---

전체 구조 설계

처음에는 단계별 프롬프트 파일(P01~P10)을 만들어놓고 담당자가 순서대로 실행하는 방식이었습니다. 근데 그게 또 일이더라고요. 프롬프트 파일 열고, 내용 복사하고, AI에 붙여넣고, 결과 저장하고…

그래서 "파이프라인을 파이프라인답게" 다시 설계했습니다.

파일 업로드 (담당자 1회)

↓ 자동

HWPX 파싱 → RFP 분석 → 역량 매핑 → 갭 분석

↓ 자동

전략 후보 제시 → 담당자 확인 (★ 유일한 의사결정)

↓ 자동

사업 설계 → 섹션별 집필 → 3단계 검토 → HWPX 출력

담당자가 실제로 판단해야 하는 순간은 딱 하나. "이 혁신 포인트들 중 어떤 걸 쓸 거야?" 그 질문에 "1, 3번. 제목은 B안." 이라고 대답하면 나머지는 AI가 이어갑니다.

---

핵심 과제 1: 한글 파일(HWPX) 읽기

한국 공공기관 문서는 대부분 한글(.hwp/.hwpx)로 작성됩니다. 문제는 Python 생태계에 신뢰할 수 있는 HWP 파서가 없다는 것.

HWPX가 사실 ZIP 구조라는 점을 활용해서 직접 파서를 만들었습니다.

def extract_hwpx(file_path: str) -> str:

"""HWPX 파일에서 텍스트 추출"""

paragraphs = []

with zipfile.ZipFile(file_path, 'r') as zf:

section_files = sorted([

n for n in zf.namelist()

if re.match(r'Contents/section\d+\.xml', n)

])

for sec in section_files:

with zf.open(sec) as f:

paras = parsehwpx_section(f.read())

paragraphs.extend(paras)

return '\n\n'.join(paragraphs)

HWPX XML의 텍스트 노드는 {http://www.hancom.co.kr/hwpml/2012/run}t 태그 안에 있습니다. 네임스페이스 처리가 핵심이었고, 실패 시 태그 제거 방식으로 fallback하는 구조로 만들었습니다.

구형 .hwp 바이너리는 파싱이 안 됩니다. → 한글에서 열어 HWPX로 재저장하면 해결.

---

핵심 과제 2: RFP에 배점표가 없을 때

공고마다 배점을 명시하는 곳도 있고, 그냥 "다음 항목을 작성하시오" 식으로만 나오는 곳도 있습니다. 후자의 경우 갭 분석 자체가 흔들립니다.

이 부분을 AI 추론으로 해결했습니다. P01 프롬프트에 2단계 로직을 넣었어요.

[1단계] 배점표 탐색

RFP 본문에서 배점표, 심사 기준표, 평가 기준이 명시되어 있는가?

- 있으면: 배점 항목을 그대로 추출하고 점수 높은 순으로 정렬

- 없으면: [2단계]로 이동

[2단계] 배점 AI 추론 (배점표가 없는 경우)

RFP 전체 맥락을 분석해서:

a) 사업의 핵심 가치와 우선순위 파악

b) 목차/항목별 서술 분량 비중 분석

c) "필수", "반드시", "중점" 등 강조 키워드 출현 빈도 분석

d) 유사 정부 사업의 일반적 배점 패턴 참조

이를 종합해서 추정 배점 테이블 작성 (총점 100점)

⚠ 표 상단에 "AI 추정 배점 — 실제 공고와 다를 수 있음" 표시

실제로 배점 없는 RFP에 돌려보니 생각보다 그럴듯한 배점이 나왔습니다. 물론 ±10점 정도의 오차는 감안해야 합니다.

---

핵심 과제 3: 갭 분석 프롬프트 — 3자료 동시 교차

이 파이프라인에서 가장 중요한 단계가 갭 분석입니다. "선정기관 수준을 어떻게 넘을 것인가"를 찾는 단계거든요.

핵심은 세 가지 파일을 동시에 넣는 것입니다.

아래 3가지 자료를 교차 분석해줘:

[자료 1] rfp_structure.md ← RFP 배점 항목

[자료 2] reference_patterns.md ← 선정기관 공통 전략

[자료 3] capacity_map.md ← 우리 기관 역량

RFP 고배점 항목에서:

1. 선정기관들의 평균 접근 수준

2. 우리 기관이 현재 낼 수 있는 수준

3. 우리 기관이 선정기관을 능가할 수 있는 근거

를 항목별로 비교 정리해줘.

v1에서는 이 세 파일을 담당자가 직접 복사해서 붙여넣어야 했습니다. v2에서는 Claude Code가 파일 경로를 직접 읽어서 자동으로 제공합니다. 작은 차이 같지만 실제로 엄청 귀찮은 작업이었거든요.

---

핵심 과제 4: HWPX 출력 생성

최종 산출물을 HWPX로 만드는 것이 가장 까다로웠습니다. Python에 HWP 쓰기 라이브러리가 없어서, HWPX가 ZIP 구조라는 점을 이용해 XML을 직접 조립했습니다.

HWPX_SECTION_HEADER = '''<?xml version="1.0" encoding="UTF-8"?>

<hsp:HWPMLTextBody

xmlns:hsp="http://www.hancom.co.kr/hwpml/2012/hsp"

xmlns:hp="http://www.hancom.co.kr/hwpml/2012/paragraph"

xmlns:hr="http://www.hancom.co.kr/hwpml/2012/run">

'''

def generate_hwpx(sections, output_path, doc_title=''):

xml_parts = [HWPX_SECTION_HEADER]

for sec in sections:

if sec.title:

style = {1: 'h1', 2: 'h2', 3: 'h3'}.get(sec.level, 'h3')

xml_parts.append(_make_paragraph(sec.title, style))

for para in sec.paragraphs:

xml_parts.append(_make_paragraph(para, 'body'))

xml_parts.append('</hsp:HWPMLTextBody>\n')

with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as zf:

zf.writestr('META-INF/container.xml', HWPX_CONTAINER)

zf.writestr('Contents/content.hpf', HWPX_CONTENT_HPF)

zf.writestr('Contents/section0.xml', ''.join(xml_parts))

서식이 완벽하진 않습니다. 글꼴 지정, 표 스타일 같은 세부 포맷은 한글에서 열어서 마지막에 다듬어야 합니다. 그래도 내용이 다 들어간 HWPX 파일이 자동으로 생성된다는 것 자체가 의미 있습니다.

---

Claude Code Skill 등록

이 모든 흐름을 /제안서파이프라인 한 줄로 시작하도록 Skill 파일을 만들었습니다.

.claude/commands/제안서파이프라인.md 에 Phase A~I를 정의하고, 각 Phase가 완료되면 다음 Phase를 자동으로 이어가도록 구성했습니다. 프로젝트 폴더에서 Claude Code를 열고 /제안서파이프라인을 치면:

1. 현재 어느 단계까지 됐는지 자동 진단

2. 빠진 단계부터 순차 실행

3. 전략 확정 단계에서만 멈춰서 확인 요청

4. 확인 받으면 집필 → 검토 → HWPX 출력까지 자동 완주

---

결과와 배운 점

결과

- 인간 개입 12단계 → 1~2단계 로 축소

- HWPX/DOCX/PDF 세 가지 형식 모두 입력 가능

- HWPX + DOCX 두 가지 형식으로 출력 생성

- 배점표 없는 RFP도 AI 추론 배점으로 처리 가능

- 새로운 사업에 같은 폴더 구조 그대로 재사용 가능

시행착오

① 구형 HWP 바이너리 문제

.hwp 파일은 ZIP이 아닌 OLE 바이너리 포맷이라 파싱이 안 됩니다. 처음엔 몰랐다가 파싱 결과가 계속 비어있어서 한참 헤맸습니다. 해결책은 한글에서 열어 HWPX로 다시 저장하는 것. 자동화 시스템의 전제 조건으로 명시해두었습니다.

② AI 추정 배점의 신뢰도

배점이 없는 RFP에 AI 추론을 쓰면 "그럴듯하지만 틀릴 수 있는" 배점이 나옵니다. 처음엔 이게 불안했는데, 생각해보면 배점이 없다는 건 심사위원도 재량껏 판단한다는 뜻이라 결국 방향성 자체는 비슷하더라고요. 대신 결과물에 "AI 추정" 표시를 반드시 붙여두고, 갭 분석에서 ±10점 유동성을 감안하도록 안내문을 넣었습니다.

③ 컨텍스트 초과

섹션이 많은 제안서를 한 번에 처리하면 중간에 컨텍스트가 넘칩니다. 섹션별로 나눠서 실행하고 나중에 병합하는 방식으로 우회했습니다. 트러블슈팅 항목으로 매뉴얼에 명시해뒀습니다.

④ "자동화"와 "품질" 사이의 긴장

자동화가 되면 편하지만, 결국 AI가 모르는 맥락이 있습니다. "우리 기관이 특별히 강한 이 부분"은 문서에 안 나와있을 수 있거든요. 그래서 역량 매핑 단계에서 "데이터 부족 — 어떤 자료를 추가하면 좋을지" 안내를 출력하도록 만들었습니다. 완전 자동화보다 "부족한 부분을 빠르게 알려주는 자동화" 가 더 현실적이라는 걸 배웠습니다.

배운 점

- 파이프라인은 설계부터 — 프롬프트 하나하나를 잘 만드는 것보다, 단계 간 연결과 산출물 규격을 먼저 설계하는 게 훨씬 중요합니다.

- 포맷 파악이 자동화의 첫 단추 — HWPX가 ZIP이라는 걸 알기 전까지는 아무것도 할 수 없었습니다. 다루려는 파일 포맷의 내부 구조를 먼저 파악하세요.

- Skill 파일은 레시피 — Claude Code의 .claude/commands/ 에 만드는 Skill 파일은 단순한 프롬프트가 아니라, "어떤 파일을 읽고, 어떤 순서로 처리하고, 어디에 저장하라"는 레시피입니다. 상세할수록 일관성이 높아집니다.

- 인간이 개입해야 하는 지점을 명확히 — "모든 걸 자동화한다"는 목표보다 "사람이 판단해야 하는 단계를 명확히 1개로 줄인다"는 목표가 훨씬 현실적이고 실용적입니다.

앞으로의 계획

- 타기관 보고서 파싱 품질 개선 (표·이미지 캡션 추출)

- 섹션 집필 시 수치 자동 삽입 (capacity_map의 실적 수치를 집필 중 자동 참조)

- 실제 사업 제안서 작성에 적용하고 결과 공유 예정

---

도움 받은 글

- HWPX 파일 포맷 공식 문서 (https://www.hancom.com/product/productExcelMain.do) — 한컴오피스 오픈 API 문서에서 XML 구조 파악

- Claude Code 공식 문서 — Skill(커스텀 슬래시 커맨드) 작성 방법

- pdfplumber GitHub — 한국어 PDF 파싱 이슈 스레드 참고

1
2개의 답글
밀어주고 끌어주는

온·오프라인 AI 스터디

AI로 어디까지 할 수 있는지
직접 확인하실 분만 신청하세요.