学习笔记 · Obsidian
Agent、Model、Message 与 Tool 核心原语
核心循环
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 成本并降低选择准确率。两类动态策略:
- 所有工具预注册,根据认证状态、权限、feature flag 或会话阶段过滤暴露给模型的子集;
- 运行时从 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。
逐页覆盖索引
| 页面 | 学习结论 |
|---|---|
| Agents | agent 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。 |
| Tools | tool schema、runtime 注入、返回值/Command、异常处理、动态选择、headless 与 server-side 执行边界。 |
代码审查清单
- ○ 工具参数是否做类型、枚举、长度、路径和权限校验?
- ○ tool call 与 tool result 是否按 ID 正确关联?
- ○ 多模态与结构化内容是否按 content blocks 处理,而非强转字符串?
- ○ 外部调用是否有 timeout、有限重试、幂等与可观察性?
- ○ 动态工具/模型选择是否受服务端可信 context 控制?
- ○ 有副作用的工具是否具备最小权限、HITL、审计与失败恢复?