1. 三层架构Runtime / Framework / Harness三层各管什么层包版本职责一句话记法Runtimelanggraph1.2.13把「调模型 → 执行工具 → 再调模型」编译成可执行的图管状态流转和终止条件管循环Frameworklangchain/langchain-core1.4.3 / 1.6.6模型封装、消息类型、工具定义、Schema 生成管零件Harnessdeepagents0.7.22在 LangGraph 之上预装文件系统、子 Agent、待办清单管预装关键理解三层是自底向上层层构建不是互相替代。四个包在同一个进程里共存。create_agent和create_deep_agent不是两个框架。后者只是在前者基础上多装配了一批默认能力。验证代码2. 最小 Agent 的构造create_agent的三个参三个参数的含义参数作用换掉会怎样model决定用哪个模型换模型 → 工具选择能力、回复风格全变tools模型能调用的工具清单不传 → 模型只能靠嘴回答无法行动system_prompt每次调用都带上的行为约束不写 → 模型倾向于只聊天不调工具system_prompt和用户问题的区别重要system_prompt每一次模型调用都自动带上是持续生效的约束用户问题只在invoke时传进去只影响这一轮图节点怎么读model和tools是执行步骤。模型要工具就走到tools工具执行完回到model循环直到模型不再请求工具。__start__/__end__是入口和出口标记。3. 工具从 Python 函数到模型看得懂的 Schema核心认知模型看不见你的 Python 代码。它看到的是一份由框架自动生成的 JSON 说明书Schema。生成依据只有三样你函数里的变成 Schema 里的作用类型标注amount: float参数的typefloat→number决定模型能传什么形状的值docstring 正文工具的description模型靠这句话决定什么时候该用它Args:下的逐行说明每个参数的description决定模型怎么填这个参数默认值to_currency: str CNY该参数从required消失并带default模型可以不传它定义一个工具不需要装饰器普通函数放进tools[...]就行。框架读函数名、类型标注、docstring。打印 Schema注意required里只有两个名字——to_currency因为有默认值自动从必填清单消失。为什么默认值是接口设计问题参数该不该给默认值直接决定模型的自由度全给默认值 → 模型会偷懒不做判断全不给 → 模型被必填项卡住只能反过来追问用户docstring 那句话更关键它决定了模型在什么场景下想起这个工具。工具好不好用一半看实现一半看这句描述。4. 一次invoke的完整生命周期四条消息live 实测原样输出消息类型对照表#类型角色决定性字段1HumanMessage用户输入content2AIMessage模型请求调工具tool_callscontent是空字符串3ToolMessage工具真实执行结果content/tool_call_id/status4AIMessage模型基于结果作答content且tool_calls为空两个AIMessage怎么区分看有没有tool_calls有 → 模型在下单content是空的没有 → 模型在交货这轮结束为什么第 2 条的content是空的两次输出通道分离的设计模型一次可以输出给用户看的自然语言和给框架看的结构化调用请求。塞进同一个字符串字段会让解析变成字符串匹配游戏引号、换行、嵌套括号都能让它崩。拆成两个字段后判断退化成布尔检查。为什么tool_call_id必须是随机串一次invoke里模型可以同时请求多个工具返回顺序不保证并发执行、耗时差异、重试都会打乱。按位置配对在单工具场景能蒙对一旦并发就是错的。更重要的随机 ID模型伪造不了。模型能编任意content但编不出和真实请求匹配的随机 ID。这是区分工具真跑了和模型自己说了算的物理判据。检查函数照搬课程实现三个断言对应三个独立环节请求正确 → 执行成功 → 对话收尾。为什么有返回消息不算证据参数校验失败同样会产生ToolMessage只是status不是success。5. Harness 白送的东西10 个工具从哪来同一个echo工具两个 API 注册后的清单9 个白送工具的用途分组组工具干什么找ls/glob/grep列目录、按文件名匹配、按内容检索读read_file读文件图片/音频/PDF 走多模态打包改write_file/edit_file/delete写入、精确替换、删除派活task委派子 Agent执行execute跑 shell 命令★ 本章最重要的一句话「工具已注册」不等于「工具已调用」。实测数据注册 10 个实际调用 1 个。那 9 个在本次任务里一个都没被碰过。工具清单只描述能力边界描述不了实际行为。判断能做什么 → 看工具清单判断做了什么 → 看消息列表里的ToolMessage图节点也多了东西多出来的是 Harness 装配的中间件节点。6. offline 与 live两种运行模式offlinelive模型来源脚本模型ScriptedChatModel应答预先写死真实模型 API是否读.env不读读是否发网络请求不发发工具函数与框架执行真实执行真实执行证明了什么机制成立真实模型会正确选工具怎么从数据上区分这个最有价值两种模式都打印passed光看日志分不出来。可靠判据是调用 ID 的形态模式调用 IDofflinech01-echo—— 脚本里写死的跑一百次都一样livecall_43ca3a45a58748d5a7581326—— 服务端生成每次不同ID 随机与否是是不是真实模型最硬的间接证据。7. 源码里值得记住的常量与设计工具按「只读 / 可变」分组为什么这么分只读工具之间没有副作用依赖可以并行批量调用可变工具会改状态必须串行。分类结果直接决定并发策略。大结果卸载第一道防线工具返回值超过阈值就从对话里卸载出去换成摘要。排除名单为什么文件工具被排除源码注释给了三条理由自带截断 —— 结果本身就不会超限卸载后会死循环 —— 模型看不到结果就再调一次无限重复永不超限的轻量操作这是框架替你做决定的典型样本。知道它存在能解释一类诡异现象为什么某个工具返回了很长内容上下文里却没被摘要掉。8. 易错点清单①os.environ[...]的语义方括号语义是取出一个名为xxx 的环境变量。把密钥塞进去 让 Python 找一个名叫sk-7MA7xxxxxxxx的环境变量必然KeyError。② 密钥写进源码文件 公开一旦文件进公开仓库密钥就不再是秘密。正确做法三项配置同时提供任何 OpenAI 兼容接口都能接入不用改框架代码③ 中文 Windows 控制台编码④ PyCharm 解释器的「名字」和「路径」不是一个东西我看到Python 3.13 (agent-learn)这个名字以为指向D:\agent-learn。实际它的homePath是D:/miniconda3/envs/yolo26/python.exe。排查解释器问题永远看路径不看名字。9. 自查清单这一章学没学会用这几个问题验#问题能答出来吗1三层各自负责什么为什么说不是替代关系2create_agent的三个参数分别是什么换掉哪个会有什么后果3两个AIMessage怎么区分第 2 条的content为什么是空的4ToolMessage里哪个字段能证明工具真的执行了为什么模型伪造不了5Deep Agent 白送几个工具本次任务实际用了几个这说明什么6怎么从数据上判断一次运行是 offline 还是 live7工具三要素分别变成 Schema 里的哪个字段默认值会造成什么后果8os.environ[sk-xxx]错在哪正确写法是什么9为什么文件工具被排除在大结果卸载之外