cert-study-app / cert_study_app /chains /study_assistant_chain.py
github-actions
Sync from GitHub d2682fe6d3fcffe93aa302c286320962009f6436
9381502
Raw
History Blame Contribute Delete
4.05 kB
from __future__ import annotations
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnableLambda
from langchain_core.output_parsers import StrOutputParser
STUDY_ASSISTANT_PROMPT = ChatPromptTemplate.from_messages(
[
(
"system",
"""๋„ˆ๋Š” Azure ์ž๊ฒฉ์ฆ ํ•™์Šต์„ ๋•๋Š” ํ•œ๊ตญ์–ด ํŠœํ„ฐ๋‹ค.
๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ๋‹ต๋ณ€ํ•˜๋ผ. Azure Docs๊ฐ€ ์˜์–ด์—ฌ๋„ ๊ทธ๋Œ€๋กœ ๋ฒˆ์—ญํ•ด์„œ ๊ธธ๊ฒŒ ์˜ฎ๊ธฐ์ง€ ๋ง๊ณ  ํ•œ๊ตญ์–ด๋กœ ์š”์•ฝํ•˜๋ผ.
์˜์–ด ์ œํ’ˆ๋ช…/๊ธฐ์ˆ  ์šฉ์–ด๋Š” ํ•„์š”ํ•  ๋•Œ๋งŒ ๊ด„ํ˜ธ๋กœ ๋ณ‘๊ธฐํ•˜๋ผ. ์˜ˆ: ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ ๊ทธ๋ฃน(NSG)
์‚ฌ์šฉ์ž๊ฐ€ ํ˜„์žฌ ๋ฌธ์ œ๋ฅผ ํฌํ•จํ•ด์„œ ์งˆ๋ฌธํ•˜๋ฉด ํ˜„์žฌ ๋ฌธ์ œ๋ฅผ 1์ˆœ์œ„ ๊ทผ๊ฑฐ๋กœ ๋‹ต๋ณ€ํ•˜๋ผ.
Azure Docs ๊ณต์‹ ๋ฌธ์„œ๋Š” ๊ฐœ๋… ์„ค๋ช…๊ณผ ์ •๋‹ต ๊ทผ๊ฑฐ ๋ณด๊ฐ•์— ์‚ฌ์šฉํ•˜๋ผ.
๊ฒ€์ƒ‰๋œ ์œ ์‚ฌ ๋ฌธ์ œ๋Š” ํ˜„์žฌ ๋ฌธ์ œ๋ฅผ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•œ ๋ณด์กฐ ๊ทผ๊ฑฐ๋กœ๋งŒ ์‚ฌ์šฉํ•˜๋ผ.
๊ทผ๊ฑฐ ์šฐ์„ ์ˆœ์œ„๋Š” ํ˜„์žฌ ๋ฌธ์ œ > Azure Docs ๊ณต์‹ ๋ฌธ์„œ > ์œ ์‚ฌ ๋ฌธ์ œ๋‹ค.
์ฐธ๊ณ  ๋ฌธ์ œ๊ฐ€ ํ˜„์žฌ ๋ฌธ์ œ์™€ ๋‹ค๋ฅด๋ฉด ์ฐจ์ด๋ฅผ ๋จผ์ € ๋งํ•˜๊ณ , ์ฐธ๊ณ  ๋ฌธ์ œ์˜ ๋‹ต์„ ํ˜„์žฌ ๋ฌธ์ œ์˜ ๋‹ต์ฒ˜๋Ÿผ ๋งํ•˜์ง€ ๋งˆ๋ผ.
๊ทผ๊ฑฐ๊ฐ€ ๋ถ€์กฑํ•˜๋ฉด ๋ถ€์กฑํ•˜๋‹ค๊ณ  ๋งํ•˜๊ณ , ์ถ”์ธกํ•˜์ง€ ์•Š๋Š”๋‹ค.
๋‹ต๋ณ€์€ ์ „์ฒด 8๋ฌธ์žฅ ์ด๋‚ด๋กœ ์š”์•ฝํ•˜๋ผ.
๋‹ต๋ณ€ ํ˜•์‹:
1. ์š”์•ฝ
2. ํ˜„์žฌ ๋ฌธ์ œ ๊ธฐ์ค€
3. ๊ทผ๊ฑฐ
4. ํ—ท๊ฐˆ๋ฆด ํฌ์ธํŠธ
ํ’€์ด ํ๋ฆ„์€ ๋‚ด๋ถ€ ์‚ฌ๊ณ  ๊ณผ์ •์„ ๊ทธ๋Œ€๋กœ ๊ธธ๊ฒŒ ๋…ธ์ถœํ•˜์ง€ ๋ง๊ณ ,
์ฐธ๊ณ  ๋ฌธ์ œ/ํ•ด์„ค์—์„œ ํ™•์ธ ๊ฐ€๋Šฅํ•œ ๊ทผ๊ฑฐ์™€ ํŒ๋‹จ ์ˆœ์„œ๋งŒ ๊ฐ„๋‹จํžˆ ์š”์•ฝํ•˜๋ผ.""",
),
(
"human",
"""์งˆ๋ฌธ:
{question}
์ฐธ๊ณ  ๋ฌธ์ œ/ํ•ด์„ค:
{context}
์œ„ ๊ทผ๊ฑฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์งง๊ฒŒ ์š”์•ฝํ•ด์„œ ๋‹ต๋ณ€ํ•˜๋ผ.""",
),
]
)
def format_context(results: list, max_chars: int = 2400) -> str:
if not results:
return "๊ฒ€์ƒ‰๋œ ์ฐธ๊ณ  ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค."
chunks = []
remaining = max_chars
for idx, item in enumerate(results, start=1):
if remaining <= 0:
break
metadata = item.metadata or {}
answer = metadata.get("answer") or ""
source = metadata.get("source") or "unknown"
source_type = metadata.get("source_type") or "question"
title = metadata.get("title") or ""
url = metadata.get("url") or ""
score = f"{item.score:.4f}" if item.score is not None else "n/a"
text = str(item.text or "")
text = text[: max(300, remaining)]
chunk = "\n".join(
[
f"[๋ฌธ์„œ {idx}] type={source_type}, id={item.id}, source={source}, score={score}",
f"title={title}" if title else "",
f"url={url}" if url else "",
text,
f"์ •๋‹ต: {answer}" if answer else "",
]
)
chunks.append(chunk)
remaining -= len(chunk)
return "\n\n".join(chunks)
def build_study_assistant_chain(llm):
"""langchain-kr ํŠœํ† ๋ฆฌ์–ผ์ฒ˜๋Ÿผ LCEL ํŒŒ์ดํ”„(|)๋กœ ๊ตฌ์„ฑํ•œ RAG ๋‹ต๋ณ€ ์ฒด์ธ."""
return (
{
"question": RunnableLambda(lambda payload: payload["question"]),
"context": RunnableLambda(lambda payload: format_context(payload["results"], payload.get("max_context_chars", 2400))),
}
| STUDY_ASSISTANT_PROMPT
| llm
| StrOutputParser()
)
def build_ollama_llm(model: str, base_url: str, temperature: float = 0.2, num_predict: int = 320):
try:
from langchain_community.chat_models import ChatOllama
try:
return ChatOllama(model=model, base_url=base_url, temperature=temperature, num_predict=num_predict)
except TypeError:
return ChatOllama(model=model, base_url=base_url, temperature=temperature)
except ImportError:
from langchain_community.llms import Ollama
try:
return Ollama(model=model, base_url=base_url, temperature=temperature, num_predict=num_predict)
except TypeError:
return Ollama(model=model, base_url=base_url, temperature=temperature)