模型驱动决策与硬编码决策
让模型负责决策,将代码留给必须保证的部分。
模型驱动决策与硬编码决策 是 CoddyKit 上的免费 Claude Architect 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Claude Architect 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Claude Architect 课程共包含 4 节课。
本课时的部分内容尚未翻译,以英文显示。
Two Ways to Decide
Every agent you build has to make decisions. Who makes them is the design choice.
There are two options:
- Model-driven: Claude looks at the situation and chooses the next step.
- Hard-coded: your code forces the step, no matter what.
The rule for the exam: let the model decide, and reserve hard code for guarantees you cannot afford to get wrong.
Why the Model Should Drive
Real tasks are open-ended. The order of steps is not known in advance.
A customer message might need one lookup, or three. A research task might branch in ways you cannot predict. Claude reads the live context every turn and adapts.
If you hard-code the path, you freeze the agent into one rigid script. It breaks the moment reality differs from your plan. So the default is: give Claude tools and let it choose.
The Agentic Loop
Here is the model-driven loop. You send the full message history every turn (the model keeps no state). Then you inspect stop_reason:
tool_use→ run the tool, append the result, loop again.end_turn→ the model is done. Stop.
The model decides what to do; your code just executes and loops.
while True:
resp = client.messages.create(
model="claude-opus-4-8",
max_tokens=16000,
tools=tools,
messages=messages, # FULL history every turn
)
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason == "end_turn":
break
if resp.stop_reason == "tool_use":
results = run_tools(resp.content)
messages.append({"role": "user", "content": results})Stop on the Signal, Not the Words
How do you know the agent is finished? Terminate on stop_reason — never by scanning the text for words like "done" or "finished".
Parsing text for completion signals is a classic anti-pattern. The model might say "I'm done thinking" mid-task, or never say "done" at all. The structured stop_reason is the real, reliable signal.
# WRONG — parsing text for a completion word
if "done" in resp.content[0].text.lower():
break
# RIGHT — terminate on the structured stop signal
if resp.stop_reason == "end_turn":
breakIteration Caps Are a Safety Net
You may add a maximum number of loop iterations. That is fine — but understand its role.
An iteration cap is a safety net that stops a runaway loop. It is never the primary stop mechanism. The primary stop is always stop_reason == "end_turn".
If your agent normally finishes only by hitting the cap, the decision logic is broken — you are hard-coding what should be model-driven.
MAX_TURNS = 20 # safety net only
for turn in range(MAX_TURNS):
resp = client.messages.create(
model="claude-opus-4-8", max_tokens=16000,
tools=tools, messages=messages,
)
messages.append({"role": "assistant", "content": resp.content})
if resp.stop_reason == "end_turn":
break # the REAL exit
messages.append({"role": "user", "content": run_tools(resp.content)})When Code Must Guarantee
Now the other half of the rule. Some outcomes are too important to leave to a probabilistic model.
A prompt is roughly 90% reliable — it usually follows instructions, but not always. For rules with financial, legal, or safety consequences, "usually" is not good enough.
For those, you reserve hard code, which is 100% deterministic. This is the one place where you take the decision away from the model.
Hooks Enforce the Hard Limits
The deterministic tool for this is a hook. A hook intercepts an action and can block it before it ever happens — with 100% certainty.
Classic example: "never refund more than $500." You do not write that as a prompt instruction. You write it as an outgoing-call hook that blocks any refund over the limit, every single time.
Hooks for guarantees, prompts for judgment.
# Deterministic policy hook — runs before the refund tool executes
def before_process_refund(tool_input):
if tool_input["amount"] > 500:
return {
"block": True,
"reason": "Refunds over $500 require human approval.",
}
return {"block": False}Programmatic Preconditions
The same idea applies to preconditions — things that must be true before an action runs.
Example: never process a refund until the customer's identity is verified. Prompt guidance ("please verify identity first") is only ~90% reliable. A programmatic precondition — block process_refund until get_customer returns a verified ID — is a deterministic guarantee.
Code enforces the precondition; the model still decides everything else.
def before_process_refund(tool_input, state):
# Deterministic precondition: identity must be verified first
if not state.get("customer_verified"):
return {"block": True,
"reason": "Call get_customer and verify identity before refunding."}
return {"block": False}Don't Over-Hard-Code
The mistake in the other direction is just as costly: hard-coding decisions that the model should make.
If you wrap every step in branching if/else logic, you have rebuilt a rigid pipeline and thrown away Claude's adaptability. The agent can no longer handle the unexpected case.
Reserve hard code for the narrow set of guarantees — money, law, safety, required preconditions. Everything else stays model-driven.
A Clean Division of Labor
Put it together as a division of labor:
- Model decides: which tool to call, in what order, when the task is complete, how to recover from an unexpected result.
- Code guarantees: policy ceilings (refund ≤ $500), required preconditions (verified ID), and the loop terminating on
stop_reason.
The model drives the trajectory. Code draws the hard boundaries it can never cross.
Fixed Pipelines vs Adaptive
One nuance: not every task is open-ended.
- For a known, sequential process, a fixed pipeline (prompt chaining) is fine — the steps really are fixed.
- For an open-ended investigation, use adaptive decomposition and let the model choose its path.
So "let the model decide" applies where the path is genuinely uncertain. Where the sequence is truly known, structure is appropriate — just don't force structure onto problems that need adaptability.
Quick Check
A support agent must never issue a refund above $500. Refunds at or below $500 should be handled smoothly within the conversation. What is the architect-grade design?
Key Takeaways
Remember the rule: let the model decide; reserve code for guarantees.
- Default to model-driven decisions — Claude adapts to live context.
- Drive the agentic loop and terminate on
stop_reason, never by parsing text. - Iteration caps are a safety net, not the primary stop.
- Use hooks and programmatic preconditions for financial, legal, or safety rules — 100% deterministic vs a prompt's ~90%.
- Don't over-hard-code: guarantees are a narrow boundary, not the whole agent.
常见问题解答
「模型驱动决策与硬编码决策」课时是免费的吗?
是的 — 「模型驱动决策与硬编码决策」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Claude Architect 课程的其余内容,请升级到 CoddyKit PRO。 Claude Architect 课程共包含 4 节课。
「模型驱动决策与硬编码决策」这节课中我会学到什么?
让模型负责决策,将代码留给必须保证的部分。 你通过在浏览器中直接运行的动手代码来练习 Claude Architect,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Claude Architect 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Claude Architect 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。
「模型驱动决策与硬编码决策」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Claude Architect 课中编写并运行代码吗?
能。每节 Claude Architect 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 什么让系统具备代理性
- 模型驱动决策与硬编码决策
- 何时使用代理
- 代理循环概览