Skip to content
Chenghao Liao
Go back

Agent 不需要预先知道整个世界,只需要知道如何发现世界

最近在看 Agent 的 Context、Skill、Tool、CLI 设计时,我发现这些看起来分散的话题,最后其实都在指向同一个方向:

Agent 不需要预先知道整个世界,只需要知道如何发现世界。

这句话背后并不只是“节省 Context”这么简单。我觉得它反映的是 Agent 架构正在发生的一种变化:

过去:
把知识、工具、历史、规则尽可能预装给 Agent

现在:
只保留一个小而稳定的核心
其余能力按需发现、加载和组合

如果继续往下推,这甚至可能意味着:

Agent Tool Design 的终点,未必是越来越丰富的 Tool Schema,而可能是越来越少、越来越通用的 Primitive,再让强模型通过 CLI、Skill 和 Retrieval 动态组合能力。


一、过去的 Agent:把整个世界塞进 Context

最直接的 Agent 设计通常是:

Agent
=
LLM
+ Prompt
+ History
+ Knowledge
+ Tools
+ Rules

需要什么,就往里面加什么。

Agent 要记住历史:

→ 把历史消息全部放进 Context

Agent 要了解领域知识:

→ 把文档塞进 Prompt

Agent 要调用工具:

→ 把所有 Tool Schema 注册给模型

Agent 要掌握某种专业能力:

→ 把 SOP 继续写进 System Prompt

当系统还比较小时,这种方式最简单。

但随着 Agent 能力持续增加,很快就会出现一个共同问题:

模型背着越来越多当前根本用不到的信息工作。

假设一个通用 Agent 背后拥有:

100 万条历史消息
10000 篇知识文档
1000 个 Tools
500 个 Skills
一个大型代码仓库

真正处理某一个问题时,也许只需要:

当前任务
1 条用户约束
3 个代码片段
1 个 Skill
4 个 Tool

如果仍然坚持把“所有可能有用的东西”都交给模型,不仅 Token 成本会上升,模型的注意力本身也会被大量无关信息污染。

所以问题逐渐从:

如何扩大 Context?

变成:

这一轮推理,到底什么东西值得进入 Context?


二、History:不需要记住所有过去,只需要知道怎么回去看

最早很多 Agent 的 Memory 本质上就是:

messages[]

用户消息、Assistant 输出、Tool Call、Tool Result 不断往后追加。

时间一长:

Context 越来越大
→ 压缩
→ 再继续
→ 再压缩

但真正更自然的方向可能是:

完整 History
      ↓
Persistent Storage
      ↓
Retrieval
      ↓
Relevant Context
      ↓
LLM

也就是说,Agent 不需要始终“记住所有过去”。

它只需要知道:

历史在哪里
+
什么时候应该查
+
怎么把相关内容取回来

这其实已经是第一次能力外置:

remember everything

变成:

retrieve when needed

所以 Memory 的核心不一定是“保存多少”,而越来越像:

如何从一个巨大的历史空间里恢复当前真正需要的信息。


三、Knowledge:优秀的 Agent 不一定知道所有答案,但应该知道去哪里找

Knowledge 也是一样。

传统方式可能把大量业务规则直接塞进 Prompt:

System Prompt
+
产品文档
+
研发规范
+
安全要求
+
业务规则

但随着知识越来越多,这显然不能无限扩展。

于是变成:

Knowledge Store
      ↓
Search / Retrieval
      ↓
Relevant Knowledge
      ↓
Context

这里发生了一个很重要的变化:

Agent 的能力,不再完全取决于它“已经知道什么”,而开始取决于它“是否知道如何获得自己不知道的东西”。

这其实很像真实工程师。

一个优秀工程师并不是把 MySQL、Linux、Kubernetes 的所有文档背下来。

更重要的是:

看到一个现象
↓
判断可能和 MVCC 有关
↓
知道应该查什么
↓
找到正确资料
↓
完成验证

所以真正稀缺的能力逐渐从:

Knowledge

变成:

Discovery + Retrieval + Reasoning

四、Skill:不需要永远背着所有 SOP

Skill 又把这个思路往前推进了一步。

假设一个 Agent 拥有很多专业能力:

SQL Injection Review
Auth Bypass Review
Database Migration Review
K8s Troubleshooting
Performance Profiling
...

最直接的做法是把所有 Instructions 塞进 Prompt。

但实际上,一个处理数据库迁移问题的 Agent,这一轮根本不需要知道:

如何排查 K8s NetworkPolicy

所以更合理的方式是渐进式加载:

Metadata
→ 知道这个 Skill 存在

Instructions
→ 真正需要时加载执行步骤

Resources / Code
→ 执行过程中再按需加载

Agent 不需要一直记得:

K8s 网络故障应该按照哪 17 个步骤排查。

它只需要知道:

我有一个 K8s Troubleshooting Skill,需要的时候可以加载。

因此:

Know every procedure

开始变成:

Know how to discover and load procedures

五、Tool:为什么一定要提前告诉 Agent 所有能力?

Tool 也是完全一样的问题。

传统 Function Calling:

Agent
├─ Tool A schema
├─ Tool B schema
├─ Tool C schema
├─ ...
└─ Tool 500 schema

当工具数量很少时,这没有任何问题。

但当 Agent 拥有上百种能力时,每轮都让模型面对完整 Tool Catalog 就开始变得不自然。

更合理的方式可能是:

当前任务
   ↓
Tool Retrieval / Router
   ↓
Top-K Candidate Tools
   ↓
Main Agent
   ↓
最终选择

也就是把:

Know every tool

变成:

Know how to discover tools

这和 RAG 的思路其实完全一样。

RAG 是:

10000 篇文档
→ 检索 5 篇
→ 给模型

Tool Routing 是:

1000 个 Tool
→ 检索 5 个
→ 给模型

它们解决的本质都是:

从一个巨大的外部空间中,找到当前最相关的一小部分。


六、CLI:甚至未必需要提前定义这么多 Tool

CLI-first 的思路则更加激进。

比如 Git 本身已经提供:

git status
git diff
git log
git blame
git branch

如果再为 Agent 包装:

GitStatusTool
GitDiffTool
GitLogTool
GitBlameTool
GitBranchTool

有时是在重复构造一层接口。

对于足够强的 Coding Agent,也许只需要给它:

execute

然后让它自己:

git --help
git log --help
git log ...

这里有一个很有意思的变化。

过去我们试图为每一种高阶能力定义 Tool:

InvestigateCommitTool
AnalyzeHistoryTool
FindRegressionTool

但 CLI 的思路更像:

提供少量 Primitive
↓
让 Agent 自己组合

例如:

git log --oneline |
grep fix |
head -20

实际上已经组合出了一个原本没有专门定义过的新能力。

所以我开始觉得:

Agent Tool Design 的终点未必是越来越丰富的 Tool Schema,而可能是越来越少、越来越通用的 Primitive。


七、这很像计算机本身的设计

我觉得一个很好理解的类比是 CPU。

我们并没有给每一个应用需求设计一个 CPU 指令。

CPU 只有少量 Primitive:

load
store
add
compare
jump
...

但这些 Primitive 组合之后,可以构造:

编译器
数据库
浏览器
游戏

Agent 也可能走向类似的方向。

真正长期存在于 Agent Core 里的能力也许并不需要很多:

read
search
edit
execute
retrieve
persist
delegate

然后:

调查 Git 历史

可以理解成:

execute + git
查领域规范

可以理解成:

retrieve + knowledge
检查 SQL Injection

则可能是:

load skill
+
search code
+
execute analyzer
+
read evidence

也就是说:

高阶能力不一定需要全部被预定义,它们可以由少量 Primitive 动态组合出来。


八、从“全能 Agent”到“Agent Kernel”

沿着这个思路继续走,我觉得未来 Agent 更像一个小型 Kernel,而不是一个预装了整个世界的全能应用。

                Agent Kernel
                     │
            ┌────────┼────────┐
            │        │        │
         Reason   Discover  Compose
            │        │        │
            └────────┼────────┘
                     ↓
               External World
        ┌────────────┼────────────┐
        │            │            │
     History      Knowledge      Skills
        │            │            │
     Artifacts      Tools         CLI

Agent Kernel 自己真正长期需要拥有的,也许只有:

当前目标
关键约束
Working State
少量核心 Primitive
发现外部能力的方法

剩下的都在外部世界中。

需要时再获取。

所以可以换一种说法:

Agent 不需要把世界放进 Context,只需要拥有访问世界的方法。


九、Context Engineering 本质上是在做“世界投影”

这样再看 Context Engineering,就会发现它远不只是:

Context 太长
→ 做 Summary

真正的问题是:

这一轮模型应该看到什么?

外部系统可能拥有:

History
Knowledge
Tools
Skills
Code
Artifacts
Subagent Results
Task State

而 Context Engineering 要做的是:

World State
     ↓
Routing / Retrieval / Filtering
     ↓
Current Context
     ↓
LLM

可以把它理解成一种:

Context Projection。

把一个巨大的真实世界投影成当前推理所需要的一小部分。

所以最近看到的这些方向:

Memory Retrieval
Skill Loading
Tool Routing
Context Compression
Subagent Context Isolation

其实不是五个独立的问题。

它们都在回答同一个问题:

什么东西现在值得进入模型的注意力?


十、但“Primitive 越少越好”也是一个陷阱

这个方向同样不能走向极端。

不能因为:

一个 shell

理论上可以完成很多操作,就认为:

所有 Tool 都应该变成 shell

越通用的 Primitive,意味着自由度越高。

同时也意味着:

可控性下降
权限边界变宽
输出更难结构化
失败语义更复杂
副作用更难管理

例如:

create_pr(title, body)

和:

gh pr create ...

后者更加通用。

但前者拥有很明显的工程优势:

参数明确
权限清晰
方便审计
容易幂等
容易记录 Effect
容易做 Evaluation

所以最终合理的架构应该不是:

Structured Tool
vs
Primitive

二选一。

而是一种分层。


十一、我更认可“小核心 + 动态外围”

最终我比较认可的形式是:

Agent Core

常驻:
- 少量核心 Tool / Primitive
- 当前任务
- Working State
- 强约束

按需:
- Domain Skills
- Knowledge
- Long-tail Tools
- MCP capabilities
- Historical Evidence
- Large Artifacts

同时按照能力本身的性质决定暴露方式。

对于:

高频
高风险
高结构化
有明确副作用

的能力,保留专门 Tool:

apply_patch
create_pr
deploy
send_message

因为这些能力需要严格定义:

input
permission
effect
retry
audit

而对于:

git
rg
semgrep
go test
jq

这类成熟、低层、可自由组合的开发环境能力,则可以更多利用 CLI。

所以我觉得比较合理的原则是:

稳定核心能力结构化,长尾能力动态发现;低风险能力允许自由组合,高风险能力保持强约束。


十二、放到 Coding Agent 里

例如一个 Security Actor,不一定需要永久注册几十个 Security Tool。

它可以常驻:

search_repository
read_file
read_artifact
execute_safe_command

同时知道自己拥有:

SQL Injection Review Skill
Auth Bypass Review Skill
Dependency Vulnerability Skill

当遇到 SQL Injection 时:

加载 SQL Injection Skill
        ↓
发现需要 Source → Sink 分析
        ↓
搜索相关代码
        ↓
必要时加载 / 调用 taint analyzer
        ↓
读取 Evidence
        ↓
形成 Finding

整个过程中,Agent 不需要:

永远看到所有 Security Tool
永远背着所有 Security SOP
永远加载整个 Repository

但它仍然能够使用这些能力。

这其实比“在 Prompt 里拥有很多东西”更接近真正的可扩展性。


结语

最近看的很多 Agent 设计,看起来分别在解决不同问题:

Context
所有 History 不要全部塞进模型
→ 按需加载

Skills
所有 Skill 不要全部塞进去
→ Progressive Disclosure

Tools
所有 Tool Schema 不要全部塞进去
→ Router / Lazy Load

CLI
甚至 Tool 本身都不用提前注册
→ 提供通用 Primitive
→ 按需发现

但继续抽象以后,它们其实正在汇聚成同一条主线:

Agent 不需要预先知道整个世界,只需要知道如何发现世界。

进一步说:

Agent 的能力,不应该由“它当前 Context 里装了多少东西”决定,而应该由“它能够按需发现、获取并组合多少外部能力”决定。

也许未来一个真正强大的 Agent,并不会拥有一个越来越庞大的 Prompt、越来越多的 Tool Schema 和越来越长的 Context。

反而可能只是:

一个足够强的模型
+
一个很小的 Working Context
+
少量通用 Primitive
+
一套可靠的 Discovery / Retrieval 机制

剩下的知识、工具、技能和历史,都在外部世界里。

需要的时候,再去拿。


Share this post:

Previous Post
当 Agent 的 Tool 太多时,是否应该加一层“工具路由”?
Next Post
Context Engineering:Agent 的核心不是能看到多少,而是每一步该看到什么