Галоўная / Артыкулы

Практычныя нататкі: AI-агент, які сам выпраўляе памылкі, на Self-RAG і LangGraph

Практычны разбор тэмы «AI-агент, які сам выпраўляе памылкі, на Self-RAG і LangGraph»: кантракты, праверкі і гатовыя фрагменты кода для каманд, якія ўкараняюць гэты падыход.

Выдавец: REACTAPP.TOP30 хв чытання6935 слоў

Крыніцы: Build a Self-Correcting AI Agent with Self-RAG & LangGraph

У гэтым карыце практычным напамінанні перакладзенаецца шлях ад сыр'ёў да рабочай сістэмы для стварэння самакорэктуючага AI-агента з Self-RAG і LangGraph. Акцэнт ставіцца на практычныя крокі, чысткія пераконтрацыі і код, які можна проста дадзець у рэпазітарый, не прабуючы здогадвацца пра мету.

Чаму стандартныя RAG-пайплайны ўразлівы

Ёсць калькюляцыя, чаму стандартныя RAG-пайплайны ўразлівы: перш чым зменяць код, неабходна візначыць вхідныя даны, адпаведальнага за крок і крытэрыя завершэння. Аператары должны магчымае перадзець крок з вядомай точкі контролю, не прабуючы здагадвацца пра схованы стан. Конфігурацыю трэба залічыць паза кодам прыемленае. Файлы сераўіса, хранільнікі секрэтных дадзеных і флагі функцый должны знаходзіцца ў аднам месцы, якое аператары можаць пераглядаць, не чытаяўшы весь граф. Неабходна апісаць тые часткі тэксту, якія фактычна ляглі в основу адпаведнай адказы. Без такой апісацыі аператары не можуць розлічыць галюцынацію ад працягу індэксавання.

Лінейны пайплайн: адзысканне і прыняцце

Для лінейной паіплайн-сістэмы: перш чым змяніць код, неабходна адзінаванне і выконанне задачы, тады трэба з’явіць вхідныя даны, адпаведальнага за крок і крытэрыі завершэння. Аператары должны магчымаць перзапуск кроку з вядомай точкі контролю, не падозруючы пра схованы стан. Неабходна адзінаванне як успешнаг, так і варыянтага шляху адкалечэння. Перапрыбуткі, людзкія перакрыцці і апрацоўка некорэктных паведамленняў ёсць часткай продукту, а не яго пазнейшай дапрацоўкі. Паказваць трэба тыя часткі тэксту, якія фактычна лежаць у падставе адпаведнай адказы. Без ціх цытатаў аператары не зможуць разлічыць галюцынацію ад працягу індэксавання.

[User Query] ──> [Vector Database] ──> [Top-K Chunks] ──> [LLM Prompt] ──> [Final Answer]

Структура тыхоўага абякання

Для аналізу безшумнай неудачы трэба прадзеўначыць вхідныя даны, абавесцявальніка крока і крэтары выходу пры змяне коду. Аператары должны магчымаць перзапуск крока з вядомай точкі контролю, не падозрываючы прыхованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выйшаў, прычына неудачы павінна вказываць на адну абавесцявальную функцыю, а не на заплутаную лінію апрацоўкі. Наводзіце тыя часткі, якія фактычна лежалі в основе адпаведнай адказы. Без цых цітатаў аператары не можуць разлічыць галюцынацію ад прасоўкі ў індэксаванні.

Асновная прычына: слепая доверлівасць

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

Рашэнне: Адналежнае впрыяўленне самапрацоўных цыклам

Для рашэння: пры введэнні сама-рэфлексійных цыклаў неабходна прадзефінаваць вхідныя даны, адпаведальную особу за крок і крэтырыя выходу пры змены коду. Аператары должны магчымае перайсці на выкананне кроку з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Запісвайце час выканання і кост токенаў або запытаў разам з функцыйнальнымі рэзультатамі. Відразлівасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмаверсіі ў спяльныя асяроддзя. Указвайце тыя часткі тэксту, якія фактычна ляглі в основу адпаведнай адказы. Без цых цітатаў аператары не можуць разлічыць галюцынацію ад прасоў у індэксаванні. Для рашэння: пры введэнні сама-рэфлексійных цыклаў неабходна прадзефінаваць вхідныя даны, адпаведальную особу за крок і крэтырыя выходу пры змены коду. Аператары должны магчымае перайсці на выкананне кроку з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Дакументавайце як «шчаслівы» шлях, так і шлях вяснавання проблем. Перапрыбуткі, людзкія контрольныя пункты і обработка неканальных паведамленняў ёсць часткай працы ў праектаванні.

ct, не пазней часу польскі.

Ад слепага адзыску да самапрацавы: патэрн Self-RAG

Калі працуеце над «Ад слепага адзыску да самапрацавы: патэрн Self-RAG», спачатку запісайце умовы: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі спіс дапамагае заліцьваваць пазнейшыя змены ў кодзе. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшоў, нявыпанне павінна вказваць на адну адпаведальнасць, а не на заплутаны ланцужок задач. Перад налаштаваннем запітоў пераканайцеся ў рэкале на фіксаваным наборы пытанняў. Частае змена запітоў рэдка калі-небудзь выправляе слабыя аспекты адзыску інфармацыі.

Тры сталпы самакорэкцыі

Калі працюеце над кнігай «Тры столпы самакорэкцыі», спачатку запісайце угоду: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі спіс контролю дапамагае заставіць пазнейшыя змены коду быць чыстымі. Спрэтавайцеся да гэтага этапу як да угоды межа данымі і перакананымі выходамі. Дайце назвы элементам, задаце крытэрыі успеху і адмовіцеся ад тыхоўага частковага завершэння. Замерыяйце ступень запамятовання на фіксаванай сэтцы пытанняў прычым рэгулюванні запрошэнняў. Частае змены запрошэнняў рэдка калі вылечваюць слабую ступень адзысквання інформацыі.

       [ Query ]
           │
           ▼
   1. Is Retrieval Needed? ──(No)──► Generate directly from parametric memory
           │
         (Yes)
           ▼
     [ Retrieve ]
           │
           ▼
   2. Are Docs Relevant? ──(No)──► Reformulate search query & retry
           │
         (Yes)
           ▼
     [ Generate ]
           │
           ▼
   3. Is Answer Faithful? ──(No)──► Regenerate or extract better context
           │
         (Yes)
           ▼
     [ Final Output ]

Токены-рэфлексія як сігналы кантролю

Калі вы працуеце з Reflection Tokens як з сігналамі кантролю, спачатку запісайце умовы вікорыстання: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць пад частковыя неудачы. Такі спіс дапамагае заліцварваць будучыя змены ў кодзе. Запісвайце час выканання і вартасць токена або запытку празаўсёды разам з рэзультатамі функцыяналу. Відразлівае паказанне вартасцей запобегае неспадзяваным расходам, калі працэўнае сераўеры пераходзяць з дамовай асяроддзя ў спакульнаную. Зберагаюце у кэшы стабільныя інструкцыі сістэмы і схемы інструментаў. Перадача таго ж самога прамэра ёсць частым выклікам некантрольаваных расходаў. Калі вы працуеце з Reflection Tokens як з сігналамі кантролю, спачатку запісайце умовы вікорыстання: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць пад частковыя неудачы. Такі спіс дапамагае заліцварваць будучыя змены ў кодзе. Адначасова задокументавайце шляхы правільнага выканання і вярнення ў нормальны стан. Перапрыбуткі, людзкія контрольны пункты і обработка некантрольаванных сітуацый ёсцю часткай продукту, а не чымось, што дадаецца пазней.

Архітэктура самапавтарэння

Архітэктура самаперагляду працюе наякшым чынам, калі яе розглядаць як вімерную паверхню. Запісаўце адна «золатая» транскрыпцыю, адын прыклад неудачы і прыметку па вярнэнню да пачатковага стану, прычым расшыруючы сферу дзеяння. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выходзіць, прычына неудачы павінна вказываць на адную адпаведальнасць, а не на заплутаны ланцужок задач. Раздзеляйце правілы часткавання інфармацыі ад правіл яе выявлення. Змена ў одных не павінна прымусваць перапісванне іншых, калі змянююцца паказнікі якосці.

graph TD
    Start[User Query] --> DecideNeed{Is Retrieval Needed?}
    DecideNeed -- No --> GenerateDirect[Generate Output]
    DecideNeed -- Yes --> Retrieve[Retrieve Documents]
    Retrieve --> GradeDocs[Grade Document Relevance]
    GradeDocs -- Irrelevant --> Fallback[Rewrite Query / Fallback]
    GradeDocs -- Relevant --> GenerateRef[Generate Response with Context]
    GenerateRef --> GradeFaith[Grade Faithfulness & Hallucinations]
    GradeFaith -- Hallucinated --> GenerateRef
    GradeFaith -- Faithful --> GradeUtility[Grade Utility]
    GradeUtility -- Low Utility --> Rewrite[Refine Response]
    GradeUtility -- High Utility --> End[Final Answer]

Порэванне ланцужкаў задач і рабочых практык

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

Праектаванне з LangGraph: ад лінейных ланцаў да машын станоў

Праектаванне з LangGraph: Ад лінейных ланцаў да машын станоў работае наякша, калі яго спрыяваць як мерыемую паверхню. Запісаце адны ідэальны прыклад працы, адну справу з бягам і прыметкі па адваротным запуску перш чым расшырваце масштаб. Запісвайце часы выканання і косты токенавання або запыткаў разам з функцыйнальнымі рэзультатамі. Відразлівасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмаверсіі ў спяльныя асяроддзя. Раздзеляйце правілы часткавання дадзеных і правілы ўзяць дадзеныя. Змена аднаго з іх не должна прымусваць перапісванне другога, калі зменяюцца паказнікі якосці. Праектаванне з LangGraph: Ад лінейных ланцаў да машын станоў работае наякша, калі яго спрыяваць як мерыемую паверхню. Запісаце адны ідэальны прыклад працы, адну справу з бягам і прыметкі па адваротным запуску перш чым расшырваце масштаб. Дакументавайце як шлях успеху, так і шлях вяснавання проблем. Перапрыбуткі, людзкія контрольныя пункты і обработка некорэктных паведамленняў ёсць часткай продукту, а не чымсь, што дадаецца пазней.

Linear RAG:    [Query] ──> [Retrieve] ──> [Generate] ──> [Response] (No correction)
Self-RAG:      [Query] ──> [Retrieve] ──> [Evaluate] ──┬─ (Valid) ──> [Response]
                              ▲                        │
                              └─────── (Invalid) ──────┘ (Loop & Refine)

Меры лінейных ланцаў

Для выявлення мер лінейных ланцаў неабходна спачатку з’явіць вхідныя даны, абавесцю крока і крэтынія выходу, перш чым зменяць код. Аператары должны магчымае перзапускаты крок з вядомай точкі контролю, не прабуючы спадарацца прыватны стан. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выконваецца, прычына неудачы должна вказываць на адну конкрэтную абавесцю, а не на заплутаны ланцюг задач. Прытамульвайце тыя часткі тэксту, якія фактычна лежаць у падставе адпаведнай адказы. Без ціх прамянаў аператары не зможаць разлічыць галюцынацію ад працягу ў індэксаванні.

Раскрыць таўарамы машыны станоў AI

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

                  ┌──────────────────────┐
                  │        Start         │
                  └──────────┬───────────┘
                             ▼
┌──────────────┐  ┌──────────────────────┐
│  Formulate   │◄─┤    Retrieve Docs     ├─┐
│  New Query   │  └──────────────────────┘ │
└──────▲───────┘                           │
       │                                   ▼
┌──────┴───────┐  ┌──────────────────────┐ │
│  Re-Retrieve │  │   Grade Relevance    │─┘
└──────────────┘  └──────────┬───────────┘
                             ▼
                  ┌──────────────────────┐
                  │    Generate Answer   │
                  └──────────┬───────────┘
                             ▼
                  ┌──────────────────────┐
                  │  Grade Hallucination │
                  └──────────────────────┘

Унутршчы канклавных компанентаў LangGraph

У рэхбуку «Внутршняя частка компанентаў LangGraph» паказваецца, як перад змянай коду неабходна задаць вхідныя даны, адпаведальнага за выкананне крока і крэтыяры завершэння. Аператары должны магчымае перайсці на выкананне крока з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Паралельна з функцыйнымі рэзультатамі неабходна фіксаваць час выканання, а таксу токенаў чы запытаў. Візуабільнасць костов выканання з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмовай асяроддзя ў спяльную. Паказваецца, якія самэ часткі тэксту сталі падставай для адпаведнага адказу. Без ціх цытатаў аператары не можуць разлічыць галюцынацію ад працягу праз прызнакі індэксавання. У рэхбуку «Внутршняя частка компанентаў LangGraph» паказваецца, як перад змянай коду неабходна задаць вхідныя даны, адпаведальнага за выкананне крока і крэтыяры завершэння. Аператары должны магчымае перайсці на выкананне крока з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Неабходна адзначыць як шлях успеху, так і шлях вярнення да нормальнага стану. Перапрыбуткі, людзкія перакрыцця і обработка некорэктных паведамленняў ёсць часткай продукту, а не дадатковым элементам пасля яго стварэння.

Калі працуеце над рэалізацыяй Центральнага стану графа, спачатку запісайце умовы вікорыстання: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць на падзею частковага невыпання. Такі спіс контроля дапамагае заліцьваты змяны ў кодзе чыстымі. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, невыпанне должна паказваць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцюг задач. Перад налаштаваннем запітоў пераканайцеся, што сістэма правільна запам’ятаўляе інформацыю, выкорыстоўваючы фіксаваны набор запітанняў. Частае зміненне запітоў рэдка калі-небудзь выправляе слабкую спроможнасць сістэмы да пошуку інформацыі.

from typing import List, TypedDict
class GraphState(TypedDict):
    """
    Represents the central state of our Self-RAG agent.

    This TypedDict serves as the single source of truth passed between
    each node in the LangGraph execution flow.
    """
    question: str       # The original user query
    generation: str     # The most recent answer generated by the LLM
    documents: List[str] # Relevant text passages retrieved from our database
    steps: List[str]    # An audit trail tracking the sequence of execution steps

Стварэнне графа, частка 1: Апісанне вузлаў стану і дзеяння

Калі працюеце над «Стварэнне графа, частка 1: Апішанне вузлаў стану і дзеяння», спачатку запісайце контракт: неабходныя вхідныя даны, сігнал успеху і тое, што выходзіць у разе частковага невыпання. Такі спіс контроля дапамагае заліцьваты змяны ў кодзе пазнейша. Спрэцьвячайце гэты этап як контракт між вхіднымі данымі і перакананымі выходнымі рэзультатамі. Дайце назвы элементам, апішыце крытэрыя успеху і не падтрымайце частковае завершэння без паведамлення. Змяркуйце ступень відтворэння інформацыі на фіксаванай сэтке запітаў прычым перад налаштаваннем підказак. Часта змена підказак рэдка калі выправляе слабкую сістэму пошуку інформацыі.

Розумэнне оркестрацыі на адной засадзе стану

Калі працюеце над «Розумэннем оркестрацыі на адказе стану», спачатку запісайце умовы вярбунка: неабходныя даныя, сігнал успеху і тое, што выканаецца пад частковай нявыходзе. Такі спіс дапамагае залічваць пазнейшыя змены ў кодзе чыста.

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

Перад налаштаваннем запрошэнняяў (prompts) пераканайцеся ў якосці адзыўа на фіксаваны набор запытанняў. Частае змены запрошэнняяў рэдка калі-небудзь вылечваюць слабкую якосць адзыўа.

Калі працюеце над «Розумэннем оркестрацыі на адказе стану», спачатку запісайце умовы вярбунка: неабходныя даныя, сігнал успеху і тое, што выканаецца пад частковай нявыходзе. Такі спіс дапамагае залічваць пазнейшыя змены ў кодзе чыста.

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

+-------------------------------------------------------------+
|                         GRAPH STATE                         |
|  - question: str                                            |
|  - documents: List[Document]                                |
|  - generation: str                                          |
|  - relevance_grade: str                                     |
+-------------------------------------------------------------+
                              |
       +----------------------+----------------------+
       |                      |                      |
       v                      v                      v
+--------------+       +--------------+       +--------------+
| Retrieve     |       | Grade Docs   |       | Generate     |
| Node         |       | Node         |       | Node         |
+--------------+       +--------------+       +--------------+

Праектаванне рэўістры спакушанага стану

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

from typing import List, Dict, Any
from typing_extensions import TypedDict
from langchain_core.documents import Document

class GraphState(TypedDict):
    """
    Represents the state of our Self-RAG graph.
    Attributes:
        question: The user query string.
        documents: A list of retrieved document chunks.
        generation: The generated answer from the LLM.
        relevance_grade: The evaluation score of our documents ('yes' or 'no').
    """
    question: str
    documents: List[Document]
    generation: str
    relevance_grade: str

Узлок выявлення: вяроўнаванне з базамі знаёмых

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

from langchain_core.vectorstores import InMemoryVectorStore
from langchain_core.embeddings import FakeEmbeddings

# Initialize a mock vector store to simulate a production knowledge base
embeddings = FakeEmbeddings(size=1536)
vectorstore = InMemoryVectorStore(embeddings)
# Seed our vector store with sample documentation chunks
vectorstore.add_documents([
    Document(page_content="LangGraph is a library for building stateful, multi-actor applications with LLMs.", metadata={"source": "docs"}),
    Document(page_content="Self-RAG is an architecture that introduces self-reflection and grading into retrieval chains.", metadata={"source": "paper"}),
    Document(page_content="Vector databases index text embeddings to enable fast semantic similarity search.", metadata={"source": "tech-blog"})
])
# Create a retriever interface
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})
def retrieve(state: GraphState) -> Dict[str, Any]:
    """
    Retrieve documents from the vector database based on the current question.
    Args:
        state (GraphState): The current state of the graph.
    Returns:
        dict: An update to the state containing the retrieved documents.
    """
    print("--- NODE: RETRIEVING DOCUMENTS ---")
    question = state["question"]

    # Perform the semantic vector search
    retrieved_docs = retriever.invoke(question)

    # Return the updated document list to the graph state
    return {"documents": retrieved_docs}

Узел генеравання: Сінтэза, ўрахоўваючы кантэкст

Узел «Генераванне**: Сінтэз, які врачоўвае кантэкст, працюе найэфектывней, калі яго розглядаць як вімерную паверхню. Зафіксавайце адна ідэальная транскрыпцыя, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць масштабы. Запісвайце часы выканання і косты токеноў або запытаў разам з функцыйнальнымі рэзультатамі. Візуабілізацыя костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмовай асяроддзя ў спакульную. Раздзеліце політыку часткавання дадзеных ад політыкі ўзяць іх. Змена адной з яных не павінна вымагаць перапісвання другой, калі зменяюцыся показнікі якосці. Узел «Генераванне**: Сінтэз, які врачоўвае кантэкст, працюе найэфектывней, калі яго розглядаць як вімерную паверхню. Зафіксавайце адна ідэальная транскрыпцыя, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць масштабы. Дакументавайце як успішны, так і вярнэнчы паты разам. Перапрыбуткі, людзкі контроль і обработка некорэктных паведамленняў ёсць часткай продукту, а не етапамі далейшай доўнелівання.

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.language_models.fake import FakeListLLM

# Set up a mock LLM that simulates generating structured responses
# In production, replace this with: from langchain_openai import ChatOpenAI
llm = FakeListLLM(responses=[
    "Self-RAG is an advanced architecture that uses self-reflection and document grading to improve retrieval accuracy."
])
def generate(state: GraphState) -> Dict[str, Any]:
    """
    Generate an answer using the retrieved documents as grounding context.
    Args:
        state (GraphState): The current state of the graph.
    Returns:
        dict: An update to the state containing the generated answer.
    """
    print("--- NODE: GENERATING ANSWER ---")
    question = state["question"]
    documents = state["documents"]

    # Format the retrieved documents into a single context block
    context = "\n\n".join([doc.page_content for doc in documents])

    # Construct the instruction prompt
    prompt = ChatPromptTemplate.from_template(
        "You are an assistant for question-answering tasks.\n"
        "Use the following pieces of retrieved context to answer the question.\n"
        "If you do not know the answer, say that you do not know.\n"
        "Question: {question}\n"
        "Context: {context}\n"
        "Answer:"
    )

    # Format the prompt with our state variables and run the model
    chain = prompt | llm
    generation = chain.invoke({"question": question, "context": context})

    # Save the generated response to the state
    return {"generation": generation}

Узел дакументаў прызначэння: Інспектар якосці

Для вузла дакументаў класа: інспектар якосці павінен перад змянай коду вызначыць параметры вхідных дадзеных, абавесця крока і крытэрыі завершэння. Аперацыяныя працавнікі павінны магчымае перазапускаць крок з вядомай точкі контролю, не прабуючы спадарожваць схованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выконваецца, прычына неудачы павінна вказываць на адну конкрэтную абавесць, а не на заплутаны ланцюг задач. Прытамульвайце тыя часткі тэксту, якія фактычна лежаць у падставе адпаведнай адказы. Без ціх прамянаў аперацыяныя працавнікі не зможуць адразліць галюцынацыю ад прасоўкі ў індэксацыі.

                               +-------------------+
                               |  Retrieved Docs   |
                               +-------------------+
                                         |
                                         v
                             +-----------------------+
                             |   Is Doc Relevant?    |
                             +-----------------------+
                                   /           \
                             Yes  /             \  No
                                 /               \
                                v                 v
                      +-------------------+     +------------------+
                      | Keep in State     |     | Filter / Discard |
                      | (Pass to Gen)     |     | (Trigger Loop)   |
                      +-------------------+     +------------------+
from pydantic import BaseModel, Field
from langchain_core.output_parsers import JsonOutputParser

class DocumentGrade(BaseModel):
    """Binary score for document relevance assessment."""
    binary_score: str = Field(
        description="Relevance score for the document. Must be 'yes' or 'no'."
    )
def grade_documents(state: GraphState) -> Dict[str, Any]:
    """
    Assess whether the retrieved documents are relevant to the user question.
    Filters out any irrelevant documents from the state.
    Args:
        state (GraphState): The current state of the graph.
    Returns:
        dict: Updated documents list and a global relevance grade flag.
    """
    print("--- NODE: GRADING RETRIEVED DOCUMENTS ---")
    question = state["question"]
    documents = state["documents"]

    # Use a mock parser to simulate LLM grading
    # In production, use: llm.with_structured_output(DocumentGrade)
    parser = JsonOutputParser(pydantic_object=DocumentGrade)

    filtered_docs = []
    has_relevant_doc = "no"

    # Evaluate each document individually
    for doc in documents:
        # Construct a strict grading prompt
        grade_prompt = (
            f"Question: {question}\n"
            f"Document: {doc.page_content}\n"
            "Assess if this document is relevant to the question. Output JSON with key 'binary_score' as 'yes' or 'no'."
        )

        # Simulating LLM evaluation logic (in production, run the LLM chain here)
        # For our mock run, if the query terms overlap with the document, mark 'yes'
        is_relevant = any(term.lower() in doc.page_content.lower() for term in question.split())
        score = "yes" if is_relevant else "no"

        if score == "yes":
            print(f"  -> DOCUMENT GRADING: [RELEVANT] - Source: {doc.metadata.get('source')}")
            filtered_docs.append(doc)
            has_relevant_doc = "yes"
        else:
            print(f"  -> DOCUMENT GRADING: [NOT RELEVANT] - Source: {doc.metadata.get('source')}")

    # Update state with filtered documents and set the control flag
    return {
        "documents": filtered_docs,
        "relevance_grade": has_relevant_doc
    }

Стварэнне графа, частка 2: З’ўязкі рашэнняў за дапамой умовных канцоў

Для стварэння графа, частка 2: Спаяванне рашэнняў за дапамою умовных краяў — перад зменай коду неабходна задаць вхідныя даны, адпаведальнага за крок і крытэрыя завершэння. Аператары должны магчымае перзапускіць крок з вядомай точкі контролю, не падозрываючы прыхованы стан. Спрыяйце гэтаму этапу як кантракту межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Дайце назвы артыфактам, задаць перакананні на успех і адмовіцеся ад бяспрэчнага частковага завершэння. Цітуйце тыя часткі, якія фактычна ляглі в основу адпаведнай адказы. Без цітатаў аператары не можуць разлічыць галюцынацію ад прасоў у індэксаванні.

                  +------------------+
                  |  route_question  |
                  +--------+---------+
                           |
            +--------------+--------------+
            |                             |
     [web_search]                    [retrieve]
            |                             |
            +--------------> +------------+-------------+
                             |     grade_documents       |
                             +------------+--------------+
                                          |
                                    +-----+-----+
                                    |  Decision |
                                    +-----+-----+
                                          |
                        +-----------------+-----------------+
                        |                                   |
                  (transform_query)                     (generate)
                        ^                                   |
                        |                            +------+------+
                        |                            |  Decision   |
                        |                            +------+------+
                        |                                   |
                        +--- [hallucination / unsat] -------+------> [__end__]

Маршрутазатор входнай тачкі: адначасовая пераглядка запыту

Для маршрутазаводчыка входнай точкі: спачатку перагляньце запіт. Перш чым зменіць код, задаце вхідныя даны, адміністратара крока і крытэрыя завершэння. Аператары должны магчымаць перзапуск крока з вядомай точкі контролю без неабясненняя схованага стану. Запішыце час выканання і вартась токена або запіту разам з функцыональнымі рэзультатамі. Відразувая вартась запобегае неспакоўным рахункам, калі траекторыя пераходзіць з дэмавай версіі ў спакульнаныя сераўеры. Указаце часткі тэксту, якія фактычна сталі падставай для адпаведнага адказу. Без ціх цытатаў аператары не можуць разлічыць галюцынацію ад прасоў у індэксаванні. Для маршрутазаводчыка входнай точкі: спачатку перагляньце запіт. Перш чым зменіць код, задаце вхідныя даны, адміністратара крока і крытэрыя завершэння. Аператары должны магчымаць перзапуск крока з вядомай точкі контролю без неабясненняя схованага стану. Дакументавайце як успішную, так і варыянтныя траекторыі. Перапрыбуткі, людзкія контролі і обработка некорэктных паведамленняў ёсць часткай гэтага працэсу.

Тэнпродакт, а не пазнейшая обработка.

# router.py
from typing import Literal
from pydantic import BaseModel, Field
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from state import AgentState

# Define the structured output schema for our router
class RouteQuery(BaseModel):
    """Route a user query to the most authoritative datasource."""
    datasource: Literal["vectorstore", "web_search"] = Field(
        ...,
        description="Given a user question choose to route it to web search or a vectorstore.",
    )
def route_question(state: AgentState) -> str:
    """
    Routes the initial question to either the vectorstore retrieval node or web search.

    Args:
        state (AgentState): The current graph state containing the user query.

    Returns:
        str: The next node to execute ("vectorstore" or "web_search").
    """
    print("--- ROUTING QUESTION ---")
    question = state["question"]

    # Initialize our LLM with structured output mapping to our Pydantic schema
    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
    structured_router = llm.with_structured_output(RouteQuery)

    # Create the routing system prompt
    system_prompt = """You are an expert router directing user questions to a vectorstore or web search.
    The vectorstore contains highly technical documentation regarding LangGraph, LangChain, and state machines.
    Use the vectorstore for these specialized topics. Otherwise, use web_search for general knowledge or current events."""

    route_prompt = ChatPromptTemplate.from_messages([
        ("system", system_prompt),
        ("human", "{question}"),
    ])

    # Run the router chain
    router_chain = route_prompt | structured_router
    decision = router_chain.invoke({"question": question})

    if decision.datasource == "web_search":
        print("--- ROUTING TO WEB SEARCH ---")
        return "web_search"

    print("--- ROUTING TO VECTORSTORE ---")
    return "retrieve"

The Context Gate: Ацэнка значамасці дакумента

Кал працуеце над The Context Gate: Ацэнка значамасці дакумента, спачатку запісайце кантракт: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі спіс перакладзець дапамагае залічыць пазнейшыя змены ў кодзе. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Кал якісь крок не выйшоў, нявыпанне должна паказваць на адну адпаведальнасць, а не на заплутаны ланцужок задач. Замерайце рывень адзыскання на фіксаванай сэтке запітаў прычым рэгулюванні прамптав. Частае змены прамптав рэдка калі вылечваюць слабую сістэму адзыскання інфармацыі.

# context_gate.py
from state import AgentState

def decide_to_generate(state: AgentState) -> str:
    """
    Evaluates the document grading state to choose the next step.

    If any documents were graded as relevant, we proceed to answer generation.
    If all documents were deemed irrelevant, we rewrite the query to try again.

    Args:
        state (AgentState): The current state of the agent.

    Returns:
        str: Next node to execute ("generate" or "transform_query").
    """
    print("--- ASSESSING DOCUMENT RELEVANCE ---")
    # Retrieve the decision variable set by the grading node
    run_web_search = state.get("run_web_search", False)

    if run_web_search:
        # No documents were relevant, we must rewrite and search the web
        print("--- DECISION: ALL DOCUMENTS IRRELEVANT, ROUTING TO QUERY TRANSFORMATION ---")
        return "transform_query"

    # We found relevant documents, we can proceed safely to generation
    print("--- DECISION: RELEVANT DOCUMENTS FOUND, ROUTING TO GENERATE ---")
    return "generate"

The Self-Correction Loop: Перакананне ў адданасці і практычнасці

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

                          +-------------------------+
                          |   Answer Generated      |
                          +------------+------------+
                                       |
                                       v
                      +--------------------------------+
                      |   Is the answer grounded in    |
                      |      retrieved context?        |
                      +----------------+---------------+
                                       |
                       +---------------+---------------+
                       |                               |
                     [No]                            [Yes]
                       |                               |
                       v                               v
             +-------------------+          +---------------------+
             | Re-route to:      |          | Is the answer       |
             | "generate"        |          | actually useful?    |
             +-------------------+          +----------+----------+
                                                       |
                                        +--------------+--------------+
                                        |                             |
                                      [No]                          [Yes]
                                        |                             |
                                        v                             v
                              +-------------------+         +------------------+
                              | Re-route to:      |         | Re-route to:     |
                              | "transform_query" |         | "__end__"        |
                              +-------------------+         +------------------+
# self_correction.py
from typing import Literal
from pydantic import BaseModel, Field
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from state import AgentState

class GradeHallucinations(BaseModel):
    """Binary score for hallucination present in generation."""
    binary_score: Literal["yes", "no"] = Field(
        ...,
        description="Answer is grounded in the facts, 'yes' or 'no'",
    )
class GradeAnswer(BaseModel):
    """Binary score to assess if answer addresses question."""
    binary_score: Literal["yes", "no"] = Field(
        ...,
        description="Answer addresses the question, 'yes' or 'no'",
    )
def grade_generation_v_documents_and_question(state: AgentState) -> str:
    """
    Grades the generation for hallucinations and utility.

    Args:
        state (AgentState): The current graph state.

    Returns:
        str: Next step path ("supported" -> check utility, "not supported" -> regenerate, "not useful" -> rewrite query)
    """
    print("--- CHECKING FOR HALLUCINATIONS ---")
    question = state["question"]
    documents = state["documents"]
    generation = state["generation"]

    # Initialize evaluator LLM
    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

    # ----------------------------------------
    # STEP 1: Groundedness (Hallucination) Check
    # ----------------------------------------
    hallucination_grader = llm.with_structured_output(GradeHallucinations)

    hallucination_system_prompt = """You are an objective grader assessing whether an LLM generation is grounded in / supported by a set of retrieved facts.
    Give a binary score of 'yes' if the generation is strictly grounded in and supported by the provided facts. Otherwise, give 'no'."""

    hallucination_prompt = ChatPromptTemplate.from_messages([
        ("system", hallucination_system_prompt),
        ("human", "Set of facts: \n\n {documents} \n\n LLM generation: {generation}"),
    ])

    # Format document contents into a single string context
    doc_context = "\n\n".join([doc.page_content for doc in documents])
    hallucination_chain = hallucination_prompt | hallucination_grader
    res = hallucination_chain.invoke({"documents": doc_context, "generation": generation})

    if res.binary_score == "no":
        print("--- DECISION: HALLUCINATION DETECTED! RE-TRYING GENERATION ---")
        return "generate"

    print("--- DECISION: GENERATION IS GROUNDED IN DOCUMENTS ---")

    # ----------------------------------------
    # STEP 2: Utility (Answer Relevance) Check
    # ----------------------------------------
    answer_grader = llm.with_structured_output(GradeAnswer)

    answer_system_prompt = """You are an objective grader assessing whether an LLM generation addresses and resolves the user's question.
    Give a binary score of 'yes' if the answer directly addresses and completely answers the user's question. Otherwise, give 'no'."""

    answer_prompt = ChatPromptTemplate.from_messages([
        ("system", answer_system_prompt),
        ("human", "User question: \n\n {question} \n\n LLM generation: {generation}"),
    ])

    answer_chain = answer_prompt | answer_grader
    res_answer = answer_chain.invoke({"question": question, "generation": generation})

    if res_answer.binary_score == "yes":
        print("--- DECISION: ANSWER IS USEFUL AND ACCURATE. ENDING GRAPH ---")
        return "useful"

    print("--- DECISION: ANSWER DOES NOT FULLY ADDRESS QUESTION. REWRITING QUERY ---")
    return "not useful"

Складанне і компіляцыя StateGraph

Калі працуеце над складаннем і компіляванням StateGraph, спачатку запісайце умовы вікорыстоўвання: неабходныя даны, сігнал успеху і тое, што выходзіць па частковай нявыполненасці. Такі спіс дапамагае залічыцца з пазнейшымі змянамі ў кодзе. Запісвайце час выканання і вартасць токеноў або запытак праза функцыйнае рэзультат. Відразлівае паказанне вартасцей запобегае неспадзяваным рахункам, калі працэс пераходзіць з дэмовай асяроддзя ў спакульнаныя сераўеры. Замерьце рэвізію на фіксованым наборы запытанняў прычыну налаштавання підказак. Частае змяненне підказак рэдка калі-небудзь выправляе слабкую сістэму пошуку інформацыі. Калі працуеце над складаннем і компіляванням StateGraph, спачатку запісайце умовы вікорыстоўвання: неабходныя даны, сігнал успеху і тое, што выходзіць па частковай нявыполненасці. Такі спіс дапамагае залічыцца з пазнейшымі змянамі ў кодзе. Аддзекументавайце як шлях успеху, так і шлях вярнення да нормы. Перапрыбуткі, людзкія контрольныя пункты і обработка некорэктных запытак ўжо ёсць часткай продукту, а не пазнейшым дапрацоўкам.

# graph_builder.py
from langgraph.graph import END, StateGraph
from state import AgentState

# Import node functions from Part 1
from nodes import retrieve, generate, transform_query, web_search, grade_documents
# Import conditional routing edges
from router import route_question
from context_gate import decide_to_generate
from self_correction import grade_generation_v_documents_and_question
# Initialize our state-based graph
workflow = StateGraph(AgentState)
# ----------------------------------------
# 1. Register All Computational Nodes
# ----------------------------------------
workflow.add_node("retrieve", retrieve)
workflow.add_node("grade_documents", grade_documents)
workflow.add_node("generate", generate)
workflow.add_node("transform_query", transform_query)
workflow.add_node("web_search", web_search)
# ----------------------------------------
# 2. Configure Node Routing & Transitions
# ----------------------------------------
# The entry point of our execution is dynamic, decided by the routing edge
workflow.set_conditional_entry_point(
    route_question,
    {
        "web_search": "web_search",
        "retrieve": "retrieve",
    },
)
# After retrieval, we must immediately grade our retrieved documents
workflow.add_edge("retrieve", "grade_documents")
# Once documents are graded, the Context Gate decides where to go
workflow.add_conditional_edges(
    "grade_documents",
    decide_to_generate,
    {
        "transform_query": "transform_query",
        "generate": "generate",
    },
)
# If query transformation occurs, we execute a web search to gather new data
workflow.add_edge("transform_query", "web_search")
# After web searching, we feed those newly acquired documents back to the grade step
workflow.add_edge("web_search", "grade_documents")
# Once generation occurs, our Self-Correction edge decides the final quality check
workflow.add_conditional_edges(
    "generate",
    grade_generation_v_documents_and_question,
    {
        "generate": "generate",          # Loop back to fix hallucination
        "not useful": "transform_query", # Loop back to rewrite query and search
        "useful": END,                   # Exit cleanly
    },
)
# ----------------------------------------
# 3. Compile and Run the Graph
# ----------------------------------------
app = workflow.compile()
# visualize.py
from graph_builder import app

try:
    # Print the plain text visualization of the state machine architecture
    app.get_graph().print_ascii()
except Exception as e:
    print(f"ASCII generation failed: {e}")
               +----------------+
               |  __start__     |
               +-------+--------+
                       |
             +---------+---------+
             v                   v
      +------------+      +------------+
      | web_search |      |  retrieve  |
      +-----+------+      +-----+------+
            |                   |
            |                   v
            |             +-----+------+
            |             | grade_docs |
            |             +-----+------+
            |                   |
            +---------+---------+
                      |
                      v
            +---------+---------+
            |  decide_to_gen    |
            +----+---------+----+
                 |         |
      +----------+         +----------+
      v                               v
+-----+------+                  +-----+------+
| transform_q|                  |  generate  |
+-----+------+                  +-----+------+
      |                               |
      |                               v
      |                     +---------+---------+
      |                     |  self_correct     |
      |                     +----+----+----+----+
      |                          |    |    |
      +--------------------------+    |    +---> [__end__]
                                      v
                                (regenerate)

Інжынерная сінтэза

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

Практычныя застосоўванні

Пры прыеме практычных застосоўкаў як мерыябельнай паверхні ўсё работае лепш. Зберыце адну ідэальную транскрыпцію, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану, перш чым расшырваць масштабы. Спрыяйце гэтаму этапу як кантракту межа вхіднымі дадзеннямі і перакананымі выходнымі рэзультатамі. Даўце назвы артыфактам, задаць крытэрыя успеху і адмовіцеся ад тыхнага частковага, непрыгляднага завершэння. Раздзеліце політыку часткавага апранкавання дадзеных і політыку ўтрымання іх. Змена адной з яных не павінна вымагаць перапісву другой, калі зменяюцыся паказнікі якосці.

Развітыя боты для падтрымкі клёўэнтаў

Працы для адвансаванага падтрымкі кляўэнта працуюць наякша, калі іх спрыяваць як мерыемую сферу. Зберагачыце адну ідэальную транскрыпцію, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць сферу дзеяння. Запісвайце часы выканання і кост токенаў або запытаў праза функцыйнае рэзультат. Відкрытыя даныя пра косцы з’являюцца рана, таму утрымліваецца неспакоўныя рахункі, калі працэс пераходзіць з дамавайна на спяльныя асяроддзя. Раздзеляйце політыку часткавага обрабоўвання дадзеных і політыку ўтрымання іх. Змена адной з іх не павінна вымагаць перапісвання другой, калі зменяюцыся паказнікі якосці. Працы для адвансаванага падтрымкі кляўэнта працуюць наякша, калі іх спрыяваць як мерыемую сферу. Зберагачыце адну ідэальную транскрыпцію, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць сферу дзеяння. Дакументавайце як успішны, так і вярнэнчы выкарыстоўвання робатаў. Перапробы, людзкія контрольны пункты і обрабоўванне непрацясных запытаў ёсць часткай продукту, а не пасляднім дапрацоўкам.

Автаматызаваныя сістэмы перакранчэння фактаў

Для аўтаматызаваных сістэм перакранчвання фактай неабходна пярэд змянай коду абмежыць вхідныя даны, адпаведальнага за кожны крок і крэтары выходу. Аператары должны магчымаць перзапуск крока з вядомай точкі контролю, не падозрываючы прыхованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выконваецца, прычына неудачы должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцюг задач. Прыкладзіце тыя часткі тэксту, якія фактычна лежалі в основе адпаведнай адказы. Без цых цітатаў аператары не зможуць разлічыць галюцынацію ад працягу праз прычыны, зв’язаныя з індэксаванням.

Дынамічныя двухэлементы рэкамендацый

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

Памагчыкі ў научных даследжэннях

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

Калі трэба выкорыстоўваць кожны падход?

Калі працуеце над пытаннем «Калі трэба выкорыстоўваць кожны падход?», спачатку запісайце умовы контракту: неабходныя даны, сігнал успеху і тое, што выходзіць на падчасныя неудачы. Такі чарткі дапамагаюць залічваць змяны ў кодзе. Валідзіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выходзіць, неудача должна адносіцца да адной відпаведальнасці, а не да заплутанага ланцуга задач. Перад налаштаваннем запітоў пераканайцеся, як сістэма адпаведзяў на фіксованы набор запітанняў. Частае зміненне запітоў рэдка калі-небудзь выправляе слабкую эфектыўнасць пошуку.

Нормы працы ў продакшэне: выкладкі, затрымкі і можлівасць адзоравання

Калі працюеце над кнігай «Production Guardrails: Costs, Latency, and Observability», спачатку запісайце угоду: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць у разе частковага абякання. Такій чарткі дапамагае заліцьваты пазнейшыя змены коду. Спрэцьвуйце гэты этап як угоду межа данымі і перакананымі выходамі. Дайце назвы артыкулам, задаць крытэрыя успеху і не падзеўляйцеся частковым завершэнням без паведамлення. Змяроўваце рэкалі на фіксаванай сэтке запытаў прычым падлашоўвання прапаза. Частыя змены прапаза рэдка калі выправляюць слабую эфектыўнасць адзысквання інформацыі.

Балансаванне костаў і звольнення за дапамою асіметрычнага маршрутызавання

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

Аварыяны выключальнікі ў стане LangGraph

Аварыяны выключальнікі ў стане LangGraph працуюць наяўней, калі іх розглядаць як вімерную паверхню. Зафіксавайце адна ідэальная транскрыпцыя, адзін прыклад неудачы і прыметку па адкату перш чым расшырваць масштаб. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выходзіць, прычына неудачы павінна вказываць на адную адпаведальнасць, а не на заплутаны ланцюг задач. Раздзеліце правілы часткавання інфармацыі ад правіла ўзяць яе. Змена адных не павінна вымагаць перапісву іншых, калі зменяюцыся паказчыкі якосці.

from typing import Dict, TypedDict, Literal

# Define graph state with a loop counter to act as a circuit breaker
class GraphState(TypedDict):
    question: str
    generation: str
    documents: list[str]
    loop_step: int  # Tracks iterations to prevent runaway execution costs
MAX_RETRIES = 3
def grade_generation_route(state: GraphState) -> Literal["web_search", "finalize", "max_retries_exceeded"]:
    """
    Evaluates the quality of generation and routes the agent accordingly.
    Why: Acts as a deterministic circuit breaker when LLMs get stuck in correction loops.
    """
    current_step = state.get("loop_step", 0)

    # 1. Evaluate circuit breaker before making any expensive LLM calls
    if current_step >= MAX_RETRIES:
        return "max_retries_exceeded"

    # 2. Simulated grader check (In production, this queries your grading model)
    is_accurate = False  # Assume we failed the grade in this step

    if is_accurate:
        return "finalize"
    else:
        # Route back for retrieval/generation rewrite
        return "web_search"

Структураваныя запросы для дэтэрміністычнага оценкавання

Структураваныя запросы для дэтэрміністычнага ацэнкавання работаюць наяўна, калі іх спрыяваць як мерыемую структуру. Запісаўце адну ідэальную версію рэзультата, адны прыклад неудачы і прыметкі па поверненню да пачатковага стану пры расшырэнні масштаба. Спрыяйце гэтаму этапу як кантракту межа вхіднымі дадзеннямі і паверыцельнымі выходамі. Даўце назвы артыфактам, задаце крытэрыя успеху і не падтрымайце тыхі, частковыя рэзультаты. Задаце ліміт токенав на кожны раунд і на кожную сесію. Інструменты-агенты агрэсывна расшырваюць кантэкст; строгі ліміты не дазволяюць дэманстрацыям ператварацца на неспакоючыя рахункі.

from langchain_core.pydantic_v1 import BaseModel, Field

class GradeDocument(BaseModel):
    """Binary score for document relevance assessment."""

    binary_score: str = Field(
        description="Relevance score for the document. Must be 'yes' or 'no'."
    )
    explanation: str = Field(
        description="A brief, single-sentence justification for the given score."
    )

Аналіз выканання графа з вядомасцю пра стан сістэмы

Выкананне графа трэйсінгу з адказвамі апаратных засобаў спостэрэння даходзіць до наявнасці лепшых рэзультатаў, калі яго спрыяваць як меравальную плошчу. Зберагачыце адны ідэальны транскрыпт, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба. Запісвайце часы выканання і косты токенаў або запытак паляглі разам з функцыйнальнымі рэзультатамі. Відразлівае прадставленне костаў з’являецца перашкодай неспакойным рахункам, калі працэс пераходзіць з дэмовай асяроддзя ў спяльнаныя сераўеры. Раздзеляйце політыку часткавага апрацоўвання дадзеных і політыку ўтрымання іх. Змена адной з яных не павінна вымагаць перапісвання другой, калі зменяюцыся паказнікі якосці. Выкананне графа трэйсінгу з адказвамі апаратных засобаў спостэрэння даходзіць до наявнасці лепшых рэзультатаў, калі яго спрыяваць як меравальную плошчу. Зберагачыце адны ідэальны транскрыпт, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба. Дакументавайце як успешны, так і вярнэльны шляхы выканання. Перапрыбуткі, людзкія контрольны пункты і апрацоўка неканальных паведамленняў ёсць часткай продукту, а не элементамі пазнейшага доўнелення.

[User Query] ──> [retrieve] ──> [grade_documents] (Score: No)
                                      │
                                      ▼
[finalize] <── [generate] <── [web_search] (Updated State: Loop Count = 1)

Што раскрывае рабочы працэс, керованы станам

Ёнколі трэба выявіць, што паказвае робочы працэс, калі ён керуецца станам, неабходна прадзеява параметраў, вызначэнне адпаведальнага за крок і крытэрыя завершэння пры перадзмене коду. Аперацыйныя працавікі павінны магчымае перадзначыць крок з вядомай точкі контролю, не падозрываючы прыхованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест амаль неканчатых скрыптав. Калі крок не выйшае, прычына неудачы павінна вказываць на адзін конкрэтны аспект, а не на заплутаны ланцужок задач. Наводзіце тыя часткі тэксту, якія фактычна лежаць у падставе адпаведнай адказы. Без ціх цытатаў аперацыйныя працавікі не зможуць разлічыць галюцынацію ад працявы неканчатых індэксав.

Чэрніця аперацыйнай працы

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

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

Адзінакова палітыка фрагментавання і палітыка адчынення. Змена адной з іх не павінна вымагаць перапісвання другой, калі зменяюцыся паказнікі якосці.

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

Напісце кароткі посібнік: як роўнаць клучы, як спрачыслаць чэргу, як анулюваць пярэдніе дадзеныя.

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

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

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