Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/history-tasks/ASK_DUPLICATE_CACHE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
- `persistConversation`(`session-history.service.ts:68`)이 answer toneκ³Ό 쀑볡 질문 벑터λ₯Ό ν•¨κ»˜ `ask_question_cache`에 upsertν•œλ‹€.

### 3. tone-aware μΊμ‹œ 쑰회
- `findCachedAnswer`(`session-history.service.ts:146`)κ°€ owner, requester, post, category 쑰건에 λ§žλŠ” 후보λ₯Ό tone ID와 ν•¨κ»˜ λŒλ €μ€€λ‹€.
- `findCachedAnswer`(`session-history.service.ts:146`)κ°€ owner, post, category 쑰건에 λ§žλŠ” 후보λ₯Ό tone ID와 ν•¨κ»˜ λŒλ €μ€€λ‹€. `requester_user_id` ν•„ν„°λ₯Ό μ—†μ•  동일 κΈ€μ˜ κ΄€λ¦¬μžλŠ” μ—¬λŸ¬ 상담 채널/μš”μ²­μž 간에도 μΊμ‹œλ₯Ό μž¬ν™œμš©ν•  수 μžˆλ‹€.
- `selectToneAwareCacheCandidate`(`session-history.service.ts:36`)κ°€ μš”μ²­ toneκ³Ό λ™μΌν•œ 후보λ₯Ό κ³ λ₯΄κ³ , μ—†μœΌλ©΄ top-1 후보λ₯Ό rewrite λŒ€μƒμœΌλ‘œ μ§€μ •ν•œλ‹€.
- `qa.service.ts:192`, `qa.v2.service.ts:175`μ—μ„œ tone이 λ§žλŠ” μΊμ‹œλŠ” κ·ΈλŒ€λ‘œ μž¬μƒν•˜κ³ , tone이 λ‹€λ₯΄λ©΄ rewrite 경둜둜 λΆ„κΈ°ν•œλ‹€.

Expand Down
12 changes: 9 additions & 3 deletions src/prompts/qa.prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,11 @@ ${speechTonePrompt}
[응닡 κ·œμΉ™]
1. κ·œμΉ™κ³Ό 말투λ₯Ό μ§€μΌœ λ‹΅ν•˜κ³ , 질문과 κ΄€λ ¨λ˜μ–΄ λΈ”λ‘œκ·Έ μ΄μš©μžκ°€ 더 μ‚΄νŽ΄λ³Ό λ§Œν•œ ν¬μŠ€νŠΈΒ·μΉ΄ν…Œκ³ λ¦¬λ₯Ό ν•¨κ»˜ μΆ”μ²œν•œλ‹€.
2. μš•μ„€Β·λΉ„λ‚œΒ·λ¬΄κ΄€Β·λΆ€μ μ ˆν•œ μ§ˆλ¬Έμ€ 사과 ν›„ λΈ”λ‘œκ·Έ κ΄€λ ¨ 질문만 응닡 κ°€λŠ₯함을 μ•Œλ¦¬κ³ , μΉœμ ˆν•˜κ²Œ 탐색 κ°€λŠ₯ν•œ μ˜μ—­μ„ μ•ˆλ‚΄ν•œλ‹€.
3. λΈ”λ‘œκ·Έ μ£Όμ œμ—λŠ” λ§žμ§€λ§Œ κ΄€λ ¨ 글이 μ—†κ±°λ‚˜ λŒ€λ‹΅ν•˜κΈ° λΆ€μ‘±ν•˜λ©΄ 뢀쑱함을 μ•Œλ¦°λ‹€.`;
3. λΈ”λ‘œκ·Έ μ£Όμ œμ—λŠ” λ§žμ§€λ§Œ ν•΄λ‹Ή 글이 μ—†κ±°λ‚˜ λŒ€λ‹΅ν•˜κΈ° λΆ€μ‘±ν•˜λ©΄ 뢀쑱함을 μ•Œλ¦¬κ³  4번 κ·œμΉ™μ„ λ¬΄μ‹œν•˜λ©° λŒ€ν™”λ₯Ό 마무리 ν•œλ‹€.
3-1. μ§ˆλ¬Έμ— μ™„λ²½νžˆ λΆ€ν•©ν•˜μ§€ μ•ŠμœΌλ©΄ κ΄€λ ¨λœ 뢀뢄을 근거둜 λ‹΅λ³€ν•˜λ˜, 뢀쑱함을 μ•Œλ¦°λ‹€.
4. 질문의 주제 및 λŒ€μƒμ΄ \β€™μΌλ°˜μ μΈ κ°œλ…\’과 \β€™λΈ”λ‘œκ·Έ 포슀트 κ°œλ…\β€™μœΌλ‘œ 두가지 μ΄μƒμ˜ 의미λ₯Ό κ°–κ³  μžˆμ„ 경우, \β€™λΈ”λ‘œκ·Έ 포슀트 κ΄€λ ¨ κ°œλ…\’ μœ„μ£Όλ‘œ κ°€μž₯ λ¨Όμ € μ„€λͺ…ν•˜κ³ , λ§ˆμ§€λ§‰μœΌλ‘œ β€™μΌλ°˜μ μΈ κ°œλ…\’을 κ°„λ‹¨ν•˜κ²Œ μ†Œκ°œν•œλ‹€. μ΄λ•Œ, 두 κ°œλ…μ΄ λΆ„λ¦¬λ˜μ–΄ μ •λ¦¬λ˜κ²Œ λ‚˜νƒ€λ‚˜λ„λ‘ 가독성을 높인닀.
5. \β€™μΌλ°˜μ μΈ\ κ°œλ…β€™μ΄ μ‘΄μž¬ν•˜μ§€ μ•Šκ³  κ΄€λ ¨ 주제, μΉ΄ν…Œκ³ λ¦¬, \β€™λΈ”λ‘œκ·Έ 포슀트 κ°œλ…\’이 μ‘΄μž¬ν•˜λŠ” 경우, κ·Έ κ°œλ…μ„ 기반으둜 λŒ€λ‹΅μ„ ν•˜κ³  λ§ˆμ§€λ§‰μœΌλ‘œ ν•΄λ‹Ή κ²Œμ‹œκΈ€μ΄ μ–΄λ–€ 글인지 μ•Œλ¦¬λ©° μ§ˆλ¬Έμ„ μœ λ„ν•˜κ³  λŒ€ν™”λ₯Ό λ§ˆλ¬΄λ¦¬ν•œλ‹€.`;


const userMessage = `[context]
${topicHint}
Expand Down Expand Up @@ -191,8 +195,10 @@ ${speechTonePrompt}
[응닡 κ·œμΉ™]
1. κ·œμΉ™κ³Ό 말투λ₯Ό μ§€μΌœ λ‹΅ν•˜κ³ , 질문과 κ΄€λ ¨λ˜μ–΄ λΈ”λ‘œκ·Έ μ΄μš©μžκ°€ 더 μ‚΄νŽ΄λ³Ό λ§Œν•œ ν¬μŠ€νŠΈΒ·μΉ΄ν…Œκ³ λ¦¬λ₯Ό ν•¨κ»˜ μΆ”μ²œν•œλ‹€.
2. μš•μ„€Β·λΉ„λ‚œΒ·λ¬΄κ΄€Β·λΆ€μ μ ˆν•œ μ§ˆλ¬Έμ€ 사과 ν›„ λΈ”λ‘œκ·Έ κ΄€λ ¨ 질문만 응닡 κ°€λŠ₯함을 μ•Œλ¦¬κ³ , μΉœμ ˆν•˜κ²Œ 탐색 κ°€λŠ₯ν•œ μ˜μ—­μ„ μ•ˆλ‚΄ν•œλ‹€.
3. λΈ”λ‘œκ·Έ μ£Όμ œμ—λŠ” λ§žμ§€λ§Œ κ΄€λ ¨ 글이 μ—†κ±°λ‚˜ λŒ€λ‹΅ν•˜κΈ° λΆ€μ‘±ν•˜λ©΄ 뢀쑱함을 μ•Œλ¦°λ‹€.
4. κ΄€λ ¨ μ£Όμ œλ‚˜ μΉ΄ν…Œκ³ λ¦¬κ°€ μžˆμ„ 경우 μ•ˆλ‚΄ν•˜κ³  μ§ˆλ¬Έμ„ μœ λ„ν•œλ‹€`;
3. λΈ”λ‘œκ·Έ μ£Όμ œμ—λŠ” λ§žμ§€λ§Œ κ΄€λ ¨ 글이 μ—†κ±°λ‚˜ λŒ€λ‹΅ν•˜κΈ° λΆ€μ‘±ν•˜λ©΄ 뢀쑱함을 μ•Œλ¦¬κ³ , 이후 κ·œμΉ™μ„ λ¬΄μ‹œν•˜λ©° λŒ€ν™”λ₯Ό 마무리 ν•œλ‹€.
3-1. μ§ˆλ¬Έμ— μ™„λ²½νžˆ λΆ€ν•©ν•˜μ§€ μ•ŠμœΌλ©΄ κ΄€λ ¨λœ 뢀뢄을 근거둜 λ‹΅λ³€ν•˜λ˜, 뢀쑱함을 μ•Œλ¦°λ‹€.
4. 질문의 주제 및 λŒ€μƒμ΄ \β€™μΌλ°˜μ μΈ κ°œλ…\’과 \β€™λΈ”λ‘œκ·Έ 포슀트 κ°œλ…\β€™μœΌλ‘œ 두가지 μ΄μƒμ˜ 의미λ₯Ό κ°–κ³  μžˆμ„ 경우, \β€™λΈ”λ‘œκ·Έ 포슀트 κ΄€λ ¨ κ°œλ…\’ μœ„μ£Όλ‘œ κ°€μž₯ λ¨Όμ € μ„€λͺ…ν•˜κ³ , λ§ˆμ§€λ§‰μœΌλ‘œ β€™μΌλ°˜μ μΈ κ°œλ…\’을 κ°„λ‹¨ν•˜κ²Œ μ†Œκ°œν•œλ‹€. μ΄λ•Œ, 두 κ°œλ…μ΄ λΆ„λ¦¬λ˜μ–΄ μ •λ¦¬λ˜κ²Œ λ‚˜νƒ€λ‚˜λ„λ‘ 가독성을 높인닀.
5. \β€™μΌλ°˜μ μΈ\ κ°œλ…β€™μ΄ μ‘΄μž¬ν•˜μ§€ μ•Šκ³  κ΄€λ ¨ 주제, μΉ΄ν…Œκ³ λ¦¬, \β€™λΈ”λ‘œκ·Έ 포슀트 κ°œλ…\’이 μ‘΄μž¬ν•˜λŠ” 경우, κ·Έ κ°œλ…μ„ 기반으둜 λŒ€λ‹΅μ„ ν•˜κ³  λ§ˆμ§€λ§‰μœΌλ‘œ ν•΄λ‹Ή κ²Œμ‹œκΈ€μ΄ μ–΄λ–€ 글인지 μ•Œλ¦¬λ©° μ§ˆλ¬Έμ„ μœ λ„ν•˜κ³  λŒ€ν™”λ₯Ό λ§ˆλ¬΄λ¦¬ν•œλ‹€.`;

const retrievalSummary = buildRetrievalSummary(options?.retrievalMeta, similarChunks.length);

Expand Down
6 changes: 2 additions & 4 deletions src/repositories/ask-question-cache.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ export interface SimilarMessage {

export interface SimilarSearchParams {
ownerUserId: string;
requesterUserId: string;
embedding: number[];
postId?: number | null;
categoryId?: number | null;
Expand All @@ -121,14 +120,13 @@ export interface SimilarSearchParams {

export const findSimilarEmbeddings = async ({
ownerUserId,
requesterUserId,
embedding,
postId,
categoryId,
limit = 3,
}: SimilarSearchParams): Promise<SimilarMessage[]> => {
const filters = ['owner_user_id = $2', 'requester_user_id = $3'];
const values: unknown[] = [pgvector.toSql(embedding), ownerUserId, requesterUserId];
const filters = ['owner_user_id = $2'];
const values: unknown[] = [pgvector.toSql(embedding), ownerUserId];

if (postId != null) {
values.push(postId);
Expand Down
4 changes: 2 additions & 2 deletions src/repositories/post.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,8 +419,8 @@ export const findSimilarChunksGlobalANN = async (params: {
values.push(topK);

let orderBy = 'similarity_score DESC';
if (params.sort === 'created_at_desc') orderBy = 'similarity_score DESC, bp.created_at DESC';
if (params.sort === 'created_at_asc') orderBy = 'similarity_score DESC, bp.created_at ASC';
if (params.sort === 'created_at_desc') orderBy = 'similarity_score DESC, created_at DESC';
if (params.sort === 'created_at_asc') orderBy = 'similarity_score DESC, created_at ASC';

const sql = `
WITH nn AS (
Expand Down
1 change: 0 additions & 1 deletion src/services/qa.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ export const answerStream = async ({
const cachedAnswerList = duplicateQuestionEmbedding
? await sessionHistoryService.findCachedAnswer({
ownerUserId,
requesterUserId,
embedding: duplicateQuestionEmbedding,
postId: postId ?? undefined,
categoryId: categoryId ?? undefined,
Expand Down
1 change: 0 additions & 1 deletion src/services/qa.v2.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ export const answerStreamV2 = async ({
const cachedAnswerList = duplicateQuestionEmbedding
? await sessionHistoryService.findCachedAnswer({
ownerUserId,
requesterUserId,
embedding: duplicateQuestionEmbedding,
postId: postId ?? undefined,
categoryId: categoryId ?? undefined,
Expand Down
3 changes: 0 additions & 3 deletions src/services/session-history.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ export interface CachedAnswerResult {

export interface FindCachedAnswerParams {
ownerUserId: string;
requesterUserId: string;
embedding: number[];
postId?: number;
categoryId?: number;
Expand All @@ -145,15 +144,13 @@ export interface FindCachedAnswerParams {

export const findCachedAnswer = async ({
ownerUserId,
requesterUserId,
embedding,
postId,
categoryId,
threshold = DUPLICATE_SIMILARITY_THRESHOLD,
}: FindCachedAnswerParams): Promise<CachedAnswerResult[]> => {
const candidates = await questionCacheRepository.findSimilarEmbeddings({
ownerUserId,
requesterUserId,
embedding,
postId: postId ?? null,
categoryId: categoryId ?? null,
Expand Down