Spaces:
Running
Running
| [ | |
| { | |
| "id": "docs-ollama-models", | |
| "certification": "Docs Study", | |
| "title": "Ollama ๋ชจ๋ธ ์คํ ํ๋ฆ", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-1", "docs-lab-2"], | |
| "summary": "Ollama๋ ๋ก์ปฌ์์ LLM ๋ชจ๋ธ์ ๋ด๋ ค๋ฐ๊ณ ์คํํด CLI ๋๋ REST API๋ก ์ฌ์ฉํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฒฝ๋ ๋ชจ๋ธ ์๋ฒ์ ๋๋ค. `ollama run`์ผ๋ก ๋ํํ๊ณ , `ollama serve`๋ก API ์๋ฒ๋ฅผ ์ ์งํฉ๋๋ค.", | |
| "example": "# ๋ชจ๋ธ ๋ค์ด๋ก๋ ๋ฐ ์คํ\nollama pull qwen2.5:14b\nollama run qwen2.5:14b\n# ์ค์น๋ ๋ชจ๋ธ ๋ชฉ๋ก\nollama list", | |
| "common_mistake": "๋ชจ๋ธ ์ด๋ฆ์ ํ๊ทธ(:14b, :latest ๋ฑ)๋ฅผ ์๋ตํ๋ฉด `:latest`๋ก ์๋ ์ค์ ๋ฉ๋๋ค. ๋ชจ๋ธ์ด ๋ก์ปฌ์ ์์ ๋ `ollama run`์ด ์๋์ผ๋ก pullํฉ๋๋ค.", | |
| "keywords": ["ollama", "pull", "run", "serve", "model tag", "GGUF", "local LLM"], | |
| "source_id": "official-docs-ollama", | |
| "details": [ | |
| "**`ollama run`**: ๋ชจ๋ธ์ด ์์ผ๋ฉด ์๋ ๋ค์ด๋ก๋ ํ ๋ํํ ์ธ์ ์์. `--nowordwrap` ์ต์ ์ผ๋ก ๊ธด ์ถ๋ ฅ ์ฒ๋ฆฌ ๊ฐ๋ฅ.", | |
| "**`ollama serve`**: 11434 ํฌํธ์์ OpenAI ํธํ REST API ์ ๊ณต. `OLLAMA_HOST=0.0.0.0`์ผ๋ก ์ธ๋ถ ์ ๊ทผ ํ์ฉ ๊ฐ๋ฅ.", | |
| "๋ชจ๋ธ ํ์ผ์ `~/.ollama/models`์ GGUF ํ์์ผ๋ก ์ ์ฅ๋ฉ๋๋ค. `Modelfile`๋ก ์ปค์คํ ์์คํ ํ๋กฌํํธ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-ollama-api", | |
| "certification": "Docs Study", | |
| "title": "Ollama REST API ํธ์ถ", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-3"], | |
| "summary": "Ollama๋ `localhost:11434`์์ REST API๋ฅผ ์ ๊ณตํฉ๋๋ค. `/api/generate`(์์ฑํ), `/api/chat`(๋ํํ), `/api/embeddings`(์๋ฒ ๋ฉ) ์๋ํฌ์ธํธ๋ฅผ OpenAI ํธํ ํ์์ผ๋ก๋ ์ง์ํฉ๋๋ค.", | |
| "example": "# chat ์๋ํฌ์ธํธ\ncurl http://localhost:11434/api/chat -d '{\n \"model\": \"qwen2.5:7b\",\n \"messages\": [{\"role\": \"user\", \"content\": \"์๋ \"}],\n \"stream\": false\n}'", | |
| "common_mistake": "Ollama ์๋ฒ(`ollama serve`)๊ฐ ์คํ ์ค์ด์ง ์๊ฑฐ๋ ๋ชจ๋ธ์ด ๋ก์ปฌ์ ์์ผ๋ฉด API ํธ์ถ์ด ์คํจํฉ๋๋ค. ๋จผ์ `ollama list`๋ก ๋ชจ๋ธ ์กด์ฌ๋ฅผ ํ์ธํ์ธ์.", | |
| "keywords": ["ollama", "REST API", "generate", "chat", "embeddings", "localhost:11434", "stream"], | |
| "source_id": "official-docs-ollama", | |
| "details": [ | |
| "**OpenAI ํธํ API**: `http://localhost:11434/v1/chat/completions`๋ก OpenAI Python SDK๋ LangChain์ `ChatOpenAI(base_url=...)` ๊ทธ๋๋ก ์ฌ์ฉ ๊ฐ๋ฅํฉ๋๋ค.", | |
| "**์คํธ๋ฆฌ๋ฐ**: `\"stream\": true` ์ค์ ์ ์๋ต์ JSON ์ค ๋จ์๋ก ์คํธ๋ฆฌ๋ฐ. `\"done\": true` ์ค์ด ์๋ฃ ์ ํธ์ ๋๋ค.", | |
| "**์๋ฒ ๋ฉ**: `POST /api/embeddings`์ `{\"model\":\"nomic-embed-text\", \"prompt\":\"ํ ์คํธ\"}`๋ฅผ ๋ณด๋ด๋ฉด ๋ฒกํฐ ๋ฐฐ์ด์ ๋ฐํํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-dotenv", | |
| "certification": "Docs Study", | |
| "title": "python-dotenv โ ํ๊ฒฝ๋ณ์ & .env ๊ด๋ฆฌ", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-4"], | |
| "summary": "python-dotenv๋ `.env` ํ์ผ์ ํค-๊ฐ ์์ `os.environ`์ ์๋์ผ๋ก ๋ก๋ํฉ๋๋ค. API ํค ๊ฐ์ ๋ฏผ๊ฐ ์ ๋ณด๋ฅผ ์ฝ๋์ ์ง์ ์ฐ์ง ์๊ณ ํ์ผ๋ก ๋ถ๋ฆฌํด ๊ด๋ฆฌํ๋ ํ์ค ๋ฐฉ๋ฒ์ ๋๋ค.", | |
| "example": "# .env ํ์ผ\nOPENAI_API_KEY=sk-...\nOLLAMA_BASE_URL=http://localhost:11434\n\n# Python ์ฝ๋\nfrom dotenv import load_dotenv\nimport os\n\nload_dotenv() # .env ํ์ผ ๋ก๋\napi_key = os.getenv('OPENAI_API_KEY')", | |
| "common_mistake": "`load_dotenv()`๋ฅผ ํธ์ถํ๊ธฐ ์ ์ `os.getenv()`๋ฅผ ์ฐ๋ฉด ํญ์ `None`์ ๋ฐํํฉ๋๋ค. ๋ฐ๋์ ํ์ผ ์๋จ์์ ๊ฐ์ฅ ๋จผ์ `load_dotenv()`๋ฅผ ํธ์ถํ์ธ์.", | |
| "keywords": ["dotenv", "load_dotenv", ".env", "os.getenv", "ํ๊ฒฝ๋ณ์", "API ํค"], | |
| "source_id": "official-docs-python", | |
| "details": [ | |
| "**์ฐ์ ์์**: `load_dotenv(override=False)`(๊ธฐ๋ณธ๊ฐ)๋ ์ด๋ฏธ ์ค์ ๋ ํ๊ฒฝ๋ณ์๋ฅผ ๋ฎ์ด์ฐ์ง ์์ต๋๋ค. CI/CD ํ๊ฒฝ์์ ์์คํ ํ๊ฒฝ๋ณ์๊ฐ .env๋ณด๋ค ์ฐ์ ํฉ๋๋ค.", | |
| "**.gitignore**: `.env`๋ ๋ฐ๋์ `.gitignore`์ ์ถ๊ฐํด์ผ ํฉ๋๋ค. `.env.example`์ ํค ์ด๋ฆ๋ง ์ ์ด ํ์์๊ฒ ์ด๋ค ๋ณ์๊ฐ ํ์ํ์ง ์๋ ค์ฃผ๋ ์ฉ๋๋ก ์ปค๋ฐํฉ๋๋ค.", | |
| "**Streamlit ์ฐ๋**: ๋ก์ปฌ ๊ฐ๋ฐ ์ `load_dotenv()`๋ก ํค๋ฅผ ๋ก๋ํ๊ณ , ๋ฐฐํฌ ์์๋ `st.secrets`๋ก ์ ๊ทผํ๋๋ก ๋ถ๊ธฐํ๊ฑฐ๋ ์ฒ์๋ถํฐ `st.secrets`๋ง ์ฐ๋ ๋ฐฉ์ ์ค ํ๋๋ฅผ ์ ํํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-prompt-template", | |
| "certification": "Docs Study", | |
| "title": "ChatPromptTemplate โ ํ๋กฌํํธ ๊ตฌ์กฐํ", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-5", "docs-lab-6"], | |
| "summary": "ChatPromptTemplate์ ์์คํ ํ๋กฌํํธ, ์ฌ์ฉ์ ๋ฉ์์ง, ๋ณ์ ํ๋ ์ด์คํ๋๋ฅผ ๊ตฌ์กฐํ๋ ๋ฐฉ์์ผ๋ก ์ ์ํฉ๋๋ค. ๋จ์ f-string ๋์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ณ LangChain ํ์ดํ๋ผ์ธ์ ์ฐ๊ฒฐ๋๋ ํ๋กฌํํธ๋ฅผ ๋ง๋ค ๋ ์๋๋ค.", | |
| "example": "from langchain_core.prompts import ChatPromptTemplate\n\nprompt = ChatPromptTemplate.from_messages([\n (\"system\", \"๋น์ ์ ๋์์ด ๋๋ AI ์ด์์คํดํธ์ ๋๋ค. ์ปจํ ์คํธ: {context}\"),\n (\"human\", \"{question}\")\n])\n\n# ์ฒด์ธ์ ์ฐ๊ฒฐ\nchain = prompt | llm | StrOutputParser()\nchain.invoke({\"context\": \"...\", \"question\": \"์์ฝํด์ค\"})", | |
| "common_mistake": "`PromptTemplate`์ ๋จ์ ๋ฌธ์์ด ํฌ๋งท์ฉ(๋ณ์ ํ๋), `ChatPromptTemplate`์ ์ญํ ์ด ๊ตฌ๋ถ๋ ๋ฉ์์ง ๋ฐฐ์ด์ฉ์ ๋๋ค. RAG์์ ์์คํ ํ๋กฌํํธ์ ์ง๋ฌธ์ ๊ตฌ๋ถํ๋ ค๋ฉด ํญ์ ChatPromptTemplate์ ์๋๋ค.", | |
| "keywords": ["ChatPromptTemplate", "from_messages", "system", "human", "placeholder", "PromptTemplate"], | |
| "source_id": "official-docs-langchain", | |
| "details": [ | |
| "**MessagesPlaceholder**: ๋ํ ํ์คํ ๋ฆฌ๋ฅผ ํต์งธ๋ก ์ฃผ์ ํ ๋ ์๋๋ค. `(\"placeholder\", \"{chat_history}\")`๋ก ์ ์ธํ๋ฉด ๋ฉ์์ง ๋ฆฌ์คํธ๊ฐ ๊ทธ ์๋ฆฌ์ ํผ์ณ์ง๋๋ค.", | |
| "**partial**: `prompt.partial(context=\"๊ณ ์ ๊ฐ\")`์ผ๋ก ํน์ ๋ณ์๋ฅผ ๋ฏธ๋ฆฌ ์ฑ์ธ ์ ์์ต๋๋ค. context๋ ๊ณ ์ ํ๊ณ question๋ง ๋ฐํ์์ ๋ฐ์ ๋ ์ ์ฉํฉ๋๋ค.", | |
| "**ํ์ ์์ ์ฑ**: from_messages์ `(\"system\", \"...\")` ํํ ๋์ `SystemMessage(content=\"...\")`๋ฅผ ์ฌ์ฉํด๋ ๋์ผํฉ๋๋ค. ํํ ๋ฐฉ์์ด ๋ ๊ฐ๊ฒฐํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-document-loaders", | |
| "certification": "Docs Study", | |
| "title": "LangChain Document Loaders โ ๋ฌธ์ ์ผ๊ด ๋ก๋", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-7"], | |
| "summary": "Document Loader๋ PDF, ๋งํฌ๋ค์ด, ์น ํ์ด์ง, ๋๋ ํ ๋ฆฌ ๋ฑ ๋ค์ํ ์์ค์์ ๋ฌธ์๋ฅผ LangChain `Document` ๊ฐ์ฒด๋ก ๋ณํํฉ๋๋ค. RAG ํ์ดํ๋ผ์ธ์ ์ฒซ ๋จ๊ณ์ ๋๋ค.", | |
| "example": "from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader\n\n# ๋๋ ํ ๋ฆฌ ๋ด ๋ชจ๋ .md ํ์ผ ๋ก๋\nloader = DirectoryLoader('./notes', glob='**/*.md')\ndocs = loader.load()\n\n# ๊ฐ ๋ฌธ์์ ์ถ์ฒ ํ์ธ\nfor doc in docs:\n print(doc.metadata['source'], len(doc.page_content))", | |
| "common_mistake": "`loader.load()`๋ ๋ชจ๋ ๋ฌธ์๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ฆฝ๋๋ค. ๋์ฉ๋ ๋๋ ํ ๋ฆฌ์์๋ `loader.lazy_load()`๋ก ์ ๋๋ ์ดํฐ๋ฅผ ์ฐ๊ฑฐ๋ ๋ฐฐ์น๋ก ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.", | |
| "keywords": ["DirectoryLoader", "PyPDFLoader", "WebBaseLoader", "glob", "metadata", "source", "lazy_load"], | |
| "source_id": "official-docs-langchain", | |
| "details": [ | |
| "**metadata['source']**: ๋ก๋๋ ๋ฌธ์๋ `metadata` ๋์ ๋๋ฆฌ์ ํ์ผ ๊ฒฝ๋ก(`source`)๋ฅผ ํฌํจํฉ๋๋ค. RAG ๋ต๋ณ์ ์ถ์ฒ๋ฅผ ํ์ํ ๋ ์ด ๊ฐ์ ์๋๋ค.", | |
| "**glob ํจํด**: `glob='**/*.md'`๋ ํ์ ํด๋๊น์ง ์ฌ๊ท ๊ฒ์ํฉ๋๋ค. `glob='*.pdf'`๋ ํ์ฌ ํด๋๋ง ๊ฒ์ํฉ๋๋ค.", | |
| "**WebBaseLoader**: URL ๋ฆฌ์คํธ๋ฅผ ๋๊ธฐ๋ฉด ์น ํ์ด์ง๋ฅผ ํฌ๋กค๋งํด Document๋ก ๋ณํํฉ๋๋ค. BeautifulSoup ๊ธฐ๋ฐ์ด๋ฉฐ `bs_kwargs`๋ก ํ์ฑ ๋ฒ์๋ฅผ ์ง์ ํ ์ ์์ต๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-langchain-rag", | |
| "certification": "Docs Study", | |
| "title": "LangChain RAG ๊ธฐ๋ณธ ํ๋ฆ", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-8", "docs-lab-9"], | |
| "summary": "LangChain์ ๋ฌธ์ ๋ก๋ โ ๋ถํ โ ์๋ฒ ๋ฉ โ ๊ฒ์ โ ์์ฑ์ RAG ํ์ดํ๋ผ์ธ์ ์ปดํฌ๋ํธ ์กฐํฉ์ผ๋ก ๊ตฌํํฉ๋๋ค. Retriever๊ฐ ๊ด๋ จ ๋ฌธ์๋ฅผ ์ฐพ์ LLM ์ปจํ ์คํธ๋ก ์ฃผ์ ํฉ๋๋ค.", | |
| "example": "from langchain_community.vectorstores import Chroma\nretriever = Chroma.from_documents(docs, embeddings).as_retriever(k=3)\nchain = (\n {\"context\": retriever, \"question\": RunnablePassthrough()}\n | prompt | llm | StrOutputParser()\n)", | |
| "common_mistake": "Retriever๊ฐ ์ฐพ์ ๋ฌธ์๋ฅผ ๊ทธ๋๋ก ์ ๋ต์ผ๋ก ๋ฏฟ์ง ๋ง์ธ์. ๊ฒ์๋ ์ฒญํฌ๊ฐ ์ง๋ฌธ๊ณผ ๋ค๋ฅธ ๋งฅ๋ฝ์ผ ์ ์์ด ํ๋กฌํํธ์์ ๋ช ์์ ์ผ๋ก '์๋ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด'๋ผ๊ณ ์ง์ํด์ผ ํฉ๋๋ค.", | |
| "keywords": ["langchain", "RAG", "retriever", "vectorstore", "document loader", "text splitter"], | |
| "source_id": "official-docs-langchain", | |
| "details": [ | |
| "**ํ์ดํ๋ผ์ธ ๋จ๊ณ**: DocumentLoader โ TextSplitter(์ฒญํฌ ๋ถํ ) โ Embeddings โ VectorStore โ Retriever โ LLM Chain.", | |
| "**TextSplitter**: `RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)`์ด ์ผ๋ฐ์ ์์์ . overlap์ด ์์ด์ผ ์ฒญํฌ ๊ฒฝ๊ณ์์ ๋ฌธ๋งฅ ์์ค์ ์ค์ ๋๋ค.", | |
| "`MultiQueryRetriever`๋ `ContextualCompressionRetriever`๋ก ๊ฒ์ ํ์ง์ ๋์ผ ์ ์์ต๋๋ค. ๋จ์ ์ ์ฌ๋ ๊ฒ์๋ณด๋ค ๊ด๋ จ ์ฒญํฌ ์ ๋ณ ์ ํ๋๊ฐ ์ฌ๋ผ๊ฐ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-lcel", | |
| "certification": "Docs Study", | |
| "title": "LangChain LCEL โ ์ฒด์ธ ๊ตฌ์ฑ", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-10", "docs-lab-11"], | |
| "summary": "LCEL(LangChain Expression Language)์ `|` ํ์ดํ ์ฐ์ฐ์๋ก Runnable ์ปดํฌ๋ํธ๋ฅผ ์ง๋ ฌยท๋ณ๋ ฌ ์ฐ๊ฒฐํด ์ฒด์ธ์ ์ ์ธ์ ์ผ๋ก ์ ์ํฉ๋๋ค.", | |
| "example": "from langchain_core.runnables import RunnablePassthrough\nchain = (\n RunnablePassthrough.assign(context=retriever)\n | prompt\n | llm\n | StrOutputParser()\n)\nresult = chain.invoke({\"question\": \"What is RAG?\"})", | |
| "common_mistake": "์ฒด์ธ ๊ฐ ๋จ๊ณ์ ์ ์ถ๋ ฅ ํ์ ์ด ๋ง์์ผ ํฉ๋๋ค. LLM์ `str` ๋๋ `BaseMessage`๋ฅผ ๋ฐ๊ณ ๋ฐํํ๋ฏ๋ก, ์ ๋จ๊ณ๊ฐ ๋์ ๋๋ฆฌ๋ฅผ ๋ฐํํ๋ฉด ํ๋กฌํํธ ํ ํ๋ฆฟ์ด ์ค๊ฐ์์ ๋ฐ์ ์ฒ๋ฆฌํด์ผ ํฉ๋๋ค.", | |
| "keywords": ["LCEL", "Runnable", "pipe", "chain", "invoke", "stream", "batch"], | |
| "source_id": "official-docs-langchain", | |
| "details": [ | |
| "**3๊ฐ์ง ์คํ ๋ฐฉ์**: `invoke`(๋จ์ผ ๋๊ธฐ), `stream`(์คํธ๋ฆฌ๋ฐ yield), `batch`(๋ฆฌ์คํธ ๋ณ๋ ฌ ์ฒ๋ฆฌ). ์คํธ๋ฆฌ๋ฐ UI์๋ `stream`์ ์๋๋ค.", | |
| "**RunnablePassthrough**: ์ ๋ ฅ์ ๊ทธ๋๋ก ๋ค์ ๋จ๊ณ๋ก ์ ๋ฌ. `.assign(key=fn)`์ผ๋ก ์ถ๊ฐ ํค๋ฅผ ๋ถ์ฌ ๋์ ๋๋ฆฌ๋ฅผ ํ์ฅํฉ๋๋ค.", | |
| "**RunnableParallel**: `{\"a\": fn1, \"b\": fn2}` ํํ๋ก ์ฌ๋ฌ ์ฒด์ธ์ ๋์์ ์คํํด ๊ฒฐ๊ณผ๋ฅผ ๋์ ๋๋ฆฌ๋ก ํฉ์นฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-vectorstore", | |
| "certification": "Docs Study", | |
| "title": "VectorStore์ Retriever โ ๋ฒกํฐ ๊ฒ์", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-11", "docs-lab-12"], | |
| "summary": "๋ฌธ์๋ฅผ ์๋ฒ ๋ฉ ๋ฒกํฐ๋ก ๋ณํํด ์ ์ฅํ๊ณ , ์ฟผ๋ฆฌ์ ์ฝ์ฌ์ธ ์ ์ฌ๋๋ก ๊ด๋ จ ์ฒญํฌ๋ฅผ ๊ฒ์ํฉ๋๋ค. Chroma, FAISS, pgvector ๋ฑ ๋ค์ํ ๋ฐฑ์๋๋ฅผ LangChain์ด ์ถ์ํํฉ๋๋ค.", | |
| "example": "from langchain_community.vectorstores import Chroma\nfrom langchain_ollama import OllamaEmbeddings\n\nembeddings = OllamaEmbeddings(model='nomic-embed-text')\ndb = Chroma.from_documents(docs, embeddings, persist_directory='./db')\nretriever = db.as_retriever(search_type='mmr', search_kwargs={'k': 4})", | |
| "common_mistake": "์๋ฒ ๋ฉ ๋ชจ๋ธ์ ๋ณ๊ฒฝํ๋ฉด ๋ฒกํฐ ์ฐจ์์ด ๋ฌ๋ผ์ ธ ๊ธฐ์กด ์ปฌ๋ ์ ๊ณผ ํธํ๋์ง ์์ต๋๋ค. ๋ชจ๋ธ์ ๋ฐ๊ฟ ๋๋ ์ปฌ๋ ์ ์ ์๋ก ๋ง๋ค์ด์ผ ํฉ๋๋ค.", | |
| "keywords": ["vectorstore", "Chroma", "FAISS", "embedding", "similarity", "MMR", "retriever"], | |
| "source_id": "official-docs-langchain", | |
| "details": [ | |
| "**๊ฒ์ ์ ํ**: `similarity`(์์ ์ ์ฌ๋ ์์ k๊ฐ), `mmr`(MMR: ๋ค์์ฑ ๊ณ ๋ ค), `similarity_score_threshold`(์๊ณ๊ฐ ์ด์๋ง).", | |
| "**Chroma**: ๋ก์ปฌ ํ์ผ๋ก ์ ์ฅ ๊ฐ๋ฅ(`persist_directory`). ํ๋กํ ํ์ ์ ์ ํฉ. ํ๋ก๋์ ์ pgvector(PostgreSQL), Qdrant, Pinecone ๊ถ์ฅ.", | |
| "์๋ฒ ๋ฉ์ ํ ์คํธ์ ์๋ฏธ์ ์ ์ฌ๋๋ฅผ ์ก์ง๋ง, ์ ํํ ํค์๋ ๋งค์นญ์ด ํ์ํ๋ฉด BM25 ๋ฑ ํค์๋ ๊ฒ์๊ณผ `EnsembleRetriever`๋ก ํ์ด๋ธ๋ฆฌ๋ ๊ตฌ์ฑ์ ๊ณ ๋ คํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-streamlit-state", | |
| "certification": "Docs Study", | |
| "title": "Streamlit session_state โ ์ํ ๊ด๋ฆฌ", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-16", "docs-lab-17"], | |
| "summary": "Streamlit์ ์ํธ์์ฉ๋ง๋ค ์คํฌ๋ฆฝํธ ์ ์ฒด๋ฅผ rerunํฉ๋๋ค. ๋ฒํผ ํด๋ฆญยท์ ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ rerun ์ดํ์๋ ์ ์งํ๋ ค๋ฉด `st.session_state`์ ์ ์ฅํด์ผ ํฉ๋๋ค.", | |
| "example": "if 'count' not in st.session_state:\n st.session_state.count = 0\nif st.button('์ฆ๊ฐ'):\n st.session_state.count += 1\nst.write(f'ํด๋ฆญ ํ์: {st.session_state.count}')", | |
| "common_mistake": "์ผ๋ฐ ์ ์ญ ๋ณ์๋ ํจ์ ๋ด ์ง์ญ ๋ณ์๋ rerun๋ง๋ค ์ด๊ธฐํ๋ฉ๋๋ค. ์ํ ๋ณด์กด์ด ํ์ํ ๋ชจ๋ ๊ฐ์ ๋ฐ๋์ `st.session_state`๋ฅผ ์ฌ์ฉํ์ธ์.", | |
| "keywords": ["session_state", "rerun", "widget", "state management", "callback"], | |
| "source_id": "official-docs-streamlit", | |
| "details": [ | |
| "**์ด๊ธฐํ ํจํด**: `st.session_state.setdefault('key', default_value)` ๋๋ `if 'key' not in st.session_state:` ๋ธ๋ก์ผ๋ก ์์ ํ๊ฒ ์ด๊ธฐํํฉ๋๋ค.", | |
| "**Widget key**: `st.text_input('์ด๋ฆ', key='username')`์ผ๋ก ์์ ฏ ๊ฐ์ด ์๋์ผ๋ก `st.session_state.username`์ ์ ์ฅ๋ฉ๋๋ค.", | |
| "**callback**: `on_change=my_func`์ผ๋ก ์์ ฏ ๋ณ๊ฒฝ ์ ํจ์๋ฅผ ์คํํฉ๋๋ค. callback ์์์ session_state๋ฅผ ์์ ํ๋ฉด rerun ์ ์ ์ฒ๋ฆฌ๋ฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-streamlit-cache", | |
| "certification": "Docs Study", | |
| "title": "Streamlit Cache โ ์บ์ ๋ฐ์ฝ๋ ์ดํฐ", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-18"], | |
| "summary": "rerun๋ง๋ค ๋ฐ๋ณต ์คํ๋๋ ๋น์ฉ ๋์ ๊ณ์ฐยท๋ฆฌ์์ค ๋ก๋ฉ์ ์บ์ํด ์ฑ๋ฅ์ ๋์ ๋๋ค. `@st.cache_data`๋ ์ง๋ ฌํ ๊ฐ๋ฅ ๋ฐ์ดํฐ, `@st.cache_resource`๋ DBยท๋ชจ๋ธ ๊ฐ์ ๊ณต์ ๊ฐ์ฒด์ ์๋๋ค.", | |
| "example": "@st.cache_resource\ndef load_model():\n return SentenceTransformer('all-MiniLM-L6-v2')\n\n@st.cache_data(ttl=300)\ndef fetch_data(query: str):\n return db.execute(query).fetchall()", | |
| "common_mistake": "`cache_data`์ `cache_resource`๋ฅผ ํผ๋ํ๋ฉด ๋ฌธ์ ๊ฐ ์๊น๋๋ค. LLM ๋ชจ๋ธ์ด๋ DB ์ฐ๊ฒฐ์ฒ๋ผ ๊ณต์ ํด์ผ ํ๋ ๊ฐ์ฒด๋ ๋ฐ๋์ `cache_resource`๋ฅผ ์จ์ผ ํฉ๋๋ค.", | |
| "keywords": ["cache_data", "cache_resource", "TTL", "rerun", "performance"], | |
| "source_id": "official-docs-streamlit", | |
| "details": [ | |
| "**`@st.cache_data`**: ํจ์ ์ธ์๋ฅผ ํค๋ก ๊ฒฐ๊ณผ๋ฅผ ๋ณต์ฌํด ์บ์. DataFrame, ๋ฆฌ์คํธ ๋ฑ ์ง๋ ฌํ ๊ฐ๋ฅ ๋ฐํ๊ฐ์ ์ ํฉ. `ttl` ์ธ์๋ก ๋ง๋ฃ ์๊ฐ ์ค์ ๊ฐ๋ฅ.", | |
| "**`@st.cache_resource`**: ์ฑ๊ธํค์ฒ๋ผ ํ ๋ฒ๋ง ์์ฑํด ๋ชจ๋ ์ธ์ ์ด ๊ณต์ . ๋ชจ๋ธ ๋ก๋ฉ, DB ์ฐ๊ฒฐ, ๋ฒกํฐ ์คํ ์ด ์ด๊ธฐํ์ ์ ํฉ.", | |
| "์บ์ ๋ฌดํจํ: `st.cache_data.clear()` / `st.cache_resource.clear()`๋ก ์๋ ์ด๊ธฐํ. ํจ์ ๋ณธ๋ฌธ์ด ๋ฐ๋๋ฉด ์๋์ผ๋ก ์บ์๊ฐ ๋ฌดํจํ๋ฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-streamlit-secrets", | |
| "certification": "Docs Study", | |
| "title": "Streamlit Secrets โ ๋น๋ฐ ๊ด๋ฆฌ", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-4"], | |
| "summary": "API ํค, DB ๋น๋ฐ๋ฒํธ ๋ฑ ๋ฏผ๊ฐ ์ ๋ณด๋ฅผ ์ฝ๋์ ๋ฃ์ง ์๊ณ `.streamlit/secrets.toml` ํ์ผ ๋๋ Streamlit Cloud์ Secrets UI์ ์ ์ฅํฉ๋๋ค.", | |
| "example": "# .streamlit/secrets.toml\n[database]\nhost = 'localhost'\npassword = 'secret'\n\n# ์ฝ๋์์ ์ ๊ทผ\nimport streamlit as st\ndb_pass = st.secrets['database']['password']", | |
| "common_mistake": "`.streamlit/secrets.toml`์ `.gitignore`์ ์ถ๊ฐํ์ง ์์ผ๋ฉด ๋ฏผ๊ฐ ์ ๋ณด๊ฐ Git์ ์ปค๋ฐ๋ ์ ์์ต๋๋ค. ๋ฐ๋์ ์ ์ธํ์ธ์.", | |
| "keywords": ["secrets", "secrets.toml", "API key", ".gitignore", "Streamlit Cloud"], | |
| "source_id": "official-docs-streamlit", | |
| "details": [ | |
| "๋ก์ปฌ ๊ฐ๋ฐ: `.streamlit/secrets.toml`์ TOML ํ์์ผ๋ก ์ ์ฅ. ์ฑ ์ฝ๋์์ `st.secrets`๋ก ๋์ ๋๋ฆฌ์ฒ๋ผ ์ ๊ทผํฉ๋๋ค.", | |
| "Streamlit Cloud: ์ฑ Settings โ Secrets์ ๊ฐ์ TOML ๋ด์ฉ์ ๋ถ์ฌ๋ฃ์ผ๋ฉด ๋ฐฐํฌ ์ ์๋ ์ฃผ์ ๋ฉ๋๋ค.", | |
| "`st.secrets`๋ `os.environ`๋ณด๋ค ๊ตฌ์กฐํ๋ ์ ๊ทผ์ ์ง์ํฉ๋๋ค. `st.secrets['key']`์ `st.secrets.key` ๋ ๋ฐฉ์ ๋ชจ๋ ๊ฐ๋ฅํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-hf-spaces", | |
| "certification": "Docs Study", | |
| "title": "Hugging Face Spaces โ ์ฑ ๋ฐฐํฌ", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-19"], | |
| "summary": "Hugging Face Spaces๋ Streamlit, Gradio, Docker ์ฑ์ ๋ฌด๋ฃ๋ก ํธ์คํ ํ๋ ํ๊ฒฝ์ ๋๋ค. README.md ์๋จ์ YAML ๋ฉํ๋ฐ์ดํฐ๋ก SDK์ ํ์ผ์ ์ง์ ํฉ๋๋ค.", | |
| "example": "# README.md ์๋จ (YAML frontmatter)\n---\ntitle: My App\nsdk: streamlit\napp_file: app.py\npython_version: '3.11'\n---", | |
| "common_mistake": "API ํค ๋ฑ ๋ฏผ๊ฐ ์ ๋ณด๋ ์ฝ๋์ ํ๋์ฝ๋ฉํ์ง ๋ง์ธ์. Space Settings โ Secrets์ ๋ฑ๋กํ๊ณ ์ฝ๋์์๋ `os.environ['MY_KEY']`๋ก ์ฐธ์กฐํฉ๋๋ค.", | |
| "keywords": ["huggingface", "spaces", "SDK", "secrets", "app_file", "README metadata"], | |
| "source_id": "official-docs-huggingface", | |
| "details": [ | |
| "**๋ฌด๋ฃ ํฐ์ด**: CPU ๊ธฐ๋ณธ ์ ๊ณต, ๊ณต๊ฐ Space๋ ๋ฌด๋ฃ. GPU๋ ๋น๊ณต๊ฐ Space๋ ์ ๋ฃ ํ๋ ๋๋ ZeroGPU(๋ฌด๋ฃ ๊ณต์ GPU) ํ์ฉ.", | |
| "**Secrets**: `Settings โ Repository secrets`์ ํค-๊ฐ์ผ๋ก ๋ฑ๋ก. ๋น๋ ๋ฐ ๋ฐํ์์ ํ๊ฒฝ ๋ณ์๋ก ์ฃผ์ ๋ฉ๋๋ค.", | |
| "Space๋ฅผ Duplicate(๋ณต์ )ํ๋ฉด fork์ฒ๋ผ ๋ ๋ฆฝ๋ Space๊ฐ ์์ฑ๋ฉ๋๋ค. ํ์ธ์ ๋ชจ๋ธยท์ฑ์ ๋ด Secrets์ ํจ๊ป ์ปค์คํ ํ๋ ์ผ๋ฐ์ ์ธ ํจํด์ ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-hf-docker-space", | |
| "certification": "Docs Study", | |
| "title": "Hugging Face Docker Space", | |
| "level": "์ ๋ฌธ", | |
| "related_practices": ["docs-lab-20"], | |
| "summary": "Dockerfile๋ก ์ฑ ํ๊ฒฝ์ ์ง์ ์ ์ํ๋ Space ๋ฐฐํฌ ๋ฐฉ์์ ๋๋ค. Streamlit/Gradio SDK ์ ์ฝ์ ๋์ด FastAPI, ์ปค์คํ ์๋ฒ ๋ฑ ์ด๋ค ์ฑ๋ ๋ฐฐํฌํ ์ ์์ต๋๋ค.", | |
| "example": "# README.md\n---\ntitle: My API\nsdk: docker\napp_port: 7860\n---\n\n# Dockerfile\nFROM python:3.11-slim\nCOPY . .\nRUN pip install -r requirements.txt\nEXPOSE 7860\nCMD [\"uvicorn\", \"main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"7860\"]", | |
| "common_mistake": "Docker Space๋ ํฌํธ 7860์ ๊ธฐ๋ณธ์ผ๋ก ๋ ธ์ถํฉ๋๋ค(`app_port: 7860`). ์ฑ์ด ๋ค๋ฅธ ํฌํธ๋ฅผ ์ฌ์ฉํ๋ฉด README ๋ฉํ๋ฐ์ดํฐ์ `app_port`์ ์ผ์น์์ผ์ผ ํฉ๋๋ค.", | |
| "keywords": ["docker", "Dockerfile", "Spaces", "app_port", "FastAPI", "custom server"], | |
| "source_id": "official-docs-huggingface", | |
| "details": [ | |
| "**๋น๋ ์บ์**: Space๋ ์ด์ ๋น๋ ๋ ์ด์ด๋ฅผ ์บ์ํฉ๋๋ค. `COPY requirements.txt .` ํ `RUN pip install`์ ๋ฐฐ์นํด ์์กด์ฑ ๋ ์ด์ด๋ฅผ ์ฑ ์ฝ๋๋ณด๋ค ์์ ๋๋ฉด ๋น๋๊ฐ ๋น ๋ฆ ๋๋ค.", | |
| "**Secrets**: `docker build --build-arg`๊ฐ ์๋ Runtime Secrets๋ก ์ฃผ์ ํด์ผ ์ด๋ฏธ์ง์ ๋ฏผ๊ฐ ์ ๋ณด๊ฐ ํฌํจ๋์ง ์์ต๋๋ค. `os.environ`์ผ๋ก ์ ๊ทผํฉ๋๋ค.", | |
| "**๋ชจ๋ธ ํ์ผ**: ๋ํ ๋ชจ๋ธ์ Space ์ ์ฅ์์ ์ง์ ๋ฃ์ง ๋ง๊ณ `huggingface_hub.snapshot_download()`๋ก ๋ฐํ์์ ๊ฐ์ ธ์ค๊ฑฐ๋ Dataset ์ ์ฅ์๋ฅผ ๋ง์ดํธํ๋ ๋ฐฉ์์ ์๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-fastapi", | |
| "certification": "Docs Study", | |
| "title": "FastAPI โ LLM ์๋น์ค API ์๋ฒ", | |
| "level": "์ค๊ธ", | |
| "related_practices": ["docs-lab-21"], | |
| "summary": "FastAPI๋ Python ํ์ ํํธ ๊ธฐ๋ฐ์ ๊ณ ์ฑ๋ฅ ๋น๋๊ธฐ API ํ๋ ์์ํฌ์ ๋๋ค. RAG ์ฒด์ธ์ด๋ LLM ๊ธฐ๋ฅ์ REST API ์๋ํฌ์ธํธ๋ก ๋ ธ์ถํ ๋ ๊ฐ์ฅ ๋ง์ด ์ฐ์ ๋๋ค.", | |
| "example": "from fastapi import FastAPI\nfrom pydantic import BaseModel\n\napp = FastAPI()\n\nclass Query(BaseModel):\n question: str\n\n@app.post('/ask')\nasync def ask(q: Query):\n answer = chain.invoke(q.question)\n return {\"answer\": answer}\n\n# ์คํ\n# uvicorn main:app --reload", | |
| "common_mistake": "LangChain ์ฒด์ธ ๊ฐ์ ๋ฌด๊ฑฐ์ด ๊ฐ์ฒด๋ฅผ ์์ฒญ๋ง๋ค ์์ฑํ์ง ๋ง์ธ์. ๋ชจ๋ ๋ ๋ฒจ์์ ํ ๋ฒ ์ด๊ธฐํํ๊ฑฐ๋ `lifespan` ์ด๋ฒคํธ๋ก ์ฑ ์์ ์ ๋ก๋ํ์ธ์.", | |
| "keywords": ["fastapi", "uvicorn", "pydantic", "async", "REST API", "endpoint", "lifespan"], | |
| "source_id": "official-docs-fastapi", | |
| "details": [ | |
| "**Pydantic**: ์์ฒญ/์๋ต ์คํค๋ง๋ฅผ `BaseModel`๋ก ์ ์ํ๋ฉด ์๋ ๊ฒ์ฆ, OpenAPI ๋ฌธ์(`/docs`), JSON ์ง๋ ฌํ๊ฐ ๋ฌด๋ฃ๋ก ์ ๊ณต๋ฉ๋๋ค.", | |
| "**์คํธ๋ฆฌ๋ฐ ์๋ต**: `StreamingResponse`์ async generator๋ก LLM ์ถ๋ ฅ์ Server-Sent Events(SSE)๋ก ์คํธ๋ฆฌ๋ฐํ ์ ์์ต๋๋ค.", | |
| "**lifespan**: `@asynccontextmanager`๋ก ์ฑ ์์ ์ ๋ชจ๋ธยทDB ์ฐ๊ฒฐ์ ์ด๊ธฐํํ๊ณ ์ข ๋ฃ ์ ์ ๋ฆฌํ๋ ํจํด. FastAPI 0.95+ ๊ถ์ฅ ๋ฐฉ์์ ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-langsmith", | |
| "certification": "Docs Study", | |
| "title": "LangSmith โ LLM ์ถ์ & ํ๊ฐ", | |
| "level": "์ค๊ธ", | |
| "related_practices": ["docs-lab-13"], | |
| "summary": "LangSmith๋ LangChain ํ์ดํ๋ผ์ธ์ ๋ชจ๋ LLM ํธ์ถ, ํ๋กฌํํธ, ์๋ต, ์ง์ฐ์๊ฐ์ ์๋ ์ถ์ ํฉ๋๋ค. ๋ฒ๊ทธ ๋๋ฒ๊น , ํ๋กฌํํธ ๋น๊ต, ํ๊ฐ ๋ฐ์ดํฐ์ ๊ด๋ฆฌ๋ฅผ ํ ๊ณณ์์ ํฉ๋๋ค.", | |
| "example": "import os\nos.environ['LANGCHAIN_TRACING_V2'] = 'true'\nos.environ['LANGCHAIN_API_KEY'] = 'ls__...'\nos.environ['LANGCHAIN_PROJECT'] = 'my-rag-app'\n\n# ์ดํ LangChain ์ฝ๋๋ ์๋์ผ๋ก ์ถ์ ๋จ\nresult = chain.invoke({'question': '์ง๋ฌธ'})", | |
| "common_mistake": "์ถ์ ํ์ฑํ๋ ํ๊ฒฝ๋ณ์ 3๊ฐ(`TRACING_V2=true`, `API_KEY`, `PROJECT`)๊ฐ ๋ชจ๋ ์์ด์ผ ํฉ๋๋ค. ํ๋๋ผ๋ ๋น ์ง๋ฉด ์กฐ์ฉํ ์ถ์ ์ด ์ ๋ฉ๋๋ค.", | |
| "keywords": ["langsmith", "tracing", "LangChain", "debugging", "evaluation", "dataset", "prompt"], | |
| "source_id": "official-docs-langchain", | |
| "details": [ | |
| "**Run ํธ๋ ์ด์ค**: ์ฒด์ธ ์คํ๋ง๋ค tree ํํ๋ก ๊ฐ ๋จ๊ณ์ ์ ์ถ๋ ฅยทํ ํฐ ์ยท์ง์ฐ์๊ฐ์ ๊ธฐ๋กํฉ๋๋ค. ์ด๋ ๋จ๊ณ์์ ์ค๋ฅ๊ฐ ๋ฌ๋์ง ์ฆ์ ํ์ ํ ์ ์์ต๋๋ค.", | |
| "**๋ฐ์ดํฐ์ & ํ๊ฐ**: ํ๋ก๋์ ์ค๋ฅ ์ผ์ด์ค๋ฅผ Dataset์ผ๋ก ์ ์ฅ โ Evaluator(LLM-as-judge ๋ฑ)๋ก ์๋ ํ๊ฐ โ CI์ ํตํฉํ๋ ํ๋ฆ์ ์ง์ํฉ๋๋ค.", | |
| "**Playground**: LangSmith UI์์ ํน์ Run์ ํ๋กฌํํธ๋ฅผ ๋ฐ๋ก ์์ ํด ์ฌ์คํ ๊ฐ๋ฅ. ํ๋กฌํํธ ์์ง๋์ด๋ง ๋ฐ๋ณต์ ์ ์ฉํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-guardrails", | |
| "certification": "Docs Study", | |
| "title": "Guardrails AI โ LLM ์ถ๋ ฅ ๊ฒ์ฆ", | |
| "level": "์ค๊ธ", | |
| "related_practices": ["docs-lab-14"], | |
| "summary": "Guardrails AI๋ LLM ์ ๋ ฅ/์ถ๋ ฅ์ ๊ฒ์ฆ ๊ท์น(Guard)์ ์ ์ฉํฉ๋๋ค. ์ ํด ์ฝํ ์ธ ์ฐจ๋จ, JSON ์คํค๋ง ๊ฐ์ , PII ๋ง์คํน ๋ฑ ํ๋ก๋์ LLM ์ฑ์ ์์ ์ฅ์น ์ญํ ์ ํฉ๋๋ค.", | |
| "example": "from guardrails import Guard\nfrom guardrails.hub import ToxicLanguage\n\nguard = Guard().use(ToxicLanguage(threshold=0.5, on_fail='exception'))\n\nresult = guard(\n llm_api=openai.chat.completions.create,\n prompt='์ฌ์ฉ์ ์ ๋ ฅ: {{user_input}}',\n user_input=user_message\n)", | |
| "common_mistake": "Guard๋ LLM ํธ์ถ์ ๋ํํ๋ฏ๋ก ์๋ต ์๊ฐ์ด ์ฆ๊ฐํฉ๋๋ค. ๋ชจ๋ ์์ฒญ์ heavy Guard๋ฅผ ๊ฑธ๋ฉด ์ง์ฐ์ด ์ปค์ง๋, ์ ๋ ฅ ๊ฒ์ฆ๊ณผ ์ถ๋ ฅ ๊ฒ์ฆ์ ๋ถ๋ฆฌํด ํ์ํ ๊ฒ๋ง ์ ์ฉํ์ธ์.", | |
| "keywords": ["guardrails", "guard", "validation", "toxic", "PII", "JSON schema", "on_fail", "safety"], | |
| "source_id": "official-docs-guardrails", | |
| "details": [ | |
| "**Guard ํ๋ธ**: `guardrails hub install hub://...`์ผ๋ก ์ปค๋ฎค๋ํฐ Guard๋ฅผ ์ค์นํฉ๋๋ค. ToxicLanguage, ValidJson, DetectPII, RegexMatch ๋ฑ ์์ญ ๊ฐ์ง๊ฐ ์์ต๋๋ค.", | |
| "**on_fail ๋์**: `'exception'`(์์ธ ๋ฐ์), `'reask'`(LLM์ ์ฌ์์ฒญ), `'fix'`(์๋ ์์ ), `'noop'`(ํต๊ณผ) ์ค ์ ํํฉ๋๋ค.", | |
| "**๊ตฌ์กฐํ ์ถ๋ ฅ**: `Guard.from_pydantic(OutputModel)`์ผ๋ก LLM์ด ํญ์ ์ง์ ํ ์คํค๋ง์ JSON์ ๋ฐํํ๋๋ก ๊ฐ์ ํ ์ ์์ต๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-gradio", | |
| "certification": "Docs Study", | |
| "title": "Gradio โ ML ๋ฐ๋ชจ UI", | |
| "level": "์ค๊ธ", | |
| "related_practices": ["docs-lab-22"], | |
| "summary": "Gradio๋ ML ๋ชจ๋ธ ๋ฐ๋ชจ๋ฅผ ๋ช ์ค๋ก ๋ง๋๋ UI ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค. `gr.Interface`๋ก ํจ์๋ฅผ ๊ฐ์ธ๋ฉด ์ฆ์ ์น UI๊ฐ ์๊ธฐ๊ณ , HuggingFace Spaces์ ๋ค์ดํฐ๋ธ ํตํฉ๋ฉ๋๋ค.", | |
| "example": "import gradio as gr\n\ndef chat(message, history):\n response = chain.invoke(message)\n return response\n\ndemo = gr.ChatInterface(\n fn=chat,\n title='RAG ์ฑ๋ด',\n examples=['๋ฌธ์ ์์ฝํด์ค', '์ฃผ์ ํค์๋๋?']\n)\ndemo.launch()", | |
| "common_mistake": "Streamlit๊ณผ ๋ฌ๋ฆฌ Gradio๋ ํจ์ ๋จ์๋ก UI๋ฅผ ์์ฑํฉ๋๋ค. ๋ณต์กํ ์ํ ๊ด๋ฆฌ๋ `gr.State()`๋ก, ์ฌ๋ฌ ์ปดํฌ๋ํธ๋ฅผ ์กฐํฉํ ๋๋ `gr.Blocks()` ์ปจํ ์คํธ๋ฅผ ์๋๋ค.", | |
| "keywords": ["gradio", "Interface", "Blocks", "ChatInterface", "State", "HuggingFace", "demo"], | |
| "source_id": "official-docs-gradio", | |
| "details": [ | |
| "**Interface vs Blocks**: `gr.Interface`๋ ์ ๋ ฅโํจ์โ์ถ๋ ฅ ๋จ์ ๊ตฌ์กฐ, `gr.Blocks`๋ ๋ ์ด์์๊ณผ ์ด๋ฒคํธ๋ฅผ ์์ ๋กญ๊ฒ ๊ตฌ์ฑ. LLM ์ฑ๋ด์๋ `gr.ChatInterface`๊ฐ ๊ฐ์ฅ ์ ํฉํฉ๋๋ค.", | |
| "**์คํธ๋ฆฌ๋ฐ**: `gr.ChatInterface(fn=chat)`์์ `chat`์ generator ํจ์๋ก ๋ง๋ค๊ณ `yield`๋ก ํ ํฐ์ ๋ด๋ณด๋ด๋ฉด ์๋์ผ๋ก ์คํธ๋ฆฌ๋ฐ UI๊ฐ ๋ฉ๋๋ค.", | |
| "**HF Spaces ํตํฉ**: `demo.launch()`๋ง ํ๋ฉด HF Spaces Gradio SDK๋ก ์ฆ์ ๋ฐฐํฌ๋ฉ๋๋ค. ๋ณ๋ ์๋ฒ ์ค์ ์์ด `sdk: gradio`๋ง README์ ์ ์ธํ๋ฉด ๋ฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-chroma", | |
| "certification": "Docs Study", | |
| "title": "Chroma โ ์์ ๋ฒกํฐ DB", | |
| "level": "์ค๊ธ", | |
| "related_practices": ["docs-chroma-1", "docs-chroma-2"], | |
| "summary": "Chroma๋ ์ฌ์์ํด๋ ๋ฐ์ดํฐ๊ฐ ์ ์ง๋๋ ์คํ์์ค ๋ฒกํฐ DB์ ๋๋ค. FAISS๋ `save_local()`์ ์ง์ ํธ์ถํด์ผ ํ์ง๋ง, Chroma๋ `persist_directory`๋ง ์ง์ ํ๋ฉด ์๋์ผ๋ก ๋ก์ปฌ DB์ ์ ์ฅํฉ๋๋ค.", | |
| "example": "from langchain_chroma import Chroma\n\n# ์์ฑ & ์๋ ์ ์ฅ\ndb = Chroma.from_documents(\n chunks,\n embeddings,\n persist_directory='./chroma_db'\n)\n\n# ๋ค์ ์คํ ์ โ ์๋ฒ ๋ฉ ์ฌ๊ณ์ฐ ์์ด ๋ก๋\ndb = Chroma(\n persist_directory='./chroma_db',\n embedding_function=embeddings\n)", | |
| "common_mistake": "FAISS์ฒ๋ผ `save_local()`์ ๋ณ๋๋ก ํธ์ถํ ํ์๊ฐ ์์ต๋๋ค. `persist_directory`๋ฅผ ์ง์ ํ๋ฉด ์๋ ์ ์ฅ๋ฉ๋๋ค. ๋จ, `persist_directory`๋ฅผ ์๋ตํ๋ฉด ์ธ๋ฉ๋ชจ๋ฆฌ๋ก๋ง ๋์ํฉ๋๋ค.", | |
| "keywords": ["Chroma", "persist_directory", "from_documents", "collection", "chromadb", "์์"], | |
| "source_id": "official-docs-chromadb", | |
| "details": [ | |
| "**FAISS vs Chroma**: FAISS๋ ์ธ๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฐ์ผ๋ก `save_local()`๋ก ์๋ ์ ์ฅํด์ผ ํฉ๋๋ค. Chroma๋ `persist_directory`๋ง ์ง์ ํ๋ฉด SQLite ๊ธฐ๋ฐ ๋ก์ปฌ DB์ ์๋ ์ ์ฅ๋ฉ๋๋ค.", | |
| "**์ปฌ๋ ์ **: Chroma๋ ๋ฐ์ดํฐ๋ฅผ ์ปฌ๋ ์ ๋จ์๋ก ๊ด๋ฆฌํฉ๋๋ค. `collection_name` ํ๋ผ๋ฏธํฐ๋ก ์ฌ๋ฌ ๋ฌธ์ ์ธํธ๋ฅผ ๋ถ๋ฆฌํด ์ ์ฅํ๊ณ ๊ฐ๋ณ๋ก ๊ฒ์ํ ์ ์์ต๋๋ค.", | |
| "**๋ฉํ๋ฐ์ดํฐ ํํฐ๋ง**: `db.similarity_search(query, filter={\"source\": \"file.pdf\"})`์ฒ๋ผ ๋ฉํ๋ฐ์ดํฐ ์กฐ๊ฑด์ผ๋ก ๊ฒ์ ๋ฒ์๋ฅผ ์ ํํ ์ ์์ต๋๋ค. FAISS๋ ์ง์ํ์ง ์๋ ๊ธฐ๋ฅ์ ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-sentence-transformers", | |
| "certification": "Docs Study", | |
| "title": "sentence-transformers โ ๋ก์ปฌ ์๋ฒ ๋ฉ", | |
| "level": "์ค๊ธ", | |
| "related_practices": ["docs-embed-1"], | |
| "summary": "sentence-transformers๋ HuggingFace ์๋ฒ ๋ฉ ๋ชจ๋ธ์ ๋ก์ปฌ์์ ์คํํฉ๋๋ค. OpenAI API ์์ด ์์ ๋ก์ปฌ RAG๋ฅผ ๊ตฌ์ฑํ ์ ์๊ณ , ํ๊ตญ์ด ํนํ ๋ชจ๋ธ๋ ์ ํํ ์ ์์ต๋๋ค.", | |
| "example": "from langchain_huggingface import HuggingFaceEmbeddings\n\nembeddings = HuggingFaceEmbeddings(\n model_name='sentence-transformers/all-MiniLM-L6-v2'\n)\n\n# ์๋ฒ ๋ฉ ๋ฒกํฐ ์์ฑ\nvector = embeddings.embed_query('ํ์ด์ฌ์ด ๋ญ์ผ?')\nprint(len(vector)) # 384์ฐจ์\n\n# Chroma์ ํจ๊ป\ndb = Chroma.from_documents(chunks, embeddings, persist_directory='./db')", | |
| "common_mistake": "์ฒซ ์คํ ์ ๋ชจ๋ธ ํ์ผ์ ๋ค์ด๋ก๋ํ๋ฏ๋ก ๋๋ฆฝ๋๋ค. Streamlit ์ฑ์์๋ `@st.cache_resource`๋ก ๊ฐ์ธ ํ ๋ฒ๋ง ๋ก๋ํ์ธ์. ์๋ฒ ๋ฉ ๋ชจ๋ธ์ ์ค๊ฐ์ ๋ฐ๊พธ๋ฉด ๊ธฐ์กด VectorStore์ ํธํ๋์ง ์์ ์ ์ฒด ์ฌ์ธ๋ฑ์ฑ์ด ํ์ํฉ๋๋ค.", | |
| "keywords": ["HuggingFaceEmbeddings", "sentence-transformers", "all-MiniLM-L6-v2", "embed_query", "๋ก์ปฌ ์๋ฒ ๋ฉ", "384์ฐจ์"], | |
| "source_id": "official-docs-huggingface", | |
| "details": [ | |
| "**๋ชจ๋ธ ์ ํ**: `all-MiniLM-L6-v2`๋ ๋น ๋ฅด๊ณ ๊ฒฝ๋(384์ฐจ์), `all-mpnet-base-v2`๋ ํ์ง์ด ๋ ๋์ง๋ง ๋๋ฆฝ๋๋ค. ํ๊ตญ์ด๊ฐ ๋ง๋ค๋ฉด `jhgan/ko-sroberta-multitask` ๊ฐ์ ํ๊ตญ์ด ํนํ ๋ชจ๋ธ์ ์๋๋ค.", | |
| "**OpenAI vs ๋ก์ปฌ**: OpenAI `text-embedding-3-small`์ ํ์ง์ด ๋์ง๋ง API ๋น์ฉ์ด ๋ฐ์ํฉ๋๋ค. ๋ก์ปฌ ์๋ฒ ๋ฉ์ ๋ฌด๋ฃ์ด๋ GPU ์์ด๋ ๋์ฉ๋์์ ๋๋ฆฝ๋๋ค.", | |
| "**์ฐจ์ ๊ณ ์ ์ฃผ์**: ํ ๋ฒ ์๋ฒ ๋ฉํ ๋ชจ๋ธ์ ๋ฐ๊พธ๋ฉด ๊ธฐ์กด ์ธ๋ฑ์ค์ ํธํ๋์ง ์์ต๋๋ค. ์ ๋ชจ๋ธ๋ก ์ ์ฒด ์ธ๋ฑ์ค๋ฅผ ์ฌ์์ฑํด์ผ ํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-ragas", | |
| "certification": "Docs Study", | |
| "title": "Ragas โ RAG ํ์ง ์๋ ํ๊ฐ", | |
| "level": "์ค๊ธ", | |
| "related_practices": ["docs-ragas-1", "docs-ragas-2"], | |
| "summary": "Ragas๋ RAG ์์คํ ์ ํ์ง์ ์๋์ผ๋ก ์์นํํฉ๋๋ค. Faithfulness(ํ๊ฐ ์๋๊ฐ), Answer Relevancy(์ง๋ฌธ๊ณผ ๋ง๋ ๋ต์ธ๊ฐ), Context Precision(๊ด๋ จ ๋ฌธ์๋ฅผ ์ ์ฐพ์๋๊ฐ)์ LLM-as-judge๋ก ๊ณ์ฐํฉ๋๋ค.", | |
| "example": "from ragas import evaluate\nfrom ragas.metrics import faithfulness, answer_relevancy, context_precision\nfrom datasets import Dataset\n\ndata = {\n 'question': ['LangChain์ด ๋ญ์ผ?'],\n 'answer': ['LangChain์ LLM ์ฑ ํ๋ ์์ํฌ์ ๋๋ค.'],\n 'contexts': [['LangChain์ LLM ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ์ํ ํ๋ ์์ํฌ์ ๋๋ค.']],\n 'ground_truth': ['LangChain์ LLM ์ฑ ๊ฐ๋ฐ ํ๋ ์์ํฌ์ ๋๋ค.']\n}\n\ndataset = Dataset.from_dict(data)\nresult = evaluate(dataset, metrics=[faithfulness, answer_relevancy, context_precision])\nprint(result)", | |
| "common_mistake": "Ragas๋ ํ๊ฐ์ LLM์ ์ฌ์ฉํฉ๋๋ค. ๊ธฐ๋ณธ์ผ๋ก OpenAI GPT๋ฅผ ์๋๋ค. `evaluate(..., llm=your_llm, embeddings=your_embeddings)`๋ก ๋ค๋ฅธ ๋ชจ๋ธ์ ์ง์ ํ ์ ์์ต๋๋ค.", | |
| "keywords": ["ragas", "evaluate", "faithfulness", "answer_relevancy", "context_precision", "LLM-as-judge", "Dataset"], | |
| "source_id": "official-docs-ragas", | |
| "details": [ | |
| "**3๊ฐ์ง ํต์ฌ ๋ฉํธ๋ฆญ**: Faithfulness(๋ต๋ณ์ด ๊ฒ์๋ ์ปจํ ์คํธ์ ๊ทผ๊ฑฐํ๋๊ฐ โ ํ๊ฐ ํ์ง), Answer Relevancy(๋ต๋ณ์ด ์ง๋ฌธ๊ณผ ๊ด๋ จ ์๋๊ฐ), Context Precision(๊ด๋ จ ๋ฌธ์๊ฐ ์์ k๊ฐ ์์ ์๋๊ฐ).", | |
| "**MLflow ์ฐ๋**: `result.to_pandas()`๋ก DataFrame ๋ณํ ํ `mlflow.log_metrics()`๋ก ๊ธฐ๋กํ๋ฉด chunk_size, k ํ๋ผ๋ฏธํฐ๋ณ ํ์ง ๋ณํ๋ฅผ ์ถ์ ํ ์ ์์ต๋๋ค.", | |
| "**ground_truth ์์ด๋ ๊ฐ๋ฅ**: `ground_truth`๊ฐ ์์ผ๋ฉด faithfulness, answer_relevancy๋ง ๊ณ์ฐํฉ๋๋ค. Answer Correctness ๋ฉํธ๋ฆญ์ ground_truth๊ฐ ํ์ํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-summarization", | |
| "certification": "Docs Study", | |
| "title": "LangChain ์์ฝ ์ฒด์ธ โ map_reduce & stuff", | |
| "level": "์ค๊ธ", | |
| "related_practices": ["docs-news-1", "docs-news-2"], | |
| "summary": "LangChain์ `load_summarize_chain`์ ๊ธด ๋ฌธ์๋ฅผ LLM ์ปจํ ์คํธ ํ๊ณ ๋ด์์ ์์ฝํ๋ ์ฒด์ธ์ ๋ง๋ญ๋๋ค. ๋ฌธ์๊ฐ ์งง์ผ๋ฉด `stuff`, ๊ธธ๋ฉด `map_reduce` ๋ฐฉ์์ ์๋๋ค.", | |
| "example": "from langchain.chains.summarize import load_summarize_chain\nfrom langchain_core.documents import Document\n\n# map_reduce: ๊ฐ ์ฒญํฌ ์์ฝ โ ์ต์ข ์์ฝ\nchain = load_summarize_chain(llm, chain_type='map_reduce')\n\ndocs = [Document(page_content=article) for article in articles]\nresult = chain.invoke(docs)\nprint(result['output_text'])", | |
| "common_mistake": "`stuff` ๋ฐฉ์์ ๋ชจ๋ ๋ฌธ์๋ฅผ ํ๋์ ํ๋กฌํํธ์ ๋ฃ์ต๋๋ค. ๋ฌธ์๊ฐ LLM ์ปจํ ์คํธ ์ฐฝ๋ณด๋ค ํฌ๋ฉด ์ค๋ฅ๊ฐ ๋ฉ๋๋ค. ์ฌ๋ฌ ๋ฌธ์๋ ๊ธด ๋ฌธ์๋ ํญ์ `map_reduce`๋ฅผ ๋จผ์ ๊ณ ๋ คํ์ธ์.", | |
| "keywords": ["load_summarize_chain", "map_reduce", "stuff", "refine", "output_text", "์์ฝ"], | |
| "source_id": "official-docs-langchain", | |
| "details": [ | |
| "**chain_type ๋น๊ต**: `stuff`(์ ์ฒด ํ ๋ฒ), `map_reduce`(์ฒญํฌ๋ณ ์์ฝ ํ ํฉ์นจ), `refine`(์ด์ ์์ฝ์ ๋ค์ ์ฒญํฌ์ ๋ฐ์). ํ์ง์ refine > map_reduce > stuff์ด์ง๋ง ์๋๋ ๋ฐ๋์ ๋๋ค.", | |
| "**map_prompt / combine_prompt**: `load_summarize_chain`์ `map_prompt`์ `combine_prompt`๋ฅผ ์ง์ ํด ์์ฝ ์ง์๋ฌธ์ ์ปค์คํฐ๋ง์ด์งํ ์ ์์ต๋๋ค.", | |
| "**๋น๋๊ธฐ**: `chain.ainvoke(docs)`๋ก ๋น๋๊ธฐ ์์ฒญ์ด ๊ฐ๋ฅํฉ๋๋ค. ์ฌ๋ฌ ๋ด์ค ๊ธฐ์ฌ๋ฅผ ๋ณ๋ ฌ ์์ฝํ ๋ `asyncio.gather`์ ํจ๊ป ์ฐ๋ฉด ์๋๊ฐ ํฌ๊ฒ ๊ฐ์ ๋ฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-sql-chain", | |
| "certification": "Docs Study", | |
| "title": "LangChain Text-to-SQL โ ์์ฐ์ด๋ก DB ์กฐํ", | |
| "level": "์ค๊ธ", | |
| "related_practices": ["docs-sql-1", "docs-sql-2"], | |
| "summary": "LangChain์ `create_sql_query_chain`์ ์์ฐ์ด ์ง๋ฌธ์ SQL ์ฟผ๋ฆฌ๋ก ๋ณํํฉ๋๋ค. `SQLDatabase`๋ก DB ์คํค๋ง๋ฅผ ์๋์ผ๋ก ์ฝ์ด LLM์๊ฒ ์ปจํ ์คํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.", | |
| "example": "from langchain_community.utilities import SQLDatabase\nfrom langchain.chains import create_sql_query_chain\n\ndb = SQLDatabase.from_uri('sqlite:///./mydb.db')\nchain = create_sql_query_chain(llm, db)\n\nsql = chain.invoke({'question': '๊ฐ์ฅ ๋ง์ด ํ๋ฆฐ ์ํ 5๊ฐ๋?'})\nprint(sql) # SELECT product, SUM(quantity) ...\n\nresult = db.run(sql)\nprint(result)", | |
| "common_mistake": "LLM์ด ์์ฑํ SQL์ ๋ฐ๋ก `db.run()`์ ๋๊ธฐ๋ฉด ์๋ชป๋ ์ฟผ๋ฆฌ๊ฐ ์คํ๋ฉ๋๋ค. Guardrails์ `ValidSQL`์ด๋ ๋ณ๋ ํ์ฑ์ผ๋ก ๊ฒ์ฆํ ๋ค ์คํํ์ธ์.", | |
| "keywords": ["SQLDatabase", "create_sql_query_chain", "from_uri", "db.run", "Text-to-SQL", "sqlite"], | |
| "source_id": "official-docs-langchain", | |
| "details": [ | |
| "**์คํค๋ง ์๋ ์ฃผ์ **: `SQLDatabase`๋ ์ฐ๊ฒฐ๋ DB์ ํ ์ด๋ธ๋ช ๊ณผ ์ปฌ๋ผ ์ ๋ณด๋ฅผ ์๋์ผ๋ก ํ๋กฌํํธ์ ์ฃผ์ ํฉ๋๋ค. LLM์ด ์กด์ฌํ๋ ํ ์ด๋ธ/์ปฌ๋ผ๋ง ์ฐธ์กฐํ๋๋ก ์ ๋ํฉ๋๋ค.", | |
| "**QuerySQLDatabaseTool**: SQL ์์ฑ๊ณผ ์คํ์ ํ๋์ ํด๋ก ๋ฌถ์ ๊ณ ์์ค ์ธํฐํ์ด์ค. Agent์ ๋ฑ๋กํ๋ฉด LLM์ด ํ์ํ ๋ DB๋ฅผ ์ง์ ์กฐํํ ์ ์์ต๋๋ค.", | |
| "**๋ณด์ ์ฃผ์**: `db.run()`์ ์ค์ DB๋ฅผ ์์ ํ ์ ์์ต๋๋ค. ์ฝ๊ธฐ ์ ์ฉ ์ฌ์ฉ์ ๊ณ์ ์ผ๋ก ์ฐ๊ฒฐํ๊ฑฐ๋ SELECT๋ง ํ์ฉํ๋ wrapper๋ฅผ ๋๋ ๊ฒ์ด ์์ ํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-langgraph", | |
| "certification": "Docs Study", | |
| "title": "LangGraph โ ์ํ ๊ธฐ๋ฐ ์์ด์ ํธ ์ํฌํ๋ก", | |
| "level": "๊ณ ๊ธ", | |
| "related_practices": ["docs-graph-1", "docs-graph-2"], | |
| "summary": "LangGraph๋ LLM ์์ด์ ํธ๋ฅผ ๊ทธ๋ํ(๋ ธ๋ + ์ฃ์ง)๋ก ์ ์ํฉ๋๋ค. ๋จ์ ์ฒด์ธ์ AโBโC์ ๋ฌ๋ฆฌ ์กฐ๊ฑด ๋ถ๊ธฐ, ๋ฃจํ, ๋ณ๋ ฌ ์คํ์ด ๊ฐ๋ฅํด ์ค์ ์์ด์ ํธ ํ๋์ ํํํฉ๋๋ค.", | |
| "example": "from langgraph.graph import StateGraph, END\nfrom typing import TypedDict\n\nclass State(TypedDict):\n question: str\n answer: str\n\ndef retrieve(state: State) -> State:\n return {\"answer\": str(retriever.invoke(state[\"question\"]))}\n\ndef generate(state: State) -> State:\n return {\"answer\": chain.invoke(state)}\n\ngraph = StateGraph(State)\ngraph.add_node(\"retrieve\", retrieve)\ngraph.add_node(\"generate\", generate)\ngraph.set_entry_point(\"retrieve\")\ngraph.add_edge(\"retrieve\", \"generate\")\ngraph.add_edge(\"generate\", END)\n\napp = graph.compile()\nresult = app.invoke({\"question\": \"LangChain์ด ๋ญ์ผ?\"})", | |
| "common_mistake": "LangGraph๋ LangChain ์ฒด์ธ์ด ์๋๋๋ค. `graph.compile()` ํ `app.invoke()`๋ฅผ ์๋๋ค. State TypedDict๋ฅผ ์ ํํ ์ ์ํ์ง ์์ผ๋ฉด ๋ ธ๋์์ ํค ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.", | |
| "keywords": ["LangGraph", "StateGraph", "State", "node", "edge", "compile", "conditional_edges", "END"], | |
| "source_id": "official-docs-langgraph", | |
| "details": [ | |
| "**๋ ธ๋ vs ์ฒด์ธ**: ์ฒด์ธ์ AโBโC ์ ํ. ๊ทธ๋ํ๋ A์์ ์กฐ๊ฑด์ ๋ฐ๋ผ B ๋๋ C๋ก ๋ถ๊ธฐ, D์์ A๋ก ๋ฃจํ ๋ฑ ๋ณต์กํ ํ๋ฆ์ ํํํ ์ ์์ต๋๋ค.", | |
| "**conditional_edges**: `graph.add_conditional_edges('judge', router_fn, {'retry': 'retrieve', 'done': END})`์ฒ๋ผ ๋ ธ๋ ๋ฐํ๊ฐ์ ๋ฐ๋ผ ๋ค์ ๋ ธ๋๋ฅผ ๋์ ์ผ๋ก ๊ฒฐ์ ํฉ๋๋ค. ReAct ์์ด์ ํธ์ ํต์ฌ์ ๋๋ค.", | |
| "**checkpointer**: `MemorySaver`๋ฅผ `graph.compile(checkpointer=...)`์ ๋๊ธฐ๋ฉด ์คํ ์ํ๋ฅผ ์ ์ฅํด ์ค๋จ ํ ์ฌ๊ฐ, ๋ฉํฐํด ๋ํ ์ ์ง๊ฐ ๊ฐ๋ฅํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-airflow", | |
| "certification": "Docs Study", | |
| "title": "Apache Airflow โ ์ํฌํ๋ก ์ค์ผ์คํธ๋ ์ด์ ", | |
| "level": "๊ณ ๊ธ", | |
| "related_practices": ["docs-lab-23"], | |
| "summary": "Airflow๋ DAG(Directed Acyclic Graph)๋ก ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ์ ์ ์ํ๊ณ ์ค์ผ์ค๋งยท๋ชจ๋ํฐ๋งํฉ๋๋ค. ML ํ์ดํ๋ผ์ธ(๋ฐ์ดํฐ ์์ง โ ์ ์ฒ๋ฆฌ โ ํ์ต โ ๋ฐฐํฌ)์ด๋ ๋ฌธ์ ์ฌ์ธ๋ฑ์ฑ ์๋ํ์ ์๋๋ค.", | |
| "example": "from airflow import DAG\nfrom airflow.operators.python import PythonOperator\nfrom datetime import datetime\n\ndef reindex():\n # ๋ฌธ์ ๋ก๋ โ ์๋ฒ ๋ฉ โ VectorStore ์ ๋ฐ์ดํธ\n pass\n\nwith DAG('daily_reindex', schedule='@daily', start_date=datetime(2024,1,1)) as dag:\n task = PythonOperator(task_id='reindex', python_callable=reindex)", | |
| "common_mistake": "DAG ํ์ผ์ Airflow ์ค์ผ์ค๋ฌ๊ฐ ์ฃผ๊ธฐ์ ์ผ๋ก ํ์ฑํฉ๋๋ค. ํ์ผ ์ต์์์ ๋ฌด๊ฑฐ์ด ์ฐ์ฐ(DB ์ฐ๊ฒฐ, ๋ชจ๋ธ ๋ก๋)์ ๋๋ฉด ํ์ฑ๋ง๋ค ์คํ๋ผ ์ค์ผ์ค๋ฌ๊ฐ ๋๋ ค์ง๋๋ค. ๋ฐ๋์ task ํจ์ ์์ ๋ฃ์ผ์ธ์.", | |
| "keywords": ["airflow", "DAG", "task", "operator", "schedule", "XCom", "pipeline", "orchestration"], | |
| "source_id": "official-docs-airflow", | |
| "details": [ | |
| "**Operator ์ข ๋ฅ**: `PythonOperator`(ํ์ด์ฌ ํจ์), `BashOperator`(์ ธ ๋ช ๋ น), `DockerOperator`(์ปจํ ์ด๋ ์คํ) ๋ฑ. ML ํ์ดํ๋ผ์ธ์ ์ฃผ๋ก PythonOperator๋ฅผ ์๋๋ค.", | |
| "**XCom**: task ๊ฐ ๋ฐ์ดํฐ ์ ๋ฌ ๋ฉ์ปค๋์ฆ. `ti.xcom_push(key, value)` / `ti.xcom_pull(task_ids, key)`๋ก ์๋ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํฉ๋๋ค. ๋์ฉ๋์ S3/GCS ๊ฒฝ๋ก๋ฅผ ์ ๋ฌํ๋ ๋ฐฉ์์ ์๋๋ค.", | |
| "**์์กด์ฑ**: `task_a >> task_b >> task_c` ๋๋ `task_a.set_downstream(task_b)` ๋ก ์คํ ์์๋ฅผ ์ ์ํฉ๋๋ค. ๋ณ๋ ฌ ์คํ์ `[task_b, task_c] >> task_d` ํํ๋ก ํํํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-mlflow", | |
| "certification": "Docs Study", | |
| "title": "MLflow โ ์คํ ์ถ์ & ๋ชจ๋ธ ๊ด๋ฆฌ", | |
| "level": "๊ณ ๊ธ", | |
| "related_practices": ["docs-lab-15"], | |
| "summary": "MLflow๋ ML ์คํ์ ํ๋ผ๋ฏธํฐ, ๋ฉํธ๋ฆญ, ์ํฐํฉํธ๋ฅผ ์ถ์ ํ๊ณ ๋ชจ๋ธ์ ๋ฒ์ ๊ด๋ฆฌํฉ๋๋ค. RAG์์ chunk_size, k, ์๋ฒ ๋ฉ ๋ชจ๋ธ ๋ฑ ํ๋ผ๋ฏธํฐ ์คํ ๊ฒฐ๊ณผ๋ฅผ ์ฒด๊ณ์ ์ผ๋ก ๋น๊ตํ ๋ ์๋๋ค.", | |
| "example": "import mlflow\n\nwith mlflow.start_run(run_name='rag-exp-1'):\n mlflow.log_param('chunk_size', 500)\n mlflow.log_param('k', 4)\n mlflow.log_metric('answer_relevance', 0.87)\n mlflow.log_metric('faithfulness', 0.92)\n mlflow.log_artifact('eval_results.json')", | |
| "common_mistake": "run์ `with mlflow.start_run()` ๋ธ๋ก์ผ๋ก ๊ฐ์ธ์ง ์์ผ๋ฉด ์ค์๋ก ์ด์ run์ ๋ก๊น ๋๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค. ํญ์ context manager๋ฅผ ์ฌ์ฉํ์ธ์.", | |
| "keywords": ["mlflow", "experiment", "run", "log_param", "log_metric", "artifact", "model registry"], | |
| "source_id": "official-docs-mlflow", | |
| "details": [ | |
| "**UI**: `mlflow ui` ๋ช ๋ น์ผ๋ก localhost:5000์์ ์คํ ๋น๊ต ๋์๋ณด๋๋ฅผ ์คํํฉ๋๋ค. ํ๋ผ๋ฏธํฐ๋ณ ๋ฉํธ๋ฆญ ์ถ์ด๋ฅผ ์๊ฐ์ ์ผ๋ก ๋น๊ตํ ์ ์์ต๋๋ค.", | |
| "**Model Registry**: `mlflow.log_model()`๋ก ๋ชจ๋ธ์ ์ ์ฅํ๊ณ `Staging`โ`Production` ๋จ๊ณ๋ฅผ ๊ด๋ฆฌํฉ๋๋ค. ๋ฐฐํฌ ์ `mlflow.pyfunc.load_model('models:/name/Production')`์ผ๋ก ๋ก๋ํฉ๋๋ค.", | |
| "**LangChain ํตํฉ**: `mlflow.langchain.autolog()`๋ฅผ ํ์ฑํํ๋ฉด ์ฒด์ธ ์คํ๋ง๋ค ํ๋ผ๋ฏธํฐ์ ๋ฉํธ๋ฆญ์ด ์๋ ๊ธฐ๋ก๋ฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-mcp", | |
| "certification": "Docs Study", | |
| "title": "MCP โ Model Context Protocol", | |
| "level": "๊ณ ๊ธ", | |
| "related_practices": ["docs-lab-24"], | |
| "summary": "MCP(Model Context Protocol)๋ LLM ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ธ๋ถ ๋๊ตฌยท๋ฐ์ดํฐ์์ค์ ํ์คํ๋ ๋ฐฉ์์ผ๋ก ์ฐ๊ฒฐํ๋ Anthropic ์คํ ํ๋กํ ์ฝ์ ๋๋ค. Claude Desktop์ด๋ Claude Code์ ๋ก์ปฌ MCP ์๋ฒ๋ฅผ ์ฐ๊ฒฐํ๋ฉด ํ์ผ ์์คํ , DB, ์ธ๋ถ API๋ฅผ LLM์ด ์ง์ ์ฌ์ฉํ ์ ์์ต๋๋ค.", | |
| "example": "# mcp_server.py (FastMCP ์ฌ์ฉ)\nfrom mcp.server.fastmcp import FastMCP\n\nmcp = FastMCP('my-server')\n\n@mcp.tool()\ndef search_docs(query: str) -> str:\n '''๋ฒกํฐ DB์์ ๊ด๋ จ ๋ฌธ์๋ฅผ ๊ฒ์ํฉ๋๋ค.'''\n results = retriever.invoke(query)\n return '\\n'.join(r.page_content for r in results)\n\nmcp.run(transport='stdio')", | |
| "common_mistake": "MCP ์๋ฒ๋ stdio ๋๋ SSE transport ์ค ํ๋๋ฅผ ์ ํํฉ๋๋ค. Claude Desktop์ stdio(๋ก์ปฌ ํ๋ก์ธ์ค), Claude Code๋ SSE(HTTP ์๋ฒ) ๋ฐฉ์์ ์ฃผ๋ก ์๋๋ค. transport ๋ถ์ผ์น ์ ์ฐ๊ฒฐ์ด ์ ๋ฉ๋๋ค.", | |
| "keywords": ["MCP", "Model Context Protocol", "tool", "resource", "FastMCP", "stdio", "Claude", "agent"], | |
| "source_id": "official-docs-mcp", | |
| "details": [ | |
| "**3๊ฐ์ง ๊ธฐ๋ณธ ์์**: `tool`(LLM์ด ํธ์ถํ๋ ํจ์), `resource`(LLM์ด ์ฝ๋ ๋ฐ์ดํฐ), `prompt`(์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ํ๋กฌํํธ ํ ํ๋ฆฟ). ๋๋ถ๋ถ์ ์๋ฒ๋ `tool`๋ง ๊ตฌํํฉ๋๋ค.", | |
| "**Claude Desktop ์ฐ๊ฒฐ**: `~/Library/Application Support/Claude/claude_desktop_config.json`์ ์๋ฒ ๊ฒฝ๋ก์ ๋ช ๋ น์ด๋ฅผ ๋ฑ๋กํ๋ฉด ๋ํ ์ค ์๋์ผ๋ก ๋๊ตฌ๊ฐ ๋ณด์ ๋๋ค.", | |
| "**FastMCP**: Anthropic ๊ณต์ Python SDK์ ๊ณ ์์ค ๋ํผ. `@mcp.tool()` ๋ฐ์ฝ๋ ์ดํฐ๋ก ํจ์๋ฅผ ๋๊ตฌ๋ก ๋ฑ๋กํ๋ฉด ์คํค๋ง ์์ฑ, ์ ์ถ๋ ฅ ๊ฒ์ฆ์ด ์๋์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-litellm", | |
| "certification": "Docs Study", | |
| "title": "LiteLLM โ ์ฌ๋ฌ LLM์ ํ๋์ ์ธํฐํ์ด์ค๋ก", | |
| "level": "๊ณ ๊ธ", | |
| "related_practices": ["docs-litellm-1"], | |
| "summary": "LiteLLM์ OpenAI, Anthropic, Ollama, Gemini ๋ฑ 100๊ฐ ์ด์์ LLM ํ๋ก๋ฐ์ด๋๋ฅผ ๋์ผํ API ํ์์ผ๋ก ํธ์ถํฉ๋๋ค. ๋ชจ๋ธ์ ๋ฐ๊ฟ ๋ ์ฝ๋ ์์ ์์ด ๋ชจ๋ธ๋ช ๋ง ๋ณ๊ฒฝํ๋ฉด ๋ฉ๋๋ค.", | |
| "example": "from litellm import completion\n\n# Ollama ๋ก์ปฌ\nresponse = completion(\n model='ollama/llama3.2',\n messages=[{'role': 'user', 'content': '์๋ '}]\n)\n\n# OpenAI โ ์ฝ๋ ๋์ผ, ๋ชจ๋ธ๋ช ๋ง ๋ณ๊ฒฝ\nresponse = completion(\n model='gpt-4o-mini',\n messages=[{'role': 'user', 'content': '์๋ '}]\n)\n\nprint(response.choices[0].message.content)", | |
| "common_mistake": "๋ชจ๋ธ๋ช ํ์์ `'ํ๋ก๋ฐ์ด๋/๋ชจ๋ธ๋ช '`์ ๋๋ค. Ollama๋ `'ollama/llama3.2'`, Anthropic์ `'anthropic/claude-3-5-sonnet-20241022'`. OpenAI๋ง ์์ธ๋ก ์ ๋์ฌ ์์ด `'gpt-4o-mini'`์ฒ๋ผ ์๋๋ค.", | |
| "keywords": ["LiteLLM", "completion", "model", "provider", "๋ฒค๋ ๋ ๋ฆฝ", "OpenAI ํธํ", "ChatLiteLLM"], | |
| "source_id": "official-docs-litellm", | |
| "details": [ | |
| "**๋น์ฉ ์ถ์ **: `litellm.success_callback`์ผ๋ก ๊ฐ ํธ์ถ์ ํ ํฐ ์์ ์์ ๋น์ฉ์ ์๋ ๊ธฐ๋กํ ์ ์์ต๋๋ค. ์ฌ๋ฌ ๋ชจ๋ธ์ ์คํํ ๋ ๋น์ฉ ๋น๊ต์ ์ ์ฉํฉ๋๋ค.", | |
| "**LangChain ํตํฉ**: `from langchain_community.chat_models import ChatLiteLLM`์ผ๋ก LangChain ์ฒด์ธ์์ LiteLLM์ ์๋๋ค. LCEL ํ์ดํ๋ผ์ธ์ ๋ฐ๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค.", | |
| "**Fallback**: `completion(..., fallbacks=['gpt-4o-mini', 'ollama/llama3.2'])`์ฒ๋ผ ์ฃผ ๋ชจ๋ธ ์คํจ ์ ์๋์ผ๋ก ๋ฐฑ์ ๋ชจ๋ธ๋ก ์ ํํ๋ ๊ธฐ๋ฅ์ ์ง์ํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-chainlit", | |
| "certification": "Docs Study", | |
| "title": "Chainlit โ ์ฑ๋ด UI ํนํ ํ๋ ์์ํฌ", | |
| "level": "๊ณ ๊ธ", | |
| "related_practices": ["docs-chainlit-1"], | |
| "summary": "Chainlit์ LLM ์ฑ๋ด UI์ ํนํ๋ ํ๋ ์์ํฌ์ ๋๋ค. Streamlit๊ณผ ๋ฌ๋ฆฌ ์น์์ผ ๊ธฐ๋ฐ์ผ๋ก ๋์ํด ์คํธ๋ฆฌ๋ฐ ์๋ต, ํ์ผ ์ ๋ก๋, ๋ฉํฐ์คํ ์งํ ํ์๊ฐ ์์ฐ์ค๋ฝ์ต๋๋ค.", | |
| "example": "import chainlit as cl\n\n@cl.on_message\nasync def main(message: cl.Message):\n # ์คํธ๋ฆฌ๋ฐ ์๋ต\n msg = cl.Message(content='')\n async for chunk in chain.astream({'question': message.content}):\n await msg.stream_token(chunk)\n await msg.send()\n\n# ์คํ: chainlit run app.py", | |
| "common_mistake": "Chainlit์ `async` ๊ธฐ๋ฐ์ ๋๋ค. LangChain์ `chain.invoke()`(๋๊ธฐ)๋ฅผ ์ฐ๋ฉด ์ด๋ฒคํธ ๋ฃจํ๊ฐ ๋ธ๋กํน๋ฉ๋๋ค. ๋ฐ๋์ `chain.ainvoke()` ๋๋ `chain.astream()`์ ์ฌ์ฉํ์ธ์.", | |
| "keywords": ["chainlit", "on_message", "Message", "stream_token", "async", "astream", "on_chat_start"], | |
| "source_id": "official-docs-chainlit", | |
| "details": [ | |
| "**๋ฐ์ฝ๋ ์ดํฐ ๊ธฐ๋ฐ**: `@cl.on_chat_start`(์ธ์ ์์ ์ ์ฒด์ธ ์ด๊ธฐํ), `@cl.on_message`(๋ฉ์์ง ์์ ), `@cl.on_stop`(์คํธ๋ฆฌ๋ฐ ์ค๋จ)์ผ๋ก ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.", | |
| "**Step UI**: `async with cl.Step(name='๊ฒ์ ์ค...'):` ๋ธ๋ก์ผ๋ก ์์ด์ ํธ์ ๊ฐ ๋จ๊ณ(๊ฒ์, ์ถ๋ก ๋ฑ)๋ฅผ UI์ ์ค์๊ฐ์ผ๋ก ํผ์ณ ๋ณด์ฌ์ค๋๋ค. LangGraph ์์ด์ ํธ์ ํจ๊ป ์ฐ๋ฉด ๊ฐ๋ ฅํฉ๋๋ค.", | |
| "**ํ์ผ ์ ๋ก๋**: `@cl.on_message`์์ `message.elements`๋ก ์ฒจ๋ถ ํ์ผ์ ๋ฐ์ ์ ์์ต๋๋ค. PDF ์ ๋ก๋ โ ์ฆ์ RAG ์ธ๋ฑ์ฑ ํ๋ฆ์ ๋ช ์ค๋ก ๊ตฌํํฉ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-redis", | |
| "certification": "Docs Study", | |
| "title": "Redis โ ๋ํ ๋ฉ๋ชจ๋ฆฌ ์์ํ & LLM ์บ์ฑ", | |
| "level": "๊ณ ๊ธ", | |
| "related_practices": ["docs-redis-1"], | |
| "summary": "Redis๋ ์ธ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ ์ ์ฅ์๋ก LLM ์ฑ์์ ๋ํ ํ์คํ ๋ฆฌ ์์ํ์ LLM ์๋ต ์บ์ฑ์ ์๋๋ค. ์๋ฒ๋ฅผ ์ฌ์์ํด๋ ๋ํ๊ฐ ์ ์ง๋๊ณ , ๋์ผ ์ง๋ฌธ์ ๋ํ LLM ํธ์ถ ๋น์ฉ์ ์ ๊ฐํฉ๋๋ค.", | |
| "example": "from langchain_community.chat_message_histories import RedisChatMessageHistory\nfrom langchain_core.runnables.history import RunnableWithMessageHistory\n\ndef get_session_history(session_id: str):\n return RedisChatMessageHistory(\n session_id=session_id,\n url='redis://localhost:6379'\n )\n\nchain_with_history = RunnableWithMessageHistory(\n chain,\n get_session_history,\n input_messages_key='question',\n history_messages_key='chat_history'\n)", | |
| "common_mistake": "Redis ์๋ฒ๊ฐ ์คํ ์ค์ด์ง ์์ผ๋ฉด ์ฐ๊ฒฐ ์ค๋ฅ๊ฐ ๋ฉ๋๋ค. ๋ก์ปฌ ๊ฐ๋ฐ ์ `docker run -d -p 6379:6379 redis`๋ก ๋จผ์ Redis๋ฅผ ์คํํ์ธ์.", | |
| "keywords": ["Redis", "RedisChatMessageHistory", "session_id", "url", "์์ํ", "์บ์ฑ", "TTL"], | |
| "source_id": "official-docs-redis", | |
| "details": [ | |
| "**์ธ๋ฉ๋ชจ๋ฆฌ ๊ต์ฒด**: ๊ธฐ์กด `ChatMessageHistory`(์ฌ์์ ์ ์๋ฉธ)๋ฅผ `RedisChatMessageHistory`๋ก ๊ต์ฒดํ๋ฉด `get_session_history` ํจ์ ํ ์ค๋ง ๋ฐ๊ฟ๋ ์์์ฑ์ ์ป์ต๋๋ค.", | |
| "**TTL**: `RedisChatMessageHistory(session_id, url, ttl=3600)`์ผ๋ก 1์๊ฐ ํ ์๋ ๋ง๋ฃ๋ฉ๋๋ค. ๋ฌดํํ ์์ด๋ ํ์คํ ๋ฆฌ์ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํฉ๋๋ค.", | |
| "**LLM ์๋ต ์บ์ฑ**: `from langchain.cache import RedisCache; langchain.llm_cache = RedisCache(redis_client)`๋ก ๋์ผ ์ง๋ฌธ์ ๋ํ LLM ์๋ต์ ์บ์ํด ๋น์ฉ๊ณผ ์๋ต ์๊ฐ์ ์ค์ ๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-unstructured", | |
| "certification": "Docs Study", | |
| "title": "Unstructured โ PDFยทWordยท์ด๋ฏธ์ง ํ์ฑ", | |
| "level": "๊ณ ๊ธ", | |
| "related_practices": ["docs-unstructured-1"], | |
| "summary": "Unstructured๋ PDF, Word, Excel, PowerPoint, ์ด๋ฏธ์ง ๋ฑ ๋น์ ํ ๋ฌธ์๋ฅผ ํ ์คํธ๋ก ๋ณํํฉ๋๋ค. LangChain์ `UnstructuredFileLoader`์ ํตํฉ๋์ด ํ์ฅ์์ ์๊ด์์ด ๋์ผ ์ฝ๋๋ก RAG ํ์ดํ๋ผ์ธ์ ์ฐ๊ฒฐํฉ๋๋ค.", | |
| "example": "from langchain_community.document_loaders import UnstructuredFileLoader\n\n# ๋จ์ผ ํ์ผ โ ํ์ฅ์ ์๋ ๊ฐ์ง\nloader = UnstructuredFileLoader('./report.pdf')\ndocs = loader.load()\n\n# ํผํฉ ํ์ ๋๋ ํ ๋ฆฌ\nfrom langchain_community.document_loaders import DirectoryLoader\nloader = DirectoryLoader(\n './docs',\n glob='**/*',\n loader_cls=UnstructuredFileLoader\n)\ndocs = loader.load()", | |
| "common_mistake": "`pip install unstructured`๋ ๊ธฐ๋ณธ ์ค์น์ ๋๋ค. PDF์๋ `pip install unstructured[pdf]`, ์ด๋ฏธ์ง OCR์๋ `pip install unstructured[local-inference]`์ฒ๋ผ ๋ณ๋ extra๋ฅผ ์ค์นํด์ผ ํฉ๋๋ค.", | |
| "keywords": ["Unstructured", "UnstructuredFileLoader", "PDF", "Word", "OCR", "๋น์ ํ ๋ฌธ์", "elements"], | |
| "source_id": "official-docs-unstructured", | |
| "details": [ | |
| "**์๋ ํ์ผ ๊ฐ์ง**: ํ์ฅ์์ ๋ฐ๋ผ ์๋์ผ๋ก ์ ์ ํ ํ์๋ฅผ ์ ํํฉ๋๋ค. `.pdf`, `.docx`, `.pptx`, `.jpg`, `.eml` ๋ฑ์ ๋์ผ ์ฝ๋๋ก ์ฒ๋ฆฌํฉ๋๋ค.", | |
| "**์์ ๋ถ๋ฅ**: `mode='elements'`๋ก ๋ก๋ํ๋ฉด Title, NarrativeText, Table, Image ๋ฑ ์์ ํ์ ์ด ๋ฉํ๋ฐ์ดํฐ์ ์ ์ฅ๋ฉ๋๋ค. ํค๋๋ฅผ ์ฒญํฌ ๋ฉํ๋ฐ์ดํฐ๋ก ํ์ฉํ๊ฑฐ๋ ํ ์ด๋ธ๋ง ๋ฐ๋ก ์ถ์ถํ ๋ ์๋๋ค.", | |
| "**API vs ๋ก์ปฌ**: Unstructured Cloud API๋ ๊ณ ํ์ง OCR๊ณผ ๋ ์ด์์ ๋ถ์์ ์ ๊ณตํฉ๋๋ค. ๋ก์ปฌ์ ๋ฌด๋ฃ์ด๋ ์ด๋ฏธ์ง๋ ๋ณต์กํ ๋ ์ด์์์ PDF ํ์ง์ด ๋ฎ์ ์ ์์ต๋๋ค." | |
| ] | |
| }, | |
| { | |
| "id": "docs-conversation-memory", | |
| "certification": "Docs Study", | |
| "title": "LangChain ๋ํ ๋ฉ๋ชจ๋ฆฌ โ ๋ฉํฐํด ์ฑ๋ด", | |
| "level": "๊ณ ๊ธ", | |
| "related_practices": ["docs-lab-6", "docs-brain-1"], | |
| "summary": "RunnableWithMessageHistory๋ LangChain ์ฒด์ธ์ ๋ํ ํ์คํ ๋ฆฌ๋ฅผ ์๋์ผ๋ก ์ฃผ์ ํฉ๋๋ค. ๋งค ์์ฒญ๋ง๋ค ์ด์ ๋ํ๋ฅผ ์ง์ ๊ด๋ฆฌํ์ง ์์๋ session_id๋ง ๋๊ธฐ๋ฉด ํ์คํ ๋ฆฌ๊ฐ ์ ์ง๋ฉ๋๋ค.", | |
| "example": "from langchain_community.chat_message_histories import ChatMessageHistory\nfrom langchain_core.runnables.history import RunnableWithMessageHistory\n\nstore = {} # session_id โ ChatMessageHistory\n\ndef get_session_history(session_id: str):\n if session_id not in store:\n store[session_id] = ChatMessageHistory()\n return store[session_id]\n\nchain_with_history = RunnableWithMessageHistory(\n chain,\n get_session_history,\n input_messages_key=\"question\",\n history_messages_key=\"chat_history\"\n)\n\nchain_with_history.invoke(\n {\"question\": \"์๋ \"},\n config={\"configurable\": {\"session_id\": \"user-1\"}}\n)", | |
| "common_mistake": "`session_id`๋ฅผ ๋ชจ๋ ์ฌ์ฉ์์๊ฒ ๋์ผํ๊ฒ ๋๊ธฐ๋ฉด ์ ์ฒด ์ฌ์ฉ์๊ฐ ํ๋์ ๋ํ ํ์คํ ๋ฆฌ๋ฅผ ๊ณต์ ํฉ๋๋ค. ์ฌ์ฉ์๋ณ๋ก ๊ณ ์ ํ session_id๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค.", | |
| "keywords": ["RunnableWithMessageHistory", "ChatMessageHistory", "session_id", "chat_history", "๋ฉํฐํด"], | |
| "source_id": "official-docs-langchain", | |
| "details": [ | |
| "**ํ์คํ ๋ฆฌ ์ ์ฅ์**: ์ธ๋ฉ๋ชจ๋ฆฌ(`ChatMessageHistory`)๋ ์๋ฒ ์ฌ์์ ์ ์ฌ๋ผ์ง๋๋ค. ํ๋ก๋์ ์์๋ `RedisChatMessageHistory`, `SQLChatMessageHistory` ๋ฑ ์์ ์ ์ฅ์๋ฅผ ์๋๋ค.", | |
| "**ํ์คํ ๋ฆฌ ๊ธธ์ด ์ ํ**: ๋ํ๊ฐ ๊ธธ์ด์ง๋ฉด ํ ํฐ์ด ์ด๊ณผ๋ฉ๋๋ค. `trim_messages()` ๋๋ ์ต๊ทผ N๊ฐ ๋ฉ์์ง๋ง ์ ์งํ๋ ๋ก์ง์ ์ถ๊ฐํด์ผ ํฉ๋๋ค.", | |
| "**ํ๋กฌํํธ ์ฐ๋**: `ChatPromptTemplate`์ `MessagesPlaceholder(variable_name=\"chat_history\")`๋ฅผ ์ถ๊ฐํด์ผ ํ์คํ ๋ฆฌ๊ฐ ํ๋กฌํํธ์ ์ฃผ์ ๋ฉ๋๋ค. history_messages_key์ placeholder ์ด๋ฆ์ด ์ผ์นํด์ผ ํฉ๋๋ค." | |
| ] | |
| } | |
| ] | |