外观
Agent 的代码谁都能写,难的是管好那串文字
上一篇我们搞清楚了 Agent 的骨架:LLM + 工具 + While 循环。
核心代码就那点。
骨架只是起点。真正决定一个 Agent 好不好用的,是每一次循环里,你塞给 LLM 的那段 message —— 也是就是上下文。
那么管理好并设计好这段上下文就叫做 —— 上下文工程(Context Enginer)
这篇我们就拆开来看三件事:
- 每次循环里 LLM 到底看到了什么
- 工具调用是怎么回事
- 为什么说 Agent 工程的核心是上下文工程。
一、每次循环里,LLM 到底看到了什么
上一篇的伪代码里有一行反复出现:
Plain
response = LLM(system_prompt, tools, messages)这行代码每次被执行,就是把三样东西打包丢给 LLM:
- 系统提示词
- 工具列表
- 对话历史LLM
LLM 会读完上面一整个内容,LLM 来决定下一步干嘛。
关键来了 —— 其实 LLM 并没有记忆。
它不记得上一圈循环自己说了什么,不记得工具返回了什么结果。所以每次被调用,对它来说都是第一次。
它能知道之前发生了什么,完全是因为你把之前所有的对话记录塞在 messages 里,让它从头读了一遍。
我们用上一篇那个天气任务来看,每一圈循环时 LLM 看到的东西:
第一圈:
Plain
系统提示词:你是一个智能助手,可以查天气和设提醒...
工具列表:[查天气, 设提醒]
对话历史:
用户:查一下明天上海和北京的天气,哪个城市下雨就帮我设早上7点带伞的提醒。LLM 读完,决定:先查上海天气。输出 → 调用 check_weather(city="上海")
第二圈:
Plain
系统提示词:你是一个智能助手,可以查天气和设提醒...
工具列表:[查天气, 设提醒]
对话历史:
用户:查一下明天上海和北京的天气,哪个城市下雨就帮我设早上7点带伞的提醒。
助手:[调用 check_weather(city="上海")]
工具结果:上海,明天中雨,气温 18-22℃LLM 读完,知道上海下雨了,但北京还没查。决定:再查北京。输出 → 调用 check_weather(city="北京")
第三圈:
Plain
系统提示词:...
工具列表:[查天气, 设提醒]
对话历史:
用户:查一下明天上海和北京的天气...
助手:[调用 check_weather(city="上海")]
工具结果:上海,明天中雨
助手:[调用 check_weather(city="北京")]
工具结果:北京,明天晴,气温 15-26℃LLM 读完,上海下雨要设提醒,北京晴天不用。决定:给上海设提醒。输出 → 调用 set_reminder(time="07:00", message="上海明天中雨,记得带伞")
第四圈:
Plain
系统提示词:...
工具列表:[查天气, 设提醒]
对话历史:
用户:查一下明天上海和北京的天气...
助手:[调用 check_weather(city="上海")]
工具结果:上海,明天中雨
助手:[调用 check_weather(city="北京")]
工具结果:北京,明天晴
助手:[调用 set_reminder(time="07:00", message="上海明天中雨,记得带伞")]
工具结果:提醒已设置成功LLM 读完,天气都查了,该设的提醒也设了,任务完成。决定:直接回复用户。stop_reason = "end_turn",循环结束。
看到了吗?每一圈,LLM 看到的东西都比上一圈多一点——多了自己上一轮的决策,多了工具返回的结果。它就是靠这些不断累积的文字,知道自己做到哪了、下一步该干嘛。
这就是上下文。
上下文就是 Agent 的工作记忆。没有它,LLM 每次被调用都像一个失忆的人,什么都不知道。有了它,LLM 才能在多轮循环里保持连贯的推理。
但这里有一个问题:这个列表只会越来越长。
每一圈循环都在往里塞东西——LLM 的回复、工具的结果、新的决策。四圈循环下来,对话历史已经不短了。如果是一个复杂任务,可能要跑几十圈,对话历史会膨胀到非常长。
而 LLM 能读的文字长度是有上限的,这就是上下文窗口。超过这个窗口,最早的内容就会被截掉,LLM 会忘记之前发生了什么。
任务可以无限复杂,但工作台的大小是有限的。这是 Agent 最核心的约束。
二、工具调用:LLM 怎么知道该用什么工具
上一节你看到,每次调用 LLM 时,除了对话历史,还传了一个 tools 工具列表。
这个列表长什么样?还是用天气那个例子:
Plain
工具名称:check_weather
工具描述:查询指定城市明天的天气预报
参数:
- city(字符串):城市名称,如上海、北京
工具名称:set_reminder
工具描述:设置一个定时提醒
参数:
- time(字符串):提醒时间,如 07:00
- message(字符串):提醒内容就是一段文字。名称、描述、需要什么参数——全是文字。
LLM 拿到这段描述之后,结合用户的任务,自己判断该调哪个工具、传什么参数,然后输出一段格式化的文字,比如:
Plain
调用 check_weather(city="上海")注意,LLM 自己不会执行任何东西。它输出的只是一段文字,表达了它想调用这个工具的意图。真正去执行这个工具的,是 Agent Loop 里你写的那段代码——execute_tool。
LLM 完全不知道工具背后的代码长什么样。它不知道 check_weather 是调了一个天气 API,还是爬了一个网页,还是查了一个数据库。它只看到了那段文字描述,然后做出了判断。
所以,工具对 LLM 来说就是两部分:
描述(给 LLM 看的):告诉它这个工具叫什么、干什么、需要什么参数。LLM 根据这段描述来决定要不要用、怎么用。
实现(给代码跑的):Agent Loop 拿到 LLM 的调用请求后,真正去执行的那段逻辑。这段代码和 LLM 完全无关,LLM 看不到也不需要看到。
这就引出一个关键问题:工具描述写得好不好,直接决定 LLM 会不会用对。
描述写得模糊,LLM 该调的时候不调,不该调的时候乱调。参数说明不清楚,LLM 传错参数。比如你写了一个搜索工具,描述只写了一句搜索,LLM 就搞不清楚这是搜网页、搜文件、还是搜数据库——它只能猜。
这本质上还是上一篇讲的那件事——Prompt 的问题。工具描述就是一种特殊的 Prompt,写给 LLM 看的说明书。说明书写得好,LLM 就能准确理解工具的用途和用法;写得烂,再强的 LLM 也会用错。
你看,从第一篇的 Prompt Engineering 到现在的工具描述,核心能力一直没变:把事情用文字说清楚。
三、所谓 Agent 工程,本质是上下文工程
现在我们把前面讲的东西拼在一起看。
每次调用 LLM,你塞给它的是什么?
- 系统提示词:告诉 LLM 它是谁、该遵守什么规则、用什么语气回答
- 工具描述:告诉 LLM 它有哪些工具可以用、每个工具干什么、怎么调
- 对话历史:用户说了什么、LLM 之前做了什么决策、工具返回了什么结果
全是文字。全塞在同一个上下文里,一起丢给 LLM。
LLM 的全部信息来源就是这串文字。它不会自己去看代码,不会自己去查文档,不会自己回忆上次的对话。你给它什么,它就知道什么。你没给的,它就不知道。
所以,Agent 开发者的日常工作是什么?
不是写更复杂的循环——循环就那十几行,写完就不用动了。
真正花时间的是:
系统提示词怎么写? 太短了 LLM 不知道该干嘛,太长了占用宝贵的上下文窗口。哪些规则必须放进去,哪些可以省掉,怎么组织才能让 LLM 理解得最准确——这全是讲究。
工具描述怎么写? 上一节讲过了,描述写得好不好直接影响 LLM 的工具选择和参数传递。
对话历史怎么管? 历史越来越长,窗口就那么大。哪些历史要保留,哪些可以压缩或丢弃,怎么在有限的空间里保留最关键的信息——这是最难的部分。
工具结果怎么处理? 工具返回的原始数据可能很长、很杂。要不要做清洗和摘要?直接塞进去会不会浪费上下文空间?
这些事情,归根到底都是同一件事:管理喂给 LLM 的那串文字。
什么时候注入什么信息,按什么顺序排列,什么时候该压缩,什么时候该丢弃——这就是上下文工程(Context Engineering)。
Agent 的代码骨架,你花一个小时就能写完。但上下文的设计和调优,可能要花几个月。
这也是为什么市面上那么多 Agent 框架,底层的 while 循环大同小异,但做出来的 Agent 质量天差地别。差别不在代码上,在上下文的管理水平上。
例子: 不同 IDE 上面的 Opus4.6 用起来味道就是不一样。
结语:LLM 文字交互模型
两篇文章下来,我们从 ChatGPT 的聊天说到 Prompt,从 Prompt 说到工具,从工具说到 While 循环,从循环说到上下文。
但拆到底,每一圈循环里发生的事就是:一段文字进去,一段文字出来。
LLM 不知道自己是一个 Agent,不知道有人在旁边守着帮它执行工具,不知道自己在一个循环里。它只是每次被调用的时候,读完你给它的那一大段文字,然后输出它认为最合理的下一段文字。
不管外面包了多少层——Agent、Tool、SubAgent、MCP、多 Agent 协作——最底层永远是这个。
所有的智能,都是在这个基础上,用代码和文字搭出来的。
Loop 代码就那十几行,谁都能写。真正的功夫,在于你喂给 LLM 的那串文字,组织得好不好。
这就是上下文工程——Agent 工程师的核心能力。
来源:飞书 · AI Spark 知识库 | 原文(最新版):https://lcnniolukk80.feishu.cn/wiki/R34XwSEioi73IQkBosbcJ860nAg | 归档:2026-06-04