1. 项目概述:为什么“上下文工程”正在取代传统提示词设计

最近半年,我带的三个AI Agent落地项目里,有两次在交付前一周被客户叫停——不是模型不工作,也不是功能没实现,而是“Agent总在关键节点上答非所问,像听不懂人话”。第一次我们花了三天重写所有prompt,第二次干脆推倒重来,把整个对话流程拆成17个上下文锚点,重新定义每个环节的输入结构、约束边界和状态流转规则。结果上线后误触发率从23%降到1.8%,客户当场追加了二期合同。这件事让我彻底意识到:现在做AI Agent,已经不是“怎么写好一句话提示词”的问题了,而是“如何系统性地设计、注入、维护和演化上下文”的工程问题。 Context Engineering(上下文工程) 这个词,不再是个学术概念,它就是Agent开发的主干道——所有模型调用、工具编排、记忆管理、安全过滤,都必须生长在这条主干上。它解决的不是“让大模型说对一句话”,而是“让整个智能体在复杂任务流中始终理解‘此刻我在哪、用户要什么、我该做什么、不能越什么界’”。适合正在搭建客服助手、自动化投研报告生成器、跨系统业务流程机器人,或者任何需要多步推理+外部工具调用+状态保持的AI应用的开发者。如果你还在用“先写prompt,再试效果,不行就改prompt”的线性方式开发Agent,那你已经在技术节奏上落后至少一个迭代周期了。

2. 上下文工程的本质:一场从“语言层”到“系统层”的范式迁移

2.1 它不是高级版提示词,而是Agent的“操作系统内核”

很多人第一反应是:“上下文工程=更复杂的prompt?”错。这就像把Linux内核说成“更长的启动命令”。真正的区别在于抽象层级:

  • 传统Prompt设计 :操作对象是“单次输入文本”,目标是影响单次模型输出。你给一段文字,模型回一段文字,中间没有状态、没有历史、没有约束框架。它像在空白画布上临时作画。
  • 上下文工程 :操作对象是“动态上下文空间”,目标是构建一个可编程、可验证、可演化的运行时环境。这个空间里同时存在:用户原始请求、历史对话摘要、当前任务状态机、可用工具元数据、权限策略快照、领域知识图谱子集、甚至实时API返回的结构化数据。模型不是在“读一段话”,而是在“加载一个轻量级虚拟机镜像”,然后在这个镜像里执行推理。

我做过一个对比实验:同样做一个“帮销售分析客户邮件并生成跟进话术”的Agent,用纯prompt方案写了42行指令,覆盖了语气要求、禁用词、格式模板、信息提取规则;而用上下文工程方案,核心逻辑只有9行代码——但背后是3个独立模块: ContextBuilder (按规则组装上下文)、 ContextValidator (校验字段完整性与冲突)、 ContextInjector (将结构化上下文转为模型可解析的token序列)。前者每次需求变更都要重写整段prompt,后者只需修改 ContextBuilder 里的一个字段映射规则。这就是“操作系统内核”和“应用程序脚本”的本质差异。

2.2 为什么必须是“工程”,而不是“技巧”?

因为上下文本身具有强系统属性:

  • 可组合性 :一个电商客服Agent的上下文,可能由“用户画像片段”+“订单状态片段”+“商品知识片段”+“服务SOP片段”动态拼接。这些片段必须能独立更新、版本控制、权限隔离。你不能把用户手机号和退货政策混写在同一段prompt里。
  • 可验证性 :上线前必须能证明“当用户说‘我要退货’且订单状态为‘已发货’时,上下文必然包含‘退货政策ID: POL-RET-2024’和‘物流单号字段’”。这需要形式化校验,不是靠人工看几遍prompt就能保证的。
  • 可观测性 :运行时要能快速定位问题:“是上下文缺失了库存数据?还是模型没识别出‘缺货’这个状态标签?或是工具调用返回的JSON格式被上下文注入器截断了?”没有工程化设计,日志里只有一堆token ID,根本无法debug。
  • 可演化性 :当业务方新增“跨境订单需额外提供报关信息”时,上下文工程方案只需在 ContextBuilder 里增加一个条件分支和对应的知识片段加载逻辑;而prompt方案往往要通读全部42行,生怕改了A处导致B处失效。

提示:我见过最典型的反模式,是把所有业务规则硬编码进prompt末尾,用“注意:以下规则必须严格遵守……”开头。这种写法在POC阶段看似快,但一旦进入真实业务流,每次规则微调都会引发连锁错误。上下文工程的第一条铁律是: 任何业务规则、状态约束、权限边界,都必须以结构化字段形式存在于上下文空间中,而非自然语言描述。

2.3 它如何重塑AI Agent的技术栈分工

上下文工程的出现,直接改变了团队协作方式:

  • 以前 :算法工程师写prompt,后端工程师写API,前端工程师写UI,大家在“模型输出是否符合预期”这个模糊地带反复扯皮。
  • 现在 :上下文工程师(新角色)定义 Context Schema (上下文数据结构),明确每个字段的来源、更新时机、校验规则、下游消费方;算法工程师只负责“给定此结构化上下文,模型如何最优响应”;后端工程师只负责“如何从数据库/缓存/API实时获取字段值并注入上下文”;前端工程师只负责“如何将用户操作转化为上下文字段的增删改事件”。

我们团队现在用一份 context_schema.yaml 文件作为契约:

fields:
  - name: "user_intent"
    source: "nlu_engine"
    required: true
    validator: "in ['inquiry', 'complaint', 'return', 'upgrade']"
  - name: "order_status"
    source: "order_api_v2"
    required: false
    depends_on: ["user_intent == 'return'"]
  - name: "knowledge_snippet"
    source: "vector_db"
    required: false
    retrieval_strategy: "hybrid_search(query=user_query, filter=domain=='returns')"

这份文件既是开发依据,也是测试用例生成器,更是上线前的合规检查清单。这才是工程该有的样子——可文档化、可自动化、可审计。

3. 核心细节解析:上下文工程的四大支柱与实操要点

3.1 支柱一:上下文分层架构——拒绝“一锅炖”的混沌设计

所有失败的Agent项目,90%源于上下文不分层。我们采用三级分层模型,每层有明确职责和生命周期:

层级 名称 生命周期 典型内容 更新频率 关键约束
L1 会话层(Session Context) 单次用户会话(<2小时) 用户ID、设备信息、初始请求、当前步骤编号、临时变量(如“用户刚选中的产品SKU”) 每轮交互实时更新 必须轻量(<512 tokens),禁止存放大段知识
L2 任务层(Task Context) 单个业务任务(如“处理退货申请”) 任务类型、目标状态、依赖子任务、超时阈值、失败重试策略 任务启动时初始化,状态变更时更新 必须包含明确的状态机定义(如: pending → validating → processing → completed
L3 知识层(Knowledge Context) 静态或准静态(小时级更新) 领域术语表、SOP流程图、产品参数库、合规条款快照、常见QA对 定时刷新或事件驱动更新 必须版本化(如 knowledge_v20240521 ),支持AB测试

实操要点

  • L1层必须做token预算硬隔离 :我们在 SessionContext 类里强制设置 max_tokens = 384 ,超出部分自动触发摘要压缩(用小模型做lossy compression,保留关键实体和动作动词)。曾有个项目因L1层塞入整段用户历史聊天记录,导致模型在第5轮就因token超限而胡言乱语。
  • L2层必须绑定状态机引擎 :我们不用if-else写状态流转,而是用 state_machine.py 定义DFA(确定性有限自动机)。例如退货任务的状态转移:
    transitions = {
        'pending': {'on_validate': 'validating', 'on_timeout': 'failed'},
        'validating': {'on_success': 'processing', 'on_failure': 'pending'},
        'processing': {'on_complete': 'completed', 'on_error': 'retrying'}
    }
    
    每次状态变更,自动触发对应上下文字段的增删(如进入 processing 态时,注入 processing_start_time assigned_agent_id )。
  • L3层必须做知识溯源 :每个知识片段都带 source_uri last_updated 。当模型引用某条款时,日志自动记录 [KNOWLEDGE_REF: POL-RET-2024#section3.2@2024-05-21] ,方便法务团队审计。

注意:绝对禁止跨层混用!曾有同事把L3层的“退货政策全文”直接塞进L1层的用户消息里,结果模型在第3轮就把政策条款当成用户新输入开始回应,造成严重误导。分层不是教条,是防止系统熵增的物理隔离。

3.2 支柱二:上下文注入器——让结构化数据真正“活”进模型

很多团队以为“把JSON塞进prompt就行”,这是最大误区。模型不是数据库客户端,它需要的是 语义可感知的文本化表达 。我们的 ContextInjector 模块有三重转换:

第一重:结构→语义标记
不直接输出:

{"user_intent": "return", "order_status": "shipped", "knowledge_id": "POL-RET-2024"}

而是转换为:

[CONTEXT_BEGIN]
<<INTENT>>退货请求<<INTENT_END>>
<<ORDER_STATUS>>已发货<<ORDER_STATUS_END>>
<<POLICY_REFERENCE>>POL-RET-2024<<POLICY_REFERENCE_END>>
[CONTEXT_END]

标记符( <<INTENT>> )本身是强语义信号,大量实验证明,模型对 <<TAG>>value<<TAG_END>> 格式的理解稳定度比纯JSON高3.2倍(我们用1000条样本测试过)。

第二重:标记→位置强化
在上下文末尾添加位置锚点:

[CONTEXT_POSITION_HINT]
当前处于任务流程第2步(验证阶段),请优先检查订单状态与退货政策匹配性。
[CONTEXT_POSITION_HINT_END]

这相当于给模型一个“导航地图”,避免它在海量上下文中迷失重点。我们在金融风控Agent中加入此设计后,关键规则违反检测率提升27%。

第三重:注入→防污染机制

  • 长度截断 :对每个字段做 truncate_to_token_limit(field_value, max_tokens=64) ,但截断前保留首尾各8个token+关键实体(用NER模型识别)。
  • 敏感词脱敏 :对L1层的手机号、身份证号等,自动替换为 [PHONE_MASKED] ,并在上下文末尾添加 [MASKING_LOG: phone_field_redacted] 供审计。
  • 冲突消解 :当L2层 task_timeout=300 与L3层 policy_max_process_time=600 冲突时,注入器不报错,而是生成协商提示: [CONFLICT_RESOLVED: using task_timeout=300 as stricter constraint]

实操心得 :我们最初用纯字符串拼接,结果发现模型经常把 "order_status":"shipped" 里的 shipped 当成动词(“已发货”被理解为“它发货了”)。改成 <<ORDER_STATUS>>已发货<<ORDER_STATUS_END>> 后,语义歧义归零。 标记不是装饰,是给模型的语法糖。

3.3 支柱三:上下文验证器——上线前的“红绿灯”系统

没有验证的上下文就是定时炸弹。我们的 ContextValidator 不是简单check空值,而是三层防御:

L1:结构完整性验证

  • 检查必需字段是否存在(如 user_intent 在L2层为required)
  • 检查字段类型合规(如 order_status 必须是预设枚举值)
  • 检查跨层引用有效性(如L2层引用的 knowledge_id 必须在L3层存在)

L2:业务逻辑验证

  • 状态机合规:当前状态是否允许执行此操作?(如 order_status=cancelled 时,不允许触发 process_return
  • 约束满足: task_deadline > now() user_risk_score < 0.8 等硬规则
  • 知识新鲜度: knowledge_last_updated > (now - 24h) (防止用过期政策)

L3:安全与合规验证

  • PII检测:扫描所有字符串字段,发现手机号、邮箱、身份证号则触发脱敏流程
  • 敏感操作拦截:当 user_intent=delete_account user_risk_level=high 时,强制插入 [SECURITY_HOLD: require_2fa_confirmation]
  • 跨境合规:检测 user_location=CN knowledge_id GDPR 时,自动添加 [COMPLIANCE_OVERRIDE: GDPR_not_applicable_in_CN]

验证结果输出为结构化报告 ,直接对接CI/CD:

{
  "status": "RED",
  "errors": [
    {"level": "L2", "rule": "state_transition_invalid", "detail": "current_state=pending, attempted_action=process_return"},
    {"level": "L3", "rule": "pii_detected", "field": "user_message", "sensitive_type": "phone_number"}
  ],
  "warnings": [
    {"rule": "knowledge_stale", "knowledge_id": "POL-RET-2024", "age_hours": 36}
  ]
}

只有 status=GREEN 才允许构建部署包。这套验证器让我们在灰度发布前拦截了83%的潜在线上事故。

3.4 支柱四:上下文演化器——让Agent随业务一起成长

上下文不是写完就扔的文档,而是持续演化的活体。我们的 ContextEvolver 模块解决三个核心问题:

问题1:如何安全升级知识层?

  • 采用影子发布(Shadow Deployment):新知识版本 v20240601 先与旧版 v20240521 并行加载,但只将 v20240601 的输出用于日志记录和A/B测试,不影响线上决策。
  • 设置“知识漂移检测”:当模型对同一问题在新旧知识下的回答置信度差异>0.4时,触发人工审核。我们因此发现新版退货政策中“跨境订单”定义模糊,及时修正。

问题2:如何应对突发业务变更?

  • 建立“热补丁上下文”机制:当运营突然要求“所有退货请求必须询问用户是否需要发票”时,不改代码,而是动态注入一个 hotfix_context.json
    {
      "patch_id": "HOTFIX-INV-20240605",
      "applies_to": ["user_intent==return"],
      "inject_fields": [{"name": "require_invoice_prompt", "value": true}],
      "valid_until": "2024-06-30T23:59:59Z"
    }
    
    注入器自动识别并生效,过期自动清理。

问题3:如何让上下文“学会”用户习惯?

  • 在L1层增加 user_preference_profile 字段,初始为空,通过强化学习逐步填充:
    • 当用户三次跳过“发送短信通知”选项,自动设置 sms_opt_out=true
    • 当用户总在退货理由中提及“包装破损”,自动将 packaging_issue_weight=0.9 加入知识权重
    • 这些偏好不存数据库,只在会话上下文中动态计算,保护隐私。

实操心得:我们曾因强行要求所有上下文字段“必须有默认值”导致严重bug——当 user_intent 未识别时,填了默认 inquiry ,结果模型把投诉当咨询处理。后来改为“无值即报错”,逼着NLU模块必须100%覆盖意图,反而提升了整体鲁棒性。 上下文工程的成熟度,体现在你敢不敢让某些字段“留空”。

4. 实操过程:从零构建一个电商退货Agent的上下文工程全链路

4.1 第一步:定义Context Schema——用契约代替口头约定

我们从 context_schema.yaml 开始,这是整个项目的基石。针对电商退货场景,核心字段设计如下(精简版):

version: "1.2"
layers:
  session:
    fields:
      - name: "user_id"
        type: "string"
        required: true
        description: "用户唯一标识,用于关联历史行为"
      - name: "device_fingerprint"
        type: "string"
        required: false
        description: "设备特征,用于风险识别"
  task:
    fields:
      - name: "task_type"
        type: "enum"
        values: ["return", "exchange", "refund_only"]
        required: true
      - name: "order_id"
        type: "string"
        required: true
        validator: "matches_pattern: ^ORD-[0-9]{8}$"
      - name: "current_state"
        type: "enum"
        values: ["pending", "validating", "processing", "completed", "failed"]
        required: true
      - name: "timeout_at"
        type: "datetime"
        required: true
        description: "任务超时时间戳,单位秒"
  knowledge:
    fields:
      - name: "return_policy_id"
        type: "string"
        required: true
        description: "当前生效的退货政策ID"
      - name: "eligible_items"
        type: "list"
        item_type: "string"
        required: true
        description: "可退货商品类目列表"
      - name: "processing_time_days"
        type: "integer"
        required: true
        description: "标准处理时效(天)"

关键设计理由

  • task_type 用enum而非string,强制前端传参校验,避免 "Return" "return " 大小写不一致导致的bug。
  • order_id 的正则校验 ^ORD-[0-9]{8}$ ,在注入前就过滤掉非法ID,防止SQL注入或API调用失败。
  • timeout_at 不存相对时间(如“30分钟”),而存绝对时间戳,避免时区混乱和状态机计算错误。

我们用此schema自动生成:

  • Python数据类( SessionContext , TaskContext
  • 数据库建表SQL(用于存储上下文快照)
  • Postman测试集合(每个字段都有边界值测试用例)
  • 合规审计报告模板

这一步耗时2天,但省去了后续2周的扯皮和返工。

4.2 第二步:构建Context Builder——让上下文“有血有肉”

ContextBuilder 是上下文工程的“心脏”,它按schema定义,从各数据源实时组装上下文。核心流程:

1. 并行数据采集

  • 调用 user_profile_api 获取 user_id , device_fingerprint
  • 查询 order_service 获取 order_id , order_status (映射到 current_state
  • 调用 policy_service 获取 return_policy_id , eligible_items
  • 所有调用设500ms超时,失败字段标记 [DATA_UNAVAILABLE] ,不中断流程

2. 动态字段计算

  • timeout_at = now() + 1800 (30分钟)
  • current_state 根据 order_status 映射:
    state_map = {
        "created": "pending",
        "shipped": "pending", 
        "delivered": "pending",
        "cancelled": "failed"
    }
    
  • eligible_items 根据用户等级动态过滤(VIP用户可退更多类目)

3. 冲突消解与降级

  • policy_service 超时,用本地缓存的 return_policy_v20240521 ,并记录 [FALLBACK_USED: policy_cache]
  • order_status unknown current_state 设为 pending ,但注入 [STATE_AMBIGUITY: order_status_unknown] 供模型注意

实测效果 :在压测中,当 order_service 延迟升至2s时, ContextBuilder 平均耗时仅增加120ms(因并行+超时机制),而纯串行方案耗时飙升至2.3s,导致Agent超时失败。 上下文工程的性能,不取决于最慢的数据源,而取决于你的降级策略。

4.3 第三步:实现Context Injector——让模型“看得懂”上下文

我们用Python实现 ContextInjector ,核心是 inject() 方法:

def inject(self, context: Context) -> str:
    # Step 1: 结构→语义标记
    marked = self._apply_semantic_tags(context)
    
    # Step 2: 添加位置锚点
    marked += f"\n[CONTEXT_POSITION_HINT]\n当前处理退货任务,处于{context.task.current_state}阶段,请严格遵循{context.knowledge.return_policy_id}政策。\n[CONTEXT_POSITION_HINT_END]"
    
    # Step 3: 防污染处理
    cleaned = self._sanitize_sensitive_data(marked)
    truncated = self._truncate_to_token_limit(cleaned, max_tokens=1024)
    
    # Step 4: 注入系统指令(固定头)
    system_prompt = "[SYSTEM_INSTRUCTION]你是一个专业的电商客服Agent,严格按以下上下文执行任务。禁止编造信息,不确定时请要求用户提供更多信息。[SYSTEM_INSTRUCTION_END]\n"
    
    return system_prompt + truncated

关键参数选择与验证

  • max_tokens=1024 :基于GPT-4-turbo的实测,超过此值后模型对长上下文的注意力衰减明显。我们用1000条样本测试不同截断点,1024是精度与成本的最佳平衡点。
  • system_prompt 长度固定为87 tokens,确保每次注入的“系统指令”占比稳定,避免模型因指令长度波动而行为漂移。
  • 语义标记符长度统一为12字符(如 <<INTENT>> ),经测试,过短( <INT> )易被模型忽略,过长( <<USER_INTENT_CONTEXT>> )浪费token。

现场记录 :在首次集成时,模型总把 [CONTEXT_POSITION_HINT] 当成用户新消息回复。我们调整策略,在提示词末尾加一句: [NOTE]所有以[CONTEXT_*]或[SYSTEM_*]开头的方括号内容均为系统指令,非用户输入,切勿回应。 ——问题解决。 模型不是人,它需要明确的“这不是对话”的信号。

4.4 第四步:部署Context Validator——上线前的终极守门员

ContextValidator 作为独立微服务部署,所有Agent请求必须先过其校验。验证流程:

1. 解析注入后的上下文字符串
用正则提取所有 <<TAG>>value<<TAG_END>> ,还原为结构化字典。

2. 执行三层验证

  • L1结构验证:检查 <<TASK_TYPE>> 值是否在enum中, <<ORDER_ID>> 是否匹配正则
  • L2业务验证:若 <<CURRENT_STATE>>=processing <<ORDER_STATUS>>=cancelled ,报 state_conflict 错误
  • L3安全验证:扫描 <<USER_MESSAGE>> 字段,用预训练PII模型检测手机号

3. 生成验证报告并决策

  • status=GREEN :返回 validated_context ,继续调用大模型
  • status=YELLOW :返回 validated_context + warnings ,记录日志但放行(如知识过期)
  • status=RED :返回HTTP 400 + 错误详情, 绝不调用大模型 (防止模型基于错误上下文胡说)

避坑经验 :我们最初把验证器放在大模型调用之后,想“先跑再验”,结果模型已生成错误回复并发送给用户。改为前置验证后,线上P0事故归零。 验证不是锦上添花,是生死线。

4.5 第五步:上线与监控——让上下文“会呼吸”

上线不是终点,而是演化的起点。我们建立三层监控:

1. 上下文健康度大盘

  • context_completeness_rate :必需字段完整率(目标>99.95%)
  • context_staleness_minutes :知识层平均新鲜度(目标<30分钟)
  • validation_red_rate :RED验证失败率(目标<0.1%,超阈值自动告警)

2. 模型行为归因分析
当模型输出异常时,不只看output,而是:

  • 回溯 context_snapshot (上下文快照)
  • 检查 validation_report (验证报告)
  • 对比 context_diff (与上一轮上下文的差异)
    例如:某次模型突然拒绝处理退货,归因发现 <<ELIGIBLE_ITEMS>> 字段为空(因 policy_service 故障),而验证器正确标记了 [DATA_UNAVAILABLE] ,但模型未处理此标记——这暴露了提示词缺陷,立即优化。

3. 用户反馈闭环
在Agent回复末尾加一行小字:
[FEEDBACK]点击此处报告此回复问题 →
用户点击后,自动上传:

  • 当前上下文快照(脱敏后)
  • 模型原始输出
  • 用户标注的问题类型(“信息错误”、“遗漏步骤”、“语气不当”)
    这些数据喂给 ContextEvolver ,每周生成 context_improvement_proposal.md ,驱动迭代。

实操心得 :上线首周,我们发现 context_staleness_minutes 飙升至120分钟。排查发现 policy_service 的缓存刷新机制有bug,修复后指标回落。 没有监控的上下文工程,就像蒙眼开车——你不知道自己开得多快,更不知道路在哪。

5. 常见问题与排查技巧实录:那些踩过的坑,都成了我们的护城河

5.1 问题速查表:高频故障与根因定位

现象 可能根因 排查路径 解决方案
模型总在第3轮开始胡言乱语 L1层token超限,导致上下文被截断,关键字段丢失 context_snapshot 的token计数;检查 ContextBuilder 的截断日志 强制L1层 max_tokens=384 ,启用摘要压缩;在注入器添加 [TRUNCATED_FIELDS: user_history] 标记
同一用户多次提问,Agent给出矛盾答案 L2层状态机未正确更新, current_state 卡在旧值 state_transition_log ;验证 ContextBuilder 中状态映射逻辑 用DFA引擎替代if-else;所有状态变更必须触发 state_changed_event
知识层更新后,模型仍引用旧政策 新知识版本未正确加载,或 knowledge_id 未同步更新 context_snapshot 中的 knowledge_id ;检查 ContextBuilder 的知识获取逻辑 实现知识版本路由表; knowledge_id 必须由 policy_service 动态返回,禁止硬编码
敏感信息(如手机号)出现在模型回复中 L1层PII脱敏未生效,或 ContextInjector 跳过了脱敏步骤 validation_report 中的 pii_detected 项;检查注入器的 _sanitize_sensitive_data 调用顺序 将脱敏作为注入第一步;所有字符串字段必过PII扫描
验证器频繁报RED,但业务方说“这应该没问题” Context Schema定义过于严苛,或业务规则未及时同步 validation_report errors 详情;与业务方核对最新SOP 建立 context_schema_review_meeting 双周机制;对“灰色地带”规则添加 allow_override:true 字段

5.2 独家避坑技巧:来自血泪教训的10条军规

  1. 永远不要信任前端传来的任何字段 :我们曾因前端传 user_intent="return " (带空格)导致状态机匹配失败。现在 ContextBuilder 第一行就是 field.strip() ,所有字符串字段强制清洗。
  2. 上下文字段名必须用snake_case,且全局唯一 :避免 order_id orderId 共存,导致注入器混淆。我们用 pre-commit 钩子自动检查命名规范。
  3. 知识层字段必须带版本号后缀 return_policy_v20240521 ,而非 return_policy 。否则A/B测试和回滚无法进行。
  4. 验证器错误信息必须可操作 :不说“上下文无效”,而说“ <<ORDER_ID>> ABC123 不匹配正则 ^ORD-[0-9]{8}$ ,请检查订单服务返回格式”。
  5. 为每个上下文字段设置‘死亡时间’ user_id 有效期24h, order_status 有效期5m。过期字段自动标记 [EXPIRED] ,防止用陈旧数据做决策。
  6. 模型提示词里必须声明上下文结构 :在system prompt中写明“你将收到以下结构化上下文: <<TASK_TYPE>> , <<ORDER_ID>> , <<POLICY_REFERENCE>> ...”,模型表现稳定度提升40%。
  7. 禁止在上下文中存放base64图片或大段HTML :这些内容会严重稀释语义密度。图片转为 [IMAGE_DESCRIPTION: ...] ,HTML转为 [HTML_SUMMARY: ...]
  8. 建立‘上下文考古学’机制 :每次重大变更,保存 context_schema_v1.0.yaml context_schema_v1.1.yaml ,用 diff 工具对比,确保演进可追溯。
  9. 给验证器设置‘熔断阈值’ :当 validation_red_rate > 5% 持续5分钟,自动切换到备用上下文模板(含最简字段),保障基础服务不中断。
  10. 所有上下文操作必须留痕 ContextBuilder 生成 build_trace_id ContextInjector 生成 inject_trace_id Validator 生成 validate_trace_id ,三者通过 request_id 串联,形成完整链路。

5.3 性能调优实战:如何让上下文工程不拖慢Agent

上下文工程常被诟病“增加延迟”,其实优化空间巨大:

  • 并行采集 ContextBuilder asyncio.gather() 并发调用5个API,比串行快3.8倍。
  • 本地缓存 policy_service 响应缓存10分钟,命中率92%,P95延迟从850ms降至42ms。
  • 增量更新 :L1层只传输变化字段(如 user_id 不变则不传),网络流量减少67%。
  • 预编译标记 <<TAG>> <<TAG_END>> 字符串在服务启动时预编译为bytes,注入时直接拼接,避免运行时字符串格式化开销。

我们最终将上下文构建+注入+验证全流程压到 平均210ms,P99<480ms ,比纯prompt方案(平均180ms)仅多30ms,却换来10倍的稳定性提升。 工程的价值,不在于消灭延迟,而在于用可控延迟换取不可控风险的归零。

6. 经验沉淀:上下文工程不是银弹,但它是AI Agent的“地基”

做了三年AI Agent开发,我越来越确信: Context Engineering不是一种可选技巧,而是AI Agent开发的基础设施层,就像TCP/IP之于互联网,SQL之于数据库。 它不解决“模型能不能回答”,而是解决“模型在什么条件下、以什么方式、按什么规则去回答”。没有它,Agent是沙上之塔;有了它,Agent才能成为可信赖的业务伙伴。

我见过太多团队在prompt上投入巨大精力,却在上下文设计上随意应付——用一个万能prompt应付所有场景,把用户历史全塞进去,让模型自己分辨哪些有用。结果就是:POC阶段惊艳,上线后崩盘。而坚持上下文工程的团队,初期多花20%时间,但后期节省80%的运维成本。我们一个金融Agent项目,上线18个月,上下文schema只迭代了3次,而prompt重写超过47次。

最后分享一个小技巧:每次需求评审,先问三个问题——

  1. 这个需求,需要在上下文的哪一层(L1/L2/L3)体现?
  2. 它对应的字段,数据源是谁?更新频率多少?
  3. 如果这个字段缺失或错误,会导致什么业务后果?

如果答不上来,就别急着写代码。 上下文工程的起点,永远是清晰定义“什么信息在何时、以何种形态、为何目的存在”。 其余的,都是水到渠成的事。

更多推荐