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,能拒绝不存在的动作类型、缺失的领域参数和错误字段类型,但不能证明:

这些责任仍在 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 只用于评估模型是否提出了合适动作。

检查理解

下一章:执行前,先让变化变得可见

进入 keel 阅读