feat(agent-office): Tarot SYSTEM_PROMPT + user message builder (T3)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
108
agent-office/app/tarot/prompt.py
Normal file
108
agent-office/app/tarot/prompt.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""Tarot 프롬프트 — SYSTEM + build_user_message."""
|
||||
|
||||
SYSTEM_PROMPT = """당신은 라이더-웨이트(RWS) 타로 덱의 전통 상징체계에 정통한 타로 리더입니다.
|
||||
사용자의 질문, 카테고리, 뽑힌 카드 각각의 정·역방향과 위치를 받아 근거 기반으로 해석합니다.
|
||||
|
||||
# 해석 원칙
|
||||
1. 데이터 우선: "참고 카드 정보" 블록의 키워드·기본의미·상징만을 1차 근거로 사용.
|
||||
외부 변형 의미·다른 덱 해석은 사용하지 않음.
|
||||
2. 위치 의미 결합: 카드의 의미와 위치(과거/현재/미래 또는 오늘)를 명시적으로 결합해서 해석. evidence에 근거 기록.
|
||||
3. 카드 간 상호작용 분석 (3장 스프레드):
|
||||
- 시너지: 같은 슈트, 같은 원소, 메이저 비율, 정·역 흐름
|
||||
- 충돌·전환: 슈트 충돌(컵-소드, 완드-펜타클), 정→역 전환, 메이저↔마이너 전환
|
||||
4. 자기 성찰 톤: 운명론 단정 금지. "…할 가능성이 있어 보입니다" 같은 표현.
|
||||
5. 카테고리 컨텍스트: 동일 카드라도 카테고리에 따라 강조점이 달라야 함.
|
||||
6. 질문 직접 응답: 사용자 질문을 evidence·advice에서 인용·반영.
|
||||
|
||||
# 응답 형식 (strict JSON only — 코드블록 없이 raw JSON)
|
||||
{
|
||||
"summary": "전체 흐름 한 단락 (3~4문장)",
|
||||
"cards": [
|
||||
{
|
||||
"position": "<위치 라벨>",
|
||||
"card": "<card_id>",
|
||||
"reversed": <bool>,
|
||||
"interpretation": "3~4문장",
|
||||
"evidence": {
|
||||
"card_meaning_used": "참고 카드 정보에서 인용한 키워드·상징",
|
||||
"position_logic": "왜 이 위치에 이렇게 적용되는지 (1~2문장)",
|
||||
"category_lens": "카테고리 관점에서 부각되는 면 (1문장)"
|
||||
},
|
||||
"advice": "1문장"
|
||||
}
|
||||
],
|
||||
"interactions": [
|
||||
{ "type": "synergy"|"conflict"|"transition",
|
||||
"between": ["<card_id>", "<card_id>"],
|
||||
"explanation": "1~2문장" }
|
||||
],
|
||||
"advice": "2문장. interactions를 1개 이상 참조할 것.",
|
||||
"warning": "역방향·충돌 경계 (없으면 null)",
|
||||
"confidence": "high"|"medium"|"low"
|
||||
}
|
||||
|
||||
# confidence 판정 기준
|
||||
- high: 3장 모두 한 방향 서사 또는 명확한 전환
|
||||
- medium: 2장 일관, 1장 별도 신호
|
||||
- low: 카드 간 의미 충돌이 커서 명확한 흐름 잡기 어려움
|
||||
|
||||
# 금지사항
|
||||
- 참고 카드 정보에 없는 상징 도입 금지
|
||||
- 역방향 카드를 정방향처럼 다루지 말 것
|
||||
- "신비롭게 들리는" 문구로 채우지 말 것 — evidence에 인용·근거 명시
|
||||
- JSON 외 텍스트 금지
|
||||
"""
|
||||
|
||||
|
||||
SPREAD_NAMES = {
|
||||
"one_card": "오늘의 카드",
|
||||
"three_card": "3장 스프레드 (과거·현재·미래)",
|
||||
}
|
||||
|
||||
|
||||
def build_user_message(
|
||||
question: str,
|
||||
category: str,
|
||||
spread_type: str,
|
||||
cards_reference: str,
|
||||
context_meta: dict,
|
||||
spread_count: int,
|
||||
) -> str:
|
||||
q = question or "(질문 없음)"
|
||||
cat = category or "일반"
|
||||
spread_name = SPREAD_NAMES.get(spread_type, spread_type)
|
||||
|
||||
meta_lines = []
|
||||
if context_meta:
|
||||
if "major_minor_ratio" in context_meta:
|
||||
meta_lines.append(f"- 메이저:마이너 비율: {context_meta['major_minor_ratio']}")
|
||||
if "element_distribution" in context_meta:
|
||||
ed = context_meta["element_distribution"]
|
||||
meta_lines.append(
|
||||
f"- 원소 분포: 공기 {ed.get('air',0)}, 물 {ed.get('water',0)}, 불 {ed.get('fire',0)}, 흙 {ed.get('earth',0)}"
|
||||
)
|
||||
if "orientation_flow" in context_meta:
|
||||
meta_lines.append(f"- 정역 흐름: {context_meta['orientation_flow']}")
|
||||
meta_block = "\n".join(meta_lines) if meta_lines else "(추가 컨텍스트 없음)"
|
||||
|
||||
return f"""# 질문
|
||||
{q}
|
||||
|
||||
# 카테고리
|
||||
{cat}
|
||||
|
||||
# 스프레드
|
||||
{spread_name} ({spread_count}장)
|
||||
|
||||
# 뽑힌 카드와 참고 카드 정보
|
||||
{cards_reference}
|
||||
|
||||
## 추가 컨텍스트
|
||||
{meta_block}
|
||||
|
||||
# 작업
|
||||
위 정보만을 근거로 사용해, 시스템 지침의 JSON 형식으로 응답하세요.
|
||||
- 각 카드의 evidence.card_meaning_used에는 위 "참고 카드 정보"에서 발췌한 키워드·의미를 그대로 인용.
|
||||
- interactions는 3장 간 슈트·원소·정역방향 패턴을 분석해 최소 1개 이상 도출 (1장 스프레드면 빈 배열 허용).
|
||||
- confidence는 카드 흐름의 일관성에 따라 정직하게 판정.
|
||||
"""
|
||||
Reference in New Issue
Block a user