跳到正文
DEV Community· Jack M·· 3 小時前AI 評分62

AI 智能體依賴鎖定檔:追蹤工具與套件的靜默漂移

AI Agent Dependency Lockfiles: Stop Silent Tool and Package Drift

AI 導讀

AI 智能體依賴鎖定檔把模型、提示詞、MCP 工具、政策、檢索設定及套件的實際解析身份記錄在可審核的快照中,補足一般 package-lock.json 未涵蓋的執行依賴。CI 可比較候選鎖定檔與已提交版本,按模型版本、工具權限或工具結構描述等差異安排測試和審批。部署引用不可變的鎖定檔摘要,並將鎖定檔 ID 加入追蹤記錄及評測結果,以便重現執行環境或回滾至先前版本。

正文

An agent can behave differently on Tuesday even when nobody changed its prompt or application code. A package resolves to a newer release, an MCP server updates a tool description, a model alias moves, or a tool image is rebuilt. The workflow still starts. The tests may still be green. But the agent is no longer the runtime you reviewed.

That is why a normal package-lock.json is necessary but incomplete for an AI feature. It pins part of the application, while the agent also depends on models, prompts, tool servers, policy bundles, retrieval configurations, and external packages. Treat those as one dependency graph. Then record the resolved graph in an AI agent dependency lockfile.

This is not a claim that a lockfile makes an agent safe. It gives you a specific, reviewable answer to a much more useful question: what exactly did this agent run with? That answer makes bad changes easier to spot, reproduce, and roll back.

What belongs in an agent dependency lockfile?

Start with dependencies that can change behavior or permissions without changing the business workflow. A useful lockfile records both the requested selector and the resolved identity.

Dependency Weak reference Useful locked identity
Model fast-model provider, model revision or immutable deployment ID
Prompt support-v3 repository commit and content digest
MCP tool billing-tools:latest image/package digest, server version, tool-schema digest
Library agent-sdk:^4 exact package version and integrity hash
Policy default-policy policy bundle digest and decision version
Retrieval config help-center index revision, embedding model, and chunking config digest

The point is not to freeze every choice forever. The point is to separate intent from resolution. latest can remain an input to an update job, but it should not be the only record of what production executed.

The trap: configuration looks less risky than code

Teams often review source changes carefully and accept an environment variable such as MODEL=fast-model or TOOLS_URL=https://tools.internal as harmless wiring. In an agent system, that wiring can change output quality, tool availability, permissions, latency, or data handling.

The same issue appears with agent-installed dependencies. If a coding agent adds a package because it recognizes a familiar name, the pull request can hide a new transitive tree behind one import. If an agent fetches a tool server by a mutable tag, an image rebuild can change the runtime after review. Current public guidance on agent supply chains explicitly includes models, agents, libraries, developer tools, and MCP-server packages in scope. The boundary is wider than requirements.txt.

A small lockfile format that is easy to review

Use a format your tools can parse and your reviewers can read. JSON is convenient for CI, though YAML or TOML works too. This example deliberately avoids storing credentials and raw customer data.

{
  "lockVersion": 1,
  "agent": {
    "name": "refund-assistant",
    "workflowCommit": "8e9b1f2",
    "policy": {
      "selector": "refund-policy",
      "resolvedDigest": "sha256:6b4d..."
    }
  },
  "model": {
    "selector": "support-fast",
    "provider": "example-provider",
    "resolvedId": "support-fast-2026-10-18"
  },
  "prompts": [{
    "path": "prompts/refund.md",
    "gitCommit": "8e9b1f2",
    "sha256": "f18c..."
  }],
  "tools": [{
    "name": "get_order",
    "serverImage": "registry.example/tools@sha256:a91d...",
    "serverVersion": "2.4.1",
    "schemaSha256": "ce33...",
    "scopes": ["orders.read"]
  }],
  "packages": {
    "agent-sdk": { "version": "4.2.3", "integrity": "sha512-..." }
  },
  "retrieval": {
    "indexRevision": "kb-2026-10-23-04",
    "embeddingModel": "embed-small-r17",
    "chunkerDigest": "sha256:9d70..."
  }
}

Two details matter here. First, the selector preserves the human-facing intent, while the immutable ID or digest preserves what actually resolved. Second, the lockfile captures only references and hashes. A lockfile should never become a second secret store.

Generate the file; do not hand-edit it in production

Create one command that resolves inputs, validates them, and writes a canonical lockfile. A minimal TypeScript-style sketch looks like this:

type ResolvedTool = {
  name: string;
  serverImage: string;
  schemaSha256: string;
  scopes: string[];
};

async function lockTool(name: string): Promise<ResolvedTool> {
  const server = await registry.resolveImmutableImage(name);
  const schema = await mcp.inspect(server.digest);

  if (!schema.tools.every(tool => allowedTools.has(tool.name))) {
    throw new Error(`Unexpected tool exposed by ${name}`);
  }

  return {
    name,
    serverImage: server.digest,
    schemaSha256: sha256(stableJson(schema)),
    scopes: minimalScopes(schema)
  };
}

Canonical serialization is important. If equivalent JSON can produce different bytes, a hash diff becomes noise. Sort keys, normalize line endings, and write the generated file deterministically. Commit it next to the workflow definition just as you commit an ordinary package lockfile.

Make dependency diffs a release gate

A lockfile only helps if a changed resolution gets attention. In CI, generate a candidate lockfile, compare it with the committed version, and classify the diff.

Change Default handling Why
Patch-level library update test and review behavior may still change
New MCP tool or expanded scope block pending approval expands agent capability
Tool-schema digest changed contract tests + approval arguments or semantics may drift
Model revision changed evaluation suite + staged rollout behavior can shift without API errors
Policy digest changed policy-owner approval decision boundary changed
Retrieval index revision freshness and regression checks evidence may have changed

Avoid a single “lockfile changed” checkbox. A new read-only tool and a tool that can issue refunds are not equivalent. The classifier should turn a mechanical diff into an appropriate review path.

Here is a shell-shaped CI outline:

agentctl lock --config agent.yaml --out agent.lock.next.json
agentctl lock verify --file agent.lock.next.json
agentctl lock diff agent.lock.json agent.lock.next.json --format json > diff.json
agentctl lock policy-check diff.json
agentctl test contracts --lock agent.lock.next.json
agentctl eval run --suite refund-safety --lock agent.lock.next.json

The policy-check command should fail closed for prohibited changes, such as a mutable image tag, an unapproved registry, a newly write-capable tool, or a missing integrity digest. It should produce a readable report for permitted changes, not merely a pass/fail bit.

Keep resolution separate from activation

Do not let a production process silently resolve new dependencies at startup. Instead, use a two-step path:

  1. Resolve: an update job produces a candidate lockfile from declared selectors.
  2. Validate: CI runs package scans, tool-contract tests, workflow tests, and representative evaluations.
  3. Approve: reviewers accept the classified dependency diff.
  4. Activate: deployment references the immutable lockfile digest.
  5. Observe: logs attach the lockfile ID to each run; a canary receives a limited traffic slice.
  6. Roll back: redeploy the prior known-good lockfile if failure signals cross a threshold.

This is deliberately less magical than allowing a runtime to “get the newest compatible tool.” Predictable change is the goal. If fast security patches are needed, the same path can be accelerated with an explicit emergency approval and a short retrospective requirement.

Record the lockfile ID in operational evidence

Attach agent_lock_digest to traces, decision records, and evaluation results. When a support team asks why an agent started choosing a different tool, you can group failures by the exact dependency set instead of guessing from deploy timestamps.

That also makes incident work smaller. You can reproduce an affected run in a sandbox using the workflow commit plus lockfile, then compare it with the previous digest. A release manifest tells you the bundle identity; the dependency lock tells you which mutable ecosystem references became concrete artifacts.

Common failure modes

Locking a name, not content. tools: 2.4.1 is better than latest, but a package version alone may not identify the exact artifact. Use an integrity value, immutable image digest, or registry-provided content hash where possible.

Treating tool schemas as documentation. A schema can alter required fields, defaults, descriptions, or side effects while the server name stays the same. Snapshot the inspected schema and run contract tests against it.

Locking only dependencies. A model alias, prompt file, retrieval index, and policy bundle can each change an agent’s behavior. Include the components that matter to your threat model and debugging path.

Making updates impossible. A lockfile that nobody refreshes becomes stale theater. Run a scheduled candidate-resolution job, send bounded diffs to owners, and maintain a tested fast lane for security patches.

Logging secrets by accident. Store a tool’s allowed scope and identity, not an access token, endpoint query string, or customer payload. Scan generated lockfiles before commit.

A practical adoption plan

Begin with one agent that has meaningful external effects. Inventory its model, prompt, tool servers, packages, policy, and retrieval configuration. Add immutable IDs for the two or three components most likely to drift. Then make one CI rule visible: any newly write-capable tool requires a human approval.

After that, add schema snapshots and trace correlation. Only when those pieces work should you expand the lock to every runtime dependency. The artifact should reduce ambiguity for engineers, not create a giant metadata file nobody can review.

Use the lockfile with, not instead of, an inventory

A lockfile answers “what did this release resolve?” An inventory answers “what agent components exist across the organization?” Keep both. The inventory is useful for ownership, patch notifications, and discovering an unmaintained tool server; the lockfile is useful for exact runtime reproduction. Mixing the two creates a document that is too broad for a deploy and too stale for security operations.

Think of the lockfile as a release-level snapshot and the inventory as a portfolio-level map. A tool may appear in the inventory with an owner, risk classification, and approved registry. Each agent lockfile then states the immutable tool artifact, schema digest, and scopes it actually used. This distinction gives a security reviewer a short answer during a release review and gives an operations team a larger answer when a vulnerability advisory arrives.

When a dependency advisory appears, first query the inventory to identify candidate owners and workloads. Next, query deployment records for lockfile digests that reference the affected artifact. That keeps response work evidence-based: do not restart every agent merely because a similarly named package exists somewhere in a repository.

What a good review looks like

Reviewers should be able to answer four questions from the pull request: What changed? Which capability or behavior could change? What tests exercised the new resolution? How do we return to the previous known-good digest? Include those answers in the generated diff summary.

For example, a tool image update with an unchanged schema may need integration tests and a vulnerability scan. A schema diff adding issue_refund requires a capability-owner approval even if the image has no known CVEs. A new model revision needs representative task evaluation, because its interface can be stable while its decisions move. The lockfile makes these different kinds of changes visible in one place without pretending they carry the same risk.

FAQ

Is an AI agent dependency lockfile different from a package lockfile?

Yes. A package lockfile resolves language dependencies. An agent lockfile extends the same idea to behavior-relevant dependencies such as models, prompts, MCP tools, policies, and retrieval revisions.

Should every model request use a pinned model version?

For production workflows where repeatability matters, record the resolved deployment or revision identity when your provider exposes one. If only an alias exists, record the alias, provider metadata available at resolution time, and the evaluation evidence used for the rollout.

How do I version an MCP server safely?

Pin its immutable image or package integrity value, capture the inspected tool-schema digest, test its tool contracts, and require approval when the exposed tools or scopes expand.

Can a lockfile prevent a malicious dependency?

No. It helps you know and reproduce what was selected. Combine it with trusted registries, integrity verification, vulnerability scanning, least-privilege credentials, code review, and runtime controls.

How often should we refresh an agent lockfile?

Generate a candidate on a predictable cadence and when declared dependencies change. Apply updates only after the appropriate checks; urgency can change the approval speed, not the evidence you retain.

What should happen when a lockfile changes during an incident?

Compare the new and previous resolved identities, correlate failures with the lockfile digest, deploy the last known-good lockfile if justified, then preserve the diff and test results for follow-up.

Do small teams need this much process?

Start small: pin package and tool identities, commit one generated file, and review capability changes. The same habit scales better than reconstructing a changed agent runtime from scattered environment variables later.

來源:DEV Community · dev.to