schedules/anchoring — backend 를 import 하지 않는 독립 컨테이너 배치 서비스.
회사 × 협력사유형(1유통/2제조/3총판) × 가격구간(3,000원, 33,334칸)별 앵커링
값(정수 천분율)을 격주 토 00:00 KST 에 협상 성공률로 자동 조정한다.
- 판정 = "가격 흔적" 기준: last_offered_price 가 있는 종료 재협상만 표본,
DONE & bid ≤ 박제 앵커만 성공, 나머지(초과 합의·결렬·가격 쓰고 이탈) 실패.
앵커는 비노출(엔진 내부 체결 임계) — agent 무변경
- 저장 = anchoring.rate_adjustments 1개(append-only, consumed_session_ids 박제),
소비 경계 = sessions.anchoring_adjustment_id 마킹(멱등·이월). DDL 은 모듈
소유(schema.sql, sessions 3컬럼 ALTER 포함)
- 안정성: 조정 INSERT+마킹 한 트랜잭션 + rowcount 불일치 전체 롤백,
Redis TTL 7일 + 매주 조정 칸 re-SET, socket timeout 0.3s, DB 폴백,
가격 제시율 0% WARN, --once 수동 캐치업
- 정적 기본 테이블(전 구간 10‰, 상한 정확히 1억·초과분 마지막 인덱스 클램프)
기동 검증 실패 시 기동 중단
- 전체 async(SQLAlchemy+asyncpg, redis.asyncio) — negodata 가 reader 를 그대로
이식 가능(docs/인수인계.md). 최종 문서 docs/{개발용,기획용,워크플로우}.md
- 테스트 15종: 골든 벡터(§11) + DB 통합(멱등·이월·격리·rowcount 롤백)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
8.0 KiB
앵커링 시스템 워크플로우 설명 (비개발자용)
문서 성격:
개발용.md의 워크플로우를 비개발자도 이해할 수 있게 풀어 쓴 안내서. 버전: v1.2 기준 (2026-07-02) — 정책 배경은기획용.md, 기술 상세는개발용.md참조.
한 줄 요약
협상마다 "이 가격 이하면 합의한다"는 기준선을 장부에서 찾아 정하고, 협상이 끝날 때마다 결과가 쌓이고, 2주에 한 번 시스템이 그 결과를 채점해서 장부의 숫자를 한 칸씩 조정한다 — 이 순환 구조입니다.
등장하는 것 4가지
| 이름 | 비유 | 역할 |
|---|---|---|
| 기준표 (정적 기본 테이블) | 공장 출하 시 기본 설정값 | 모든 칸의 출발점(전부 1%). 절대 안 바뀌는 내장 표 |
협상 기록 (negotiation.sessions) |
협상 한 건 한 건의 계약서 철 | "그때 기준가가 얼마였고, 상대가 얼마를 써냈고, 얼마에 끝났는지"가 적힘 |
조정 장부 (anchoring.rate_adjustments) |
가격 정책 변경 대장 | "언제, 어떤 근거로, 몇 %에서 몇 %로 바꿨다"가 한 줄씩만 추가됨 |
| 빠른 조회판 (Redis) | 벽에 붙여둔 최신 가격표 | 협상 시작할 때 즉시 참조하는 사본. 원본은 항상 조정 장부 |
여기서 칸(cell) 이란 값을 관리하는 최소 단위로, 어느 회사 × 어떤 협력사 유형(유통/제조/총판) × 어떤 가격대(3천 원 단위, 0원~1억, 총 33,334개) 조합입니다. 1억을 넘는 금액은 전부 마지막 가격대 칸으로 들어갑니다.
워크플로우 — 시간 순서대로
① 서버가 켜질 때
기준표(33,334개 가격구간 × 시작값 1%)를 메모리에 올리고, 표가 손상됐으면 아예 서버를 켜지 않습니다. 잘못된 가격으로 협상하는 것보다 안 켜지는 게 낫다는 안전장치입니다.
② 견적(협상 건)이 만들어질 때 — "기준선을 정한다"
재협상 견적이 생성되는 시점에 견적 시스템(negodata)이 이 협상의 칸을 찾습니다. 그 칸의 현재 앵커링 값(깎는 비율)을 빠른 조회판에서 읽고 — 없으면 조정 장부, 그것도 없으면 기준표 순서로 —
기준가(앵커링가) = 목표가 × (1 − 앵커링 값), 1원 단위 내림
예) 목표가 30,000원, 앵커링 값 3% → 기준가 29,100원 — 협력사가 이 이하를 써내면 그 가격으로 합의
이 기준가는 협력사 화면에 표시되지 않고, 챗봇이 합의 가능 여부를 판단하는 내부 기준선으로만 동작합니다(정보 비대칭 유지 전략).
을 계산합니다. 그리고 이 협상에 쓴 비율과 기준가를 협상 기록에 도장 찍듯 고정(박제) 합니다. 이후 2주 정산이 지나가서 칸의 값이 바뀌어도, 이미 만들어진 협상의 기준가는 절대 흔들리지 않습니다. 협상이 다음 라운드로 재생성될 때도 옛 값을 물려받지 않고 그 시점의 칸 값으로 새로 계산합니다.
③ 협력사가 가격을 써낼 때 — "가격 흔적"
협력사가 협상 채팅에서 가격을 입력할 때마다, 그 마지막 제시가가 협상 기록에 남습니다(last_offered_price).
이게 중요한 이유: 가격을 써낸 협상과 한 번도 안 써낸 협상은 정책적으로 완전히 다르게 취급하기 때문입니다.
- 가격을 써냈는데 기준가 아래로 합의가 안 됨(결렬·중간 이탈 포함) = "기준이 시장보다 세다"는 신호 = 실패로 카운트
- 가격을 한 번도 안 써내고 끝남(미참여·무응답, 담당자 부재 등) = 기준가는 화면에 안 보이므로 우리 기준과 무관 = 판단 재료에서 제외
④ 협상이 끝나면
따로 하는 일이 없습니다. 계약서 철(협상 기록)에 결과가 이미 다 남아 있으니까요.
이게 이번 설계(v1.2)의 특징입니다 — 별도 표본 장부를 만들지 않고, 협상 기록 자체를 나중에 채점 근거로 씁니다. 기준가·마지막 제시가·투찰가·종료 상태가 전부 확정된 값이라, 언제 채점해도 같은 결과가 나옵니다.
⑤ 격주 토요일 자정 — "정산"
2주에 한 번 시스템이 깨어나 아직 채점 안 된 종료 협상들을 전부 꺼내 채점합니다:
| 상황 | 채점 |
|---|---|
| 기준가 이하로 합의 성사 | 성공 |
| 기준가보다 높게 합의(예외적) | 실패 |
| 가격을 써냈지만 합의 못 함 — 결렬·중간 이탈 포함 | 실패 |
| 가격을 한 번도 안 써내고 끝남 | 제외 (셈에서 뺌) |
칸별로 모아서 유효 결과가 10건 이상인 칸만 성공률을 내고, 3단계 규칙으로 딱 한 계단만 조정합니다:
| 성공률 | 판단 | 조치 |
|---|---|---|
| 60% 이상 | 잘 통하고 있다 | 올림 (유통 ±2%p / 총판 ±1.5%p / 제조 ±1%p) |
| 30% ~ 60% | 적당하다 | 유지 |
| 30% 미만 | 너무 셌다 | 내림 (같은 폭) |
값은 어떤 경우에도 1% 아래로 내려가지 않고 20% 위로 올라가지 않습니다.
정산이 끝나면:
- 조정 장부에 한 줄 추가 — "몇 건 중 몇 건 성공, 1% → 3%, 어떤 협상들을 근거로"
- 채점에 쓴 협상들에 "이 조정에 사용됨" 스탬프를 찍음 (같은 협상이 두 번 채점되는 일 방지)
- 벽의 가격표(빠른 조회판)를 새 값으로 갱신
10건이 안 되는 칸은 스탬프를 안 찍고 그대로 둡니다 — 그게 이월입니다. 다음 정산 때 4주치가 함께 채점되고, 그래도 부족하면 6주, 8주… 로 자연스럽게 기간이 늘어납니다.
⑥ 그리고 다시 ②로
다음 재협상은 조정된 값으로 시작합니다. 이 순환이 반복되면서 각 칸의 값은 "시장이 받아주는 한계선" 근처에서 자연스럽게 안정됩니다.
이 구조가 주는 안전장치
- 같은 협상이 두 번 채점될 수 없음 — 스탬프 찍힌 협상은 다음 정산에서 자동으로 빠집니다. 정산이 실수로 두 번 돌아도 결과가 같습니다.
- 정산이 한 번 빠져도 문제 없음 — 다음 정산이 4주치를 한 번에 채점하고, 그래도 조정은 한 계단만 하므로 값이 튀지 않습니다.
- 진행 중 협상은 절대 안 흔들림 — 기준가는 협상 생성 시점에 고정되므로, 정산이 값을 바꿔도 이미 시작한 협상에는 영향이 없습니다.
- "왜 이 칸이 7%야?"에 항상 답할 수 있음 — 조정 장부에 모든 변경이 근거(어떤 협상들, 성공률)와 함께 영구 보존됩니다. 장부는 수정·삭제가 금지돼 있습니다.
- 빠른 조회판이 날아가도 무사 — 어차피 사본이라 조정 장부에서 언제든 다시 만들 수 있습니다. 조회판(Redis)이 아예 꺼져 있어도 협상은 원본 장부를 직접 읽어 계속 동작하고, 조회판에 옛 값이 남아 있더라도 매주 정산 시각에 최신 값으로 전부 다시 붙입니다.
- 회사 간 칸막이 — A사의 협상 결과는 A사의 칸에만 반영됩니다. 다른 회사의 값과 기록은 완전히 분리됩니다.
자주 나올 질문
Q. 값이 조정되면 기준표가 바뀌는 건가요? 아닙니다. 기준표는 출발선이고 절대 바뀌지 않습니다. 조정 장부에 이력이 한 줄 쌓여서 "현재 위치"가 바뀌는 것입니다.
Q. 결과가 많이 쌓이면 값이 크게 움직이나요? 아닙니다. 13건이 쌓였든 30건이 쌓였든 성공률만 계산하고, 조정은 정산일당 딱 한 계단입니다.
Q. 거래가 거의 없는 칸은요? 10건이 찰 때까지 정산일마다 기다립니다(2주 → 4주 → 6주…). 그동안은 시작값(1%) 근처에 머무는데, 거래가 없는 칸이니 사업 영향도 작습니다.
Q. 사람이 수동으로 값을 바꿀 수 있나요? 현재 정책에서는 없습니다. 값은 오직 협상 결과 데이터로만 움직이고, 모든 변경은 이력으로 추적 가능합니다.