【OpenClaw】通过Nanobot源码学习架构---(3)AgentLoop 配置与验证:TaoToken 统一 Key 接入 settings.json 骨架
发布时间:2026/9/29 5:11:04来源:尧图网络
1. 从 AgentLoop 源码看配置入口为什么 settings.json 才是架构的“总开关”OpenClaw 里的 Nanobot 是一套很典型的 Agent 运行时AgentLoop 是它真正干活的地方从消息总线收消息、拼上下文、调模型、执行工具、把结果写回会话再决定是继续循环还是收尾。很多人读源码时盯着_run_agent_loop()里的 while 循环看半天却忽略了这些行为其实都由一份配置驱动——模型是谁、走哪个 API 通道、最大迭代多少次、温度多少、工作目录在哪全部来自settings.json。这篇是系列第三篇聚焦 AgentLoop 的配置与验证。目标很明确给你一份可以直接复制的settings.json骨架把 TaoToken 的统一 Key 和 API 通道接进去然后教你用几个检查动作确认 AgentLoop 真的按这份配置加载起来了。适合正在读 Nanobot 源码、想在自己机器上复现架构理解的同学也适合已经跑通基础对话、准备把模型通道统一管理的开发者。读源码最怕“看懂了但跑不起来”。AgentLoop 的初始化参数有十几个散落在__init__里如果一个个手动传很容易漏。而settings.json的价值就在于它把 AgentLoop 关心的所有开关集中到一处加载器读完之后再分发给provider、context、tools这些组件。理解了这份配置你就理解了 AgentLoop 的“输入面”。2. TaoToken 前置统一 Key 与 API 通道在 AgentLoop 里的位置在 Nanobot 的架构里AgentLoop 本身不直接持有 API Key它拿到的是一个LLMProvider实例。Provider 负责和模型服务通信Key、Base URL、模型名这些都在 Provider 层。所以接入 TaoToken 的本质是让配置加载器构造出一个指向 TaoToken 的 Provider再交给 AgentLoop。TaoToken 在这里扮演的是统一模型通道一个 Key 可以覆盖多种模型Base URL 固定模型名通过参数切换。对 AgentLoop 来说它只关心provider.chat()能不能正常返回不关心背后是哪家模型。这种解耦正好符合 Nanobot “精简”的设计哲学——Agent 循环只管调度通道细节下沉到 Provider。你需要先拿到两样东西一个 API Key以及确认要用的模型名。Key 在控制台的 API Keys 页面创建模型名参考文档里的可用列表。这两样会写进settings.json的 provider 段。注意Key 属于敏感信息不要提交到 Git 仓库。建议用环境变量占位配置文件里只写引用名加载时再替换。相关入口我放在这里按需取用获取 API Keyhttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentsettings_jsonutm_campaignrewrite接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentsettings_jsonutm_campaignrewrite控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentsettings_jsonutm_campaignrewrite3. 可复制配置settings.json 骨架与 AgentLoop 字段映射下面这份骨架是按 Nanobot 的配置结构整理的字段名对齐 AgentLoop 初始化时读取的键。你可以直接复制把api_key和model换成自己的值。{ provider: { type: openai_compatible, base_url: https://taotoken.net/api, api_key: ${TAOTOKEN_API_KEY}, model: claude-sonnet-4-5, temperature: 0.1, max_tokens: 4096 }, agent: { max_iterations: 40, memory_window: 100, restrict_to_workspace: true, workspace: ./workspace }, tools: { exec: { timeout: 30, path_append: }, web_search: { api_key: } }, channels: { cli: { enabled: true } } }这份配置和 AgentLoop 的对应关系是这样的provider段决定LLMProvider怎么构造base_url指向 TaoToken 的 API 地址model决定self.modeltemperature和max_tokens直接传给provider.chat()。agent段里的max_iterations就是_run_agent_loop()里那个 while 循环的上限memory_window控制session.get_history()取多少条历史restrict_to_workspace决定文件工具是否被限制在workspace目录内。tools段对应_register_default_tools()里注册的那些工具。exec.timeout传给ExecToolweb_search.api_key传给WebSearchTool。如果你暂时不用搜索留空即可工具注册时不会因为空 Key 报错只是调用时返回失败。环境变量替换这一步取决于你的加载器实现。如果用的是标准 JSON 解析${TAOTOKEN_API_KEY}不会被自动替换需要在代码里做一层处理import json import os def load_settings(path: str) - dict: with open(path, r, encodingutf-8) as f: raw f.read() # 替换 ${VAR} 形式的环境变量占位 for key, value in os.environ.items(): raw raw.replace(f${{{key}}}, value) return json.loads(raw)这样 Key 就只存在于环境变量里配置文件可以安全地进版本库。设置环境变量的方式export TAOTOKEN_API_KEY你的KeyWindows 下用set TAOTOKEN_API_KEY你的Key或者写进系统环境变量。4. 验证请求确认 AgentLoop 按配置加载并跑通一次循环配置写好了接下来要验证 AgentLoop 真的读到了这些值。分三步走先验证 Provider 能通再验证 AgentLoop 初始化参数正确最后跑一次完整循环。第一步单独测 Provider。写一个最小脚本用同一份配置构造 Provider 并发一条消息import asyncio from nanobot.provider import LLMProvider async def main(): provider LLMProvider( base_urlhttps://taotoken.net/api, api_key你的Key, modelclaude-sonnet-4-5, ) resp await provider.chat( messages[{role: user, content: 只回复两个字收到}], tools[], modelclaude-sonnet-4-5, temperature0.1, max_tokens64, ) print(content:, resp.content) print(has_tool_calls:, resp.has_tool_calls) asyncio.run(main())如果打印出content: 收到说明通道是通的。这一步排除了 Key、Base URL、模型名的问题后面出问题就只可能是 AgentLoop 的配置加载。第二步验证 AgentLoop 初始化。在构造 AgentLoop 之后把关键属性打出来loop AgentLoop( busbus, providerprovider, workspacePath(./workspace), modelsettings[provider][model], max_iterationssettings[agent][max_iterations], temperaturesettings[provider][temperature], max_tokenssettings[provider][max_tokens], memory_windowsettings[agent][memory_window], restrict_to_workspacesettings[agent][restrict_to_workspace], ) print(model:, loop.model) print(max_iterations:, loop.max_iterations) print(temperature:, loop.temperature) print(memory_window:, loop.memory_window) print(tools:, list(loop.tools._tools.keys()))对照settings.json里的值逐个核对。tools那行会列出所有注册的工具名正常情况下能看到read_file、write_file、edit_file、list_dir、exec、web_search、web_fetch、message、spawn这些。如果少了某个说明对应的注册分支没走到回去检查配置字段名是否拼错。第三步跑一次完整循环。发一条会触发工具调用的消息比如让它读一个文件msg InboundMessage( channelcli, chat_idlocal, sender_idtester, content读一下 workspace/README.md 的前 5 行, ) await loop._dispatch(msg)观察日志里有没有Tool call: read_file(...)这一行。如果有说明_run_agent_loop()里的工具分支被正确执行了AgentLoop 的完整链路是通的。日志里还会打印Response to cli:tester:后面跟回复预览这就是最终返回。5. 本篇常见错排查AgentLoop 加载失败的几个典型现象配置和验证过程中最容易踩的坑集中在下面几类。现象一Provider 报 401 或鉴权失败。先确认环境变量有没有真正注入。在 Python 里print(os.environ.get(TAOTOKEN_API_KEY))看一下如果是None说明 export 没生效或者加载器没做替换。另一个常见原因是 Key 前后带了空格或换行从控制台复制时容易带上strip 一下再写进配置。现象二AgentLoop 初始化报TypeError: unexpected keyword argument。这通常是配置字段名和__init__参数名对不上。比如配置里写max_iter代码里是max_iterations就会报这个。对照第 3 节的字段映射表逐个核对或者直接看AgentLoop.__init__的签名。现象三工具列表为空。_register_default_tools()在__init__末尾调用如果它抛了异常但被吞掉工具就不会注册。检查exec_config是否正确构造ExecToolConfig的导入是运行时导入如果nanobot.config.schema路径不对会失败。另外restrict_to_workspace为 true 时workspace目录必须存在否则文件工具注册时可能报错。现象四循环跑满 max_iterations 还没结束。日志里会出现Max iterations (40) reached。这通常不是配置问题而是模型一直在调工具不返回最终答案。可以先把max_iterations调小到 5 观察行为确认是模型策略问题还是工具返回值有问题。工具返回内容过长也会让模型反复尝试检查ExecTool的输出有没有被截断。现象五/stop没反应。run()里用asyncio.wait_for(..., timeout1.0)保证每秒检查一次如果事件循环被阻塞/stop就处理不了。检查有没有在_dispatch之外的地方做了同步阻塞调用比如同步的文件读写或网络请求。提示排查时把日志级别调到 DEBUG_run_agent_loop()里每次provider.chat()的入参和返回都会打出来比猜快得多。6. 语义一致 CTA把配置跑通之后往哪走配置跑通、AgentLoop 能正常加载之后下一步通常是两件事一是把模型通道固定下来长期用二是开始做真正的编码或 Agent 任务。如果你主要在做模型验证和对话调试可以直接用模型对话页面快速切换模型对比效果https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentsettings_jsonutm_campaignrewrite如果你准备把 AgentLoop 用在长期编码任务上或者要跑多轮工具调用的 Agent 流程Coding Plan 更适合额度和通道都按长任务场景设计https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentsettings_jsonutm_campaignrewrite配置过程中如果遇到接入层面的报错先翻接入文档里的错误码对照https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentsettings_jsonutm_campaignrewrite我自己的习惯是每改一次settings.json先跑第 4 节的第一步 Provider 测试再跑第二步初始化检查最后才发消息。这三步顺序固定下来出问题能立刻定位到是哪一层比直接发消息看报错省时间。
网站建设高端定制企业官网