Agent面试详解(中):记忆、工具与多用户并发

Agent面试详解(中):记忆、工具与多用户并发
《Agent面试详解》系列上篇运行时与上下文 · 中篇记忆、工具与并发 · 下篇评测、安全与落地上篇搭好了 Agent 的运行时骨架状态机驱动循环checkpoint 负责恢复上下文按 Token 预算动态组装。接下来要把它放进真实的多用户环境。这一步比接入一个向量数据库或 MCP Server 难得多。长期记忆会重复、冲突和过期工具会超时、越权并产生不可逆副作用两个 Worker 可能同时执行同一个步骤。中篇集中处理这些数据一致性和并发问题。长期记忆不能只有 insert 和 search把所有历史对话做 embedding再按相似度取 Top K不等于长期记忆。它很快会遇到重复、冲突、过期、越权和无限膨胀。先把记忆分层层次生命周期例子Working memory单次模型调用当前 Prompt、最近 observationSession state当前 runplan、step、checkpoint、预算Episodic memory跨 run 的经历某次部署失败及其原因Semantic memory稳定事实用户偏好、系统约束、领域知识Procedural memory长期规则Skill、操作步骤、验收规范LangChain 的上下文工程文档也区分 runtime context、会话 state 和跨会话 store并建议通过生命周期中间件完成摘要、工具筛选和状态更新。Context Engineering分层的价值不只是便于命名而是让每类信息有不同的写入条件和淘汰策略。一次工具返回属于 observation不应因为与用户问题相似就自动升级成长期事实一次成功操作也不应直接变成永远有效的流程规则。给记忆设计“遗忘”真正的 Memory Service 至少要支持写入、检索、合并、修订和遗忘相同实体、相同事实去重。新事实覆盖旧版本同时保留审计链。临时信息设置 TTL。根据重要性、置信度和使用频率衰减。多条 episode 定期合并成 semantic memory。长期不命中的内容进入冷存储。每个租户和用户设置容量配额。用户可以查看、纠正和删除自己的记忆。“删除”也不能只删向量索引。原始对象、派生摘要、向量、缓存和搜索索引都要通过同一条删除链路处理否则用户删除了一条记忆Agent 仍可能从旧摘要里把它找回来。检索先过权限再谈相似度每条记忆应带上来源、时间、租户、用户、权限、置信度和版本。检索不能只看向量距离WHERE tenant_id :tenant_id AND permission_scope :allowed_scopes AND valid_from :now AND (expires_at IS NULL OR expires_at :now) ORDER BY relevance_score DESC, confidence DESC, last_used_at DESC LIMIT :budgeted_k先做硬过滤再做语义排序。否则“很相似但属于别的客户”的记忆正是最危险的数据泄漏。检索结果还要受本轮 Token 预算约束Top K 只是候选数量不表示候选必须全部进入上下文。工具层要和模型彻底解耦一个生产工具不能只是 Python 函数名加 description。它需要明确的执行合同name: orders.refund version: 2 input_schema: RefundRequest output_schema: RefundResult timeout_ms: 10000 retry_policy: no_automatic_retry idempotency: required permission: orders.refund side_effect_level: irreversible approval: required error_taxonomy: - validation_error - permission_denied - provider_timeout - business_rejectedTool Registry 负责描述和发现Tool Gateway 负责控制执行。模型只提交结构化调用不直接获得第三方 Token也不直接连数据库。这里有一个容易混淆的边界Tool Registry 回答“有哪些工具、参数是什么”Tool Gateway 回答“当前租户能不能调用、这次调用是否需要审批、失败能不能重试”。把两者合在模型侧会让工具描述、凭证和策略同时暴露给一个不完全确定的决策者。大结果不要原样返回模型工具执行后可以同时生成四种结果原始结果存对象存储供审计和下载。结构化结果供程序继续处理。模型摘要只包含下一步决策需要的信息。类型化错误驱动重试、改参、重规划或停止。例如数据库查询返回 20 万行时模型不需要看到全部内容。它需要字段、行数、统计摘要、异常样本和原始结果引用。Anthropic 在工具工程实践中强调工具应该定义清楚、能够组合、谨慎占用上下文并通过评测反复改进。Writing Effective Tools for AI AgentsMCP 解决了工具如何暴露给不同客户端的问题但不自动解决租户隔离、审批、幂等、执行沙箱和企业审计。这些仍然属于 Harness。多用户并发冲突怎么处理Agent 一旦支持多用户就会遇到三类冲突同一用户打开两个会话同时修改同一 run 或同一文档。不同用户操作同一个业务对象例如工单、代码分支或订单。两个 Worker 误以为自己都拥有同一个 run重复产生副作用。这三类冲突不能只靠“每个用户一个 session”解决。session 隔离的是交互上下文业务对象、run 所有权和外部副作用仍然可能共享。先让每一层都认识租户Run、step、message、memory、tool call、trace 和 artifact 都必须带租户边界tenant_id / user_id / session_id / run_id / step_id / tool_call_id不能只在 API 入口检查一次然后让内部队列和记忆库丢掉tenant_id。租户隔离必须贯穿入口、状态、队列、工具、存储和日志。状态冲突用版本不用长锁更新 run 时携带版本号UPDATE agent_runs SET state :new_state, version version 1 WHERE id :run_id AND tenant_id :tenant_id AND version :expected_version;更新行数为 0说明状态已经变化。此时重新读取并判断是否重规划而不是覆盖别人的结果。数据库悲观锁只应该包围毫秒级的原子更新不能跨模型调用和网络调用。让事务等模型思考 30 秒会直接把连接池和并发拖垮。Worker 使用租约和心跳Worker 获取的是有过期时间的 lease不是永久所有权。执行期间续租崩溃后 lease 到期其他 Worker 才能接管。接管者从最后一个已提交 checkpoint 继续而不是猜测前一个 Worker 做到哪里。租约时间需要覆盖一次正常心跳抖动但不能长到故障后迟迟不能接管。比较实用的起点是租约时长为心跳间隔的三到五倍续租失败后立即停止领取新步骤真正执行副作用前再确认租约和状态版本仍然有效。副作用必须幂等idempotency_key run_id step_id tool_call_id同一个 key 的退款、发送、创建和写入只能成功一次。Agent 的“恰好一次执行”通常无法端到端保证更现实的做法是 at-least-once 调度加业务侧幂等。如果数据库状态更新和事件发布必须同时成功可以使用 transactional outbox事务内只写业务状态和 outbox独立 relay 再把事件送入队列。Planning 不等于先写一份漂亮清单静态计划在第一步执行后就可能过时。一个有效 plan 至少包含最终可观察目标。步骤依赖。每一步验收证据。当前状态和未解决阻塞。失败后的恢复策略。当工具返回与假设冲突、依赖不可用、预算明显不足或连续两次没有产生新证据时应触发重规划。重规划不是把原计划再说一遍而是明确撤销哪些假设、保留哪些证据、为什么换路径。单 Agent 是默认选择Subagent 适合并行检索、独立 review、上下文隔离和不同领域分析。Multi-Agent 只适合任务真正可分、角色确实不同、结果可验证的场景。多 Agent 最常见的问题不是智力不足而是重复搜索和重复调用工具。状态版本不同步。子 Agent 互相强化错误。通信 Token 超过实际工作。最终没有人对结果负责。委派协议应明确输入、输出 schema、预算、截止时间和完成条件。子 Agent 返回的不是“我研究完了”而是一份可验证的结果包。中篇留下的状态到这里Agent 的记忆有生命周期工具有执行合同多租户状态有版本Worker 有租约外部副作用有幂等键。它已经不容易因为重试或并发直接写坏数据。但“没有写坏”还不等于“做对了”。下篇要回答最后一组问题怎样还原一次 run怎样测试不确定的执行轨迹安全边界放在哪里以及哪些 Agent 场景值得真正投入。继续阅读下篇评测、安全与落地《Agent面试详解》系列上篇运行时与上下文 · 中篇记忆、工具与并发 · 下篇评测、安全与落地