Галоўная / Артыкулы / LangChain 1.x у практыцы: ланцюгі, RAG, інструменты та агенты локальна

LangChain 1.x у практыцы: ланцюгі, RAG, інструменты та агенты локальна

Навучыцеся ствараць ланцюгі, генераванне з падтрымкам даступу да інформацыі, інструменты та агентные системы RAG за дапамою LangChain 1.x, выкарыстоўваючы безкоштовную локальную наладку Ollama, без неабяжнасці API-клучоў.

3586 слоў

Эта частка ўскладненая серыі практычных нарадзеў, якія продыржаюць паказваць, як ствараць RAG і агентаў з нуля простым Python. Падход тут намерна іншы: уместо таго, каб самостайна складаць кожную дзейнічую частку, вы пазірэце, як LangChain упаковвае тую ж самую структуру ў калькі ліній коду. Паколькі вы вялікай часткай яшчэ самі стварылі базовыя элементы, вы знаходзіцеся ў хорашых умовах, каб зрозумець, што на самай працэ ўрабляе кожная абстракцыя, а не спрыйматы яе як чагось незрозумелага. Гэта разуменне мае важнае значэння — гэта тое, што адлічвае разліку межы разработнікамі, якія эфектыўна выкарыстоўваюць LangChain, і тымі, якія постаўляюць сталую борбу з яго функцыямі.

Усё, што практыкуецца ў гэтым нарадзе, працюе локальна і безкоштовна, выкарыстоўваючы локальны модель через Ollama асабліва з локальными эмбеддінгамі. Не трэба API-клучоў, і няма неабходнасці турбавацца пра ліміты выкарыстоўвання.

Зьвярненне да версіях: гэты нарадчык прызначан для LangChain 1.x, пераканаліцельны з langchain==1.3.11 і langchain-core==1.4.8. У версіі LangChain 1.0 была адкрытая значныя перарганізацыя — нынешняя API агента базуецца на create_agent, тады калі старэйшыя компаненты, такія як AgentExecutor і initialize_agent, былі перанесены ў адзіны пакет langchain-classic. Большасць нарадчыкаў, якія циркулююць у Інтэрнете, яшчэ деманструюць патерны да версіі 1.0; імпорты, паказаны тут, ўжо сучасныя, і кожны з іх быў пераканалены, каб парадыктуальна працаваў.

Як следавць: ачыніце файл пад назвай lc.py, запускайце кожны блок коду па спэктры і выкананыце завданні „Ваша чарга“, калі яны з’являюцца. Калі вы бачыце фразу „Вы створылі гэта“, яна адносіцца да ручнай реалізацыі з паканячых трэнінгаў у гэтай серыі.

Шаг 0 — Чаму ёсць LangChain

LangChain лепей усвядоміць як колекцыю стандартызаваных, вярніх адносна адны другога компонентав для стварэння прыкладоў практычнага выкарыстоўвання LLM — такіх як обгорткі для модэляў, шаблоны запитаў, прыстроі для пошуку, хранальнікі вектараў, інструменты та агенты. Усе гэтыя элементы паслухаюцца адной і той жа інтэрфейсу, што значыць, ўжо можна з’єднваць іх між сабой і заменяць адны на другія (заменіць модэль, змяніць хранальнік вектараў) без неабходнасці перапісвання логіки вашага прыкладу.

Кансэпт, які з’едынае ўсё, — це Runnable. Кожны компанент выклікае той самы метод .invoke(), і будзь-два компаненты можна склець адно з іншым за дапамою опэратора трубопроводу |. Штаты такога механізма называюцца LCEL — скрацанне ад LangChain Expression Language. Калі кожны элемент вашай системы паводлівае інтэрфейсу Runnable, цэлы пайплайн RAG або агент можна выразіць всего за калькі ліній.

Адекватны ўзмаўкі, якія варта згадаць з самага пачатку: LangChain скарочвае колькість павтараючагуся коду і дае вам доступ да шырокага каталогу готавых інтеграцый. У замяну ён вводзіць шары абстракцыі, якія можу зробіць адлагоджванне сложнейшым — будуць моменты, калі вам будзе прыемней разглядаць просты цикл, які вы самі напісалі. Розумець, калі такая абстракцыя варта тых зусиль, — гэта справжня навык, і мы знову паглядзім на гэты ўзмаўк у Кроку 7.

Настройка (бесплатны, локальны стак)

pip install langchain langchain-core langchain-ollama langchain-huggingface langchain-text-splitters sentence-transformers

Вам таксама патрэбна установлена Ollama (яна бесплатная і працюе локальна), пасля чаго вам следуе завантажыць модель, якая можа выкананы каліранні інструментаў:

ollama pull llama3.2     # ~2 GB; needs ~8 GB RAM. qwen2.5 also works well.

Якщо вы хочаце адзінаковае прыняць рашэнне без викорыстоўвання Ollama, вы все рава можете запускаць часткі chain і RAG за дапамою локальнага модэлю Hugging Face через langchain-huggingface. Аднак часткі agent завісяць ад надзеянага спосабу вызывання інструментаў, чыяму маленькія модэлі, заснованыя на CPU, часта паслужаюць слабка. Для крокаў 4-6 настойчыва рэкамендуецца викорыстоўваць Ollama.

Крок 1 — Асновны крок: ланцоўка з выразам |

У пакульшнай інструкцыі па RAG вы ручна складалі запит за дапамою f-string, перадавалі яго модэлю і чыставалі выходны результат за дапамою .strip(). LangChain фіксуе гэты той самы выраз у виглядзе ланцоўкі. Дадайце гэта ў lc.py:

from langchain_ollama import ChatOllama
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

llm = ChatOllama(model="llama3.2", temperature=0)

prompt = ChatPromptTemplate.from_template(
    "Explain {topic} in exactly one sentence."
)

# The chain: prompt -> model -> plain-string parser
chain = prompt | llm | StrOutputParser()

print(chain.invoke({"topic": "retrieval-augmented generation"}))

Чытанне каналу з левага на правую: prompt ператварае вашы слоўнік уводу ў правільна сформатаваны запрос, llm ператварае гэты запрос у адпаведны адказ моделі, а StrOutputParser() выкарыстоўваецца для выявлення чыстага тексту з об’екта адказу.

Вы вже створылі гэта. Штырь гэтага каналу функцыональна ідэнтычны f"Explain {topic}...", за якім следуе generator(prompt), а потым [0]["generated_text"].strip() з паказаў RAG — тры ручныя крокі, якія тепер выражаюцца чераз тры элементы, з’єднаныя штырём. Логіка не зменілася; толькі інтерфейс стандартызаваны.

Ваша чарга: кожны Runnable таксама падтрымлівае .batch() і .stream() без дадатковых налаштаванняў. Спробуйце гэта:

for piece in chain.stream({"topic": "vector embeddings"}):
    print(piece, end="", flush=True)   # tokens arrive as they're generated
print()
print(chain.batch([{"topic": "agents"}, {"topic": "chunking"}]))  # two at once

Зауважыце, што функцыі стрімінгу та групавання дадзеныя прыходзяць без даплатаў проста таму, што вы выкарыстоўвалі стандартную інтэрфейс Runnable. Гэты момент „без даплатаў“ ёсць, у скарынкаваным выглядзе, вся прычына викорыстання LangChain.

Крок 2 — RAG, спосаб LangChain

Прыйшоў час перазбудаваць вашу ручную пайплайн-систему RAG за дапамогою элементаў, якія надае LangChain. Кожны з эых элементаў адпавядае безпосередна чыму-небудзь, што вы вже напісалі ручна.

from langchain_huggingface import HuggingFaceEmbeddings
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_text_splitters import RecursiveCharacterTextSplitter

# Same Nimbus knowledge base from the RAG tutorial
DOCUMENTS = [
    "Nimbus is a fictional note-taking app. The free plan, Nimbus Lite, allows up to 50 notes and 1 GB of storage.",
    "Nimbus Pro costs 8 dollars per month billed annually, or 10 dollars billed monthly. It includes 50 GB of storage and collaboration for up to 5 people.",
    "Nimbus stores notes encrypted at rest with AES-256. End-to-end encryption is Pro-only and must be enabled in Settings > Security.",
    "Nimbus offers a 30-day refund policy on all paid plans. Refunds reach the original payment method within 5 business days.",
    "Nimbus live chat support is staffed for Pro customers, Monday to Friday, 9am-6pm UTC. Free users get email support with a 48-hour response time.",
]

# 1. Split (↔ your chunk_text function)
splitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=40)
chunks = splitter.create_documents(DOCUMENTS)

# 2. Embed locally (↔ your sentence-transformers model)
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")

# 3. Store + index (↔ your numpy array of vectors). No server needed.
vectorstore = InMemoryVectorStore.from_documents(chunks, embeddings)

# 4. Retriever (↔ your retrieve() with cosine top-k)
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})

for doc in retriever.invoke("How much does Pro cost?"):
    print("-", doc.page_content[:70], "...")

↔ Вы самі створылі гэта — усю систему. RecursiveCharacterTextSplitter выполняе роль вашага функцыя для разбівання тексту, але робіць гэта болей акуратна: ён дзельны текст па межах абзацаў і рэчэнак, а не проста па лікві словаў. HuggingFaceEmbeddings — цэха, якая абгрунтуе той самы модель all-MiniLM-L6-v2, які вы вжылі раней. InMemoryVectorStore заменяе ваш набор вектараў у формате numpy, а яго метод .as_retriever() выконвае той самы пошук за дапамою косай сумараднасці top-k, які вы напісалі ручна. Чатыры лініі тут пакрываюць усё, што вы створылі на кроках 2–4 раней.

Далей паў’язайце процес пошуку з генераванням за дапамою LCEL:

from langchain_core.runnables import RunnablePassthrough
from langchain_core.output_parsers import StrOutputParser

rag_prompt = ChatPromptTemplate.from_template(
    "Answer using only the context. If it's not there, say you don't know.\n\n"
    "Context:\n{context}\n\nQuestion: {question}\nAnswer:"
)

def format_docs(docs):
    return "\n\n".join(d.page_content for d in docs)

rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | rag_prompt
    | llm
    | StrOutputParser()
)

print(rag_chain.invoke("How much does Nimbus Pro cost per month?"))

Слоўнік, які знаходзится на пачатку ланцюга, запускае два варыянты паралельна: question проста перадае вхідны даны без змян, тады як context направляе тыя ж даны через прыстрой для адзыскання і форматуе рэзультаты. Пасля чаго оба выходныя даны потрапляюць у запит. ↔ вы створылі гэта — это па сутнасці ваша старая функцыя rag_answer(): адзысканне, вставка ў запит, генераванне — усе цэе сконцентравана ў адной выразе.

Ваша чарга: Спробуйце вызваць rag_chain.invoke("Можаць вільныя корыстувачы выкорыстоўваць жывую чат-супаведамленнё?"), а пасля — неякое незвязанае запытанне, напрыклад rag_chain.invoke("Кальвіна століця Францыі?"). Следзіце за адказам "Я не ведаю" — гэта той самы пераканальны чыннік з пачатковага трэнінгу RAG, який падкрэпляе тую ж ідею: якосць адзысквання інфармацыі вялічы якосць адказу. Пасля чаго вызывайце retriever.invoke(...) окрема, каб точна бачыць, што было адзыскана, калі адказ здаецца некоректным. Такое раздзеленне — пераканальвання адзысквання незалежна ад стварэння адказу — ёсць прыкметай дэбагавання, яку вы вжывалі раней, а LangChain падтрымлівае яе, заставаючы гэтыя два крокі аднойчыннымі Runnables.

Крок 3 — Адзінкі

У навчальным матэрыялах для агентаў вы парадактавалі інструменты як слоўнік TOOLS і самі напісалі парсер на аднойчынных выразах, каб выявіць назву інструмента і його даны з неапранутага текстовага выходу модэлю. LangChain цалкам пазбавляе нас патрэбы ў такім парсеры за дапамогою внутршняго вызову інструментаў: вы описваеце, што робіць інструмент, модэль адпавядае структураваным вызамом, а LangChain керуе направленнем. Парадактаванне інструмента выглядае так, выкарыстоўваючы декоратар @tool:

from langchain_core.tools import tool
import ast, operator, datetime

_OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul,
        ast.Div: operator.truediv, ast.Pow: operator.pow, ast.USub: operator.neg}
def _ev(n):
    if isinstance(n, ast.Constant): return n.value
    if isinstance(n, ast.BinOp):   return _OPS[type(n.op)](_ev(n.left), _ev(n.right))
    if isinstance(n, ast.UnaryOp): return _OPS[type(n.op)](_ev(n.operand))
    raise ValueError("unsupported")

@tool
def calculator(expression: str) -> str:
    """Evaluate a basic arithmetic expression like '8 * 12'."""
    return str(_ev(ast.parse(expression, mode="eval").body))

@tool
def get_today(_: str = "") -> str:
    """Return today's date in ISO format."""
    return datetime.date.today().isoformat()

Ось тут, дзе варта зупініцца болей дакладна. Вы можете пераглядзець, што самэўсёлі LangChain на адной з вашых функцый:

print(calculator.name)         # 'calculator'
print(calculator.description)  # the docstring
print(calculator.args)         # {'expression': {'title': 'Expression', 'type': 'string'}}

Эя пасляпэўная лінія — гэта справжні, парабярэны выхад. LangChain пераглядзеў вашыя пазначэнні типа (expression: str) асобліва з докстрынгам і створыў на ўсём гэтым схему — саме гэтую схему чытае модель, каб вырашыць, чы і як запускаць інструмент. ↔ гэта вы створылі, толькі раней вы ручна пісалі апісацыі інструментоў у своем SYSTEM_PROMPT і самі парасканавалі выхад модэлі. Тепер сам докстрынг стае апісацыяй, а парасканаванне вядзеца автаматычна. Гэта пояснюе, чаму докстрынгі і пазначэнні типа маюць вялікую значымасць — гэта не проста дакументацыя, адным словам, гэта вядомае, як модель разумее і выкарыстоўвае інструмент. Недбалы докстрынг прыводзіць да таго, што модель неправяма вызывае інструмент.

Ваша чарга: Заменіце документацыйную строчку калькулятара на ўжо неадказнае значэнне, напрыклад """вырахоўвае матэматыку""", а пасля зноў пераканайцеся ў значэнні .description. У 4-му кроку вы на власныя вочы пабачыце, як слабейшая документацыйная строчка прыводзіць да гorsых рашэнняў па выбору інструмента з боку модэлю. Апіс, які вы напішыце, будзе служыць вашым керам у кантролі поведзення модэлю.

4-й крок — Агенты ў аднам вызыве

Хутчэйшыя рэзультаты даходзяць саме тут. Агент, які вы створылі самі, патрабаваў циклу, тэмпарарыя, парсера, абрабоцкі кэшу для памяты, механізма абрабоцкі бягаў, ліміту па колькасці крокаў і системнага запросу, які навучыў модэль формату ReAct. У LangChain 1.x усё гэта зводзіцца да аднаго вызыву функцыі: create_agent.

from langchain.agents import create_agent

agent = create_agent(
    model=llm,                                   # your ChatOllama from Step 1
    tools=[calculator, get_today],               # the @tool functions from Step 3
    system_prompt="You are a helpful assistant. Use tools for math and dates.",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "What is 8 times 12, and what is today's date?"}]}
)
print(result["messages"][-1].content)

Это ўсі элементы агента, з самага пачатку да канца. ↔ Вы самі створылі ўсё гэта. Функцыя create_agent внутршняя часткаю запускае цыкл «прычына-дзеянне-спазірванне», направляе задачу да правильнага інструмента, падае спазірвання назад у модель, пераказвае умовы зупнення та сяглівае ліміт колькасці крокаў — усё гэта ёсць тыя элементы, якія вы ручна сабралі ў функцыі run_agent. Пад спаднім рэверам яна выкарыстоўвае LangGraph, і самэ гэта ёсць прычыной таго, што цыклічная працэса такая надзеяная.

Якщо вы хочаце пазірэць, як развіваецца процес выважвання — той самы эфект, які даваў вам параметр verbose=True — тады трэба трансляваць проміжныя крокі, а не проста чакаць на фінальны адказ:

inputs = {"messages": [{"role": "user", "content": "How much is a year of Nimbus Pro?"}]}
for chunk in agent.stream(inputs, stream_mode="updates"):
    print(chunk)

Калі ён працюе, вы паблікуеце кожную рашынку, якую прымеяе модель, і кожны рэзультат, які вяртае інструмент, выдрукаваныя адна за другой. Це та самая схема «Мысль/Дзеянне/Зявішча» з вашага ручнага аналізу, толькі яна представляецца у вачыню структураваных об’ектаў апошніх змян, а не у вачыню суровага тексту, які трэба было самостайна парсаваць.

Ваша чарга: Спробуйце задаць запит, які змусіць модель скорыстацца двумя інструментамі адночасна — напрыклад, папрабавце пачаць расчытак канечнай даты 30-дзённага періяда для вярнення грошаў, якщо прымер быў пачаты сёння. Спаглядайце, чы правільна модель спачатку вызывае get_today, а потым calculator у парадку. Пасля этага верніцеся да 7-го крока матэрыялу пра агенты — кожны спосаб збою, які вы там задокументавалі (змены формата выходных даных, выдуманыя назвы інструментаў, бесконечныя ціклы), можа з’явіцца і тут. Фрэймворк не пасілішвае спосаб мыслэння слабкай моделі; ён проста закрывае структуру, якая застосоввана пад час ўзнікнення рашэння. Розумеўшы гэтыя разлікі, вы будете быстрей дыбагаваць гэтых агентоў, чым тыя, хто пераходзіць адразу да фрэймворка, не стварыўшы спачатку сопственную модель.

5-й крок — Аб’еднанне: агент, які запошчае даны (агэнтны RAG)

Хто тут сабраныя ўсе тры прынцыпавыя урокі. Возьміце свога ретрывера і выкорыстайце яго як інструмент, пасля чаго даце гэты інструмент агенту. З гэтага момента сам агент вырашае колі патрэбна пошук дакументаў — і ён можа шукаць колькіразоў, або спалучаць процес выявлення інфармацыі з вычысленням за патрэбай.

@tool
def search_nimbus_docs(query: str) -> str:
    """Search the Nimbus product documentation for facts about plans, pricing, refunds, security, and support."""
    docs = retriever.invoke(query)
    return "\n\n".join(d.page_content for d in docs)

smart_agent = create_agent(
    model=llm,
    tools=[search_nimbus_docs, calculator, get_today],
    system_prompt=(
        "You answer questions about the Nimbus app. "
        "Use search_nimbus_docs for any product facts, and calculator for arithmetic. "
        "Base answers only on retrieved facts."
    ),
)

q = "How much would Nimbus Pro cost a team of 4 for a full year?"
result = smart_agent.invoke({"messages": [{"role": "user", "content": q}]})
print(result["messages"][-1].content)

Ёжы правільна адпаведаць на такое запитанне, агент спачатку должен шукаць цэну месячнай падпіскі, а толькі пасля чаго вычысляць 8 * 12 * 4. Гэта є выявлення інфармацыі (з першага туторыяла), якае выкорыстоўваецца як інструмент (з трэцьяго), кераванае агентам (з другага) — тры разлічныя ідэі, якія працуюць як адна система. Дазволіць агенту выбіраць, калі выявляць інфармацыю, значна ўжо болей гнучкая за фіксаваны пат трасы rag_chain з 2-го крока, і гэта шаблон, які часта з’яўляецца ў рэальных прыменных системах.

Ваша чарга: Таксама трансляюце выконанне гэтаго агента, используючы smart_agent.stream(..., stream_mode="updates"), і паказваце порядак аператыў — пошук выкананы раней за вычысленні. Якщо ваш локальны модель прагне рашыць арыфметычныя задачы сама, замест таго каб скорастаць да інструмента для вычысленняў (што ёсць распашчастая тэндэнцыя у меньшых моделях), змяніце системны прапант на кшталт "Вы ПАВІННЫ выкарыстоўваць калькулятор для кожнага арыфметычнага крока." Гэта той жа спосаб, які працаваў у навучальным матэрыяле з агентамі.

Шаг 6 — Короткая екскурсія па тым, што ўсё ще є ў пакете

На гэты момент у вас ўжо є основная структура. Є калькі дадатковых элементаў LangChain, пра якія варта знаты, кожны з яых адпавядае чамусь, што вы вже створылі самі:

  • З’явальнікі дакументаў (langchain-community) — прабрамляюць PDF-файлы, веб-сторанкі, сторанкі Notion і падобныя джерелы безпасэродзе ў тыя ж Document-об’екты, якія вже выкарыстоўвае ваш роздзеляч тэксту. Це заменяе ручнае вставлянне тэксту ў список на справжню, структураваную працэсу прабрамлення.
  • Хранілішчы вектараў высокага стандарту — заменяюць хранілішча ў памяці на Chroma або FAISS (імпортуецца через from langchain_chroma import Chroma) для трывалага зберагачэння эмбеддінгаў на дыску і расшырэння магчымасцей за межы, якія дазволяе памяць. Паколькі оба выкананыя прымаюць той самы інтерфейс .as_retriever(), ніч у вашай ланцюговой структуре не павінна змяніцца — самэ гэта ўзаемна адпаведанне і є сенсам такой замены.
  • Історыя памяці і паведамленняў — абгортайце ланцюг, каб ён зберагаў контекст пакананых раундав, ператвараючы ланцюг адзінаго запиту на трывалую розмову.
  • Парсеры выходных даных за межамі звычных стрэнгаў — прымусова ператварайце адпаведзь моделі на JSON або перакананы об’ект Pydantic, замест таго каб спадзявацца, што неапрануты текст будзе правільна структураваны.
  • LangGraph — калі логіка цыклу, ўбудованая ў create_agent, стае недастатковай (шляхі з розгалужэннямі, крокі затверджэння з участю чалавека, саўместнае працаванне калькі агентаў), тады вы пераходзите да LangGraph — ніжнага рэверу графаў, на яком сам create_agent пабудаваны.
  • Шаг 7 — Калі варта выкарыстоўваць LangChain, а калі ня

    У гэты момент вы створылі той самы тип системы два разы — аднойчы з нуля, аднойчы за дапамою фрэймворку — што ставяе вас у хорашыя умовы, каб вы самі здзейснілі гэты вызов. Саме для гэтага і было неабяжна працаваць з обомі версіямі.

    LangChain становіцца корыстным, калі вам трэба з’еднаць безліч існуючых інтеграцый — калькі чытача дакументаў, колькасць хранілішча вектароў, больш аднаго прадавця модэляў — і вам не хочацца самостайна реалізаваць логіку стрімінгу, групавання, пракатовання спроб і трэйсінгу для кожной з іх. Ён таксама корыстны, калі вы плануеце часта зміняць елементы і хочаце стабільны інтерфейс для ўзмінення іх, або калі вы ствараеце агента і не хочаце самі падтрымваць цикл аналізу.

    Калі напрыклад, прыгранак ёсць досыта маленькі, што навучэнне абстракцый LangChain займе больш часу, чым проста напісанне пяцідзесятай лініі коду, якія вы вже ведаеце пісаць, тады напісанне коду вручную часто ёсць кращым выборам. Це таксама кращы варыянт, калі вам патрэбна повная прозрачнасць ў тым, што выканаецца — праходжэнне праз разныя шары фреймворку для діагностикі проблемы є справжнім джерелам трудносцяў, і такая прычына є правамернай; або калі дадаць шар непрямасці могла б сховаць логіку, якая на самай працоўнай Python є болей зрозумелая. Канвэй RAG і агент, які вы створылі вручную ў паканальных нарадах, абсалютна падходяць для прыменення ў рэальных умовах; вжыванне фреймворку ніяк не паднімае ценнасць коду, напісанага вручную.

    Цікавага пытанне не мае аднаго правильнага адказу. Прычына, чаму вы спачатку выучылі ручную версію, заключаецца ў тым, што выбор адпраўкі являе сабою свядомае рашэнне, пры якім вы цалкам разумееце, што ёна заменяе, а не стандартны варыянт, да якога прыходзіце таму, што внутранія механізмы застаюцца незрозумелымі.

    Шаг 8 — Куда працягваць

    • Якщо ваша локальная наладка выдаецца занадта медленной, існуюць безкоштовныя версіі модэляў, якія можна выкарыстоўваць у Groq і Google Gemini. Пераключэнне адбываецца за дапамогою адной лініі коду — заменіце ChatOllama на ChatGroq, або выкарыстаце init_chat_model("gemini-...", model_provider="google_genai") — адтуды ўсё інша функціонуе через той самы стандартны інтэрфейс. Для кожнага з варыянтаў патрэбны ключ API, але ўсі безкоштовныя тарифы не купуюцца.
  • LangSmith — это адынструмент для трэйсінгу та дыбаггіну з LangChain. Кале ланцюг або агент паводзіцца незвычна, ён дазваляе перагледзець кожны крок, кожны вхідны дадзенык і кожны выходны рэзултат. У ёнай є бесплатны рівень, і ён яўляецца прымусовай адказам на скаргу "Я не можу пазірэць унутра фрамворку".
  • LangGraph варта адкрыць, калі вам патрэбны рабочыя процесы з станамі, калькольвыя агенты або контрольныя пункты з участю чалавека, якія выходзяць за межы простага циклу вызову інструменту.
  • Афіцыйная дакументацыя знаходзіцца на docs.langchain.com. Абавязкова пераканайцеся, што тое, што вы чытаете, аднасоўваецца да версіі 1.x — усё, што напісаная раней чым 1.0, будзе аднасоўвацца да AgentExecutor, initialize_agent або LLMChain, якія ўсе вэлі або былі знятыя з выкарыстоўвання.
  • Ментальная модэль, якую варта зберагчы

    LangChain — это практычна вашыя сабраныя самімі компаненты, стандартызаваныя за дапамою аднаго інтэрфейсу — Runnable — і з’яеднаныя за дапамою |. Нічога з гэтага не ўжо ёсць сапраўдна новай ідеяй, калі вы власноруч стварылі этыя элементы:

    • «Ланцуг» — это праймт-до-модэлю-до-парсера, які вы вже напісалі, проста з’ѐеднаныя разам.
    • «Рэтрывер» — это ваша логіка вбудоввання дадзеных і пошуку за методам косайн, упакаваная ў спяшчаны інтэрфейс.
    • «Інструмент» — это функцыя, яку вы напісалі, плюс автаматычна створаная схема, якая дазволяе модэлю вызываць яе безпасобна, замест таго каб вы самі парсавалі яе текстовы выхід.
    • «Агент», за дапамою create_agent, — это весь ваш цыкл «расумець-дзейнаць-спазіраваць», з’еднаны ў адзіны вызыв.

    Калі ўтвараюцца проблемы, вы яе усуняеце так сама, як і завжды: выделяеце нештае, што вызвало праблему. Перапрацаваеце адпаведны элемент окрема, выведзіце значэння .args інструмента або перадаеце проміжныя крокі агента. Фрамворк толькі зменяе колькасць коду, які трэба запісаць — ён не зменяе таго, што на самай працы відбываецца, а вы вже розумееце, што відбываецца.

    Усуненне проблем

    • Якщо вы падаеце на помылку ImportError пад вызывамі create_agent або langchain_ollama, верагатэльна, у вас ўстановлена версія ранейшая за 1.0 або не хватает пакета. Запусціце pip install -U langchain langchain-ollama і пераканайцеся, што langchain.__version__ пачынаецца з 1..
  • Якщо у інструкцыі, яю вы чытаете, викорыстоўваецца AgentExecutor або initialize_agent, то гэта старыя API. У версіі 1.x яны былі перанесены ў langchain-classic; новы код павінен викорыстоўваць create_agent у замене.
  • Пярэчанне „connection refused“ ад Ollama значыць, што сервер не працуе — запускайте яго за дапамою ollama serve або ачыніце прыкладку і пераканайцеся, што ваша модель показваецца пад ollama list.
  • Якщо агент ігнаруе інструмент або прабуе самастоятельна выконваць арыфметычныя расчыткі, модель, верагатна, не можа надзеяна вызываць інструменты, што ёсць распашчаная проблема меньшых модэляў, або докстрынг занадта нечыста. Уточніце системны прампт і докстрынг інструмента, або спробуйце болей сильную модель, напрыклад qwen2.5.
  • HuggingFaceEmbeddings здаецца повольным праз першы раз, калі яго вы викорыстоўваете, таму што ён завантажае модель эмбеддінга (прыблізна 80 МБ) і зберагае яе у локальной памяці. Сам прыем даных пасля чаго выконваецца быстра.
  • Першы сам пакіянь до моделі через Ollama є повольным, таму што модель завантажаецца у RAM; наступныя пакіяньы выконваюцца швядка.
  • Тепер вы створылі RAG, агентаў і фрэймворк, який ўключае ў сябе абодва — спачатку вручную, а потым за дапамогою LangChain. Вы розумеете той слой, да якога большасць людзей падключаецца толькі ззаўні. Насолоджваюцеся ўжыткам.

    Спадневаная література

  • Управлець LLM-суддзёй як жывай системай вырабоцтва — Дазвольце дазнацца, як чатыроэтапны цикл жыцця Netflix — даныя з рэальнага свету, навчанне па спецыяльным критэрыям, апавернутая запуск і стацыонарны манітарынг — дапамагае LLM-суддзе заліцца точной у масштабных умовах.