Skip to content

feat: 채널 기반 비즈니스 용어 사전 (Semantic Federation) 구현#235

Open
thrcle wants to merge 1 commit into
CausalInferenceLab:masterfrom
thrcle:feat/semantic-federation
Open

feat: 채널 기반 비즈니스 용어 사전 (Semantic Federation) 구현#235
thrcle wants to merge 1 commit into
CausalInferenceLab:masterfrom
thrcle:feat/semantic-federation

Conversation

@thrcle
Copy link
Copy Markdown
Contributor

@thrcle thrcle commented Jun 7, 2026

#️⃣ Issue Number

  • 235

📝 요약(Summary)

  • 팀별로 비즈니스 용어 정의가 달라 LLM이 잘못된 SQL을 생성하는 문제를 해결하기 위해 Semantic Federation 기능을 구현했습니다.
  • 채널을 팀 경계로 활용해 전사(guild) / 채널(팀) / 개인(member) 3계층 용어 사전을 구성하며, lookup은 개인 > 채널 > 전사 순으로 narrow→wide 상속합니다.
  • /org_setup으로 DB 스캔 + LLM 자동 추출, /term_custom으로 Discord modal 기반 수동 등록이 가능합니다.

[주요 커멘드 목록]
/setup : DB 연결 (guided form)
/org_setup : 테이블 스캔 + LLM 용어 자동 추출 및 저장
/term_custom : 비즈니스 용어 등록·조회·삭제
/semantic_show : 현재 채널에 적용 중인 정의 보기
/enrich : DB 컬럼 메타데이터 자동 보강

💬 To Reviewers (선택)

  • 채널을 팀 경계로 삼는 설계 방향이 적절한지 확인 부탁드립니다. (기존 설계안은 org/team/member + entity명 직접 입력 방식이었으나, 팀 멤버십 관리 문제를 피하기 위해 채널 기반으로 전환했습니다.)
  • kv_list_prefix의 LIKE 이스케이프 처리 방식(ESCAPE '!')이 SQLite에서 안전한지 검토 부탁드립니다.
  • org_setup clearinferred=True인 항목만 삭제하는 정책이 적절한지 의견 부탁드립니다.

PR Checklist

  • pytest -q 113개 전체 통과
  • SemanticFederationTool (/term_custom): 채널/전사/개인 계층 용어 CRUD
  • OrgSetupTool (/org_setup): DB 스캔 + LLM 용어 자동 추출
  • Discord 2단계 UX: selectbox(범위 선택) → modal(용어 입력)
  • kv_list_prefix() 추가 + LIKE 와일드카드 이스케이프 (ESCAPE '!')
  • channel_id fallback 불일치 수정 (DM에서 채널 용어 누락 방지)
  • org_setup clear 범위 제한 (수동 등록 용어 보존)
  • term_wizard.on_submit 예외 처리 (무한 로딩 방지)

- SemanticFederationTool(/term_custom): 채널(팀)/전사/개인 3계층 용어 등록·조회·삭제
- OrgSetupTool(/org_setup): DB 스캔 + LLM으로 팀별 용어 자동 추출 → 전사(guild) 레이어 저장
- Discord UI: /term_custom 호출 시 범위 selectbox → 용어 입력 modal (2단계 UX)
- 채널이 팀 경계 역할 → 팀 멤버십 관리 불필요, 충돌 설계상 없음
- lookup: 개인 > 채널(팀) > 전사(guild) (narrow→wide, git branch 방식)
- kv_list_prefix() 추가 + LIKE 와일드카드 이스케이프 보안 수정

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Collaborator

@seyoung4503 seyoung4503 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기능 방향성 좋습니다 👍 테스트 113개 통과, 충돌 없음 확인했고, Claude + Codex 두 관점으로 교차검토했어요. 머지 전에 하나만 짚고 가면 좋겠고, 하나는 결정 사항입니다. 나머지는 후속 가능한 제안이에요. 🙏

꼭 짚고 싶은 것 (blocking 🚨)

  • /org_setup 자동 추출 용어가 전사(guild) 레이어로 저장돼 팀별 격리가 안 됩니다 — PR의 핵심 목적과 충돌

결정 필요 (🟠)

  • 전사 용어 등록·/org_setup·clear에 권한 체크가 없어 누구나 전사 프롬프트를 바꿀 수 있음

논의했으면 (question/nit) — 인라인 코멘트 참고

)
ctx.store.kv_set(
scope,
f"{_SEMFED_PREFIX}:{term.lower()}:guild",
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 blocking/org_setup이 추출 용어를 전부 cterm:{term}:guild(전사 공통)로 저장하는데, 그러면 팀별 격리가 안 됩니다. 같은 guild에서 A팀·B팀이 각각 돌리면 동명 용어가 서로 덮어써요 (예: 재무팀 "활성고객"을 마케팅팀이 덮어씀). PR의 목적이 "채널=팀 경계"인데 자동 추출 경로만 이걸 우회합니다. docstring(:11)도 cterm:{term}:team:{org}라고 적혀 있어서, 채널/org 레이어로 저장하는 게 의도였던 것 같아요. 저장 키를 바꾸는 게 어떨까요? 🙏

},
)

async def run(self, args: dict[str, Any], ctx: "HarnessContext") -> ToolResult:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 결정 필요/org_setup·/org_setup clear와 전사 용어 등록에 is_admin 체크가 없어 보여요. Identity.is_admin은 이미 있는데 신규 툴에서 안 쓰는 것 같습니다. 전사 용어는 모든 멤버의 SQL 생성에 영향을 줘서, 아무나 등록/clear 가능하면 실수나 장난으로 전체가 영향받을 수 있어요. 위 scope 파라미터를 넣는다면 "전사 선택 시 관리자만" 가드를 같이 두면 좋겠습니다. (LLM이 term_custom(layer=guild)로도 부를 수 있어서 가드는 툴 run() 안에 둬야 실효가 있어요.)
이건 필요한 작업이라고 보는데, 이번 PR에서 같이 갈지 / 후속 PR로 뺄지 어떻게 생각하세요? 🔐


scope = ctx.identity.guild_id or f"dm:{ctx.identity.user_id}"
user_id = ctx.identity.user_id or "unknown"
channel_id = ctx.identity.thread_id or ctx.identity.channel_id or ""
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

questionchannel_id = thread_id or channel_id라 스레드 안에서는 채널이 아니라 스레드 ID로 조회되는데요. 부모 채널에서 등록한 channel 용어가 스레드 질문엔 안 잡히고, 반대도 마찬가지일 것 같아요. "채널=팀" 의도와 어긋날 수 있는데, 스레드를 부모 채널로 정규화하는 게 맞지 않을까요? 🤔

# cterm:{term}:guild 형식으로 저장 → 전사 공통 레이어 (narrow→wide 최하단)
saved_terms: list[str] = []
for t in terms:
term = str(t.get("term", "")).strip()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 nitterm_custom: 포함 term을 거부하는데(semantic_federation.py:146) org_setup은 검증이 없네요. LLM이 : 든 term을 뱉으면 cterm:{term}:guild 키가 깨져서 _load_allsplit(":",3)이 레이어를 오판 → 조회에서 조용히 누락될 수 있어요. 동일한 : 검증을 추가하면 좋겠습니다.

handlers.enrich(to_identity(_interaction_context(interaction)), table=table, clear=clear),
)

@tree.command(name="term_custom", description="비즈니스 용어 등록·조회·삭제 (조직/팀/개인 범위)")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 nit/term_custom remove에 layer 인자가 없어서 기본값 member만 삭제되는 것 같아요. wizard로 guild/channel 용어를 만들 수 있는데 슬래시로는 그 레이어를 못 지우는 비대칭이 있습니다.

self._ctx_factory = ctx_factory

async def on_submit(self, interaction: discord.Interaction) -> None:
await interaction.response.defer(ephemeral=True, thinking=True)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 nitdefer()가 try 밖에 있어서, defer 자체나 except 안의 followup이 실패하면(webhook 만료 등) 여전히 처리가 안 됩니다. 일반 케이스 무한로딩은 잘 막았어요 👍 — 엣지만 참고로요.

@thrcle
Copy link
Copy Markdown
Contributor Author

thrcle commented Jun 8, 2026

237에서 일부 해결된 이슈들이 있어 237 기준으로 일괄 작업 예정

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants