KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
03. 让 Ollama 只负责提出动作 — keel 龙骨
现在接入真实模型,但只交给它适合语义判断的部分:从用户目标和当前状态中提出候选动作。模型不会直接访问配置 API,也不会生成可信权限字段。
现在接入真实模型,但只交给它适合语义判断的部分:从用户目标和当前状态中提出候选动作。模型不会直接访问配置 API,也不会生成可信权限字段。
输入必须同时说明事实和边界
用户目标:把 staging 的 payment-service 连接池从 20 调到 40,并通知值班群。
当前事实:pool_limit=20,resource_version=cfg-7。
可提议动作:set_pool_limit、send_notification。
要求:只输出符合 schema 的动作提议;不要声称动作已执行。
模型看到的是一次规划快照。执行前还要重新检查资源版本,因为外部状态可能已经改变。
Structured Outputs 解决的是形状,不是信任
Ollama 可以按 Pydantic schema 返回:
class ProposedPoolLimitAction(BaseModel):
kind: Literal["set_pool_limit"]
arguments: PoolLimitArguments # 必须包含 1..200 的 value
class ProposedNotificationAction(BaseModel):
kind: Literal["send_notification"]
arguments: NotificationArguments # 必须包含 channel 和 message
class ActionProposal(BaseModel):
summary: str
actions: list[Annotated[
ProposedPoolLimitAction | ProposedNotificationAction,
Field(discriminator="kind"),
]]
判别联合让每种动作拥有自己的参数 schema,能拒绝不存在的动作类型、缺失的领域参数和错误字段类型,但不能证明:
- 用户有权修改目标服务;
target属于当前租户;- 当前连接池仍是 20;
- 40 符合业务上限;
- 通知内容不含秘密;
- 动作已经执行。
这些责任仍在 Harness、Safety Controls 和 Execution Gateway 中。
运行真实模型
ollama serve
ollama pull qwen3:8b
$env:OLLAMA_MODEL = "qwen3:8b"
python courses/advanced/real-world-execution/course/project/examples/02_ollama_plan.py
输出只显示模型的 ActionProposal,并明确说明它没有执行。下一步示例再由程序构造 ActionCommand;run_id、intent_id、租户、资源版本、deadline、幂等键和 fingerprint 都必须来自运行时。
为什么不让模型直接生成命令行
下面的接口把自然语言直接拼进 Shell:
subprocess.run(f"deploy {model_text}", shell=True)
它同时失去了参数边界、命令白名单、资源校验、审计和隔离。正确方向是让模型选择受限动作,再由 Adapter 使用结构化参数调用确定的 API。
模型:{"kind":"set_pool_limit","arguments":{"value":40}}
程序:校验 kind/target/value/resource_version
Adapter:config_client.set_pool_limit(service, environment, value, version)
模型不可用时,执行协议仍应可测试
幂等、审批绑定、状态转换和补偿不依赖模型随机性。测试使用固定 Proposal 或直接构造 Command;Ollama 只用于评估模型是否提出了合适动作。
检查理解
- 结构化输出为什么不能替代授权?
- 哪些 Command 字段必须由运行时补充?
- 为什么真实模型测试和执行状态机测试要分开?