
智能产品里上下文和工具如何分工智能文档、设计软件和代码编辑器都需要让模型理解当前工作区又不能把整个文档、画布或仓库每轮都塞进提示词。判断分工时可以用一个简单标准帮助模型理解当前任务的信息进入上下文需要读取最新状态、做确定性计算或产生副作用的动作交给工具。两者之间还要有权限和数据校验不能只靠模型自觉。1. 上下文保存决策所需信息上下文通常包含系统规则、当前请求、用户主动选择的对象、近期已确认决定和完成任务所需的少量引用材料。每段内容应标明来源与有效期。页面导航、文件修改或选择变化后旧快照要失效长期偏好则单独保存经用户确认后再按需注入。系统规则与外部内容不能混成一段。文档、网页和工具结果都属于不可信数据即使其中写着“忽略规则”也不应获得指令优先级。当前选择也可能含有敏感信息采集前要按产品权限过滤并让用户知道模型正在使用什么。历史不是越多越好。摘要要保留尚未解决的问题、已经执行的副作用和关键约束而不是只压缩措辞。对“准备删除”和“已经删除”这类状态应用应保存结构化记录不能让模型从自然语言摘要里猜。2. 工具读取真相并执行动作画布坐标、文件内容、字数、编译结果和数据库状态会变化适合通过工具按需读取。移动节点、替换文本、保存文件和发起外部请求会改变状态也必须由工具执行。模型负责提出参数工具层负责 Schema 校验、权限、目标解析、超时、幂等和审计。工具不必切得过碎。若完成一次用户动作必然需要连续读取多个内部字段可以由一个业务工具在程序内完成减少模型来回协调。反过来一个“执行任意命令”或“修改任意对象”的万能工具权限太宽也难以准确确认影响。工具粒度应围绕可理解、可授权的业务动作。3. 调度器要管理预算与循环调度器先保留不可丢的系统规则和当前请求再根据任务选择上下文。预算应按真实 Token 计数、模型窗口和预留输出计算不能用固定对话轮数代替。工具调用要有单轮上限与总时间预算连续得到同一错误时应停止并把缺少的信息告诉用户。4. TypeScript 调度模块示例下面的代码展示了工具注册、消息裁剪和调用分发的基本结构。它是一个原型需要结合产品权限继续补全。import { ChatCompletionMessageParam, ChatCompletionTool } from openai/resources/chat; export interface ToolDefinition { name: string; description: string; parameters: Recordstring, any; execute: (args: Recordstring, any) Promiseany; } export class AIContextAndToolManager { private tools: Mapstring, ToolDefinition new Map(); private maxContextTokens: number; constructor(maxContextTokens: number 3000) { this.maxContextTokens maxContextTokens; } // 注册确定性工具 public registerTool(tool: ToolDefinition) { this.tools.set(tool.name, tool); } // 导出 OpenAi 适配的 Tool 描述符 public getOpenAITools(): ChatCompletionTool[] { return Array.from(this.tools.values()).map((tool) ({ type: function, function: { name: tool.name, description: tool.description, parameters: tool.parameters, }, })); } // 上下文预算裁剪模拟按 token 计数裁剪历史 public pruneContext( systemPrompt: string, historyMessages: ChatCompletionMessageParam[], currentSelectionState: string ): ChatCompletionMessageParam[] { const systemMsg: ChatCompletionMessageParam { role: system, content: ${systemPrompt}\n\n[当前视口状态摘要]: ${currentSelectionState}, }; // 仅保留最近 3 轮对话避免长上下文带来的注意力分散与成本拉升 const recentHistory historyMessages.slice(-6); return [systemMsg, ...recentHistory]; } // Tool Call 执行器与分发适配 public async dispatchToolCall(toolName: string, rawArgs: string): Promisestring { const tool this.tools.get(toolName); if (!tool) { throw new Error(未注册的 Tool 名称: ${toolName}); } try { const parsedArgs JSON.parse(rawArgs); const result await tool.execute(parsedArgs); return JSON.stringify({ status: SUCCESS, data: result }); } catch (err: any) { return JSON.stringify({ status: ERROR, message: err.message || Tool 执行失败 }); } } }5. 示例代码的缺口类中保存了maxContextTokenspruneContext却没有使用它只截取最后六条消息。消息长短差异很大这不构成 Token 预算系统提示和当前选择拼接后也可能单独超限。当前选择属于外部数据直接拼进 system content 会模糊指令与数据边界适合改为带明确标签的用户上下文消息并先过滤敏感内容。工具参数与结果都使用anyJSON.parse后没有按parameters校验也没有权限、超时、取消和调用次数限制。execute抛出的错误文本可能含内部细节直接返回模型前应映射为安全的错误类型。结果还要限制大小并处理无法 JSON 序列化的对象。工具名存在于 Map 只证明已注册不证明当前用户可以调用。评估分工效果时用产品自己的任务集比较回答是否引用了正确上下文修改是否命中正确对象工具失败后能否停止延迟和 Token 分别花在哪一步。没有可复查实验时不给出精确的成本下降或准确率数字。6. 落地时逐项确认确定性计算进入程序尺寸、计数、语法解析和对象定位由代码执行模型使用结果做语义判断。工具输入输出有 Schema参数校验后再执行返回最少必要字段并标明截断、版本和错误类型。副作用有权限与确认读取和写入分开授权高风险修改先展示准确目标与预览。循环有停止条件总步骤、总时间和重复错误都有上限停止后保留已完成状态不自动无限重试。上下文按任务选择Focus 或选择可以提示相关范围但 Hover 这类瞬时行为不应自动发送敏感内容采集需符合用户预期。上下文与工具不是此消彼长的两个桶。上下文负责让模型知道正在解决什么工具负责提供最新事实和受控行动调度器负责预算与停止。责任分开后错误也更容易定位材料选错、模型判断错还是工具执行边界没有守住。