链载Ai
标题: 我来彻底说说 AI 上下文工程(下) [打印本页]
作者: 链载Ai 时间: 昨天 22:40
标题: 我来彻底说说 AI 上下文工程(下)
在前两篇里,我们从概念与基础实践(上),聊到了 LangChain、Claude Code 等工程化案例(中)。
这篇我们会把故事收尾:
一端是 Manus 和 Kiro 代表的工程极致;
另一端,是比「上下文工程」更远一步的「环境工程」视角。
从 Manus 看「极致工程化」的上下文设计
(manus System Architecture and Workflow)
很多人第一次看到 Manus 的结构图时,第一反应都是:
这已经不是「调 prompt」,而是「围绕 KV 缓存和上下文做系统软件工程」了。
我们从 6 个关键点来拆解 Manus 的做法,这其实就是一套可借鉴的「高级上下文工程 checklist」。
1. 围绕 KV Cache 设计
把「缓存命中率」当成核心 KPI
对于复杂 Agent,一个典型 loop 是这样的:
上下文越来越长 → 输出其实很短 → 输入 token : 输出 token ≈ 100 : 1
这时候,有没有命中 KV 缓存,直接决定了成本和延迟:
Manus 的做法:
把「让前缀保持稳定」当作工程目标来设计整个系统:
1)所有状态都只追加(append-only),而不是频繁重写前面的内容。2)JSON 等结构化内容必须是「可重复序列化」的
- 避免带时间戳、随机 ID 写进 prompt。ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.034em;background-color: transparent;">
ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.034em;background-color: transparent;">3)需要「断缓存」的地方要显式标记
- 例如:上下文中插入一个特殊 marker,告诉推理引擎「从这之后不能继承 KV」。
可以直接抄的实践:
如果你现在有一个多轮 Agent:
- 把「每轮重新构造 prompt」改为「固定前缀 + 逐条 append 日志」;
- 对所有 JSON/结构化上下文,写一个“稳定序列化函数”,保证每次顺序一致。
你会立刻看到成本和延迟下降。
2. 遮蔽工具,而不是「动态删工具」
随着 Agent 越做越复杂,工具数量会爆炸。
直觉上,你可能会想:
「当前状态用不到的工具,就从 tool list 里删了吧?」
Manus 给出的结论是:不要删,用「遮蔽」代替「移除」。
为什么不能删?
1)工具列表变了,前缀就变了,KV 缓存大概率失效。
- 它可能还会「想用」,结果发现 schema 不在;
Manus 的做法:
- 工具列表是稳定的(写死在 system / tool 定义里);
- 真正的「可用性」由一个状态机 + 解码时 logits mask控制:
- 当前状态不允许用 Tool A,就在解码时把「调用 Tool A」相关 token 的概率屏蔽掉;
- 需要强制走某个工具,就给那个工具的 token 增强权重。
这背后的理念是:
「行为空间」控制放在「解码时」,而不是「上下文结构变更」上。
3. 把文件系统当成「终极上下文」
长上下文实际遇到的 3 个老问题:
- 上下文超过一定长度后,模型性能反而下降(注意力腐蚀、信息稀释);
Manus 的选择是:
把文件系统当成「上下文的一部分」,而不是单纯的“外部存储”。
- 「写文件」= 把大段内容 offload 到磁盘;
示例设计思路:
[Observation]
已爬取页面:https://example.com/a
内容已保存至:/data/pages/a.md
内容摘要:这是一篇关于上下文工程的博客,包含 A/B/C 三部分……
要点:
- 上下文里只留「引用」和「摘要」,大体量内容放文件系统。
- 文件系统本身就变成了「长期记忆 + scratchpad」,而且天然无限扩容。
4. 用「复述」操控注意力
把目标不断推到上下文末尾
Manus 的一个任务,动辄要 50 次工具调用。
这么长的交互链,很容易出现:
Manus 的手法非常简单:
不断在上下文末尾「复述任务目标 / todo 列表」。
- 这些复述会出现在最新的几条 message 里,从而被模型的注意力高权重地看到。
可借鉴的 prompt 片段:
[System 或 Tool 输出的一部分]
当前任务全局目标(请始终对齐):
1. 为用户完成 X 功能
2. 确保代码具备单元测试与基本文档
3. 最终以 README + 源码压缩包形式交付
当前未完成子任务列表:
- [ ] 完成模块 A 的接口定义
- [ ] 实现模块 A 核心逻辑
- [ ] 为模块 A 添加 3 条单测
……
这其实是在「手动操控注意力分配」:
通过把关键目标信息「挪到最近的 token 段」,对冲长上下文的「中间信息遗忘」问题。
5. 把「错误」保留在上下文里
在多步骤任务中,失败是常态而不是例外。
很多团队做 Agent 的第一反应是:
「这条调用失败了,那我就别让模型看到失败日志,重新组织一下,给它一个“干净”的上下文。」
Manus 的选择是反过来:
这实际上为模型提供了负样本 + 反事实反馈:
- 它会在内部更新「先验」:
Action2A这类行为的后验成功率变得更低;
换句话说:
「上下文」本身就成了在线 RLHF / 经验回放的一部分。
6. 刻意引入「多样性」,避免被 Few-shot「锁死」
Few-shot 是大家非常熟悉的技巧,但在 Agent 场景里,会带一个隐藏坑:
- 在遇到不适用的场景时,反而「照猫画虎」、产生幻觉或过拟合式行为。
Manus 的经验是:
适度地在「行动 / 观察」序列中加入结构化的微小变化,
例如:
目的不是制造混乱,而是:
- 放宽它的泛化空间,让它更敢于在新情况里调整策略,而不是照搬样本。
从 Vibe Coding 到 Spec-Driven
Kiro 展示的「规范驱动 + 上下文工程」
另一端的典型,是 Kiro —— 它解决的是「AI 参与软件开发」里一个更长期的问题:
不是「怎么把功能做出来」,
而是「怎么在半年、一年后,这个系统还可维护、可协作」。
1. Vibe Coding 的局限:
所谓 Vibe Coding,本质是:
Prompt → Code
「你把需求模糊地说一遍,模型帮你写大段代码。」
短期很爽,长期有几个致命问题:
1) 指望用户写出高质量 Prompt 不现实
- 更不会系统性覆盖边界条件、非功能需求(性能、安全等)。ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.034em;background-color: transparent;">
ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.034em;background-color: transparent;">2) 快速生成的代码技术债极高
- 很适合 demo,不适合长期演进。ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.034em;background-color: transparent;">
ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.034em;background-color: transparent;">3) 开发者对生成代码的理解有限
- 一旦需要手动调试 / 重构 / 扩展,就会非常痛苦;
2. Spec-Driven 的核心理念:
「先把世界说清楚,再让模型动手」
Spec-Driven Development 的基本路径是:
Spec → Design → Tasks → Code
而不是:
Prompt → Code
具体来说,至少包含三层规范:
1)需求规范(requirements.md)
- 由 LLM 初稿、人类审阅 / 修改、再由 LLM 迭代细化。
WHEN [condition/event] THE SYSTEM SHALL [expected behavior]
- 先把「系统在什么条件下,该做什么」说清楚。ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.034em;background-color: transparent;">
ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.034em;background-color: transparent;">2)设计规范(design.md)
- 架构与模块划分、接口与调用流程、数据模型 / 表结构;
ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.034em;background-color: transparent;">3)任务拆分(tasks.md)
这三层本身,就是极佳的「上下文素材」:
3. 上下文工程 + Spec-Driven:如何落地到你自己的项目?
如果你想在团队里引入这种模式,可以按下面这条路线做:
Step 1:把自然语言需求结构化
- 为 PM 或开发者提供一个「需求模板」,让他们按模板写;
- 或者提供一个「需求助手 Agent」,把杂乱描述转成「EARS 风格」的条目。
示例:
WHEN 用户在移动端点击「一键下单」
THE SYSTEM SHALL 创建一条订单记录,并在 3 秒内返回下单结果。
Step 2:让模型基于需求生成 design draft
- 修改后的 design 再作为后续所有 Agent 的「高优先级上下文」。
Step 3:自动从 design 拆出 tasks
例子:
Task: 为订单模块新增 create_order API
- 修改文件:/backend/order/api.py
- 要求:
- 接收参数:user_id, item_id, quantity
- 检查库存 & 用户有效性
- 写入数据库并返回订单号
- 添加至少 3 条单元测试用例
Step 4:Agent 执行 task 时的上下文构成
这样做的结果是:
- 上下文是可复用的(新成员 / 新任务都复用同一个 spec + design);
从「上下文工程」到「环境工程」
当我们把 Manus、Kiro 这些实践放在一起看,会发现一条共同的趋势:
以前我们在「给模型塞信息」;
现在我们在「给模型建设一个可操作的环境」。
用一个简单的对比表来概括:
1. 什么是「环境工程」?
可以理解为:
在「上下文」之上,再加一层「可感知、可操控、可演化的环境」。
环境包含的要素不只有:
还包括:
1) 可持续演化的「世界状态」
- 外部服务状态(工单系统、CI/CD 状态等)。ingFang SC", system-ui, -apple-system, BlinkMacSystemFont, "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.034em;background-color: transparent;">
在环境工程视角下:
2. 上下文工程 vs 环境工程:实现上的关键差异
你可以这样理解演进路径:
1) 上下文工程解决的是:
- 「在这一次调用里,我怎么把信息组织好,让模型少犯错?」
- 「在一个长生命周期里,
模型怎么“活着”,
怎么记住过去、影响未来、和他人协作?」
具体差异体现在:
状态持久化方式不同
- 上下文工程:更多依赖「一次调用的 context window + 一些外部存储」;
- 环境工程:世界状态(文件、数据库、任务系统)才是主角,上下文更像「观察窗口」。
控制粒度不同
- 上下文工程:控制的是「这次调用里,模型看到的 tokens」;
- 环境工程:控制的是「模型在哪些地方有读写权限、能触发哪些外部事件」。
目标函数不同
- 环境工程:看的是「长期业务指标」和「整体系统行为」。
3. 你现在就可以做的「类环境工程」实践
哪怕你暂时不搭一个完整的「环境系统」,也可以先做几件很实在的事情:
1) 把「文件系统 / 数据库」正式纳入 Agent 设计
- 明确:给 Agent 设计合理的读写 API,而不是让它随便乱写。
- 任务列表 + 状态(pending / running / done / failed);
3) Agent 可以通过工具把人类反馈变成「环境的一部分」
- 这些反馈会变成 Agent 之后决策的一部分(类似 Manus 保留错误)。
- 为高风险操作设计「两步走」流程(先 plan,再 confirm)。
上下文只是起点,环境才是终局
回到开头那句话:
上下文工程解决的是——
「怎么在一页纸之内,把信息塞好、让模型别太蠢。」
而Manus、Kiro、Claude Code这些产品已经在告诉我们:
| 欢迎光临 链载Ai (https://www.lianzai.com/) |
Powered by Discuz! X3.5 |