项目:离线工具代理骨架

项目目标

不安装 LangChain、不调用模型、不使用密钥,亲手验证模型—工具循环中不随框架版本变化的责任:模型提出结构化调用,执行器严格校验,工具只在白名单内运行,观察通过 call ID 返回,运行时限制步数、工具数和重复调用,最终输出保留可审计轨迹。

项目不是“自己重写 LangChain”。它提供一个确定性对照组:迁移到 create_agent 或 LangGraph 后,若权限、错误、预算和测试边界消失,说明框架接入破坏了工程合同。

文件结构

00-初学者路线/examples/
├── offline_agent_loop.py       # 无依赖的模型桩、两个只读工具和有界循环
├── lcel_no_key.py              # 需要 langchain-core、但不需要模型密钥的 LCEL 示例
└── test_offline_agent_loop.py  # 63 项离线回归测试

循环的数据流

user message
    ↓
deterministic model stub
    ├─ final ───────────────→ done
    └─ tool_call
         ↓ exact schema + call ID
      allowlist executor
         ↓ argument validation
      calculator / local policy lookup
         ↓ ID-bound tool message
      model stub ───────────→ final

模型响应只允许 final 或 tool_call 两种精确形状。执行器不信任工具名和参数;工具消息必须带回相同 tool_call_id。默认 CLI 结果不输出原始 messages,避免把输入全文当作普通观测日志。

在 PowerShell 7 运行

以下每个代码块都从同时包含 docs/ 与 .website/ 的项目根目录运行;它们不依赖上一个代码块修改当前工作目录:

python -B .\docs\LangChain\00-初学者路线\examples\offline_agent_loop.py '计算 12 * (3 + 2)'  # 触发受限计算器工具,验证一次正常 tool call。
python -B .\docs\LangChain\00-初学者路线\examples\offline_agent_loop.py '查询政策 privacy'  # 触发只读本地政策检索,并检查返回的来源 ID。
python -B .\docs\LangChain\00-初学者路线\examples\offline_agent_loop.py '解释什么是工具调用'  # 验证无需工具时走直接回答分支。
python -B .\docs\LangChain\00-初学者路线\examples\offline_agent_loop.py --self-test  # 运行脚本内置的确定性自检,不访问网络或模型。

预期分别出现:一次 calculator 调用与结果 60;带 offline-policy:privacy:v1 来源的本地政策;不调用工具的直接回答;5 项显式自检通过。脚本不写文件、不联网。

安全计算器验证

python -B .\docs\LangChain\00-初学者路线\examples\offline_agent_loop.py "计算 __import__('os').getcwd()"  # 验证 AST allowlist 会拒绝函数调用,而不是执行系统访问。
python -B .\docs\LangChain\00-初学者路线\examples\offline_agent_loop.py '计算 2 ** 1000000'  # 验证资源风险极高的幂运算会被结构化拒绝。

计算器使用 Python AST allowlist,只接受有限数、加减乘除、整除、取模和一元正负。函数调用、属性、变量、幂运算、过长/过深表达式、除零、非有限数和过大结果都会变成结构化工具错误。它没有使用 eval。

LCEL 无密钥示例

lcel_no_key.py 演示 RunnableLambda | RunnableParallel。它不需要模型密钥,但需要项目实际安装 langchain-core。以下版本是 2026-07-19 的已验证快照,不是永久推荐值;新项目应重新查 PyPI、变更记录和 Python 约束。

# 一次性隔离运行,不在 vault 内创建 .venv
uv run --isolated --with 'langchain-core==1.4.9' python -B .\docs\LangChain\00-初学者路线\examples\lcel_no_key.py '  hello   agent  '  # 临时安装锁定 core 版本并运行无密钥 LCEL 示例。

若依赖不存在,脚本以退出码 4 和 dependency_missing 明确结束;这表示该分支被跳过,不能声称 LCEL 已运行。2026-07-22 已用 Python 3.11.9 与隔离的 langchain-core==1.4.9 实际运行,输出规范化文本 hello agent、字符数 11、词数 2。若改用持久 venv,必须在 vault 外的练习项目中创建,固定同一依赖并运行 python -m pip check;团队项目还应保存锁文件,在升级后重跑此示例和相邻测试。

对照 LangChain 概念

离线骨架LangChain / LangGraph 对应仍由应用负责
model_stubchat model response模型选择、版本和质量评测
validate_model_response消息/工具调用 schema业务枚举、事实和来源校验
TOOLS / ToolSpec@tool 与工具注册对象级授权、网络和副作用
execute_tool工具执行器 / middleware超时、幂等、凭据和隔离
tool_call_idAI tool call ↔ ToolMessage关联、审计和迟到结果
max_model_steps / max_tool_callsrecursion/运行预算成本、deadline 和人工出口
traceLangSmith 或自建观测脱敏、保留和业务 outcome

运行 63 项测试

$examples = '.\docs\LangChain\00-初学者路线\examples'  # 集中保存测试发现目录,避免重复书写长路径。
python -B -m unittest discover -s $examples -p 'test_*.py' -v  # 在普通模式发现并运行全部相邻测试。
python -B -O -m unittest discover -s $examples -p 'test_*.py' -v  # 验证生产校验不依赖裸 assert。
python -B -W error -m unittest discover -s $examples -p 'test_*.py' -v  # 把 warning 提升为失败,及早发现兼容性问题。
python -B -O -W error -m unittest discover -s $examples -p 'test_*.py' -v  # 组合两种严格运行条件完成回归验证。

测试覆盖:AST 资源限制、工具与参数 allowlist、消息精确形状、call ID 绑定、工具错误、直接回答、两种工具、步数和工具预算、重复调用停止、原始消息不进入默认 CLI 输出,以及 LCEL 依赖存在/缺失两种合法状态。-O 模式证明测试不依赖会被移除的裸 assert。基础环境中的 63 项绿灯可能包含 dependency_missing,因此必须把“核心离线循环通过”和“LCEL 在锁定依赖下通过”分开报告;后者已按上节命令独立验证。

综合扩展任务

增加一个只读 lookup_order 工具,但先写合同:

  1. order_id 的语法、长度和当前调用者授权如何验证?
  2. 哪些字段返回模型,哪些只作为 artifact 留在应用?
  3. 未找到、无权、暂时错误如何分类?
  4. 单次结果和总轨迹的大小限制是什么?
  5. 如何防止模型用另一个用户的订单 ID 越权查询?
  6. 新增正例、无权、非法 ID、未知工具、重复调用和预算耗尽测试。

如果把它改成写工具,必须另增预览、审批、幂等键、结果未知查询和完成验证;不能只把函数名从 lookup 改成 update。

项目验收

  • 三类示例路径产生预期工具数和终态。
  • 危险计算不会执行任意 Python。
  • 工具结果与原调用 ID 严格对应。
  • 未知工具、错误参数、重复调用与预算耗尽都失败关闭。
  • 63 项测试在 normal、-O、-W error 与 -O -W error 四种模式通过。
  • LCEL 示例在锁定的 langchain-core 环境中真实运行,而不是仅返回 dependency_missing。
  • 能说明离线骨架证明了什么,以及没有证明真实 LangChain API、模型质量或生产持久化。

下一步

先进入 Layer B:无密钥 create_agent 运行时合同,把框架无关工具循环映射到真实 LangChain harness;再进入 Layer C:LangGraph 可恢复审批流,把控制流映射到 StateGraph、SQLite checkpointer 与 interrupt。

资料基线

LangChain 概念文档核对日期:2026-07-14;langchain-core 包版本与 LCEL 实跑复核日期:2026-07-19。