轻量级 Agent 架构实战:Prompt 上下文与 Tool Function 的工程边界隔离

发布时间:2026/8/10 4:36:24
轻量级 Agent 架构实战:Prompt 上下文与 Tool Function 的工程边界隔离 轻量级 Agent 架构实战Prompt 上下文与 Tool Function 的工程边界隔离在 Agent 检索流程中一个常见错误是把整篇文档放进 Tool 参数。这样既扩大了请求体也让工具承担了本应由模型处理的语义工作。Prompt 上下文与工具函数Tool Function的边界没有定义清楚时模型可能会把已有上下文重复传给工具。本文用一个长文档问答场景说明如何限制参数、裁剪结果并保留必要状态。1. 长文档被传入 Tool 参数时会发生什么以下是长文档问答流程中可能出现的tool_calls参数{ name: analyze_text, arguments: {\content\: \(此处省略 30000 字原文...)\} }Agent 把整个上下文作为参数传给本地文本分析工具会增加 Token 消耗也会把模型侧的语义解析错误地转交给函数处理。根因在于 Prompt 中没有明确限制工具函数的输入边界。模型误以为需要将前置步骤获取的所有上下文原封不动地交还给工具处理。这就是典型的上下文与工具职责混淆。上下文Prompt Context的作用是向大模型提供推理所需的背景状态与记忆工具Tool Function则是让大模型向外部系统发起具有确定性副作用的控制指令。工具参数应当只传递关键控制变量比如 ID、查询关键字、过滤条件而不是庞大的原始文本 Payload。2. 状态机视角上下文负责“思考记忆”Tool 负责“精准执行”要把这两者彻底隔离开需要引入显式的状态机治理模型。在 Agent 的单次 Loop 中上下文管理和工具调用应当各司其职上下文栈Context Stack只保留历史对话的摘要、系统指令System Prompt以及工具返回的精简结果。对于超长的工具响应必须在入栈前进行严格的剪枝与摘要化处理。工具调度器Tool Dispatcher对 Agent 吐出的 JSON 参数做强 Schema 校验。如果发现参数体积超过预设阈值或者包含了非必要的冗余文本直接拦截并触发参数修正Auto-repair提示。通过这种解耦方式上下文只需要维持模型的思考链条而工具调度器只负责执行轻量级的确定性逻辑。3. Mermaid 架构图Prompt 状态与工具调用的双向解耦下图展示了从 Prompt 上下文裁剪到 Tool 调度的隔离流控机制flowchart TD A[用户输入 User Query] -- B[上下文构建器 Context Builder] B -- C{检查历史 Token} C -- 超过阈值 -- D[上下文剪枝/摘要化 Context Trimming] C -- 正常范围 -- E[大模型推理 LLM Inference] D -- E E -- F{解析 Tool Call} F -- 包含工具调用 -- G[ Schema 校验器] F -- 直接文本输出 -- H[返回给用户] G -- 参数体积过大/类型错位 -- I[触发修正 Prompt (Auto-repair)] I -- E G -- 校验通过 -- J[本地 Tool 函数执行] J -- K[工具返回结果截断 Truncate Result] K -- B在整个闭环中所有的输入输出都需要经过确定性的闸门控制。4. 生产级 TypeScript 代码带 Schema 校验与参数截断的 Agent 调度引擎下面的 TypeScript 代码展示了如何在 Agent 运行库中实现上下文裁剪与 Tool 参数的强校验隔离。import { z } from zod; // 定义 Tool 参数规范严禁在参数中传递超长原文 export const SearchToolSchema z.object({ query: z.string().max(200, 查询关键字不能超过200个字符), limit: z.number().int().min(1).max(20).default(5), filters: z.record(z.string()).optional(), }); export type SearchToolArgs z.infertypeof SearchToolSchema; export interface AgentContextMessage { role: system | user | assistant | tool; content: string; tool_call_id?: string; } export class AgentDispatcher { private maxContextLength: number; private maxToolResultLength: number; constructor(maxContextLength 8000, maxToolResultLength 1500) { this.maxContextLength maxContextLength; this.maxToolResultLength maxToolResultLength; } // 1. 上下文截断与摘要 public pruneContext(messages: AgentContextMessage[]): AgentContextMessage[] { let currentLength 0; const pruned: AgentContextMessage[] []; // 从后往前保留最新的上下文 for (let i messages.length - 1; i 0; i--) { const msg messages[i]; const len msg.content.length; if (currentLength len this.maxContextLength msg.role ! system) { console.warn([Agent] 触发上下文剪枝丢弃 index 为 ${i} 的早期消息); continue; } currentLength len; pruned.unshift(msg); } return pruned; } // 2. 工具调用的强校验与降级处理 public async executeTool( toolName: string, rawArgsString: string, executor: (args: SearchToolArgs) Promisestring ): Promise{ success: boolean; result: string } { let parsedJson: unknown; try { parsedJson JSON.parse(rawArgsString); } catch (err) { return { success: false, result: [Tool Error] JSON 解析失败: ${(err as Error).message}。请提供合法的 JSON 参数。, }; } // 针对特定工具做 Schema 拦截 if (toolName search_docs) { const parseResult SearchToolSchema.safeParse(parsedJson); if (!parseResult.success) { const errorDetails parseResult.error.errors.map(e e.message).join(; ); console.error([Agent Tool Gate] 参数强校验不通过: ${errorDetails}); return { success: false, result: [Tool Error] 参数不符合要求: ${errorDetails}。请缩减参数体积后重试。, }; } try { const rawResult await executor(parseResult.data); // 对工具返回的大量结果进行强行截断防止塞爆下一轮 Prompt const truncated this.truncateToolResult(rawResult); return { success: true, result: truncated }; } catch (execErr) { return { success: false, result: [Tool Execution Failure] 工具执行异常: ${(execErr as Error).message}, }; } } return { success: false, result: 未知工具: ${toolName} }; } private truncateToolResult(text: string): string { if (text.length this.maxToolResultLength) { return text; } console.warn([Agent] 工具输出字符数 (${text.length}) 超过安全阈值 (${this.maxToolResultLength})强行截断); return ${text.slice(0, this.maxToolResultLength)}\n...[已截断过长内容]; } }在上述实现中用Zod对大模型生成的参数进行了强类型拦截。只要大模型尝试向search_docs传递庞大Payload就会直接触发safeParse失败并返回精简的错误描述提示模型重新调整。同时对工具执行返回的结果进行了truncateToolResult兜底保护从两端堵死了上下文溢出的风险。5. 上线前应验证哪些指标上面的策略是否有效需要在自己的模型、工具和负载下验证。至少记录以下指标并与改动前在相同任务集上对比指标观察重点单次请求 Token上下文与工具参数是否被控制在预算内首包与端到端延时裁剪、重试和工具执行是否引入额外等待参数校验拦截数Schema 是否过宽或 Prompt 是否缺少约束工具调用次数同一任务是否出现重复调用或循环Prompt 上下文负责提供推理所需的状态工具参数只传递动作所需的最小输入工具输出在进入下一轮前再做筛选。这三处边界明确后问题才更容易定位和调优。