머니페니 76e3220e77
All checks were successful
Deploy to Production / deploy (push) Successful in 3m10s
feat: 에이전트 기능 추가 (LLM 서비스, 에이전트 API, 테스트)
2026-05-06 20:56:45 +09:00

85 lines
2.6 KiB
Python

from __future__ import annotations
from langchain_core.messages import HumanMessage, SystemMessage
from app.services.llm import ModelTier, get_chat_model
COMPACTION_PROMPT = """당신은 대화 요약 전문가입니다. 아래 대화를 구조화된 요약으로 압축하세요.
반드시 다음 섹션을 포함하세요:
## 원래 질문
## 핵심 데이터
## 분석 진행 상황
## 수치 데이터 (정확한 값 유지)
## 오류/이슈
## 다음 단계"""
class ContextCompactor:
"""대화 컨텍스트가 너무 커지면 LLM으로 요약하여 압축합니다."""
@staticmethod
def _estimate_tokens(text: str) -> int:
"""텍스트의 토큰 수를 추정합니다 (~4자당 1토큰)."""
return len(text) // 4
def should_compact(
self, messages: list[dict], threshold: int = 50000
) -> bool:
"""메시지의 토큰 추정치가 임계값을 초과하는지 확인합니다.
Args:
messages: 대화 메시지 목록.
threshold: 토큰 임계값 (기본 50,000).
Returns:
압축이 필요하면 True.
"""
total_text = "".join(
str(m.get("content", "")) for m in messages
)
return self._estimate_tokens(total_text) > threshold
async def compact(
self, messages: list[dict], system_prompt: str
) -> list[dict]:
"""대화를 요약하여 압축된 메시지 목록을 반환합니다.
Args:
messages: 기존 대화 메시지 목록.
system_prompt: 원래 시스템 프롬프트.
Returns:
압축된 메시지 목록 (시스템 메시지 + 요약 메시지).
"""
# 대화 내용을 텍스트로 변환
conversation_lines: list[str] = []
for msg in messages:
role = msg.get("role", "unknown")
content = str(msg.get("content", ""))
conversation_lines.append(f"[{role}]: {content}")
conversation_text = "\n".join(conversation_lines)
llm = get_chat_model(tier=ModelTier.FAST)
response = await llm.ainvoke(
[
SystemMessage(content=COMPACTION_PROMPT),
HumanMessage(content=conversation_text),
]
)
summary_content = (
response.content
if isinstance(response.content, str)
else str(response.content)
)
return [
{"role": "system", "content": system_prompt},
{
"role": "user",
"content": f"[이전 대화 요약]\n{summary_content}",
},
]