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

Практычныя нататкі: рэв’ю кода двума агентамі на A2A і LangGraph

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

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

Крыніцы: Building a Two-Agent Code Review Loop with A2A, LangGraph, and LM Studio

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

Што на самай працы ёсць A2A (адна параграф)

Што такое A2A на практыке (адно абзац) — гэта канцэпцыя, якая лепша ўсё тады, калі яе розглядаць як вімерную плошчу. Перш чым расшырваць масштаб, неабходна зафіксаваць адны ідэальны прыклад працы, адну сітуацыю неудачы і прыметкі па поверненню да попярэдня стану. Неабходна адночасна документацыя як успішнага, так і варыянта відновлення працэсу. Перапрыбуткі, людзкі контроль і обработка некорэктных паведамленняў ёсць часткай самага продукту, а не элементамі, якія дадзены пазней для ўдосконалення. Палітыку разбівання на часткі трэба аддзельваць ад палітыкі выкарыстоўвання даных; змена адной з іх не должна вымагаць перапісвання другой, калі зменяюцыся паказнікі якосці.

Элементы

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

a2a-coder-reviewer/
├── shared/
│   ├── config.py           # tunables: system prompts, model, temperature, MAX_ROUNDS
│   ├── llm.py              # LM Studio ChatOpenAI factory
│   ├── coder_graph.py      # LangGraph graph: spec (+ feedback) -> code
│   └── reviewer_graph.py   # LangGraph graph: spec + code -> verdict + feedback
├── coder_agent/
│   ├── agent_executor.py   # A2A executor wrapping the coder graph
│   └── __main__.py         # A2A server, port 9001
├── reviewer_agent/
│   ├── agent_executor.py   # A2A executor wrapping the reviewer graph
│   └── __main__.py         # A2A server, port 9002
├── orchestrator.py         # A2A client driving the back-and-forth
└── requirements.txt

Файл налаштаванняў

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

from dataclasses import dataclass

@dataclass(frozen=True)
class AgentConfig:
    model: str
    temperature: float
    system_prompt: str


CODER_CONFIG = AgentConfig(
    model="local-model",
    temperature=0.2,
    system_prompt="""You are a careful Python engineer.
Write a single Python function that satisfies the spec.
If reviewer feedback is provided, revise your previous code to address it.
Return ONLY the code in a single ```python fenced block, no extra commentary.
""",
)

REVIEWER_CONFIG = AgentConfig(
    model="local-model",
    temperature=0.0,
    system_prompt="""You are a strict senior Python code reviewer performing a
rigorous code review. Do not approve code that has any of these problems:
- Missing a docstring explaining parameters, return value, and behavior.
- Missing type hints on parameters and the return type.
- Failing to handle edge cases implied by the spec (empty input, None,
  zero, negative numbers, single-element collections, etc.) unless the
  spec explicitly says not to.
- Silently swallowing errors or returning a sentinel value (None, "", -1,
  an error string) instead of raising, unless the spec asks for that.
- Using a data structure that visibly discards information the spec
  requires (e.g. a `set` when order or duplicate counts must be kept).

If you see ANY of the above, or anything else that would fail a real code
review, you MUST respond with VERDICT: CHANGES_REQUESTED and list the
concrete problems as bullet points, even if the code "basically works."
Only respond with VERDICT: APPROVED if the code has none of these
problems. Never approve code and then list problems as "suggestions" or
"nice to haves" — if it's worth mentioning, it's worth requesting changes
for.

Start your reply with exactly one line:
VERDICT: APPROVED
or
VERDICT: CHANGES_REQUESTED
Then, on the following lines, give concise, actionable feedback
(bullet points). If APPROVED, feedback can just be brief praise/notes.
""",
)

# Max coder<->reviewer rounds before orchestrator.py gives up.
MAX_ROUNDS = 3

Завод з LLM

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

import os
from langchain_openai import ChatOpenAI

LM_STUDIO_BASE_URL = os.environ.get(
    "LM_STUDIO_BASE_URL", "http://localhost:7777/v1"
)

def get_llm(model: str = "local-model", temperature: float = 0.2) -> ChatOpenAI:
    return ChatOpenAI(
        base_url=LM_STUDIO_BASE_URL,
        api_key="lm-studio",       # placeholder, LM Studio ignores it
        model=model,
        temperature=temperature,
    )

Граф кодавальніка

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

from typing import TypedDict, Optional
from langgraph.graph import StateGraph, END
from shared.config import CODER_CONFIG
from shared.llm import get_llm

class CoderState(TypedDict):
    spec: str
    previous_code: Optional[str]
    feedback: Optional[str]
    code: str


def _generate(state: CoderState) -> CoderState:
    llm = get_llm(model=CODER_CONFIG.model, temperature=CODER_CONFIG.temperature)
    user_msg = f"Spec:\n{state['spec']}\n"
    if state.get("previous_code"):
        user_msg += f"\nPrevious code:\n{state['previous_code']}\n"
    if state.get("feedback"):
        user_msg += f"\nReviewer feedback to address:\n{state['feedback']}\n"

    response = llm.invoke(
        [
            {"role": "system", "content": CODER_CONFIG.system_prompt},
            {"role": "user", "content": user_msg},
        ]
    )
    state["code"] = response.content
    return state


def build_coder_graph():
    graph = StateGraph(CoderState)
    graph.add_node("generate", _generate)
    graph.set_entry_point("generate")
    graph.add_edge("generate", END)
    return graph.compile()


coder_graph = build_coder_graph()
import re
from typing import TypedDict, Optional
from langgraph.graph import StateGraph, END
from shared.config import REVIEWER_CONFIG
from shared.llm import get_llm


class ReviewerState(TypedDict):
    spec: str
    code: str
    verdict: str
    feedback: str


def _review(state: ReviewerState) -> ReviewerState:
    llm = get_llm(model=REVIEWER_CONFIG.model, temperature=REVIEWER_CONFIG.temperature)
    user_msg = f"Spec:\n{state['spec']}\n\nCode to review:\n{state['code']}\n"
    response = llm.invoke(
        [
            {"role": "system", "content": REVIEWER_CONFIG.system_prompt},
            {"role": "user", "content": user_msg},
        ]
    )
    text = response.content
    match = re.search(r"VERDICT:\s*(APPROVED|CHANGES_REQUESTED)", text, re.IGNORECASE)
    verdict = match.group(1).upper() if match else "CHANGES_REQUESTED"
    feedback = text[match.end():].strip() if match else text.strip()

    state["verdict"] = verdict
    state["feedback"] = feedback
    return state


def build_reviewer_graph():
    graph = StateGraph(ReviewerState)
    graph.add_node("review", _review)
    graph.set_entry_point("review")
    graph.add_edge("review", END)
    return graph.compile()


reviewer_graph = build_reviewer_graph()

Упакоўкі графа як адэнтара A2A

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

aph.

from a2a.server.agent_execution.agent_executor import AgentExecutor
from a2a.server.agent_execution.context import RequestContext
from a2a.server.events.event_queue import EventQueue
from a2a.server.tasks.task_updater import TaskUpdater
from a2a.types import Part, Task, TaskState, TaskStatus

from shared.coder_graph import coder_graph

class CoderAgentExecutor(AgentExecutor):
    async def execute(self, context: RequestContext, event_queue: EventQueue) -> None:
        user_message = context.message
        task_id = context.task_id
        context_id = context.context_id

        await event_queue.enqueue_event(
            Task(
                id=task_id,
                context_id=context_id,
                status=TaskStatus(state=TaskState.TASK_STATE_SUBMITTED),
                history=[user_message] if user_message else [],
            )
        )
        updater = TaskUpdater(
            event_queue=event_queue, task_id=task_id, context_id=context_id
        )
        working_message = updater.new_agent_message(
            parts=[Part(text="Generating code...")]
        )
        await updater.start_work(message=working_message)

        query = context.get_user_input()
        spec, previous_code, feedback = _parse_input(query)

        try:
            result = coder_graph.invoke(
                {
                    "spec": spec,
                    "previous_code": previous_code,
                    "feedback": feedback,
                    "code": "",
                }
            )
        except Exception as exc:
            error_message = updater.new_agent_message(
                parts=[Part(text=f"❌ Code generation failed: {exc}")]
            )
            await updater.failed(message=error_message)
            return

        await updater.add_artifact(
            parts=[Part(text=result["code"])], name="code", last_chunk=True
        )
        await updater.complete()

...

Адмініструванне кожнага агента

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

import uvicorn

from starlette.applications import Starlette
from a2a.server.request_handlers import DefaultRequestHandler
from a2a.server.routes import create_agent_card_routes, create_jsonrpc_routes
from a2a.server.tasks.inmemory_task_store import InMemoryTaskStore
from a2a.types import AgentCapabilities, AgentCard, AgentInterface, AgentSkill

from coder_agent.agent_executor import CoderAgentExecutor

HOST = "127.0.0.1"
PORT = 9001
RPC_URL = "/a2a/jsonrpc"

def build_agent_card() -> AgentCard:
    skill = AgentSkill(
        id="write_code",
        name="Write / revise Python code",
        description="Writes a Python function from a spec, or revises "
                    "previous code given reviewer feedback.",
        tags=["coding", "python"],
        examples=["SPEC: write a function that reverses a linked list"],
        input_modes=["text"],
        output_modes=["text", "task-status"],
    )
    return AgentCard(
        name="Coder Agent",
        description="Generates and revises Python code based on a spec "
                    "and optional reviewer feedback.",
        version="0.1.0",
        capabilities=AgentCapabilities(streaming=True, push_notifications=False),
        default_input_modes=["text"],
        default_output_modes=["text", "task-status"],
        skills=[skill],
        supported_interfaces=[
            AgentInterface(
                protocol_binding="JSONRPC",
                protocol_version="1.0",
                url=f"http://{HOST}:{PORT}{RPC_URL}",
            ),
        ],
    )

def main():
    agent_card = build_agent_card()
    request_handler = DefaultRequestHandler(
        agent_executor=CoderAgentExecutor(),
        task_store=InMemoryTaskStore(),
        agent_card=agent_card,
    )

    routes = []
    routes.extend(create_agent_card_routes(agent_card=agent_card))
    routes.extend(create_jsonrpc_routes(request_handler=request_handler, rpc_url=RPC_URL))

    app = Starlette(routes=routes)
    uvicorn.run(app, host=HOST, port=PORT)


if __name__ == "__main__":
    main()

Оркестрабільнік

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

import asyncio
import sys
import uuid

import httpx
from a2a.client import A2ACardResolver, ClientConfig, create_client
from a2a.helpers import get_artifact_text, get_message_text
from a2a.types import Message, Part, Role, SendMessageRequest
from shared.config import MAX_ROUNDS

CODER_URL = "http://127.0.0.1:9001"
REVIEWER_URL = "http://127.0.0.1:9002"


async def get_client_for(httpx_client: httpx.AsyncClient, base_url: str):
    resolver = A2ACardResolver(httpx_client, base_url)
    card = await resolver.get_agent_card()
    return await create_client(card, client_config=ClientConfig(httpx_client=httpx_client))

async def send_and_collect(client, text: str) -> str:
    message = Message(
        role=Role.ROLE_USER,
        message_id=str(uuid.uuid4()),
        parts=[Part(text=text)],
        context_id=str(uuid.uuid4()),
    )
    request = SendMessageRequest(message=message)

    result_text = ""
    async for event in client.send_message(request):
        if event.HasField("message"):
            result_text = get_message_text(event.message, delimiter="\n")
        elif event.HasField("artifact_update"):
            result_text += get_artifact_text(
                event.artifact_update.artifact, delimiter="\n"
            )
        elif event.HasField("status_update"):
            status = event.status_update.status
            if status.state == TaskState.TASK_STATE_FAILED:
                error_text = (
                    get_message_text(status.message, delimiter="\n")
                    if status.HasField("message")
                    else "Task failed with no error message."
                )
                raise RuntimeError(error_text)
    return result_text
async def run(spec: str) -> dict:
    """
    Runs the coder<->reviewer loop for `spec`. Returns a result dict:
        {"approved": bool, "rounds": int, "code": str, "review": str}
    or, if a task failed, {"approved": False, "error": str, "code": str | None}.
    """
    async with httpx.AsyncClient(timeout=120) as httpx_client:
        coder = await get_client_for(httpx_client, CODER_URL)
        reviewer = await get_client_for(httpx_client, REVIEWER_URL)

        code = None
        feedback = None
        review_text = ""

        try:
            for round_num in range(1, MAX_ROUNDS + 1):
                print(f"\n=== Round {round_num}: Coder ===")
                coder_prompt = f"SPEC: {spec}\n"
                if code:
                    coder_prompt += f"PREVIOUS_CODE: {code}\nFEEDBACK: {feedback}\n"
                code = await send_and_collect(coder, coder_prompt)
                print(code)

                print(f"\n=== Round {round_num}: Reviewer ===")
                reviewer_prompt = f"SPEC: {spec}\nCODE: {code}"
                review_text = await send_and_collect(reviewer, reviewer_prompt)
                print(review_text)

                if review_text.startswith("VERDICT: APPROVED"):
                    print("\n✅ Approved. Final code:\n")
                    print(code)
                    return {
                        "approved": True,
                        "rounds": round_num,
                        "code": code,
                        "review": review_text,
                    }

                feedback = review_text.split("\n", 1)[-1]

            print(f"\n⚠️ Max rounds ({MAX_ROUNDS}) reached without approval. Last code:\n")
            print(code)
            return {
                "approved": False,
                "rounds": MAX_ROUNDS,
                "code": code,
                "review": review_text,
            }
        except RuntimeError as exc:
            print(f"\n{exc}")
            return {"approved": False, "error": str(exc), "code": code}
        finally:
            await coder.close()
            await reviewer.close()

Експлуатацыя

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

pip install -r requirements.txt

# terminal 1
python -m coder_agent

# terminal 2
python -m reviewer_agent

# terminal 3
python orchestrator.py "write a function that checks if a string is a palindrome"
curl http://127.0.0.1:9001/.well-known/agent-card.json

Прыклад рэальнага запуску

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

Тое, што зламалася, і як гэта практычна выправіць

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

ModuleNotFoundError: No module named 'a2a.server.apps'

ModuleNotFoundError: No module named 'a2a.server.apps' лепей усвядомляць як мерыябельную паверхню. Зафіксавайце адны ідэальны прыклад работы, адну сітуацыю абяроны і прыказку па вярнэнню да пачатковага стану пры расшырэнні масштаба. Спрыяйце гэтам этапу як даўгастрахованаму кантракту межа вхідных дадзеных і перакананых выходных рэзультатаў. Даць назвы артыфактам, задаць крытэрыя успеху і не праграмаваць мовчанлівага частковага завершэння задачы. Храніце стан графа ў простам і тыпаваным фармаце. Вярнутыя структуры дадзеных маскуюць інфармацыю пра тое, які вузел запісаў кожны поле, і спаказваюць возможнасць прызначэння задачы пасля перарываў. ModuleNotFoundError: No module named 'a2a.server.apps' лепей усвядомляць як мерыябельную паверхню. Зафіксавайце адны ідэальны прыклад работы, адну сітуацыю абяроны і прыказку па вярнэнню да пачатковага стану пры расшырэнні масштаба. Храніце настройкі за межамі коду аплікацыі. Файлы сяродавысці, хранальнікі секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, якое аператары можаць пераглядаць без неабясненага чытання всего графа.

ModuleNotFoundError: Не знайдзена модуль ‘sse_starlette’

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

Таўмачыльныя таймауты апошніх 5 секунд

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

Мадэлі аргументаў паглотваюць усе

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

Назвы элементаў тыпу enum у Protobuf

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

Part больш не абгортае TextPart

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

Магчымасці для расшырэння

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

Апавясненні

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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