1. Chain ๊ฐ๋
: ์ฌ๋ฌ ์ปดํฌ๋ํธ๋ฅผ ์ ํด์ง ์์๋๋ก ์ฐ๊ฒฐํด ๋ณต์กํ AI ์์
์ ๋จ๊ณ๋ณ๋ก ์๋ํํ๋ ๊ตฌ์กฐ
- ๊ฐ ์ปดํฌ๋ํธ๋ ์
๋ ฅ์ผ๋ก ์ด์ ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌ ํ ๋ค์ ๋จ๊ณ๋ก ์ ๋ฌ
โข ์์ ํ๋ฆ : ์ง๋ฌธ โ ๊ฒ์ โ ์์ฝ โ ์๋ต ์์ฑ
โข ์ฅ์ : ์์
ํ๋ฆ์ ๋ช
ํ์ฑ, ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ, ์ ์ง๋ณด์ ๋ฐ ํ์ฅ์ฑ ํฅ์
โข ํ๊ณ : ์์ฐจ ์คํ ๊ตฌ์กฐ โ ์กฐ๊ฑด ๋ถ๊ธฐ, ๋ฐ๋ณต ๋ฑ ๋ณต์กํ ํ๋ฆ์ LangGraph ํ์
2. Chain ๊ตฌ์ฑ ๋ฐฉ์ ๋น๊ต
| ๋ฐฉ์ | ์ค๋ช | ์ํ |
| Off-the-shelf | LLMChain, SequentialChain | Deprecated |
| LCEL | | ์ฐ์ฐ์๋ก ์ปดํฌ๋ํธ๋ฅผ ์ ์ธ์ ์ฐ๊ฒฐ | ๊ถ์ฅ |
# Off-the-shelf(๊ตฌ ๋ฐฉ์)
chain = LLMChain(prompt=prompt, llm=model, output_parser=parser)
# LCEL(์ ๋ฐฉ์)
chain = prompt | model | parser
3. LCEL๊ณผ Runnable ์ธํฐํ์ด์ค
: LCEL๋ก ์ฐ๊ฒฐ๋๋ ๋ชจ๋ ์ปดํฌ๋ํธ๋ Runnable ์ธํฐํ์ด์ค ์์
| ๋ฉ์๋ | ์ค๋ช |
| invoke(input) | ๋จ์ผ ์ ๋ ฅ ์ฒ๋ฆฌ |
| batch(inputs) | ๋ค์ ์ ๋ ฅ ํ ๋ฒ์ ์ฒ๋ฆฌ |
| stream(input) | ์คํธ๋ฆฌ๋ฐ ๋ฐฉ์์ผ๋ก ์๋ต ๋ฐํ |
| ainvoke() / abatch() / astream() | ๋น๋๊ธฐ ๋ฒ์ |
| assign(**kwargs) | ์ ๋จ๊ณ ์ถ๋ ฅ dict์ ์ ํ๋ ์ถ๊ฐํด ์ ๋ฌ |
4. ์ฃผ์ Runnable ๊ตฌํ์ฒด
4-1. RunnableSequence
: ์ฌ๋ฌ Runnable์ ์์ฐจ ์คํ
- LCEL( | )๋ก ์ฒด์ธ ๊ตฌ์ฑ ์ ์๋ ์์ฑ๋จ
chain = prompt | model | parser
# ๋ด๋ถ์ ์ผ๋ก RunnableSequence(prompt, model, parser)์ ๋์ผ
4-2. RunnableLambda
: ์ผ๋ฐ ํจ์ or lambda ํํ์ โ Runnable
- ์ผ๋ฐ ํจ์๋ chain์ ์ง์ ํฌํจ์์ผ๋ ์๋ ๋ณํ(๊ตณ์ด ๋ช
์ ํ์ X)
# 1. lambda
c1 = RunnableLambda(lambda x: f"{x}์ ๋ํด ํ ๋ฌธ์ฅ์ผ๋ก ์ค๋ช
ํด์ค.")
# 2. ์ผ๋ฐ ํจ์ - ์ง์ ํฌํจ ๊ฐ๋ฅ
def get_value_len(value: str):
return value, len(value)
chain = prompt | model | parser | get_value_len
4-3. RunnablePassthrough
: ์
๋ ฅ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝ ์์ด ๊ทธ๋๋ก ๋ค์ ๋จ๊ณ๋ก ์ ๋ฌ
- .assign(key=Runnable, ...) : ๊ธฐ์กด dict์ ์ ํ๋ ์ถ๊ฐํด ์ ๋ฌ
# ๊ทธ๋๋ก ํต๊ณผ
rp = RunnablePassthrough()
# ํ๋ ์ถ๊ฐ
rp2 = RunnablePassthrough.assign(
address = RunnableLambda(lambda x: "์์ธ์ ๊ธ์ฒ๊ตฌ"),
tel_no = RunnableLambda(lambda x: "010-1111-2222")
)
rp2.invoke({"name":"ํ๊ธธ๋"})
# -> {"name": "ํ๊ธธ๋", "address": "์์ธ์ ๊ธ์ฒ๊ตฌ", "tel_no": "010-1111-2222"}
4-4. RunnableParallel
: ์ฌ๋ฌ Runnable์ ๋ณ๋ ฌ ์คํ ํ ๊ฒฐ๊ณผ๋ฅผ dict๋ก ๋ฐํ
- LCEL์์ chain ๋ด {} dict๋ก ์ ์ ์ ์๋์ผ๋ก RunnableParallel๋ก ์ฒ๋ฆฌ
parallel = RunnableParallel({
"value1": RunnableLambda(lambda x: x + 10),
"value2": RunnableLmabda(lambda x: x - 10),
"org_value": RunnablePassthroungh()
})
parallel.invoke(200)
# -> {"value1": 210, "value2": 190, "org_value": 200}
5. Chain๊ฐ ์ฐ๊ฒฐ
: Chain๋ Runnable ํ์
์ผ๋ก, ๋ค๋ฅธ chain ๊ตฌ์ฑ ์์๋ก ํฌํจ ๊ฐ๋ฅ
ex. itemgetter๋ก ์
๋ ฅ dict์์ ํน์ ํค ๊ฐ๋ง ์ถ์ถํด ์ ๋ฌ
from operator import itemgetter
# recipe_chain + translate_chain ์ฐ๊ฒฐ
chain = {
"content": recipe_chain # ์์๋ช
์ผ๋ก ๋ ์ํผ ์์ฑ
"language": itemgetter("language"_) # ์
๋ ฅ์์ ์ธ์ด๊ฐ ์ถ์ถ
} | translate_chain
chain.invoke({"food": "๊น์น์ฐ๊ฐ", "language": "๋
์ผ์ด"})
6. @chain ๋ฐ์ฝ๋ ์ดํฐ
: ํํํ๊ธฐ ์ด๋ ค์ด ์กฐ๊ฑด ๋ถ๊ธฐ, ๋ฐ๋ณต, ๋ณตํฉ ๋ก์ง ํ์ ์ ์ฌ์ฉ ์ผ๋ฐ ํจ์๋ฅผ RunnableLambda ํ์ ์ผ๋ก ๋ง๋ฆ
from language_core.runnables import chain
@chain
def multi_language_recipe_chain(input_data: dict) -> dict:
food = input_data['food']
language = input_data['language']
is_korean = input_data['is_korean']
korean_recipe = recipe_chain.invoke({"food": food})
result = translate_chain.invoke({"content": korean_recipe, "language": language})
final_result = {"recipe": result}
if is_korean:
final_result["korean_recipe"] = korean_recipe
return final_resultLCEL : ๋จ์ ํ์ดํ๋ผ์ธ, @chain : ํ๋ฆ ์ ์ด ํ์ํ ๋ณต์กํ ์์ด์ ํธ ๋ก์ง์ ์ ํฉ
7. LLM Cache
: ๋์ผํ ์ง๋ฌธ์ ๋ํด LLM ์ฌํธ์ถ์ด ์๋, ์ ์ฅ๋ ์๋ต ๋ฐํํด ์ฒ๋ฆฌ ์๋ ๋ฐ ๋น์ฉ ์ ๊ฐ
from langchain_core.globals import set_llm_cache
from langchain_community.cache import InMemoryCache, SQLiteCache
set_llm_cache(InMemoryCache()) # ๋ฉ๋ชจ๋ฆฌ ์บ์(ํ๋ฐ์ฑ)
set_llm_cache(SQLiteCache("cache.sqlite")) # ํ์ผ ์บ์(์์์ฑ) โข ์ค์ ํ ๋ฒ๋ง ํ๋ฉด ์ดํ ๋ชจ๋ LLM ํธ์ถ์ ์์ฉ ์ ๋
โข Chatbot์ฒ๋ผ ์ ์ฌ ์ง๋ฌธ์ด ๋ฐ๋ณต๋๋ ์ํฉ์ ํจ๊ณผ์
'STUDY > LLM' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [LLM] RAG - Embedding VectorDB (0) | 2026.07.01 |
|---|---|
| [LLM] RAG (1) | 2026.06.30 |
| [LLM] Output Parser (0) | 2026.06.26 |
| [LLM] Prompt (0) | 2026.06.25 |
| [LLM] Model (0) | 2026.06.24 |