生产级Agent(23):配置供应链与可信加载

文章摘要

前二十二篇已经把生产级 Agent 的运行、权限、审计、回放、SLO、多租户和 Policy-as-Code 串起来。

到这里,平台里真正决定 Agent 行为的东西已经远远不止模型:

Model
Prompt
Skill
Tool Schema
MCP Server
Policy
Routing
Memory Rule
Eval Gate
Sandbox Profile

这些对象任何一个被误改、被替换、加载了错误版本,Agent 行为都会变化。

但很多系统现在仍然这样部署:

Prompt从数据库读最新
Tool Schema启动时动态拉
Skill从共享目录加载
Policy看后台当前值
模型路由读一张配置表

结果就是:

同一个Agent版本
今天和明天
可能根本不是同一个运行环境

真正的生产 Agent 需要一套类似软件供应链的机制:

Source
→ Build
→ Validate
→ Sign
→ Publish
→ Promote
→ Trusted Load
→ Verify
→ Run

也就是说,把 Agent 配置本身当成可构建、可签名、可追踪、可回滚的供应链资产。

这一篇直接实现:

Agent Bundle
Content Hash
Dependency Lock
Provenance
Signature
Artifact Registry
Promotion
Trusted Loader
Revocation
Tenant Pinning
Rollback

让一次 Agent Run 能明确回答:

到底加载了哪一个模型、
哪一版Prompt、
哪一个Skill、
哪一组Tool和Policy,
以及这些东西是否来自可信发布链。

一、为什么“配置”已经等同于代码

传统应用里:

代码

决定主要行为。

Agent 系统里:

Prompt改一句

可能直接改变 Tool 选择。

Tool Description改一句

可能让模型开始频繁调用某个高风险能力。

Policy改一条

可能把:

REQUIRE_APPROVAL

变成:

ALLOW
Model Routing

也可能让敏感数据切到另一个 Provider。

这些都已经属于:

Executable Configuration

所以不能再把它们当“普通后台配置”。

二、先定义Agent Bundle

不要部署:

agent_id = research-agent

然后运行时再动态拼。

真正发布的应该是一个不可变 Bundle。

public record AgentBundleManifest(
        String agentId,
        String agentVersion,
        String modelProfileRef,
        String promptBundleRef,
        String skillLockRef,
        String toolCatalogRef,
        String policyBundleRef,
        String sandboxProfileRef,
        String evalGateRef,
        String contentHash,
        String provenanceRef,
        String signatureRef) {
}

Agent Run 只引用:

agent-bundle:v23

不直接引用一堆“当前最新”。

三、Bundle必须Immutable

错误:

agent:v23

发布后还允许后台修改 Prompt。

这样:

v23

已经失去版本意义。

正确:

任何组成变化
→生成v24

Bundle v23 永远不可变。

四、Prompt不能只保存template version

一个最终 Prompt 可能由:

System
Developer Instruction
Tenant Policy
Skill
Tool Description
Few-shot
Runtime Flags

编译而成。

所以要同时保存:

Source Version
Compiled Artifact Hash

五、Prompt Bundle

public record PromptBundle(
        String bundleId,
        String sourceVersion,
        String compilerVersion,
        String compiledContentRef,
        String compiledHash,
        int tokenCount,
        List dependencyRefs) {
}

这样 Run 能证明:

模型真正看到的是哪一版

而不是只知道:

template=v12

六、Skill要做Lock File

Agent Skill 经常继续依赖:

Tool
MCP
Prompt Fragment
Schema

如果运行时:

自动加载latest

很容易漂移。

所以像 npm lock 一样:

skills:

  contract-review:
    version: 4.2.1
    sha256: abc...

  web-research:
    version: 3.8.0
    sha256: def...

发布时锁死。

七、Tool Catalog也必须版本化

Tool 不只是:

name

还包括:

Description
Input Schema
Output Schema
Risk
Timeout
Idempotency
Provider Binding

任何字段变化都可能影响 Agent。

八、一个Tool Descriptor

public record ToolDescriptor(
        String capabilityId,
        String version,
        String description,
        JsonNode inputSchema,
        JsonNode outputSchema,
        RiskLevel risk,
        Duration timeout,
        boolean idempotent,
        String providerBindingRef,
        String contentHash) {
}

Agent Bundle 锁:

tool-catalog-v81

九、Provider Binding不要和Capability混

全局 Capability:

crm.customer.read

Tenant A:

Salesforce

Tenant B:

Dynamics

所以 Bundle 可以锁:

Capability Contract

Tenant 运行时再选择:

Approved Provider Binding

但 Provider Binding 也必须有版本和签名。

十、Model Profile不能只写model_id

模型配置至少包括:

Provider
Model
Reasoning
Temperature
Region
Fallback
Data Retention
Context Limit
public record ModelProfile(
        String profileId,
        String primaryModel,
        List fallbacks,
        String region,
        String retentionClass,
        Map parameters,
        String contentHash) {
}

如果 Provider 改了默认参数:

Profile Hash

应该发生变化。

十一、Policy Bundle继续沿用上一期的不可变版本

policy-v42

Bundle 直接锁:

policyBundleRef=policy-v42

不要运行时永远读:

current_active_policy

低风险动作可以使用 Run Snapshot。

高风险写操作执行前,再额外做:

Current Emergency Policy Re-evaluate

两层并存。

十二、Sandbox Profile也属于供应链

sandbox:
  runtime: gvisor
  image_digest: sha256:...
  cpu: 2
  memory: 2Gi
  network_policy: egress-v8
  artifact_policy: artifact-v11

如果:

image tag变了

但 Bundle 版本没变,就无法复现。

所以必须使用:

image digest

而不是:

python:3.12-latest

十三、Agent Bundle需要Dependency Graph

Agent Bundle
├─ Prompt Bundle
├─ Model Profile
├─ Skill Lock
│   ├─ Skill A
│   └─ Skill B
├─ Tool Catalog
├─ Policy Bundle
└─ Sandbox Profile

任一依赖变化:

哪些Agent受影响?

必须能算。

十四、Dependency表

create table agent_bundle_dependency (
    bundle_id varchar(128) not null,
    dependency_type varchar(64) not null,
    dependency_id varchar(128) not null,
    dependency_version varchar(64) not null,
    dependency_hash varchar(64) not null
);

例如:

Tool v19
发现安全问题

可以直接查询:

哪些Bundle引用它

十五、内容Hash是第一层完整性

每个 Artifact:

Canonical Content
↓
SHA-256

Manifest 保存:

content_hash

下载后重新算。

如果不一致:

拒绝加载

十六、但Hash不能证明“是谁发布”

攻击者同时替换:

Artifact
+
Manifest Hash

Hash仍然对。

所以还需要:

Signature

十七、发布签名

public record ArtifactSignature(
        String artifactId,
        String artifactVersion,
        String contentHash,
        String signer,
        String keyId,
        String keyVersion,
        String signature,
        Instant signedAt) {
}

私钥放:

KMS / HSM

CI 只有:

sign permission

不能导出 Key。

十八、签名者不能是开发者个人Key

不要:

张三本地签

生产供应链应该是:

Trusted Build Identity

例如:

agent-release-prod

只有通过:

CI
Tests
Approvals

的构建能使用 Production Signing Key。

十九、Dev和Prod Key必须分开

dev-signing-key
staging-signing-key
prod-signing-key

Runtime:

Production

只信:

prod key

所以开发者自己构建一个 Bundle:

即使内容完全一样

也不能被生产加载。

二十、Trusted Loader是最关键的一层

如果 Bundle 签名很好,但 Runtime 启动时:

不验证

整个供应链等于没做。

加载流程:

Fetch Manifest
↓
Verify Manifest Signature
↓
Verify Dependency Hash
↓
Verify Artifact Signature
↓
Check Revocation
↓
Check Tenant Policy
↓
Load

任何一步失败:

Fail Closed

二十一、Trusted Loader接口

public interface TrustedAgentBundleLoader {

    VerifiedAgentBundle load(
            String bundleId,
            TenantContext tenant);
}

不要让业务代码直接:

artifactStore.get(...)

所有 Agent 启动都走 Loader。

二十二、Verified Bundle

public record VerifiedAgentBundle(
        AgentBundleManifest manifest,
        VerifiedPromptBundle prompt,
        VerifiedModelProfile model,
        List skills,
        VerifiedToolCatalog tools,
        VerifiedPolicyBundle policies,
        VerifiedSandboxProfile sandbox,
        VerificationReceipt receipt) {
}

运行时拿到的是:

Verified

对象。

而不是普通字符串引用。

二十三、Verification Receipt

public record VerificationReceipt(
        String bundleId,
        String manifestHash,
        String signingKeyVersion,
        List verifiedDependencyHashes,
        Instant verifiedAt,
        String loaderVersion) {
}

每个 Run 保存它。

以后事故时:

能证明启动时做过验证

二十四、Artifact Registry不要允许覆盖

危险:

PUT /bundle/v23

把旧 v23 覆盖。

正确:

v23 immutable

任何新内容:

v24

Registry 开启:

Write Once

最好不允许 Delete,除非专门 Retention 流程。

二十五、Bundle Build要可复现

同样 Source:

相同Compiler
相同Dependencies

应该产出:

同一个Hash

如果每次 Build Hash 都不同:

说明有时间戳
随机字段
未锁依赖

供应链很难审计。

二十六、Build Manifest

{
  "builder": "agent-bundle-builder/3.2",
  "source_commit": "abc123",
  "build_time": "...",
  "dependencies_lock": "lock-v91",
  "output_hash": "sha256:..."
}

再生成 Provenance。

二十七、Provenance要回答4个问题

从哪来的?
谁构建的?
构建时用了什么?
通过了哪些Gate?

例如:

{
  "source_repo": "agent-config",
  "source_commit": "abc123",
  "builder_identity": "ci-prod",
  "tests": [
    "prompt-eval-v8",
    "policy-simulation-v42",
    "tool-contract-v19"
  ]
}

二十八、Agent配置也需要类似SBOM

软件有 SBOM。

Agent Bundle 可以做:

ABOM
Agent Bill of Materials

列出:

Model
Prompt
Skill
Tool
Policy
Sandbox
External MCP

以及版本和 Hash。

二十九、ABOM示例

agent: research-agent
version: 23

components:

  model:
    profile: reasoning-standard-v8

  prompt:
    bundle: research-prompt-v19

  skills:
    - web-research@3.8.0
    - citation-check@2.1.4

  tools:
    catalog: tools-v81

  policy:
    bundle: policy-v42

  sandbox:
    profile: gvisor-v11

发布页面一眼就能看到:

Agent里面到底装了什么

三十、第三方MCP尤其需要签名和Pinning

最危险:

mcp-server@latest

第三方发布新版本:

Tool Description变了
行为变了
权限需求变了

Agent 无感升级。

生产必须:

version pin
+
hash pin
+
publisher trust

三十一、MCP升级流程

New Version
↓
Fetch
↓
Signature Verify
↓
Schema Diff
↓
Capability Diff
↓
Sandbox Test
↓
Eval
↓
Approve
↓
New Bundle

不要动态 auto-update。

三十二、Tool Schema Diff必须进入Review

例如:

 input:
   customer_id: string
+  include_private_notes: boolean

这不是普通兼容更新。

它扩大了数据访问面。

自动:

HIGH RISK

三十三、Skill Diff也要看Capability变化

Skill v3:

只读搜索

Skill v4:

增加email.send

不能只看版本号。

需要:

Capability Manifest Diff

三十四、Agent Plugin也应该当供应链包

一个 Agent Plugin 可能打包:

Skill
MCP
Prompt
Tool

越方便复用,供应链风险越集中。

所以导入前必须扫描:

Declared Capability
External Endpoint
Secret Requirement
Network Requirement
Publisher
Signature

三十五、Secret绝不能进入Bundle

Bundle 是可复制 Artifact。

所以只允许:

secret_ref

例如:

secrets:
  crm:
    ref: secret://tenant/crm-oauth

禁止:

crm_token: sk-xxxx

CI 可以做 Secret Scan。

三十六、Tenant配置也不要直接编进全局Bundle

全局:

Agent Template

Tenant-specific:

Provider Binding
Secret Ref
Policy Overlay
Brand Config

两者分离。

否则重新发布某个客户配置:

可能影响全部租户

三十七、Tenant Binding也需要版本

public record TenantAgentBinding(
        String tenantId,
        String agentId,
        String bundleVersion,
        String tenantConfigVersion,
        String bindingHash) {
}

这样:

Tenant A用v23
Tenant B仍用v22

可以独立 Canary。

三十八、Promotion不要等同于复制文件

环境:

Dev
Staging
Prod

理想方式:

同一个Artifact Hash

逐级 Promotion。

不是:

Dev重新build
Staging再build
Prod再build

否则三个环境可能内容不同。

三十九、Promotion Pointer

prod/research-agent
→ bundle:v23@sha256:...

发布只是更新 Pointer。

Artifact 本身不变。

四十、Canary也是Binding变化

不要生成:

v23-canary-special

直接:

10% Tenant
→ v23

90%
→ v22

两个都是已签名 Bundle。

四十一、回滚也只切Pointer

v23出问题

回:

v22

不重新构建旧版。

这就是 Immutable Artifact 的价值。

四十二、但紧急撤销需要Revocation

如果发现:

v22也有严重漏洞

不能让人回滚到它。

所以 Registry 要有:

Revocation List

四十三、Revocation Record

public record BundleRevocation(
        String bundleId,
        String version,
        String reason,
        RiskLevel severity,
        Instant revokedAt,
        String revokedBy) {
}

Trusted Loader 每次加载检查。

Critical:

正在运行的Run

也可能要暂停。

四十四、Key本身也会被撤销

如果 Signing Key 泄漏:

签过的Bundle怎么办?

必须区分:

Key Compromised

和:

Key Rotated

正常 Rotation:

旧签名继续可信

Key Compromise:

从某个时间点后的签名全部重新评估

四十五、所以签名Receipt要保存签名时间

signed_at

很重要。

Security 可以判断:

泄漏发生前签的
是否继续可信

四十六、加载时还要检查Compatibility

Bundle v23:

requires runtime >= 4.2

旧 Runtime:

4.0

即使签名完全正确,也不能加载。

Manifest:

runtime:
  min_version: 4.2
  max_version: 4.x

四十七、Tool Protocol也要有Compatibility

MCP Spec、App Server Protocol、内部 Tool Schema 都可能变化。

所以依赖里保存:

protocol_version

启动时检查。

四十八、Bundle发布前至少要过5类Gate

Schema Gate
Security Gate
Eval Gate
Policy Gate
Compatibility Gate

任何一个 Fail:

不能签Prod

四十九、Schema Gate

检查:

字段完整
依赖存在
版本格式
Lock完整

五十、Security Gate

检查:

Secret
危险Capability新增
外部Endpoint
Network扩大
Unsigned Dependency

五十一、Eval Gate

运行固定 Agent Eval:

Task Success
Tool Sequence
Safety
Cost
Latency

达到阈值才继续。

五十二、Policy Gate

上一期的 Policy Simulation:

新Bundle里Policy变化

先跑历史 Decision Input。

五十三、Compatibility Gate

测试:

Runtime Version
Tool Provider
Model Availability
Region
Tenant Policy

避免 Artifact正确但生产根本跑不了。

五十四、签名发生在所有Gate之后

流程:

Build
↓
Test
↓
Simulation
↓
Approval
↓
Sign

不是:

Build
↓
Sign
↓
然后再测

Prod Signature 本身应该代表:

这个Artifact已经通过发布门禁

五十五、Release Signature和Author Signature不要混

开发者 Commit Signature:

证明谁写了Source

Prod Artifact Signature:

证明谁批准它进入生产

两者不同。

都可以保留。

五十六、Agent Runtime不允许“临时改Prompt”

线上排障最常见:

先在后台改一句Prompt看看

这会绕过供应链。

生产正确做法:

Hotfix Branch
→ Build
→ Fast Gate
→ Sign
→ Canary

流程可以很快,但不能没有。

五十七、Emergency Bundle可以有更快流程

Critical Incident

允许:

缩短普通Eval

但不能跳过:

Signature
Security Gate
Audit

而且 Emergency Bundle 要:

短TTL

事故后必须回归正式 Release。

五十八、运行中是否允许自动加载新Bundle

我不建议。

一个 Run 开始:

bundle=v23

跑到一半 Prod Pointer 变:

v24

不要中途切。

否则前半段和后半段行为不可复现。

五十九、Run Snapshot

每个 Run 创建时固定:

bundle_id
bundle_version
manifest_hash
verification_receipt

整个 Run 使用同一 Bundle。

只有安全 Emergency Deny 可以实时覆盖。

六十、长Run如果必须升级怎么办

例如:

运行24小时

新 Bundle 修复严重安全问题。

不要热替换内部组件。

更安全:

Pause
Checkpoint
End old Run
Start new Run with v24
Restore approved state

边界清晰。

六十一、Artifact Cache也必须按Hash

Runtime 为性能会缓存:

Prompt
Tool Schema
Skill

Cache Key 应该:

content_hash

而不是:

agent_id

否则 v24 发布后可能误拿 v23 Cache。

六十二、Trusted Loader失败要Fail Closed

错误:

签名服务暂时不可用
→先加载吧

生产不应该。

如果 Artifact 已经有:

可离线验证签名

Verifier 不需要在线 Signing Service。

Public Key / Trust Root 本地可用。

所以:

Verify失败
→不启动Agent

六十三、Trust Root也需要管理

Runtime信谁的Key?

prod-agent-release
prod-policy-release
approved-third-party

Trust Store 本身也是高价值配置。

不能让 Agent 修改。

六十四、Trust Store更新要双人审批

因为一旦加入恶意 Publisher Key:

后续签名都“合法”

所以:

Trust Root Change

属于 CRITICAL 级。

六十五、供应链安全还要看Source Repo

攻击路径:

Source Repo
↓
CI
↓
Artifact Registry
↓
Runtime

只保护最后签名还不够。

至少:

Branch Protection
Required Review
CI Identity
Build Isolation
Registry Immutability

都要做。

六十六、CI不能从不可信PR拿Prod Signing Permission

外部 PR:

触发CI

如果能使用:

Prod KMS Sign

这是严重供应链问题。

所以:

PR Validation

和:

Protected Branch Release

使用完全不同权限。

六十七、Build Worker也要短期身份

不要放:

长期KMS Key

CI 使用:

OIDC / Workload Identity

临时获得:

sign capability

并限制:

repo
branch
workflow
environment

六十八、一个发布身份Policy

signing:

  key: prod-agent-bundle

  allowed_if:
    repository: agent-config
    branch: main
    environment: production
    required_reviewers: 2

这样普通 Branch 不能签生产包。

六十九、Artifact Registry权限也分读写

Runtime:

Read

CI Release:

Write

Agent:

None

不要让 Agent 自己更新自己的 Bundle。

这条非常重要。

七十、Agent不能自我升级

Agent 可以:

发现新Skill
提出升级建议

但不能:

下载
签名
更新Prod Pointer

自己完成整条升级。

否则:

被Prompt Injection

以后可能升级进恶意组件。

七十一、自动更新只能到Proposal

Agent发现新版本
↓
生成Dependency Upgrade PR
↓
CI验证
↓
人/Policy批准
↓
发布

和 Dependabot 类似。

七十二、供应链需要一个统一Release Ledger

create table agent_release_ledger (
    release_id varchar(128) primary key,
    agent_id varchar(128) not null,
    bundle_version varchar(64) not null,
    manifest_hash varchar(64) not null,
    signer_key_version varchar(64) not null,
    source_commit varchar(64) not null,
    promoted_by varchar(128) not null,
    promoted_at timestamptz not null
);

以后可以追:

谁
什么时候
把什么
推到生产

七十三、运行记录引用Release Ledger

Run
→ Release ID

而不是只写:

agent_version=23

这样能直接串回:

Source Commit
Build
Signature
Gate

七十四、Metrics

agent_bundle_verify_total{
  result
}

agent_bundle_signature_invalid_total

agent_bundle_revoked_load_total

agent_bundle_dependency_mismatch_total

agent_bundle_promotion_total{
  env
}

agent_bundle_rollback_total

agent_unsigned_dependency_total

这些指标应该和普通 Agent Runtime 指标分开。

七十五、SLO

Unsigned Production Bundle = 0
Invalid Signature Load = 0
Revoked Bundle Start = 0
Unknown Dependency Hash = 0
Run Without Verification Receipt = 0

全部 Zero Tolerance。

七十六、供应链Incident怎么处理

发现:

skill-v8
被污染

流程:

Mark Dependency Revoked
↓
Find all Bundles
↓
Block new Runs
↓
Evaluate active Runs
↓
Freeze Evidence
↓
Build patched Skill
↓
New Bundle
↓
Canary
↓
Promote

Dependency Graph 这时非常关键。

七十七、Blast Radius查询

select bundle_id
from agent_bundle_dependency
where dependency_id = 'skill-x'
  and dependency_version = '8.0';

几秒就知道影响面。

没有依赖图:

靠群里问谁用了这个Skill

会非常慢。

七十八、Tenant Pinning能降低Blast Radius

Tenant A:

v23

Tenant B:

v22

新版本问题只影响 Canary Tenant。

所以不建议所有 Tenant 永远:

auto latest

七十九、但版本太碎也会增加运维成本

如果 1000 个 Tenant:

300个版本

无法维护。

所以支持窗口:

Current
Previous
LTS

例如只允许:

v23
v22
v20-LTS

其他版本强制升级。

八十、Bundle生命周期

public enum BundleLifecycle {
    DRAFT,
    BUILT,
    SIGNED,
    STAGING,
    CANARY,
    PRODUCTION,
    DEPRECATED,
    REVOKED,
    RETIRED
}

每次状态变化都进入 Release Ledger。

八十一、Deprecated和Revoked不同

Deprecated:

不建议新用
但还能跑

Revoked:

禁止启动

不要混成一个:

disabled

八十二、最终上线检查清单

□ Agent发布为Immutable Bundle
□ Prompt保存Compiled Hash
□ Skill有Lock File
□ Tool Catalog版本化
□ Model Profile版本化
□ Policy Bundle版本化
□ Sandbox使用Image Digest
□ 所有Dependency有Content Hash
□ Bundle有ABOM
□ Build可复现
□ Build生成Provenance
□ Prod Artifact由CI身份签名
□ Dev/Staging/Prod Signing Key分离
□ Runtime只信Prod Trust Root
□ Trusted Loader强制验签
□ Runtime检查Revocation
□ Registry禁止覆盖旧版本
□ Secret不进入Bundle
□ Tenant Config与Global Bundle分离
□ Promotion使用同一Artifact Hash
□ Canary通过Tenant Binding实现
□ Rollback只切Pointer
□ Third-party MCP Pin Version + Hash
□ Capability Diff进入Security Review
□ CI不允许不可信PR访问Prod Signing
□ Agent本身没有Artifact发布权限
□ 每个Run保存Verification Receipt
□ Unsigned Production Run = 0

总结

Agent 平台走到生产阶段以后,真正危险的已经不是只有:

代码供应链

而是:

行为供应链

因为 Model、Prompt、Skill、Tool、Policy 和 Sandbox 都在决定 Agent 会做什么。

如果这些组件仍然是:

运行时拉latest
后台随手改
启动时不验证

那么你即使给代码做了最严格的 CI/CD,也无法证明今天运行的 Agent 和昨天是同一个系统。

配置供应链要解决的核心只有三件事:

我加载的是什么?
它从哪里来的?
我为什么应该信它?

通过:

Immutable Bundle
+
Hash
+
Signature
+
Provenance
+
Trusted Loader

把这三件事固定下来,Agent 才真正拥有类似成熟软件系统的可信发布链。

下一篇继续推进:

生产级Agent(24):Agent Runtime升级与兼容矩阵——当模型、协议、Tool和State Schema同时演进,怎么做到不停机升级。


更多企业级 AI 应用、Agent、RAG 与模型工程化内容,我会继续整理在 智元界

https://www.zyentor.com/