
[1] ChatInput (사용자 질문)
↓
[2] MultiQuerySearch (확장된 쿼리 + Qdrant 벡터 검색)
↓ (DataFrame: 다수 문서 결과)
[3] ReRanker (HTTP 기반 OpenAI ReRank API) — 중요도 순 재정렬
↓ (DataFrame: 재배열된 문서 리스트)
[4] Parser (DataFrame → 문자열 context)
↓ (String / 텍스트)
[5] Prompt Template (context + user question → 최종 프롬프트)
↓
[6] OpenAI LLM (gpt-5) → 답변 생성
↓
[7] ChatOutput (최종 사용자 응답)
사용자 질문을 여러 의미 방향으로 확장 (Multi-Query), 각 쿼리 별로 벡터화 → Qdrant에서 검색 → 모든 쿼리 결과를 하나의 DataFrame으로 병합
MultiQuery Search 만으로는 단순 벡터 유사도 기반 정렬 → 관련성은 보장되지만 실제 “질문 의도에 맞는 핵심 문서”가 상위에 오르지 않을 수 있음
MultiQuery로 얻은 후보 문서들을 가져와, HTTP 기반 OpenAI ReRank API 로 재정렬 → 실제 질문에 더 밀접한 문서를 상위에 배치
semantic similarity + cross-document ranking → 더 의미 있고 “질문 의도에 맞는” 문서 우선
노이즈 감소, prompt에 포함할 문서의 질과 밀도 향상
왜 ReRanker가 중요한가?
일반 벡터 검색은 “의미적으로 유사한 모든 문장”을 가져오기 때문에 질문에 가장 적절한 것은 뒤에 밀릴 수 있음
ReRanker를 통하면 단순 유사도뿐 아니라 “문서 전체 문맥과 질문 간 관계성”을 기반으로 재정렬 가능
즉, RAG 품질 향상
from langflow.custom import Component
from langflow.io import DataFrameInput, Output, MessageTextInput, StrInput, SecretStrInput
from langflow.schema.dataframe import DataFrame
import pandas as pd
import requests, json
class ReRanker(Component):
display_name = "ReRanker"
description = "Re-rank documents using OpenAI ReRank API (with debug logging)"
icon = "sort"
name = "ReRanker"
inputs = [DataFrameInput(name="docs", display_name="Documents (DataFrame)", required=True),
MessageTextInput(name="query", display_name="User Question", required=True),
SecretStrInput(name="openai_api_key", display_name="OpenAI API Key", required=True),
StrInput(name="model", display_name="ReRank Model", value="text-rerank-latest", required=True),]
outputs = [Output(name="reranked_docs",display_name="ReRanked Documents",method="run_rerank",output_type=DataFrame,)]
async def run_rerank(self) -> DataFrame:
df = self.docs
# ---- DataFrame → dict list ----
if isinstance(df, pd.DataFrame):
rows = df.to_dict(orient="records")
elif isinstance(df, dict):
rows = df.get("data", [])
else:
rows = df
if rows:
first_row = rows[0]
self.log(f"[DEBUG] FIRST ROW KEYS: {list(first_row.keys())}")
self.log(f"[DEBUG] FIRST ROW RAW: {first_row}")
else:
self.status = "rows empty"
return DataFrame([])
# ---- query ----
query_input = self.query
query = getattr(query_input, "text", "") if query_input else ""
# ---- documents ----
documents = []
for row in rows:
content = (row.get("page_content") or row.get("content") or row.get("text") or "")
documents.append(content)
# ---- API call ----
API_URL = "https://api.openai.com/v1/rerank"
headers = {"Authorization": f"Bearer {self.openai_api_key}","Content-Type": "application/json"}
payload = {"model": self.model,"query": query,"documents": documents,"top_n": len(documents)}
try:
response = requests.post(API_URL, headers=headers, data=json.dumps(payload))
response.raise_for_status()
api_data = response.json().get("data", [])
self.log(f"[DEBUG] RERANK API RESPONSE: {api_data}")
except Exception as e:
self.status = f"API Error: {e}"
return DataFrame(rows)
# ---- ranking ----
ranked_rows = sorted(zip(rows, api_data), key=lambda x: x[1].get("relevance_score", 0), reverse=True,)
reranked_rows = [row for row, score in ranked_rows]
self.status = f"ReRanking 완료: {len(reranked_rows)}개 문서 재정렬"
return DataFrame(reranked_rows)
ReRanker가 반환한 DataFrame의 각 row를 사람이 읽기 좋고 LLM이 digest하기 좋은 텍스트 블록으로 변환
Parser로 생성된 문맥(context) + 사용자 질문을 기반으로 회계/감사 전문가 역할 최종 프롬프트를 생성
당신은 회계·감사 분야에 전문성을 갖춘 상급 감사 전문가입니다.
아래에는 Multi-Query 검색 및 ReRanker를 통해 선별된 실제 감사·회계 문서들이 제공됩니다.
이 문서들은 감사보고서, 지적사항, 판례, 감사지침 등을 기반으로 한 “사실 기반 근거 자료”입니다.
당신의 역할은 다음 문맥(retrieved_docs)에 기반하여
사용자의 질문에 대해 **정확하고 사실 기반이며, 규칙을 준수한 감사 전문가식 답변**을 생성하는 것입니다.
────────────────────
**사용자 질문**
{question}
**검색된 문맥(필수 근거 자료)**
{retrieved_docs}
────────────────────
# 답변 작성 규칙 (Strict Mode)
### 1) **문맥 기반 사실 설명 (Hallucination 금지)**
- 모든 설명·근거·사례는 반드시 {retrieved_docs} 내 실제 내용에서만 가져온다.
- 문맥에 존재하지 않는 사실, 규정, 수치, 사례, 용어는 절대 생성하지 않는다.
- 문맥에 없는 정보는 “문맥에 해당 정보가 존재하지 않습니다.”라고 명시한다.
### 2) **결론 우선 (Top-Down 방식)**
- 첫 문단에 질문에 대한 결론을 명확하고 간결하게 제시한다.
- 결론 다음 줄부터 근거를 정리한다.
### 3) **근거 제시 방식**
- 근거는 문맥 속 텍스트를 **직접 인용**하거나 **요약**하여 제시한다.
- 인용 시 아래 형식을 사용한다:
- “문맥 인용: …(본문 일부)…”
- 또는 “문맥 요약: …”
### 4) **유사사례 제시**
- 문맥에서 사용자 질문과 유사한 사례가 있다면 1~2개만 선택하여 요약한다.
- 유사사례는 반드시 실제 문맥 속 문서에서만 발췌해야 한다.
### 5) **규정/기준 인용 규칙**
- 문맥에 K-IFRS, 감사지침, 법령, 규정, 회계기준 등이 명시된 경우에만 정확히 인용한다.
- 문맥에 언급되지 않은 규정명·법령·판례는 새로 만들어내지 않는다.
### 6) **정보 부족 시 처리**
- 문맥 내 근거가 부족하면 아래와 같이 명확히 언급한다:
- “제공된 문맥만으로는 해당 질문에 대한 확정적인 판단이 어렵습니다.”
### 7) **작성 방식**
- 마크다운 형식으로 작성.
- 구조는 반드시 다음 순서를 따른다:
---
## 1. 결론
(핵심 답변)
## 2. 근거 (문맥 기반)
- 문맥 인용 또는 요약
- 이유 설명
## 3. 유사사례 (문맥 기반)
- 실제 문맥 내 사례 요약
## 4. 추가 설명 또는 한계
- 규정/기준 인용 (문맥에 있을 경우)
- 정보 부족 시 처리 문장 포함
---
반드시 위 규칙을 모두 준수하여 답변하라.
Prompt Template이 만든 최종 프롬프트를 입력 → 사용자 질문 + 선택된 문맥에 기반한 답변 생성
최종 GPT 응답을 사용자에게 전달