从一句“帮我安排明天晚饭”开始
假设用户说:“明天两个人吃饭,尽量用家里的食材,不要花生。”这是一条用于推演方案的例子。要把它做对,至少要知道明天对应哪个日期、家庭里还有什么、食材够几份,以及“不要花生”只是这顿饭的要求,还是用户愿意长期保存的偏好。
如果没有读取库存的能力,助手最多给出建议,不能说“已经用上了你家里的食材”。如果没有保存计划的工具,它可以整理一份待确认的晚餐方案,不能说“明天的晚餐已安排”。我会先画清这两条界线,再考虑用哪个模型。
这也决定了学习顺序:先懂接口、数据和任务状态,再去看模型如何选工具。已有的全栈开发经验在这里很有用,因为后半段仍然是参数校验、事务、超时和并发问题,只是请求参数多了一层由模型生成的过程。
模型要学,提示里放什么也要学
接模型时,我会先确认输入输出限制、工具调用协议、流式格式和实际用量,再比较回答质量。支持工具调用不等于每次都能选对工具;输出了 JSON,也不等于里面的日期和数量就对。协议正确和业务正确需要分别检查。
提示词里有几类内容,不能混成一大段:助手的职责、当前用户的问题、对话历史、查到的资料、工具返回的业务结果。角色设定主要约束语气和工作范围,例如用中文解释备菜方法;它不负责证明冰箱里还有三个鸡蛋。把这些来源分开,后面才知道一句回答到底依据了什么。
上下文长度也不是越长越好。把历史和资料全部塞进去,会增加等待时间,也可能让旧信息压过本轮条件。我更愿意保留必要的约束和相关证据,明确每段资料的来源及时间。压缩历史时,“不要花生”这样的限制不能被摘要丢掉;用户后来改口,也不能一直沿用旧要求。
资料检索先解决“找到哪一段”
我理解的 RAG,是在回答前找到相关资料,再把资料交给模型参考。它首先是一个数据问题:这份资料能不能用,版本是否有效,检索时能不能找对。向量数据库只是其中一种工具,安装之后并不会自动得到可靠知识库。
以烹饪资料为例,我会保留标题、正文、语言、来源、整理版本和有效期。切分时尽量让一个片段保留完整操作及适用条件。如果把“冷藏”和“冷冻”的前提切没了,即使命中了相似词,后面的回答仍可能用错。
小规模、关键词明确的资料,可以先做词法检索。恰饭有谱手机端用了 SQLite FTS5,结合分词和 BM25 排序;当前查询约束在编辑过的关键词上。它方便随 App 离线使用,但对换一种说法、隐含意图和知识覆盖不足并没有天然优势。FTS5 官方文档介绍了全文查询和排序能力;具体召回效果还得拿自己的题目测试。
准备升级检索时,我会先留一组问题及预期资料,再比较关键词、向量和混合方案。要分清“根本没找到正确资料”和“资料找对了但模型解释错了”。两种问题都表现为答错,修改的位置却完全不同。展示来源也只是方便核对,不能证明回答的每句话都来自那份资料。
工具负责执行,Skill 负责组织做法
工具适合做小而明确的动作,例如按日期查询计划、按关键词查菜谱。模型提出工具名称和参数,程序检查后执行,再把结果交回模型。DeepSeek 的工具调用流程也是由应用执行函数;模型不会直接取得数据库权限。
日期和关键词可以让模型填写,当前账号、家庭和权限范围应该从应用会话中取得。一个请求即使符合 JSON Schema,也可能越权,或者一次查了过大的日期范围。我会在类型检查后继续做业务校验,并限制工具次数和等待时间。
“备一顿晚饭”则更像一个 Skill:先读计划和库存,再形成候选菜,检查人数和忌口,最后给用户看草稿。它可以包含多个工具,但必须讲清入口、完成条件和失败分支。只写一个技能名称,没有实际任务跑过,说明不了执行效果。
涉及写入时还要处理重复请求。用户点了两次确认,或者保存成功后网络断了,都可能触发重试。确认应绑定这次草稿的具体内容和版本,保存结果用幂等标识核对。页面最终显示“保存成功”,应当来自业务服务的回执。
记住偏好和恢复任务,是两件事
“这次不吃花生”不能直接变成永久记忆。我会把本轮限制、近期对话和用户确认的长期偏好分开;长期内容还需要可查看、修改和删除。涉及家庭时,个人偏好也不能默认变成全家公开的信息。
另一类状态是任务进度:已经查询了什么、生成的是哪份草稿、是否确认、是否保存。它要解决的是中断之后从哪一步继续。聊天记录里有一句“正在保存”,并不能证明保存动作到底有没有发生,恢复时仍要查询业务结果。
LangGraph 的持久化文档把线程检查点和长期存储分开。这个划分很有帮助,但框架保存了节点状态,也不代表能接着生成供应商已经断掉的半句话,更不代表外部写入会自动只执行一次。
我会先明确要恢复的是什么:页面上的文字、同一个模型请求,还是包含多次业务操作的任务。恢复范围决定了存储位置、保留时间和幂等方案。单机内存里的 SSE 事件可以处理短暂断线,进程重启后就不应再承诺回放。
框架选型放在问题明确之后
LangChain 常用于组织模型和工具适配,LangGraph适合表达有分支和状态的执行过程。MCP 解决的是应用和工具服务之间如何描述及交换能力;它本身不会替我判断一笔业务是否允许执行。MCP 官方架构说明也把协议范围放在上下文交换上。接入它之后,原来的权限和审计责任仍然存在。
如果当前只有几个固定只读工具,先写清楚调用流程,通常比同时引入几套框架更容易定位问题。等到多步任务、人工确认和跨进程恢复真的需要统一管理,再用具体场景衡量迁移成本。我在恰饭有谱里也保留了这个区分:App 走原生和 Java 链路,独立 Python 核心的验证不能当成框架已经接进产品。
最后要补的是评测和可观测性。我会把错误问题留下来:读不到库存时有没有说成库存为空;用户说“不用保存”时有没有触发写入;切换家庭后有没有带上旧资料;停止后还有没有迟到的内容。记录任务标识、工具耗时、状态和脱敏后的错误原因,才能追到问题发生在哪一步。
对我来说,一份有用的 Agent 学习清单,最终应该能对应到这些问题。模型理解、检索、执行、状态和评测各自有位置;一个环节没做好,回答再流畅,也不能替用户把事办妥。
延伸阅读
对应项目恰饭有谱