目录

每天学习一个Agent - Context Engineering Foundation

Prompt

一个简单高效的Prompt应该有三部分组成:任务描述、限制与约束、输出格式

1
ATOMIC PROMPT = [TASK] + [CONSTRAINTS] + [OUTPUT FORMAT] 

比如:Write a poem about the ocean using only words with 5 letters or less in 4 lines

  • 任务[TASK]: Write a poem about the ocean
  • 限制[CONSTRAINTS]: using only words with 5 letters
  • 输出格式[OUTPUT FORMAT]: in 4 lines

+Examples

增加示例构建最简单的Few-Shot,让LLM完成 ICL(In-Context Learning),但是增加几个示例,怎么选择示例才能获得最好的收益,这个就是上下文工程要解决的问题了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
┌───────────────────────────────────────┬─────────────────────────────────────┐
│ Prompt                                │ Prompt + Examples                   │
├───────────────────────────────────────┼─────────────────────────────────────┤
│ "Classify this review as positive     │ "Classify the sentiment of reviews.  │
│  or negative:                         │                                      │
│                                       │ Review: 'The food was amazing!'      │
│  'The service was terrible and        │ Sentiment: Positive                  │
│   the food was cold.'"                │                                      │
│                                       │ Review: 'Waited 30 minutes and       │
│                                       │  the food was cold.'                 │
│                                       │ Sentiment: Negative                  │
│                                       │                                      │
│                                       │ Review: 'The service was terrible    │
│                                       │  and the food was cold.'"            │
│                                       │ Sentiment:                           │
└───────────────────────────────────────┴─────────────────────────────────────┘

示例格式

可以以不同的格式Pattern增加示例,几种常用的格式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
┌─────────────────────────┐  ┌───────────────────┐  ┌───────────────────┐
│ PREFIX-SUFFIX           │  │ INPUT-OUTPUT PAIRS│  │ CHAIN-OF-THOUGHT  │
├─────────────────────────┤  ├───────────────────┤  ├───────────────────┤
│ <instruction>           │  │ <instruction>     │  │ <instruction>     │
│                         │  │                   │  │                   │
│ <example1> → <result1>  │  │ Input: <example1> │  │ Input: <example1> │
│                         │  │ Output: <result1> │  │ Thinking: <step1> │
│ <example2> → <result2>  │  │                   │  │           <step2> │
│                         │  │ Input: <example2> │  │ Output: <result1> │
│ <new_input> →           │  │ Output: <result2> │  │                   │
└─────────────────────────┘  │                   │  │ Input: <example2> │
                             │ Input: <new_input>│  │ Thinking: <step1> │
                             │ Output:           │  │           <step2> │
                             └───────────────────┘  │ Output: <result2> │
                                                    │                   │
                                                    │ Input: <new_input>│
                                                    │ Thinking:         │
                                                    └───────────────────┘
  • 前缀-后缀:最简单,适用于简单任务
  • 输入输出对:界限清楚,适用于结构化数据
  • COT:包含推理步骤,适用于复杂任务

示例数量

当然示例的个数不是越多越好,$Accuracy= f(num_examplar)$ 总体曲线类似于对数函数,随着示例数量的增加收益递减,一般的示例个数建议:

任务类型 示例个数
分类 1-3个/每种类型
生成 2-5
结构化参数提取 2-4(覆盖所有字段)
推理 2-3(包含思考过程)
翻译 3-5(不同复杂程度)

示例可以存储到数据库中,根据用户输入召回相似度最高的几个示例填充到上下文中,如可以存储到向量数据库中,直接根据Embedding语义召回,或者存储到结构化数据库中,根据标签分类召回

示例选择组装的几个注意点:

  • 示例的格式跟效果是有关系的,可以根据不同任务选择不同的示例展现格式
  • 示例的选择比较重要,要保障示例的多样性、边缘场景等,示例的顺序也会影响最终结果
  • 示例的个数增加获得收益递减,考虑成本、效果与上下文长度,要选择合理的示例个数

+Memory/State

没有记忆与状态,与LLM的对话就会不连续,体验不好

最简单的方式是把之前的对话记录直接全部加到对话上下文中,但是随着对话历史增加,上下文超长,怎么获取最佳的性价比,就又来到了上下文工程的领域

记忆管理策略

一般我们可能有这样一些策略:

策略 说明
滑动窗口 保留最近N次对话
总结 保留最近几次对话,压缩/总结更早之前对话历史
KV存储 提取对话记录里的关键事实信息KV存储(如"username”: “Alex”),后续对话直接填充提取后的KV关键事实
优先级裁剪 根据对话历史的重要性丢弃
语义分块 将对话根据主题分组,后续根据主题选择填充

除了对话历史,在对话过程还有一些流程状态或者变量 State,比如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
┌─────────────────────────────────────────────────────────────────────┐
│ STATEFUL CALCULATOR                                                 │
│                                                                     │
│ SYSTEM: "You are a calculator assistant that maintains a running    │
│          total. Follow the user's math operations step by step."    │
│                                                                     │
│ STATE: { "current_value": 0 }                                       │
│                                                                     │
│ User: "Start with 5"                                                │
│ Assistant: "Starting with 5. Current value is 5."                   │
│ STATE: { "current_value": 5 }                                       │
│                                                                     │
│ User: "Multiply by 3"                                               │
│ Assistant: "5 × 3 = 15. Current value is 15."                       │
│ STATE: { "current_value": 15 }                                      │
│                                                                     │
│ User: "Add 7"                                                       │
│ Assistant: "15 + 7 = 22. Current value is 22."                      │
│ STATE: { "current_value": 22 }                                      │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

记忆类型与流转

上面说的都是短期记忆,对于需要长期存储的内容,可以放到外部存储中存储,比如在对话信息中提取的关键信息,领域的知识信息等,几种常见的记忆:

  • Short-term Memory/瞬时记忆
    • 最近几轮的对话
    • 刚刚收到的指令
  • Working Memory/工作记忆
    • 当前的任务
    • 当前任务用的变量State
    • 任务的进展
    • 任务的中间变量
  • Long-term Memory/长期记忆
    • 用户画像
    • 历史对话事实
    • 对话偏好

这些记忆的管理需要一个记忆管理器,记忆管理器不光负责记忆的存储和召回,还需要管理信息在各层之间流转,升级、降级、淘汰等生命周期管理

Multi-Agent

受限于上下文窗口大小限制、并行处理、多视角分析限制等问题,引入多Agent系统,多Agent系统有专业化、并行化、编排协同等特点,多Agent如何设计协同共享也作为上下文工程的一个关键部分

多Agent系统几个关键组件

  • 编排器Orchestrator:协同多个Agents,管理工作流,一个编排器可以基于规则或者使用LLM实现,主要负责:
    • 任务分解
    • Agent选择与编排
    • 信息路由
    • 冲突仲裁解决
    • 任务进展监控
    • 合并输出
  • 共享内存Shared Memory:各个Agent都可以访问使用的公共信息
    • 工作内存:当前任务状态和中间结果
    • 知识库:事实,检索信息
    • 流程日志:推理与执行的过程记录
    • 输出Buffer:存储输出结果,合成最终结果
  • 多专家Agents:根据场景定义的多个不同专业的Agents

多Agent系统几种常见的控制流

模式 核心动作 适用场景
SEQUENTIAL
串行流水线
Cell₁→Cell₂→Cell₃ 单向流动 步骤有先后依赖,比如“先检索→再总结→最后润色”
PARALLEL
并行 Map-Reduce
Split→N 个 Cell 同时跑→Merge 汇总 子任务互不依赖,比如“同时翻译 10 段文本”
FEEDBACK LOOP
反馈闭环
Cell→Cell→…→把输出再送回前面重跑 需要迭代优化,比如“写代码→跑测试→修 bug→再测试”
HIERARCHICAL
层级指挥
Boss Cell 指挥多个 Team Lead,每个 Lead 再管一批 Cell 任务本身有层级,比如“项目经理拆需求→各组开发→集成”

几个影响多Agent性能的关键要素:

  • 专业清晰度:每一个Agent的特长专业角色是否清晰定义
  • 记忆管理:高效存储和召回信息
  • 编排逻辑:协调系统是否高效
  • 错误处理:Agent错误输出的鲁棒性
  • 反馈机制:能够从结果中学习提升
  • 任务分解:问题分解成子任务的效果

多Agent系统的一些评估指标与及格线

指标 及格线 白话解释 不达标时常见症状
End-to-end Accuracy >90% 全流程最终答案正确率 低于 90% → 需要回炉重排上下文或加纠错 Agent
Total Token Usage <50% 对比单一大 prompt 比“一口气塞全部”省一半以上 token 超标 → 检索/摘要策略太粗,Context Builder 没剪干净
Latency (per step) <5 s 每一步(Agent)推理耗时 超时 → 该 Agent的 prompt 过长或模型本身慢
Error Recovery Rate >80% 出错了能在下一轮自己修好的比例 太低 → 缺少 Feedback Loop 或记忆回写机制
Context Window Utilization >70% 实际用掉的窗口占可用窗口的比例 过低 → 信息没充分利用;过高 → 临近溢出风险

多Agent系统相比于单Agent优势

  • 处理大于单个上下文长度的问题:把 100 万字拆成 200 份,每份 4K,仍能拼出全局结论
  • 通过专门的验证Agent自我纠正:安排“校对Agent”专门挑错,发现 bug 就回炉
  • 超越单个Agent的复杂多步推理能力:原来一次只能解 3 步方程,现在 30 步也能链式推理
  • 处理过程可以适应新信息加入:任务跑一半用户甩来新 PDF,Agent能热插拔更新
  • 多视角更平衡的分析:让“乐观/悲观/法律/财务”四种Agent各写一份,再汇总
  • 抵御单Agent故障的韧性:某个Agent崩溃或幻觉,其他Agent投票把它踢掉
  • 领域专业化:给不同Agent喂医学/法律/代码语料,它们自动成为单领域专家

多Agent系统面临的一些挑战

挑战 一句话场景 速修方案
Error Propagation
错误级联
第 1 个Agent把“2024”写成“2042”,后面所有Agent全跟着错。 给每步加验证Agent+回滚机制;错就立即重算。
Coordination Overhead
协调延迟
等 5 个Agent串行投票,用户已经刷新页面。 把串行改并行 Map-Reduce;关键路径拆最细。
Information Bottlenecks
信息漏斗
100 页报告被第 1 个Agent压缩成 3 句话,关键数字丢了。 摘要+原始片段双通道;只丢噪音不丢金子。
Debugging Difficulty
难调试
系统突然胡说八道,却不知道是哪个Agent出的错。 给每个Agent打日志 trace-id;一键回放历史上下文。
Cost Scaling
成本爆炸
一个任务 20 个Agent × 4k token ≈ 80k token,钱包直接报警。 动态裁剪+缓存重复计算;只让必要Agent跑必要 token。
System Design Complexity
复杂到秃头
流程图 30 个框,上线后天天改配置。 声明式 YAML描述系统,单元测试跑 100 个 mock case 再上线。

多Agent系统开发最佳实践

最佳实践 一句话落地 常见踩坑
Start Simple
先简单
MVP 只跑 1-2 个 Agent,验证能跑通再加功能 一上来就 20 个Agent,3 天后调试崩溃
Measure Cell Performance
单测Agent
每个 Agent独立跑 100 条样本,看准确率 & token 消耗 整体指标 OK,拆开后发现某个 Agent 只有 60% 正确率
Explicit Contracts
接口契约
用 JSON Schema / Pydantic 写明输入输出,谁改字段 CI 立刻报警 口头约定“大概是个字符串”,上线后互相甩锅
Comprehensive Logging
全程日志
每步输入、输出、耗时、异常全落盘,带 trace-id 可追踪 出错后只能“玄学重启”
Fault Tolerance
容灾设计
Agent遇到脏数据返回默认值 + 错误码,不直接崩溃 一个空字符串让整条链雪崩
Verification Cells
质检Agent
每个关键步骤后加“验证Agent”,发现错误立即重试或报警 把希望寄托在“下游会修”
Progressive Enhancement
渐进增强
先把主链路跑通,再逐步加缓存、并行、重试 一次性上线 5 个优化,出错不知砍哪个
Parallel When Possible
并行优先
用 Map-Reduce 跑独立子任务,减少串行等待 明明可并行却串行,用户等 30 秒