STUDY/LLM

[LLM] Chain - LCEL

seoyn 2026. 6. 27. 11:28

1. Chain ๊ฐœ๋…

 : ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ •ํ•ด์ง„ ์ˆœ์„œ๋Œ€๋กœ ์—ฐ๊ฒฐํ•ด ๋ณต์žกํ•œ AI ์ž‘์—…์„ ๋‹จ๊ณ„๋ณ„๋กœ ์ž๋™ํ™”ํ•˜๋Š” ๊ตฌ์กฐ
 - ๊ฐ ์ปดํฌ๋„ŒํŠธ๋Š” ์ž…๋ ฅ์œผ๋กœ ์ด์ „ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„ ์ฒ˜๋ฆฌ ํ›„ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ์ „๋‹ฌ
 โ€ข ์˜ˆ์‹œ ํ๋ฆ„ : ์งˆ๋ฌธ โ†’ ๊ฒ€์ƒ‰ โ†’ ์š”์•ฝ โ†’ ์‘๋‹ต ์ƒ์„ฑ
 โ€ข ์žฅ์  : ์ž‘์—… ํ๋ฆ„์˜ ๋ช…ํ™•์„ฑ, ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ, ์œ ์ง€๋ณด์ˆ˜ ๋ฐ ํ™•์žฅ์„ฑ ํ–ฅ์ƒ
 โ€ข ํ•œ๊ณ„ : ์ˆœ์ฐจ ์‹คํ–‰ ๊ตฌ์กฐ โ†’ ์กฐ๊ฑด ๋ถ„๊ธฐ, ๋ฐ˜๋ณต ๋“ฑ ๋ณต์žกํ•œ ํ๋ฆ„์€ LangGraph ํ•„์š”

 
2. Chain ๊ตฌ์„ฑ ๋ฐฉ์‹ ๋น„๊ต

๋ฐฉ์‹์„ค๋ช…์ƒํƒœ
Off-the-shelfLLMChain, SequentialChainDeprecated
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_result
LCEL : ๋‹จ์ˆœ ํŒŒ์ดํ”„๋ผ์ธ, @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