跳到正文
DEV Community· Alexander Smirnoff·· 4 小時前AI 評分45

Football Decider Lab:使用 Strands Decider 選擇替補球員

Football Decider Lab: Choosing a Substitute with Strands Decider

AI 導讀

Football Decider Lab 使用 Strands Decider 2B 按教練指示選擇替補球員,並由應用程式檢查球員資格、驗證模型回應及設定信心門檻。

正文

It is the 70th minute. Your team leads 1-0. You want to replace your right back, and three players on the bench can cover the position. The coach's instruction is clear: protect the lead.

One candidate likes attacking runs. Another holds his position and provides defensive cover. A third is better at keeping possession.

Football Decider Lab uses this situation to test how Strands Decider follows a coach's instruction when choosing a substitute. I built it for the Strands Decider Hackathon, using Python for the application and a Strands Agent with Amazon Bedrock for the explanation.

The demo uses synthetic match snapshots and player descriptions. The UI shows the eligible candidates, the selected player and the checks behind the final action.

The same bench, a different instruction

The two main scenarios use the same players:

  • bench-17: an attacking full-back who overlaps and delivers crosses.
  • bench-23: a conservative defender who can cover right back.
  • bench-31: a midfielder approved to play right back in this simulation.

All three have the same readiness score. Choosing the first player whose primary position matches would favor bench-17, even when the coach asks for defensive cover.

In protect-lead, the team leads 1-0 and the coach prefers a defender who holds position. In chase-goal, the team trails 0-1 and the coach asks for attacking width and crosses.

This gives the model a small, specific task: choose among the eligible players using the supplied instruction and descriptions.

Rules decide who can be considered

The application checks the snapshot before calling Decider.

Missing workload data or telemetry older than 15 seconds produces REVIEW_DATA. Below the synthetic substitution trigger, the action is MONITOR.

When the trigger is reached, the code checks the remaining substitution allowance and filters the bench. A candidate must be on the bench, have a readiness score of at least 60 and be approved for the outgoing player's role.

These values are settings for the simulation. They are not medical thresholds or a complete implementation of competition rules.

With no eligible candidate, the application returns NO_REPLACEMENT. With one candidate, it uses a policy result without calling Decider. With several candidates, it asks the model to choose.

This keeps eligibility under application control. The model receives only the options that passed those checks.

A player choice and a final action

I use Strands Decider 2B through its HTTP service. The request contains match context, the coach's instruction and the eligible player descriptions. Expected test answers stay outside the request.

The response includes a selected option, probabilities and confidence. The application validates the response before accepting it. An unknown player ID, an invalid probability distribution or an unexpected model identity produces an error.

A separate gate then determines the final action. The configuration looks like this:

from decision_patterns import GatePolicy

gate_policy = GatePolicy(
    threshold=0.7,
    automatic_action="SUBSTITUTE",
    review_action="REVIEW_MODEL",
    review_reason="low_confidence",
)

Below 0.7, the selected player stays in the record, but the action becomes REVIEW_MODEL. The UI can show the candidate while making the need for human review explicit.

The threshold is experimental. A confidence value of 0.74 does not mean a 74% chance that the substitution will succeed.

Explaining a fixed decision

Before generating any text, the application creates an immutable DecisionRecord. It stores the input snapshot, eligibility results, offered options, raw model response and final action. It also records hashes for the prompt, option set and gate configuration.

A Strands Agent using Amazon Bedrock then writes a short summary from that record.

The explanation must preserve the selected player and final action. Here is the relevant check from the validator:

if payload["final_action"] != frozen.get("final_action"):
    raise ExplanationError(
        "Explanation attempted to change the final action",
        stage="decision_validation",
    )

The validator also checks evidence references, player IDs and numeric claims. For REVIEW_MODEL, the summary must state that human review is needed.

These checks catch specific errors. They cannot establish that every sentence is tactically correct. The generated text summarizes the recorded facts and outcome.

If Bedrock fails or its response fails validation, the decision record remains available and the explanation failure is shown separately.

The verified demo runs the Python app and CPU-based Decider as separate services on one EC2 instance in Frankfurt. Bedrock handles the explanation call. Keeping their statuses separate makes it possible to see which step failed.

What the live run showed

The saved EC2 run from produced these results:

Scenario Selected player Confidence Final action
protect-lead bench-23 0.7403 SUBSTITUTE
chase-goal bench-17 0.1581 REVIEW_MODEL

Both scenarios used live Decider responses and Bedrock explanations that passed validation. The deployment record documents the captures.

In the defensive case, the selected candidate cleared the confidence gate. In the attacking case, Decider selected the authored target player but returned confidence below the threshold. The application kept the choice and requested human review.

That distinction matters when evaluating the result. Choosing the expected player and allowing the recommendation through the gate are separate outcomes.

These two runs verify the application path on authored examples. Assessing football quality needs independent coaching labels and a larger evaluation set.

Testing beyond the two demo cases

The CLI includes 22 synthetic scenarios covering cases such as an empty bench, stale telemetry, unavailable players and different coach instructions. The latest documented verification records 51 passing automated tests.

The runner can repeat requests and change candidate order. This helps check whether the selection changes when the same players appear in a different order.

Reports retain errors and distinguish model calls from policy decisions. An offline dry run builds requests but marks model results NOT_RUN; it has no model accuracy score.

The app also separates fixture output from live calls. Fixture mode uses test doubles and runs without AWS credentials. It is useful for checking the UI and control flow.

Replay support can read registered captures and check their hashes without making new model calls. The checked-in replay catalog is currently empty.

To open the local fixture UI from a checkout, run make run and visit http://127.0.0.1:8080.

What I would test next

The current labels are author-written, and the instructions make the preferred player fairly explicit. A transparent rules-based baseline may handle many of these cases well.

My next step would be to have coaches label less obvious situations, record where they disagree and hold out whole groups of related scenarios. Then I would compare Decider with the simpler baseline, including how often each approach needs review or fails.

The selector is already separate from football rules, HTTP transport and AWS. The repository includes an offline support-specialist example using the same selection and review pattern. That makes it possible to test the code in another domain while keeping eligibility and review policy specific to that domain.

Project repository

來源:DEV Community · dev.to