Галоўная / Артыкулы / Практычныя прытамулкі: Проектуванне циклу пасляўджэння агента: Ацэнка на рэвалюецыйскім рывне

Практычныя прытамулкі: Проектуванне циклу пасляўджэння агента: Ацэнка на рэвалюецыйскім рывне

Практычныя прытамулкі: Проектуванне циклу пасляўджэння агента: Ацэнка на рэвалюецыйскім рывне: контракты, перакананні та слоты для коду для команд, якія викорыстоўваюць гэты патэрн.

4955 слоў

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

Введэнне

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

Змест

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

Фаза 1: Фундамент

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

Настройка среды

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

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

Зробіце пераконтроўку пасля дорогіх крокаў. Програма не павінна зноў выклікаць той самы калл LLM, калі аператар прабуе зноў выконаць пазнейшы вузел.

# Install the libraries we need
pip install langgraph langchain langchain-openai langsmith
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY=your_langsmith_key
export LANGSMITH_PROJECT=agent-improvement-loop
export OPENAI_API_KEY=your_openai_key
# Step 1: Import the pieces we need
from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
# Step 2: Define two tools the agent can call
@tool
def get_account_info(account_id: str) -> str:
    """Look up basic information for an account by account_id."""
    fake_accounts = {
        "A100": "Account A100: plan=pro, status=active, email=ada@example.com",
        "A200": "Account A200: plan=free, status=suspended, email=turing@example.com",
    }
    return fake_accounts.get(account_id, f"No account found with id {account_id}")

@tool
def get_recent_orders(account_id: str) -> str:
    """Return the three most recent orders for a given account_id."""
    fake_orders = {
        "A100": "Orders for A100: #9001 shipped, #9002 processing, #9003 returned",
        "A200": "Orders for A200: no orders in the last 90 days",
    }
    return fake_orders.get(account_id, f"No orders for {account_id}")
# Step 3: Wire the tools into a ReAct agent
model = ChatOpenAI(model="gpt-4o-mini", temperature=0)
tools = [get_account_info, get_recent_orders]
agent = create_react_agent(model, tools)

Давайце працаваць з агентам

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

# Step 4: Invoke the agent with a simple query
result = agent.invoke({
    "messages": [{"role": "user", "content": "What plan is account A100 on?"}]
})

for message in result["messages"]:
    print(message.type, ":", message.content)

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

human : What plan is account A100 on?
ai :
tool : Account A100: plan=pro, status=active, email=ada@example.com
ai : Account A100 is on the pro plan.

Фаза 2: Збір лог-данных

Этап збору лог-данных Фазы 2 працюе найэфективнейша, калі яго розглядаць як вимерную паверхню. Зберагаеце адны ідеальны прыклад роботы, адзін прыклад неудачы і запіс працэй з відкатамі перш чым расширваць сферу даследжэння. Документавайце як шлях успеху, так і шлях відновлення разам. Перапрыбуткі, людзкі контроль і обработка некоректных поведэнняў є частью продукту, а не пасляднім дапрацоўкам. Храніце стан графа у простым і типаванам формате. Вкладныя структуры маскуюць інфармацыю пра тое, який вузел запісаў якое поле, і спакоююць продовжэнне виконання пасля перерываў.

Зялленне апошніх лог-данных з працуючага продукту

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

# Step 1: Create a LangSmith client
from langsmith import Client
from datetime import datetime, timedelta

client = Client()
# Step 2: List recent root runs from our project
recent_runs = list(client.list_runs(
    project_name="agent-improvement-loop",
    is_root=True,
    start_time=datetime.utcnow() - timedelta(days=1),
))

print(f"Found {len(recent_runs)} root runs in the last 24 hours")
Found 42 root runs in the last 24 hours

Сбор неабходных поль

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

# Step 3: Build a compact trace record from each run
def compact_trace(run):
    return {
        "run_id": str(run.id),
        "inputs": run.inputs,
        "outputs": run.outputs,
        "error": run.error,
        "latency_ms": (run.end_time - run.start_time).total_seconds() * 1000
            if run.end_time else None,
        "tool_calls": [
            child.name for child in client.list_runs(
                trace_id=run.trace_id, run_type="tool"
            )
        ],
    }

traces = [compact_trace(run) for run in recent_runs]
print(f"Collected {len(traces)} compact traces")
print("Example tool calls:", traces[0]["tool_calls"])
Collected 42 compact traces
Example tool calls: ['get_account_info']
# Step 4: Inspect the first trace end to end
import json
print(json.dumps(traces[0], indent=2, default=str))
{
  "run_id": "b1d2e3f4-...",
  "inputs": {"messages": [{"role": "user", "content": "What plan is account A100 on?"}]},
  "outputs": {"messages": [{"role": "ai", "content": "Account A100 is on the pro plan."}]},
  "error": null,
  "latency_ms": 1423.51,
  "tool_calls": ["get_account_info"]
}

Этап 3: Аддыяктуванне следаў за дапамой балавання

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

Слой 1: Пераконтроль правільнасці інструментаў на адной основе коду

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

# Step 1: Define a rule that says which tool SHOULD be called for a given query
import re

def expected_tool_for_query(query: str) -> str:
    q = query.lower()
    if re.search(r"\b(order|shipment|shipped|return)\b", q):
        return "get_recent_orders"
    if re.search(r"\b(plan|account|status|email)\b", q):
        return "get_account_info"
    return "any"

def score_tool_correctness(trace):
    query = trace["inputs"]["messages"][0]["content"]
    expected = expected_tool_for_query(query)
    actual = trace["tool_calls"][0] if trace["tool_calls"] else None
    if expected == "any":
        return 1.0
    return 1.0 if actual == expected else 0.0
# Step 2: Score qualitative properties with an LLM judge
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

judge_model = ChatOpenAI(model="gpt-4o-mini", temperature=0)

judge_prompt = ChatPromptTemplate.from_messages([
    ("system", "You are an expert reviewer of AI agent responses. "
               "Rate the response on a scale of 1 to 5 for helpfulness. "
               "Respond with only a single integer, nothing else."),
    ("user", "User question: {question}\n\nAgent response: {response}\n\nScore:"),
])

def score_helpfulness(trace):
    question = trace["inputs"]["messages"][0]["content"]
    response = trace["outputs"]["messages"][-1]["content"]
    chain = judge_prompt | judge_model
    result = chain.invoke({"question": question, "response": response})
    try:
        return int(result.content.strip()) / 5.0
    except ValueError:
        return 0.0

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

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

aph.

# Step 3: Model a human review signal
def score_human(trace, human_labels: dict) -> float | None:
    run_id = trace["run_id"]
    return human_labels.get(run_id)

human_labels = {
    "b1d2e3f4-...": 1.0,
    "c2e3f4g5-...": 0.0,
}

Спаўненне трохоў слоёў

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

# Step 4: Run all three scorers and attach scores to each trace
def enrich(trace):
    trace["scores"] = {
        "tool_correctness": score_tool_correctness(trace),
        "helpfulness": score_helpfulness(trace),
        "human": score_human(trace, human_labels),
    }
    return trace

enriched = [enrich(t) for t in traces]
print(json.dumps(enriched[0]["scores"], indent=2))
{
  "tool_correctness": 1.0,
  "helpfulness": 0.8,
  "human": null
}

Фаза 4: Адкрыцье шаблонаў

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

Фільтрацыя неудач

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

# Step 1: Keep only traces where at least one score is low
def is_low_scoring(trace):
    scores = trace["scores"]
    if scores["human"] is not None and scores["human"] < 0.5:
        return True
    if scores["tool_correctness"] < 0.5:
        return True
    if scores["helpfulness"] < 0.6:
        return True
    return False

failures = [t for t in enriched if is_low_scoring(t)]
print(f"{len(failures)} of {len(enriched)} traces flagged as low scoring")

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

9 of 42 traces flagged as low scoring

Разбір неудач кластэрування на категоры

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

# Step 2: Tag each failure with a category based on its scores
def categorize(trace):
    scores = trace["scores"]
    if scores["tool_correctness"] < 0.5:
        return "wrong_tool"
    if scores["helpfulness"] < 0.6 and scores["tool_correctness"] >= 0.5:
        return "unhelpful_answer"
    if scores["human"] is not None and scores["human"] < 0.5:
        return "human_flagged"
    return "other"

from collections import Counter
categories = Counter(categorize(t) for t in failures)
print(categories.most_common())
[('wrong_tool', 5), ('unhelpful_answer', 3), ('human_flagged', 1)]
# Step 3: Print the inputs and outputs for every wrong_tool failure
wrong_tool = [t for t in failures if categorize(t) == "wrong_tool"]
for trace in wrong_tool[:3]:
    print("QUERY:", trace["inputs"]["messages"][0]["content"])
    print("TOOLS CALLED:", trace["tool_calls"])
    print("RESPONSE:", trace["outputs"]["messages"][-1]["content"])
    print("---")
QUERY: Is my subscription active?
TOOLS CALLED: ['get_recent_orders']
RESPONSE: I could not find any recent orders to confirm your subscription status.
---
QUERY: Tell me about my subscription to your product
TOOLS CALLED: ['get_recent_orders']
RESPONSE: There are no recent orders for this account.
---

Этап 5: Нетваркавыя наборы тэстаў

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

Створэнне набора дадзеных

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

# Step 1: Create a LangSmith dataset for our agent
dataset_name = "agent-production-failures"

dataset = client.create_dataset(
    dataset_name=dataset_name,
    description="Production traces where the agent failed. Each example captures the user query and the expected tool call.",
)
print(f"Created dataset: {dataset.id}")

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

Created dataset: 3f2a1b0c-...
# Step 2: Convert each failure trace into a dataset example
examples = []
for trace in failures:
    query = trace["inputs"]["messages"][0]["content"]
    expected_tool = expected_tool_for_query(query)
    examples.append({
        "inputs": {"question": query},
        "outputs": {"expected_tool": expected_tool},
        "metadata": {"category": categorize(trace), "source_run_id": trace["run_id"]},
    })

client.create_examples(dataset_id=dataset.id, examples=examples)
print(f"Added {len(examples)} examples to {dataset_name}")
Added 9 examples to agent-production-failures
# Step 3: Write an evaluator that checks the agent's tool call against the expected tool
def tool_match_evaluator(inputs: dict, outputs: dict, reference_outputs: dict):
    actual_messages = outputs.get("messages", [])
    tool_called = None
    for m in actual_messages:
        if getattr(m, "tool_calls", None):
            tool_called = m.tool_calls[0]["name"]
            break
    expected = reference_outputs["expected_tool"]
    score = 1.0 if (expected == "any" or tool_called == expected) else 0.0
    return {"key": "tool_match", "score": score}

Функцыя-мета

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

# Step 4: Wrap our agent in a function that takes a LangSmith example and returns its output
def run_agent(inputs: dict) -> dict:
    result = agent.invoke({
        "messages": [{"role": "user", "content": inputs["question"]}]
    })
    return result

Фаза 6: Закрыцья цыклу

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

Адкліканне ацэнкі

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

# Step 1: Run the evaluator across the dataset with the current agent
from langsmith.evaluation import evaluate

experiment_results = evaluate(
    run_agent,
    data=dataset_name,
    evaluators=[tool_match_evaluator],
    experiment_prefix="agent-v1-baseline",
    max_concurrency=4,
)

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

View the evaluation results for experiment: 'agent-v1-baseline-...' at:
https://smith.langchain.com/o/.../datasets/.../compare?selectedSessions=...

9/9 runs | avg tool_match: 0.33

Адправка парадкку і перыяцэнка

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

# Step 2: Update the tool docstring to teach the agent about subscriptions
@tool
def get_account_info_v2(account_id: str) -> str:
    """Look up basic information for an account, including plan, status,
    subscription tier, and contact email. Use this tool for any question
    about the account itself, including subscription status."""
    fake_accounts = {
        "A100": "Account A100: plan=pro, status=active, email=ada@example.com",
        "A200": "Account A200: plan=free, status=suspended, email=turing@example.com",
    }
    return fake_accounts.get(account_id, f"No account found with id {account_id}")

tools_v2 = [get_account_info_v2, get_recent_orders]
agent_v2 = create_react_agent(model, tools_v2)

def run_agent_v2(inputs: dict) -> dict:
    result = agent_v2.invoke({
        "messages": [{"role": "user", "content": inputs["question"]}]
    })
    return result
# Step 3: Run the evaluator on the v2 agent
experiment_results_v2 = evaluate(
    run_agent_v2,
    data=dataset_name,
    evaluators=[tool_match_evaluator],
    experiment_prefix="agent-v2-docstring-fix",
    max_concurrency=4,
)
View the evaluation results for experiment: 'agent-v2-docstring-fix-...' at:
https://smith.langchain.com/o/.../datasets/.../compare?selectedSessions=...

9/9 runs | avg tool_match: 0.89

До і пасля

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

Before (v1):       After (v2):
wrong_tool: 5      wrong_tool: 1
unhelpful: 3       unhelpful: 0
human: 1           human: 0
avg score: 0.33    avg score: 0.89

Ацэнка і тэставанне

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

# Full loop driver
def run_improvement_loop():
    # 1. Pull traces
    runs = list(client.list_runs(
        project_name="agent-improvement-loop",
        is_root=True,
        start_time=datetime.utcnow() - timedelta(days=1),
    ))
    traces = [compact_trace(r) for r in runs]

    # 2. Enrich with scores
    enriched = [enrich(t) for t in traces]

    # 3. Find failures and categorize them
    failures = [t for t in enriched if is_low_scoring(t)]
    categories = Counter(categorize(t) for t in failures)

    # 4. Add failures to the dataset
    new_examples = [{
        "inputs": {"question": t["inputs"]["messages"][0]["content"]},
        "outputs": {"expected_tool": expected_tool_for_query(
            t["inputs"]["messages"][0]["content"])},
        "metadata": {"category": categorize(t), "source_run_id": t["run_id"]},
    } for t in failures]

    if new_examples:
        client.create_examples(dataset_id=dataset.id, examples=new_examples)

    # 5. Re-evaluate the current agent against the full dataset
    result = evaluate(
        run_agent_v2,
        data=dataset_name,
        evaluators=[tool_match_evaluator],
        experiment_prefix="daily-regression",
    )

    return {
        "traces_collected": len(traces),
        "failures_found": len(failures),
        "by_category": dict(categories),
        "examples_added": len(new_examples),
    }

print(run_improvement_loop())
{
  "traces_collected": 186,
  "failures_found": 12,
  "by_category": {"wrong_tool": 4, "unhelpful_answer": 6, "human_flagged": 2},
  "examples_added": 12,
  "regression_score": 0.87
}

Як яшчэ паспрацаваць над гэтым

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

Чэк-ліст для эксплуатацыі

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

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

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

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

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

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

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

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

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

Дзеянне паўжасткі 0/961: звярніце увагу на час выканання, клас памылкі і колькасць токенаў, выкарыстоўваных для гэтай змяны, а пасля, на аднойчынай базе паказаных дадзенняў, а не на індывідуальных прыкладах, выявіце, чы хацяце застаўіць гэту змяну.

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

Дзеянне паўжасткі 1/961: звярніце увагу на час выканання, клас памылкі і колькасць токенаў, выкарыстоўваных для гэтай змяны, а пасля, на аднойчынай базе паказаных дадзенняў, а не на індывідуальных прыкладах, выявіце, чы хацяце застаўіць гэту змяну.

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

Дзеянне прыцелення на змягчэнне 2/961: трэба звярнуць увагу на час выканання, класы каштоўкаў і витрату токенав для гэтай ваказкі, а пасля, на базе фіксаванага набора пытанняў, а не індывідуальных спостарожэнняў, вырашыць, чы робіцца змена.

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

Дзеянне 3/961 практыкы забезпечэння безпекі: звярзайце час выканання, класы каштоўкаў і витрату токенав для гэтай практыкі, а потым выберыце, чы робіць змену на аднойчы заданых критэрыях, а не на аснове індывідуальных спостерэнняў.

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

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

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

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

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

Дзеянне прыемкі з павышэння безпекі 6/961: вымерайце час выканання, класію паканаў і вартась токенаў для гэтай прыемкі, а пасля выберайце, чы робіць змены на адной пазначанай базе пытанняў, а не на адной толькі прыватнай інформацыі.

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

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

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

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

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

Дзялёўка забезпечэння безпекі 9/961: вымерайце час выканання, класію каштоўкаў і выкарыстанне токенаў для гэтага пункту, а потым выберайце, чы хацяць застаўіць змену, стварыўшы фіксаваны набор пытанняў, а не на базе індывідуальных спазыроў.

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

Дзеянні паўжасткі 10/961: звярніце увагу на час выканання, клас памылак і колькасць викорыстоўваных токенав для гэтага зьязку, а пасля, на аднойчынай базе фіксаванага набору пытанняў, а не на індывідуальных прыкладах, выявіце, чы хацяце застаўіць гэтыя змены.