Практычныя прытамулі: як паспрацаваць з системай RAG, якая продовжвае выкарыстоўваць некоректны контэкст
Практычныя памяткі: як вылечыць систему RAG, якая продовжае знаходзіць некоректны контэкст; кантракты, перакрыцці та слоты для коду для команд, якія використоўваюць гэты патерн.
Існавайце гэта як перапрацоўку ідэй з артыкула «Як паспрабаваць вылечыць систему RAG, якая продовжвае знаходзіць некоректны контэкст» для аператараў: чыткія этапы, аранжаваныя блакі коду і прыметкі з восстанавлення, якія застаюцца пасля перадачы задання. Этап «Апглэйв» работае найкраща, калі яго розглядаць як вимерную плошчу. Запісаўце адна ідеальная транскрыпцыю, адзін прыклад неудачы і прыметку з вярнення да пачатковага стану прычаму расшырэння масштаба. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісьць крок не выходзіць, прычына неудачы павінна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцюг задач.
Вам была патрэбна неудача, якую можна было б відтворыць
Калі вам патрабуецца этап апрацоўкі з можлівасцю няудачы, перад зменым коду неабходна задаць вхідныя даны, адпаведальнага за шаг і крэтыяры завершэння. Аперацыёныя працавнікі должны магчыма было перзапускаць шаг з вядомай точкі контролю, не падозрываючы прыхованы стан. Спрыяйце гэтаму этапу як кантракту межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Даць назвы артыфактам, задаць перакананні на успех і адмовіцца ад беззвучнага частковага завершэння. Указваць тыя часткі тексту, якія фактычна лежаць у падставе адпаведнай адказы. Без ціх цитатаў аперацыёныя працавнікі не зможуць адразніць галюцинацыю ад прасоўкі ў індэксаванні.
chunks = [
{
"id": "audit_03",
"source": "audit-logs",
"text": (
"Enterprise audit logs are retained for 365 days "
"before automatic deletion."
),
},
{
"id": "errors_07",
"source": "api-errors",
"text": (
"NX-204 means the requested resource exists but is not "
"available in the caller's current region."
),
},
{
"id": "exports_01",
"source": "csv-exports",
"text": (
"CSV exports run asynchronously and appear in the exports "
"panel when processing completes."
),
},
{
"id": "exports_04",
"source": "csv-exports",
"text": (
"A completed CSV download link remains active for seven days."
),
},
]
eval_cases = [
{
"query": "How long are enterprise audit logs kept?",
"relevant": {"audit_03"},
},
{
"query": "What does error NX-204 mean?",
"relevant": {"errors_07"},
},
{
"query": "How long is a CSV export link usable?",
"relevant": {"exports_04"},
},
]
Вы пачалі з намерна простаг абробніка даных
Для таго, каб вы пачалі з адзінаго этапа, перад змянайом код неабходна ўзначыць вхідныя даны, адпаведальнага за шаг і крэтарыя выходу. Аператары должны магчымае перайсці на гэты шаг з вядомай точкі контролю, не падозрываючы прыхованы стан. Запісвайце час выконання і вартась токенаў або запытак па боку функцыйнаых рэзультаатаў. Відразлівая вартась з самага пачатку запобегае неспакоўным рахункам, калі процес пераходзіць з дэмавайнага режыма ў спяльныя среды. Указвайце тыя часткі тексту, якія фактычна лежалі в основе адпаведнай адказу. Без цых цітатаў аператары не можаюць разлічыць галюцинацію ад прасоўкі ў індэксаванні.
import numpy as np
from sklearn.decomposition import TruncatedSVD
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.preprocessing import normalize
class LsaRetriever:
def __init__(self, chunks, dims=16):
self.chunks = chunks
self.tfidf = TfidfVectorizer(
stop_words="english",
ngram_range=(1, 2),
sublinear_tf=True,
)
term_matrix = self.tfidf.fit_transform(
chunk["text"] for chunk in chunks
)
# The corpus is tiny. SVD doesn't need dimensions it cannot use.
dims = min(
dims,
term_matrix.shape[0] - 1,
term_matrix.shape[1] - 1,
)
if dims < 1:
raise ValueError("Need more text to build the LSA index.")
self.svd = TruncatedSVD(
n_components=dims,
random_state=0,
)
self.index = normalize(
self.svd.fit_transform(term_matrix)
)
def search(self, query, limit=None):
query_vec = self.tfidf.transform([query])
query_vec = normalize(self.svd.transform(query_vec))
similarity = cosine_similarity(
query_vec,
self.index,
)[0]
ranked = np.argsort(similarity)[::-1]
if limit is not None:
ranked = ranked[:limit]
return [
(self.chunks[i], float(similarity[i]))
for i in ranked
]
1. 0.879 exports_01
CSV exports run asynchronously and appear in the exports panel...
2. 0.843 exports_02
Large exports are split into multiple compressed files.
3. 0.830 exports_03
Users can cancel an export while it is still queued...
4. 0.772 exports_04
A completed CSV download link remains active for seven days.
Найпростейшыі інструмент для адлучэння бягаў быў найкорыстнейшы
У найпростейшым стадіях адміністрацыі кашэлей неабходна прадзеява вхідных дадзеных, адначальніка крока і крэтарыяў завершэння працы перад зменым коду. Аперацыйныя працавнікі должны магчымае перайсці на гэты крок з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Конфігурацыю трэба знаходзіць за межамі коду прыемленае. Файлы сераўіса, хранальнікі секрэтных дадзеных і флагі функцый належыць у аднам месца, якое працавнікі можуць пераглядаць, не чытаючы весь код. Неабходна цітацыя тых частак, якія фактычна лежаць у падставе адпаведнай адказы. Без цітацый працавнікі не можуць адразліць галюцинацыю ад працявання з індэксамі. У найпростейшым стадіях адміністрацыі кашэлей неабходна прадзеява вхідных дадзеных, адначальніка крока і крэтарыяў завершэння працы перад зменым коду. Аперацыйныя працавнікі должны магчымае перайсці на гэты крок з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выйшаў, прычына неудачы должна вказываць на адну конкрэтную адпаведальнасць, а не на шмат.
гэта лепша, чым заплутаная сістэма трубаў.def show_hits(retriever, query, limit=5):
print(f"\n{query}\n")
for position, (chunk, score) in enumerate(
retriever.search(query, limit),
start=1,
):
print(
f"{position:>2}. {score:.3f} "
f"{chunk['id']} ({chunk['source']})"
)
print(f" {chunk['text']}\n")
Вы не хацелі, каб ацэнка была прыязваная да точных словаў
Калі працуеце на стадыі, куды вы не хацелі прыязвання, спачатку запісайце контракт: неабходныя даны, сігнал успеху і тое, што выходзіць, калі адбываецца частковая нявыплата. Гэты список контроля дапамагае заставіць пазнейшыя змены коду застацца чыстымі. Спрыяйце гэтай стадыі як контракту межаў уваходных даных і перакананых выходных рэзультатаў. Дайце назвы артыфактам, задаць тэсты на успех і адмовіцеся ад мовчанкавага частковага завершэння. Замерайце рівень запам’ятовання на фіксаванай сэтке пытанняў прычым регулюванні запрошэнняў. Частае змены запрошэнняў рэдка калі вялікі эфект на слабую систему адзыскання інформаціі.
if answer_hint in chunk["text"]:
...
def evaluate_retriever(retriever, cases, k=3):
recall_scores = []
reciprocal_ranks = []
for case in cases:
hits = retriever.search(case["query"])
relevant = case["relevant"]
relevant_positions = [
position
for position, (chunk, _) in enumerate(hits, start=1)
if chunk["id"] in relevant
]
found_in_top_k = sum(
position <= k
for position in relevant_positions
)
recall_scores.append(
found_in_top_k / len(relevant)
)
reciprocal_ranks.append(
1 / relevant_positions[0]
if relevant_positions
else 0.0
)
return {
f"recall@{k}": float(np.mean(recall_scores)),
"mrr": float(np.mean(reciprocal_ranks)),
}
Потым вы звінавалі чанківацыю
Калі працуеце над стадзіяй «Then you blamed chunking», спачатку запісайце умовы: неабяжлівыя даны, сігнал успеху і тое, што выходзіць пад частыя неудачы. Такі список контроля дапамагае заліцьварыцца пад змяны коду пазнейша. Запісвайце час выканання і кост токеноў або запытаў праза функцыйнае рэзультат. Відразлівасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмаверсіі ў спяльныя среды. Замерьце рэкалі на фіксаванай сэтке запытаў прычым пад налаштаванне прапазаў. Частыя змены прапазаў рэдка калі-небудзь выправляюць слабую эфектыўнасць адзысквання інформаціі.
chunk_size = 500
chunk_overlap = 50
BM25 зробіў эксперымент часткова нязгодным
Калі працуеце з BM25 у стадії експерыментаў, спачатку запісайце умовы викорыстоўвання: неабходныя даны, сігнал успеху і тое, што выходзіць па частковай нявыполненасці. Такі список дапамагае залічыць пазнейшыя змены ў кодзе.
Вы все жа хацелі оба сігналы
Дабы працаваць з обомі етапамі наявнаш чыннае рашэнне, якое можна вымерыць. Запісаўце адны «золаты» прыклад, адну справу з нявярным рэзультатам і прыказку пра адкатацыю, перш чым расширваць масштабы. Спрыяйце гэтаму етапу як кантракту межаў уваходных дадзеных і перакананых выходных рэзультатаў. Даўце назвы артыфактам, задаце критэрыя успеху і не падзеўляйцеся частым, непূরным выкананнем задачы. Раздзеліце правілы часткавага абрабоўвання дадзеных і правілы ўтрымання іх. Змена адных не павінна вымагаць перапісвання іншых, калі змянююцца паказнікі якосці.
from collections import defaultdict
def fuse_rankings(vector_hits, bm25_hits, rrf_k=60):
fused = defaultdict(float)
chunks_by_id = {}
for hits in (vector_hits, bm25_hits):
for rank, (chunk, _) in enumerate(hits, start=1):
chunk_id = chunk["id"]
chunks_by_id[chunk_id] = chunk
fused[chunk_id] += 1 / (rrf_k + rank)
ranked_ids = sorted(
fused,
key=fused.get,
reverse=True,
)
return [
(chunks_by_id[chunk_id], fused[chunk_id])
for chunk_id in ranked_ids
]
def hybrid_search(query, lsa, bm25, candidate_k=20):
vector_hits = lsa.search(query, limit=candidate_k)
bm25_hits = bm25.search(query, limit=candidate_k)
return fuse_rankings(vector_hits, bm25_hits)
Reranking быў последнім элементам, які вы тэставалі
Праця над переранкінгамі ў якосты рэштнага этапу даўа найлепыя результаты, калі яе рассматрываць як меркаваную велічыну. Перш чым расширваць масштабы, зафіксавайце адны ідеальны прыклад, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану. Запісвайце часы выконання, а таксу на токены чы запиты праза функцыйнальныя рэзултаты. Відразувая візуабельнасць костоў запобегае неспакойным рахункам, калі процес пераходзіць з дэмовай среды ў спакульную. Раздзеляйце правілы часткавання дадзеных ад правілаў ўзяць іх. Змена аднаго з яных не должна вымагаць перапісвання другога, калі зменяюцыся паказнікі якосці.
def cheap_local_rerank(query, candidates, limit=5):
"""
Good enough for this experiment.
I'd use a learned reranker for a real deployment.
"""
candidate_text = [
chunk["text"]
for chunk, _ in candidates
]
tfidf = TfidfVectorizer(
analyzer="char_wb",
ngram_range=(3, 5),
min_df=1,
)
matrix = tfidf.fit_transform(
[query, *candidate_text]
)
relevance = cosine_similarity(
matrix[0],
matrix[1:],
)[0]
reranked = sorted(
zip(candidates, relevance),
key=lambda row: row[1],
reverse=True,
)
return [
(chunk, float(score))
for ((chunk, _), score) in reranked[:limit]
]
Канечныя цыфры выйшлі менш цікавымі, чым вы спакоюваліся
Канцэнтрыя на стадыях працюе лепш, калі яе спрыявае можна змеры. Перад расшырэнням масштаба зафіксавайце адны ідеальны прыклад, адну справу з бягамі і прыметку па адварцыю. Храніце настройкі за межамі коду прыемліка. Файлы сераўнавання, сховішчы секрэтных данных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаць адбавіць аудыт без неабяжнага чытання всіх дадзеных. Раздзеляйце правілы часткавання дадзеных ад правілаў ўзяць іх. Змена ў адных не павінна вымагаць перапісву іншых, калі зменяюцыся паказателі якосці. Канцэнтрыя на стадыях працюе лепш, калі яе спрыявае можна змеры. Перад расшырэнням масштаба зафіксавайце адны ідеальны прыклад, адну справу з бягамі і прыметку па адварцыю. Вядомей выбірайце маленькія, тэставаныя елементы замест абмежлёных скрыптов. Калі якісь крок збягае, прычына бягу павінна вказываць на адную адпаведальнасць, а не на заплутаны ланцоўкі працы.
Праця з запитам CSV
Для стадіі «Працэўнае вярненне да CSV» неабходна пазначыць вхідныя даны, адпаведальнага за этап і крэтырыя завершэння прычыні змены коду. Аперацыйныя працавнікі должны магчымае перайсці на гэты этап з вядомага пункта контролю, не прымоўляючыся да невідомых станаў. Спрыяйце гэтай стадіі як даговору межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Даўце назвы артыфактам, пазначыце крэтырыя успеху і не прымайце часткова завершаныя рэзультаты без паведамлення. Цітуйце тыя часткі тексту, якія фактычна лежаць у падставе адпаведнай адказы. Без цітатаў аперацыйныя працавнікі не зможуць адразніць галюцинацыю ад працэсу індексавання.
How long is a CSV export link usable?
1. CSV exports run asynchronously...
2. Large exports are split...
3. Users can cancel an export...
4. A completed CSV download link remains active for seven days.
1. A completed CSV download link remains active for seven days.
2. Users can cancel an export while it is still queued...
3. CSV exports run asynchronously...
Порядак адлагоджэння тепер значна простыяй
Для правільнага адміністрування неабяжна пэраспектыва: спачатку трэба визначыць данні, адпавядаючага адпаведальнага за крок і критэрыі завершэння, прычым перад зменой коду. Аператары должны магчымаць перзапуск кроку з вядомай точкі контролю, не падозрываючы прыхованы стан. Запісваць трэба час выконання і кост токенаў або запытаў разам з функцыйнальнымі рэзултатамі. Відразувыя данні пра косцы запобегаюць неспакойным рахункам, калі процес пераходзіць з дэмавайнага сераўера ў спяльныя среды. Неабходна цітаваць тыя часткі тексту, якія фактычна лежаць у падставе адпаведнай адказы. Без цітатаў аператары не можуць разлічыць галюцинацію ад прасоў у індэксаванні.
Заключныя меркі і выводы
У фазе заключных заўважэнняў і вывара неабходна практычна адзначыць вхідныя даны, адпаведальнага за крок і крэтарыя выходу пры перадзеі коду. Аператары должны магчымаць перзапуск крока з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Конфігурацыю трэба залічваць праза код аплікацыі. Файлы сяродавішча, хранільнікі секрэтных дадзеных і флагі функцияў должны знаходзіцца ў аднам месцы, якое аператары можаць пераглядаць, не чытаяўшы весь граф. Наводзіце тыя часткі, якія фактычна ляглі в основу адпаведнай адказы. Без цых цітатаў аператары не можаць разлічыць галюцинацію ад працягу індэксавання. У фазе заключных заўважэнняў і вывара неабходна практычна адзначыць вхідныя даны, адпаведальнага за крок і крэтарыя выходу пры перадзеі коду. Аператары должны магчымаць перзапуск крока з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Валічыце маленькія, тэставальныя елементы пра вялікія скрыпты. Калі крок не выйшаў, прычына неудачы должна вказываць на адну конкрэтную адпаведальнасць, а не на...
заплутаныя трубопрацесы.Чэрткі для аператывнай роботы
Калі працуеце над чэрткамі для аператывнай роботы, спачатку запісуйце умовы контракту: неабяжлівыя данні, сигнал успеху і тое, што выканаецца у разы ўзельнага неяксамоства. Што такое чэрткі, дапамагаюць залічваць змяны ў кодзе.
Документавайце як правільны, так і альтернатыўны шляхы роботы. Практыкі перапрыбутку, людзкія контралі і обработка некоректных паведамленняў є частью продукту, а не дадатковымі практыкамі.
Перад налаштаваннем запитоў замерайце рэткуюсьць на фіксаваным наборе запитанняў. Змена запитоў рэдка калі вярнайце слабкую якасць адзысквання інформаціі.
Закрепіце версіі залежнасцяў і запісайце хеш-значэнне зображэння, якое было выкарыстоўвана для дэманстрацыі. Возможнасць павторнага стварэння результатаў лепшая за традыцыйныя знання.
Вядзьмі прыоритет над малымі, тэставанымі елементамі працэсу над вялікімі скрыптамі. Калі якісь крок не выйшае, неяксамоства должны вказываць на адну конкрэтную адпаведальнасць, а не на заплутаныя трубопрацесы.
Зьвярзіце рэгулярнасць адгукавання на фіксованыя наборы запытанняў прычымо да налаштавання прамптаў. Частае змены прамптаў рэдка калі вярнуюць эфектыўнасць процэса адзысквання інфармацыі.
Перш чым пераходзіце да наступных крокаў, заморозьце версіі, зафіксуйце ідеальны транскрыпт для критычнага маршруту і паказваце способы адвярнення змян. У спільных средах неабходны ліміты на частоту запытанняў, пераказкі стану справ і чыста вялічына адпаведальнага за секрэты. Валіце простую надзяйнасць працы над крэатывнымі, але разовымі дамах.
Запіс для 4527c294eba8: не кладзіце ключы прадаўцаў у репазітарый, задаце ліміт токена на кожную сесію і зберагачыце транскрыпты празаўседліва з элементамі ацэнкі, каб пазнейшыя змены моделей заставаліся пораўнанневымі.
Калі працюеце над першым этапам зміцнення безпекі, спачатку запісайце шэраг умов: неабяжлівыя даны, сигнал працэйскага успеху і тое, што выканаецца у разе частковага нявыполнення. Такі список дапамагае заліцвачыць змяны ў кодзе па правдзе. Зберагайце настройкі за межамі коду прыемліка. Файлы сераўнавання, храненні секрэтных данных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаюць адбавіць аудыт без неабяжлівага чытання всей структуры.
Дзеянне зміцнення 0/820: вымерайце час выканання, класію памылак і колькасць выкорыстоўваных токенаў для гэтага пункту, а потым выберайце, чы робіць змяну на адной падставе фіксаванага набора пытанняў, а не на адной лічбе прыкладаў.