学习笔记 · Obsidian

Agent、Model、Message 与 Tool 核心原语

LangChainPython

核心循环

Agent 是“模型调用工具,直到任务完成”的循环;harness 决定模型每一轮能看到什么、能做什么、失败后如何恢复。create_agent 的直接配置面包括:

  • model:provider:model 字符串或已初始化的 chat model;
  • tools:Python callable、LangChain tool 或 tool dict;
  • system_prompt:静态指令;动态指令应通过 middleware;
  • response_format:结构化结果策略;
  • state_schema、context_schema、checkpointer、store:状态与依赖;
  • middleware:可靠性、安全、上下文、计划和人工控制。

Agent state 至少包含追加式的 messages。带 checkpointer 调用时,thread_id 是会话持久性边界;同一 ID 续接历史,不同 ID 隔离会话。

Model:统一接口,不抹平能力差异

init_chat_model 为不同 provider 提供共同的初始化与 invoke、stream、batch 接口;agent 内外可复用同一模型对象。通用参数包括 temperature、max tokens、timeout、retries,但 provider 专属能力仍要查对应集成文档。

重要边界:

  • 默认会对网络错误、429 和 5xx 做带抖动的指数退避重试,文档当前默认最多 6 次;401/404 等客户端错误不会自动重试。
  • bind_tools 只让模型提出工具调用;独立使用 model 时,应用必须执行工具、生成关联 tool_call_id 的 ToolMessage 并再次调用模型。create_agent 才会自动完成循环。
  • 多数现代模型支持并行工具调用,但是否能禁用、是否支持 server-side tools、multimodal、reasoning、prompt cache、logprobs 等取决于 provider/model profile。
  • with_structured_output 可在 agent 外直接约束模型输出;应优先用 Pydantic 等可校验 schema,并区分 provider 原生约束与 tool-call 模拟。
  • 动态模型选择应复用预初始化模型,依据任务复杂度、成本、上下文长度或租户策略在 middleware 中切换,避免每轮重新创建连接对象。

Message:跨 provider 的会话协议

四个核心角色:

类型语义关键约束
SystemMessage开发者/系统指令通常置于上下文前部;不同 provider 的系统消息规则可能不同
HumanMessage用户输入可含文本和多模态内容
AIMessage模型输出可同时携带文本、tool calls、usage、reasoning 等元数据
ToolMessage工具执行结果tool_call_id 必须与发起调用对应;并行调用尤其不能错配

消息可用对象或字典构造。content 保留原始/兼容表示,content_blocks 提供标准化块视图,统一文本、reasoning、图片、音频、视频、文件、工具调用及 provider 扩展信息。不要假定 AI 输出永远是字符串。

流式模型返回 AIMessageChunk;chunk 可以相加组装完整内容和渐进 tool-call 参数。展示层应能处理不完整 JSON、空 reasoning block、多个 reasoning/text 周期和 usage metadata 延迟到达。

Tool:schema 是模型的操作说明书

工具由名称、描述、参数 schema 和实现构成。模型主要依据这些信息决定是否调用以及如何填参数,因此:

  • 函数名要稳定、动作明确;docstring 说明“何时用”和参数业务约束,而不只说明实现。
  • 复杂输入用 Pydantic/JSON Schema,字段描述、枚举、范围与必填项要清楚。
  • 通过 ToolRuntime 注入 state、runtime context、store、stream writer、execution/server info;这些参数对模型隐藏,避免模型伪造用户 ID、数据库连接等可信依赖。
  • 工具结果可为字符串、结构化对象或多模态 content blocks;需要修改 state 时返回 Command,并按需附带与当前 tool_call_id 对应的 ToolMessage。
  • return_direct=True 会跳过后续模型总结并立即结束循环,只用于结果已是最终用户输出的窄场景。
  • 异常重试、错误消息脱敏和 fallback 放在 middleware;不要把原始异常、内部 SQL、凭证或堆栈直接暴露给模型。

动态工具与执行位置

工具过多会增大 token 成本并降低选择准确率。两类动态策略:

  1. 所有工具预注册,根据认证状态、权限、feature flag 或会话阶段过滤暴露给模型的子集;
  2. 运行时从 MCP/registry 等来源注册新工具,同时严格验证 schema、来源与权限。

执行位置也分三类:

  • 普通工具:应用服务端执行;
  • headless tool:服务端只注册 schema,调用时 interrupt,由浏览器/设备实现后 resume;适合 geolocation、clipboard、IndexedDB 等本地能力;
  • provider server-side tool:模型提供商执行其内置搜索、代码解释器等能力。

不要用一个“执行任意代码”的巨型工具代替多个窄、可审计的 typed tools。

生产级 harness 关注点

create_agent 的可配置能力可分为:

  • 执行环境:工具、文件系统、sandbox、代码执行;
  • 上下文:消息修剪/总结、memory、skills、prompt cache;
  • 计划与委派:todo、subagent;
  • 容错:model/tool retry、fallback、调用次数上限;
  • guardrail:PII、内容与业务规则;
  • steering:对写文件、发送消息、执行 SQL 等高风险工具设置 HITL。

这些都应通过聚焦、可组合的 middleware 加入,不要把权限、安全、重试全部塞进 system prompt。

逐页覆盖索引

页面学习结论
Agentsagent loop、核心配置、state/invocation/streaming,以及执行环境、上下文、委派、容错、guardrail、steering 的完整 harness 地图。
Models统一初始化与 invoke/stream/batch;tool calling、structured output、multimodal/reasoning、profiles、rate limit、proxy、token usage、动态模型选择。
Messages四种角色、tool-call 关联、metadata、chunk 累积与 provider-neutral content blocks。
Toolstool schema、runtime 注入、返回值/Command、异常处理、动态选择、headless 与 server-side 执行边界。

代码审查清单

  • ○ 工具参数是否做类型、枚举、长度、路径和权限校验?
  • ○ tool call 与 tool result 是否按 ID 正确关联?
  • ○ 多模态与结构化内容是否按 content blocks 处理,而非强转字符串?
  • ○ 外部调用是否有 timeout、有限重试、幂等与可观察性?
  • ○ 动态工具/模型选择是否受服务端可信 context 控制?
  • ○ 有副作用的工具是否具备最小权限、HITL、审计与失败恢复?

延伸