concept · created Apr 27, 2026 · updated Jun 4, 2026

agent-computer-interface

#agent-engineering#tool-design

Agent-Computer Interface (ACI) — the discipline of designing tools for an Agent, not for a human developer reading API docs. By analogy with HCI: tool design shapes Agent behavior the way UI design shapes human behavior. Per tw93 in 2026-04-27-agent-principles-architecture-engineering, most “Agent picked the wrong tool” debugging traces back to the tool description, not the model. ACI is the engineered descendant of Weng’s 2023 tool-use survey (2026-06-04-llm-powered-autonomous-agents), whose MRKL experiment already found that knowing when and how to call a tool — not the tool itself — is the bottleneck, “determined by the LLM capability”.

Three generations of tool design

GenWhat it gives the AgentFailure mode
API wrappingOne tool per API endpoint, e.g. get_post + update_content + update_titleGranularity matches the API, not the goal — the Agent must coordinate multiple calls to do anything
ACIOne tool per Agent goal, e.g. update_yuque_post(post_id, title, content_markdown)Requires intentional design — a goal-shaped surface area, not just a transcribed API
Advanced Tool UseDiscovery, code-orchestration, and example-driven calling layered on top of ACIPure ACI tools are still lossy at scale (too many definitions, no examples) — Advanced Tool Use techniques compensate

Five ACI principles

  1. Tools map to goals, not endpoints. If completing one user-visible action requires two tool calls, the boundary is wrong.
  2. Parameter descriptions are constraints. post_id: string is useless; post_id: 语雀文章 ID,纯数字字符串,如 "12345678" cuts the format-mistake rate.
  3. Errors carry repair hints. A bare "Error: update failed" is a dead end. Structured errors with error_code and suggestion: "请先调用 list_yuque_posts 获取有效的 post_id" let the Agent self-correct.
  4. Definition and implementation bound together. The source uses betaZodTool (Zod schema + handler in one object) so the schema isn’t drift-prone documentation — it’s the actual contract the runtime enforces.
  5. Description tells when to use, not what it does. Like a Skill descriptor, the most actionable bit of a tool description is its use / don’t use boundary.

Advanced Tool Use — three techniques

From the source:

TechniqueMechanismReported impact
Tool SearchDon’t ship every tool definition every request — let the Agent discover tools via search_tools on demandContext retention up to ~95%; Opus 4 accuracy 49% → 74%
Programmatic Tool CallingLet the model write code that orchestrates multiple tool calls; intermediate data flows in the execution environment, not through the LLM contextA worked example: ~150K tokens → ~2K tokens
Tool Use Examples1–5 real call examples embedded with the tool definition — JSON Schema describes types, examples describe how to callTool-call accuracy 72% → 90%

(All numbers from 2026-04-27-agent-principles-architecture-engineering — flagged as needing primary citations; see open questions on the source page.)

Tool framing as harness

ACI sits inside harness: it’s where the feedback signal component meets the execution boundary component. A well-shaped tool gives the Agent a useful error to recover from; a badly-shaped tool turns recoverable failures into infinite loops.

Worked example

Bad — parameters are typed but not described, and errors are opaque:

const tool = {
  name: "update_yuque_post",
  input_schema: {
    properties: {
      post_id: { type: "string" },
      content: { type: "string" },
    },
  },
};
return "Error: update failed";

Good — Zod-bound schema, prose constraints in .describe(), structured error with a repair hint:

const updateTool = betaZodTool({
  name: "update_yuque_post",
  description: "更新语雀文章内容,不适合创建新文章",
  inputSchema: z.object({
    post_id: z.string().describe("语雀文章 ID,纯数字字符串,如 '12345678'"),
    title: z.string().optional().describe("文章标题,不改时可省略"),
    content_markdown: z.string().describe("Markdown 格式正文"),
  }),
  run: async (input) => {
    const post = await getPost(input.post_id);
    if (!post) throw new ToolError("文章 ID 不存在", {
      error_code: "POST_NOT_FOUND",
      suggestion: "请先调用 list_yuque_posts 获取有效的 post_id",
    });
    return await updatePost(input.post_id, input.title, input.content_markdown);
  },
});

Internal vs. LLM-visible messages

A practical sub-rule from the source: framework-internal events (compaction triggered, notification dispatched, tool call skipped) belong in the conversation history but not in the LLM context. Use two message types — AgentMessage for application state (carries any custom fields), Message filtered to user / assistant / tool_result for the model. Conversation history stays complete; the LLM sees only what it needs.

Anti-patterns

  • One generic update(id, content) tool wrapped over every endpoint.
  • Tool descriptions that read like API reference, with no when to use.
  • Errors as bare strings.
  • Definitions decoupled from implementation — schema documents one shape, code expects another.
  • 5+ MCP servers connected by default — definition tax burns the context budget before the user types (model-context-protocol).

Referenced by 12

2026-04-27-agent-principles-architecture-engineering 2026-06-04-llm-powered-autonomous-agents harness-why-it-matters-now agent-legibility claude-skills context-engineering harness llm-agent tool-use openai openclaw tw93
esc