本文总结当前项目已经验证的工程实践。示例身份、商户、地址、电话、接口和密钥均为虚构值或占位符。1. 项目要解决的不是问答而是受控业务执行一个业务 Agent 同时面对四类问题理解问题自然语言模糊、口语化还会省略上下文。执行问题查询、下单、修改资料、更新状态等操作权限不同。安全问题Prompt Injection、密钥套取、越权调用和误操作不能交给模型自由裁决。体验问题拒绝、澄清、待确认和执行结果必须让用户知道下一步做什么。因此本项目没有采用“用户输入直接交给 LLMLLM 自由调用全部工具”的结构而是把 Agent 设计为确定性边界 模型语义能力 受控工具执行 结构化恢复。用户输入 → BoundaryGuard注入、密钥、业务范围检查 → ChatScenePolicy角色场景三态判断 → 可信会话状态承接选择、确认和待处理动作 → LangChain ChatModel语义识别、澄清、自然语言生成 → ToolRouter工具存在性、角色权限、参数边界 → 本地服务 / SQLite / 外部受控接口 → ChatResponse Guidance结果与可恢复提示核心经验是LLM 负责不确定的语言理解程序负责不能出错的边界与状态迁移。2. 安全 Guard 必须在 LLM 之前2.1 为什么不能只靠 System PromptSystem Prompt 是模型上下文不是权限系统。只写“不要泄露密钥、不要越权”仍存在恶意输入会进入模型和供应商请求日志模型可能忽略约束或被复杂指令诱导不同模型、版本、温度下行为不稳定工具调用一旦执行事后文本纠正没有意义。项目用BoundaryGuard.classify_message()在模型调用前识别注入和密钥套取命中后直接构造阻断响应确保llm_used falsetool_calls []原始敏感输入不回显到 Guidance不把危险内容发送给模型供应商。2.2 工具权限必须在执行点再次校验预检查不能替代执行点授权。无论工具来自规则路由、模型 Tool Calling 还是 LangChain wrapper都统一经过awaittool_router.invoke(tool_name,arguments,rolecurrent_role)ToolRouter再调用BoundaryGuard.can_call_tool()避免 wrapper、模型或新业务分支绕过权限。这个“单一执行闸门”比在每个调用方复制if role ...更易审计也更不容易漏改。3. LangChain 是适配层不应吞掉领域边界本项目把模型调用放在 ChatModel 兼容接口之后把领域工具封装成 LangChain 工具但 wrapper 仍调用ToolRouter.invoke()。这样做的收益可替换 OpenAI-compatible、Anthropic 或 Mock 模型Prompt、Message、Tool Schema 和输出解析接口统一测试可以替换模型而不改业务代码安全授权、数据库事务和业务状态仍由领域层掌握。需要避免的反模式是为了“全 LangChain 化”让 Chain/Agent 直接写数据库或直调外部接口。框架负责编排领域服务负责事实与副作用。4. 业务路由要组合确定性规则、LLM 与三态判断4.1 不要在“全正则”和“全模型”之间二选一全正则可解释但同义表达覆盖成本很高全模型灵活但会受模型波动、网络失败和提示词变化影响涉及订单状态、联系人修改、目标选择等关键流程时误判成本高。本项目采用组合策略注入、权限、订单状态机、序号选择和确认提交确定性代码开放表达的业务意图和参数抽取LLM 优先模型不可用或输出不合法规则回退角色场景判断match / mismatch / unknown三态。4.2unknown比“猜一个分类”更重要如果所有输入都必须二分类短句“可以”“第一个”“这个呢”很容易被错拦截。三态策略允许明确匹配继续明确跨场景返回场景提醒信息不足进入已有上下文或澄清流程。只拦截高置信不匹配比追求表面分类准确率更符合业务 Agent 的风险目标。5. 多轮对话的关键是“可信状态”不是无限聊天记录5.1 短回复必须绑定服务端待处理状态“确认修改”“第二个”“可以”本身没有完整语义。项目通过服务端上下文保存候选商品/商户/用户已选择对象待确认动作待处理订单上次业务来源和过期时间。只有存在匹配的可信 pending context短回复才承接原流程。不能仅让 LLM 根据历史文本猜测否则用户切换话题后可能确认错误操作。5.2 会话隔离维度必须包含业务身份前端和后端上下文至少按以下维度隔离role user_id merchant_id当前场景与角色一一对应若未来一个角色支持多个独立场景应加入scene。只按user_id保存历史会导致消费者、商户、运营和管理员上下文串线尤其会污染权限和待确认动作。5.3 上下文要有 TTL 和显式失效候选、选择和待确认状态不应永久存在。实践中应在以下时机清理操作成功或取消用户明确切换业务用户、角色或商户变化TTL 到期目标实体失效。6. 写操作采用 Preview → Confirm → Commit联系人修改、商品导入、订单状态更新和创建配送等操作都不应因一句模糊自然语言直接提交。推荐流程Preview解析目标、字段、原值、新值及影响Confirm用户明确确认且会话状态仍有效Commit执行工具记录结果或审计Idempotency重复确认不重复产生副作用。重要细节用于展示的 Guidance 建议可以回填输入框但不能自动发送。否则“帮助用户恢复”会变成自动执行写操作。7. 把失败设计成结构化 Guidance仅返回一段“无法处理”会让前端无法区分注入阻断、权限不足、参数缺失、场景错误或模型不可用。项目在ChatResponse中使用结构化 Guidance常见字段包括type失败或提醒类型reason原因required_content还需补充什么examples/suggestions示例表达input允许回显时的脱敏、截断原输入scene/role当前上下文。前端可以统一渲染提醒卡片、可回填操作和“你的输入”。安全类异常则不回显原始危险内容。这说明 Agent API 的成功标准不是只有reply而是前端能否根据稳定契约帮助用户安全恢复。8. 模型输出和密钥要按不可信数据处理8.1 模型说“调用工具”不等于可以执行工具调用需要依次校验输出是否符合预期 JSON/Tool Call schema工具名是否在允许集合当前角色是否可调用参数是否完整、类型正确用户身份和商户目标是否由服务端上下文约束写操作是否已确认结果是否包含敏感数据。8.2 密钥不仅不能落库也不能进入模型请求和响应应同时防守配置文件只保留${LLM_API_KEY}等环境变量引用日志Authorization、Bearer、Token、Password 和常见 Key 形态脱敏模型请求用户输入含密钥时调用前阻断模型响应供应商异常回显密钥时丢弃或替换前端 Guidance安全异常不回显原输入。测试中的sk-test-*可以作为不可用假值验证拦截链路但必须与运行配置隔离。9. 测试重点应是业务不变量Agent 的测试不能只断言回复文案因为模型措辞会变化。优先断言是否调用 LLM调用了哪些工具及参数未授权工具是否被拒绝Guard 是否早于 LLM写操作确认前数据库是否保持不变重复确认是否幂等角色/用户/商户上下文是否隔离模型失败时是否规则回退响应是否具有稳定intent、blocked、guidance密钥是否未进入模型 payload、reply、日志或 Guidance。建议采用三层测试单元测试Guard、状态机、参数解析、脱敏函数契约测试ToolRouter、ChatModel adapter、结构化响应端到端测试FastAPI SQLite Mock LLM 的代表性多轮流程。Mock LLM 应覆盖正常 JSON、无效 JSON、异常、超时、虚构工具、敏感内容回显和模糊分类而不仅是 happy path。10. 本项目踩过或需要持续规避的问题10.1 业务关键词误伤待确认值联系人姓名、电话号码等值可能不含业务关键词。若每轮都重新做范围判断会把合法 pending value 当成越界输入。解决办法是可信待处理上下文优先于普通语义分类但不能优先于注入和密钥 Guard。10.2 目录“第 N 个”和商品“第 N 个”上下文冲突序号没有天然类型必须绑定候选来源、角色、商户和 session不能维护一个全局recent_items。10.3 同一领域存在两套订单模型模拟订单与 Commerce 订单若分别查询会让用户认为订单丢失。统一可见性层应明确来源、状态映射和可执行动作而不是简单拼接两段文案。10.4 配置热更新不等于所有依赖自动更新配置保存后需要明确哪些组件读快照、哪些按请求读取模型 client 是否重建旧请求如何完成。否则 UI 显示已更新实际运行仍使用旧值。10.5latest依赖破坏可复现构建前端依赖若使用latest可能突然要求更高 Node 版本。项目交付应固定依赖版本并声明engines.node把运行时版本纳入 CI。10.6 SQLite 文件也是敏感资产运行后的 SQLite 仍可能保存聊天上下文、订单、地址、电话、客户 JSON、审计和用户记忆。公开前不能只 grep 文本还要删除或按脱敏种子重建数据库。11. 推荐的上线前检查表安全Guard 在任何模型调用之前执行所有工具统一经过 ToolRouter 授权写操作具有预览、确认和幂等保护密钥不进入模型 payload、日志、响应和 Guidance外部 URL、超时、重试和速率限制受配置控制。上下文与身份session 按场景、角色、用户、商户隔离pending context 有 TTL、来源和目标类型客户端传入身份由服务端目录/关系校验切换角色或目标时不会继承危险状态。可观测性记录 intent、tool、耗时、结果类型和 request/session 标识日志字段级脱敏可区分规则命中、LLM 路由、fallback 和权限拒绝不记录原始 Authorization 或完整用户敏感输入。质量与交付使用 Mock LLM 的测试不依赖真实网络和密钥全量测试及关键角色矩阵通过Python、Node、依赖版本固定并在 CI 验证.env.example、配置、文档、数据库和示例数据完成脱敏扫描第三方源码与许可证不被批量改写。12. 结论一个可靠的业务 AI Agent不是把更多逻辑塞进 Prompt而是把不同风险放到正确层次Guard 管安全边界场景策略管明显错位可信状态管多轮承接LLM 管开放语义ToolRouter 管执行权限领域服务管事务与事实Guidance 管用户恢复测试管长期不变量。当模型不可用、理解错误或遭遇恶意输入时系统仍能保持权限正确、数据一致、行为可解释才算真正完成了从聊天机器人到业务 Agent 的工程化跨越。