ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Natural-Language Agent Harnesses 论文笔记:用 TaoToken 统一 Key 跑通 IHR 最小验证

Natural-Language Agent Harnesses 论文笔记:用 TaoToken 统一 Key 跑通 IHR 最小验证 1. 为什么我想在本地复现 IHR从论文到工程落地的落差Natural-Language Agent HarnessesNLAH这篇论文最吸引我的地方是它把 Agent 系统里那层“看不见的控制逻辑”拎了出来。过去我们写 Agent调度规则、重试策略、角色分工全散落在 Python 代码、框架默认配置和运行时约定里。换一个框架整套 Harness 就得重写想对比两个 Harness 的差异只能靠读代码。NLAH 提出用一份结构化的自然语言文档来描述 Harness再配一个共享运行时 Intelligent Harness RuntimeIHR去解读和执行这个思路对做 Agent 工程的人很有参考价值。但论文归论文真正要判断 IHR 能不能迁移到自己的项目得先跑通一个最小验证。我关心的不是复现论文全部实验而是三件事一份 NLAH 文档能不能被 LLM 稳定读懂IHR 的父子代理调度和文件状态持久化能不能在本地跑起来从任务下发到结果回传这条链路用统一 Key 接入 LLM 后是否顺畅。这篇就按这个目标来给你一套可复制的配置和一次完整的验证动作。适合谁看正在做 Agent 编排、想引入自然语言 Harness 的开发者手里有多个模型 Key、想统一管理调用通道的人以及读过 NLAH 论文、想动手验证 IHR 思路的工程同学。核心检索词就是 Natural-Language Agent Harnesses、IHR 最小验证、统一 Key 接入 LLM。2. 用 TaoToken 统一 Key 接入 LLMIHR 运行时的前置准备IHR 运行时里有个关键角色叫 in-loop LLM它要不停解读 NLAH 文档、当前状态和 Runtime Charter。这意味着一次任务执行里会有大量 LLM 调用父代理调度要调、子代理干活要调、Verifier 校验可能还要调。如果每个子代理各接一个模型供应商Key 管理会非常乱。我的做法是用 TaoToken 作为统一 API 通道所有 LLM 调用走同一个 Base URL 和同一个 Key模型 ID 按角色区分。TaoToken 在这里扮演的是统一接入层它提供兼容常见 SDK 的 API 通道你不需要为每个模型单独维护一套鉴权逻辑。对 IHR 这种多代理、多轮调用的场景统一通道能省掉大量胶水代码。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI 端点是 https://taotoken.net/api这个不加 UTM。先说清楚 IHR 最小验证需要哪些组件。按论文描述IHR 把任务拆成父子代理父代理轻量只负责调度子代理干实际活。状态用文件持久化放在固定路径下便于重启和审计。每次行动前检查 contracts失败就按 failure taxonomy 处理。所以本地最小验证需要一份 NLAH 文档含 Contracts、Roles、Stage Structure、一个 Runtime Charter运行时通用规则、一个状态目录、以及一个能调 LLM 的客户端。我建议目录结构这样组织后面配置片段都基于这个路径ihr-demo/ ├── harness-skill/ │ └── SKILL.md # NLAH 文档 ├── runtime/ │ └── charter.md # Runtime Charter ├── state/ # 文件状态持久化目录 │ ├── task.json │ └── artifacts/ ├── scripts/ │ └── run_tests.py # Adapters/Scripts 里的确定性钩子 └── .env # 统一 Key 配置这里有个容易踩的坑论文里 NLAH 文档通常放在类似 harness-skill/SKILL.md 的路径IHR 运行时按约定去读。你如果改了文件名或路径运行时找不到文档就会直接报错。所以最小验证阶段路径和文件名尽量跟论文保持一致等跑通了再改。关于 Key 的获取去 TaoToken 控制台创建即可地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。创建后拿到 Key填进下面的 .env。模型 ID 建议至少准备两个一个给父代理调度用轻量、快一个给子代理干活用能力强。具体模型 ID 以你控制台里可用的为准不要照抄别人的。3. 可复制配置环境变量、Base URL 与 NLAH 文档片段这一节是全文最核心的部分所有片段都可以直接复制。先配环境变量我用 .env 管理避免 Key 硬编码进代码。# .env TAOTOKEN_API_KEYsk-你的Key TAOTOKEN_BASE_URLhttps://taotoken.net/api IHR_MODEL_PLANNER你的调度模型ID IHR_MODEL_SOLVER你的执行模型ID IHR_STATE_DIR./state IHR_HARNESS_PATH./harness-skill/SKILL.md IHR_CHARTER_PATH./runtime/charter.md如果你用 Python客户端初始化可以这样写关键是 base_url 指向统一通道import os from openai import OpenAI from dotenv import load_dotenv load_dotenv() client OpenAI( api_keyos.getenv(TAOTOKEN_API_KEY), base_urlos.getenv(TAOTOKEN_BASE_URL), ) def call_llm(model_id: str, messages: list, temperature: float 0.2): resp client.chat.completions.create( modelmodel_id, messagesmessages, temperaturetemperature, ) return resp.choices[0].message.content如果你用 Node.js等价配置如下// ihr-client.js import OpenAI from openai; import dotenv/config; const client new OpenAI({ apiKey: process.env.TAOTOKEN_API_KEY, baseURL: process.env.TAOTOKEN_BASE_URL, }); export async function callLLM(modelId, messages, temperature 0.2) { const resp await client.chat.completions.create({ model: modelId, messages, temperature, }); return resp.choices[0].message.content; }接下来是 NLAH 文档片段。按论文结构它包含 Contracts、Roles、Stage Structure、Adapters/Scripts、State Semantics、Failure Taxonomy。我写一份最小可用的 SKILL.md# SKILL: 最小代码生成与验证 Harness ## Contracts - 输入一个自然语言任务描述 - 输出必须生成有效 Python 文件 solution.py - 验证规则solution.py 必须能通过 scripts/run_tests.py - 停止条件测试通过或重试达到 3 次 - 重试次数3 ## Roles - Planner读取任务输出分步计划 - Solver按计划写 solution.py - Verifier运行 scripts/run_tests.py 并报告结果 - Debugger测试失败时修复 solution.py ## Stage Structure PLAN - EXECUTE - VERIFY - (失败则 REPAIR最多 3 次) ## Adapters/Scripts - run_testspython scripts/run_tests.py ## State Semantics - 状态持久化到 state/task.json - 产物写入 state/artifacts/ - 通过路径重新打开 artifact ## Failure Taxonomy - test_failure跳到 REPAIR 阶段 - tool_error重试一次 - contract_violation重新生成Runtime Charter 是运行时通用规则跟具体任务 Harness 分开避免污染。我写一份最小 charter.md# Runtime Charter 1. 每次行动前检查当前阶段的 Contracts。 2. 父代理只负责调度不直接产出业务产物。 3. 子代理产出必须写入 state/artifacts/。 4. 状态变更后立即写回 state/task.json。 5. 失败按 Failure Taxonomy 处理不得跳过。 6. 所有 LLM 调用走统一 API 通道。这里要提醒一点NLAH 文档里的 Contracts 和 Failure Taxonomy 是 IHR 判断流程走向的依据写得越明确运行时越稳定。我试过把“测试通过”写成模糊的“结果正确”运行时就会在 VERIFY 阶段反复纠结最后超时。所以验证规则一定要可执行比如绑定到具体脚本。4. 验证请求从任务下发到结果回传的一次完整动作配置齐了现在跑一次最小验证。目标是让 IHR 读 NLAH 文档按 PLAN - EXECUTE - VERIFY 走一遍最后回传结果。我写一个简化的调度脚本模拟父代理调度和子代理执行。# ihr_min.py import json import os import subprocess from pathlib import Path from ihr_client import call_llm STATE_DIR Path(os.getenv(IHR_STATE_DIR, ./state)) HARNESS Path(os.getenv(IHR_HARNESS_PATH)).read_text(encodingutf-8) CHARTER Path(os.getenv(IHR_CHARTER_PATH)).read_text(encodingutf-8) PLANNER os.getenv(IHR_MODEL_PLANNER) SOLVER os.getenv(IHR_MODEL_SOLVER) def load_state(): f STATE_DIR / task.json return json.loads(f.read_text(encodingutf-8)) if f.exists() else {stage: PLAN, retry: 0} def save_state(state): STATE_DIR.mkdir(exist_okTrue) (STATE_DIR / task.json).write_text(json.dumps(state, ensure_asciiFalse, indent2), encodingutf-8) def run_stage(state, task): stage state[stage] base [{role: system, content: CHARTER \n\n HARNESS}] if stage PLAN: msgs base [{role: user, content: f任务{task}\n请输出分步计划。}] plan call_llm(PLANNER, msgs) state[plan] plan state[stage] EXECUTE elif stage EXECUTE: msgs base [{role: user, content: f计划{state[plan]}\n请生成 solution.py 内容。}] code call_llm(SOLVER, msgs) art STATE_DIR / artifacts art.mkdir(parentsTrue, exist_okTrue) (art / solution.py).write_text(code, encodingutf-8) state[stage] VERIFY elif stage VERIFY: r subprocess.run([python, scripts/run_tests.py], capture_outputTrue, textTrue) state[verify_output] r.stdout r.stderr if r.returncode 0: state[stage] DONE else: state[stage] REPAIR elif stage REPAIR: if state[retry] 3: state[stage] FAILED else: state[retry] 1 state[stage] EXECUTE return state if __name__ __main__: task 写一个函数 add(a, b) 返回两数之和 state load_state() while state[stage] not in (DONE, FAILED): state run_stage(state, task) save_state(state) print(f当前阶段{state[stage]}重试{state[retry]}) print(最终状态, state[stage])配套的 scripts/run_tests.py 是个确定性钩子验证 solution.py 是否可用# scripts/run_tests.py import importlib.util import sys spec importlib.util.spec_from_file_location(solution, state/artifacts/solution.py) mod importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) assert mod.add(1, 2) 3, add(1,2) 应为 3 assert mod.add(-1, 1) 0, add(-1,1) 应为 0 print(测试通过)跑起来后你会看到阶段流转PLAN - EXECUTE - VERIFY - DONE。如果 solution.py 有问题会进入 REPAIR重试计数增加。整个过程状态都写在 state/task.json重启后能从上次阶段继续。这就是 IHR 文件状态持久化的价值可审计、可恢复。验证成功的标志是终端输出“最终状态DONE”并且 state/artifacts/solution.py 存在、能通过测试。如果卡在某个阶段先看 state/task.json 里的 stage 和 retry再对照下一节的排查表。5. 常见报错排查401、local proxy failed 与 reading choices跑 IHR 最小验证时报错基本集中在接入层和解析层。我整理了几个真实遇到的对照着查。401 Unauthorized 是最常见的。原因通常是 Key 没填对、.env 没加载、或者 Base URL 写错。检查顺序先确认 TAOTOKEN_API_KEY 没有多余空格再确认 base_url 是 https://taotoken.net/api不要漏掉 /api最后确认代码里 load_dotenv() 在读取环境变量之前执行。如果你用 Node.js确认 import dotenv/config 在客户端初始化之前。local proxy failed 这类报错通常出现在客户端尝试走本地代理但代理没起来。检查你的运行环境有没有设置 HTTP_PROXY / HTTPS_PROXY 环境变量如果有但代理不可用就会失败。最小验证阶段建议清掉这些变量让请求直连统一通道。另外确认 base_url 没有写成带端口号的本地地址。reading choices 报错一般是响应结构不符合预期。可能原因模型 ID 写错返回了错误对象而不是正常 completion或者 messages 格式不对比如 system 消息放在了 user 之后。检查 call_llm 里 resp.choices[0].message.content 这一行如果 resp 里没有 choices 字段先打印 resp 看实际返回。模型 ID 一定要用控制台里可用的不要凭记忆写。OAuth 相关报错多见于某些 SDK 默认走了 OAuth 流程。如果你用的是 OpenAI 兼容客户端确认只传了 api_key没有触发其他鉴权方式。如果 SDK 版本较新检查是否有额外的 auth 配置项被默认开启。还有一类是 NLAH 文档解析失败运行时读不到 SKILL.md或者文档结构缺了 Contracts。检查 IHR_HARNESS_PATH 指向的路径是否存在文件里是否有 Contracts、Roles、Stage Structure 这几个关键段落。缺了 Contracts运行时无法判断停止条件会一直循环。报错关键词可能原因排查动作401Key 错误或未加载检查 .env、base_url、load_dotenv 顺序local proxy failed代理环境变量干扰清空 HTTP_PROXY/HTTPS_PROXYreading choices模型 ID 或 messages 格式错打印 resp核对模型 IDOAuthSDK 默认鉴权方式只传 api_key检查 SDK 配置文档解析失败路径错或缺 Contracts核对 IHR_HARNESS_PATH 和文档结构排查时建议把每次 LLM 调用的原始响应打到日志里IHR 多轮调用下定位问题靠日志比靠猜快得多。6. 把 IHR 思路迁移到自己的 Agent 项目跑通最小验证后我对 NLAH 和 IHR 的工程价值有了更具体的判断。论文里提到 Harness 显著改变了行为工具调用、LLM 调用、运行时间但 Performance 变化不大有些模块如 verifier 因为 overhead 在小样本上反而没明显提升。我在最小验证里也感受到类似现象加了 Verifier 和 REPAIR 后流程更可控、可审计但单次任务的总调用次数明显上升。所以迁移到自己的项目时我的建议是分两步。第一步先把 Harness 的控制逻辑从代码里抽出来写成 NLAH 文档哪怕暂时不用 IHR 运行时这份文档本身就能提升可读性和可迁移性。第二步再引入 IHR 式的运行时重点用它的文件状态持久化和 failure taxonomy这两块对长任务和可恢复性帮助最大。Verifier 这类高 overhead 模块可以按任务复杂度选择性开启不必默认全上。统一 Key 接入这块TaoToken 的 API 通道在 IHR 场景下确实省事所有子代理共用一个 Base URL 和 Key模型 ID 按角色分配即可。如果你要长期跑 Agent 任务可以看看 Coding Plan地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI Keys 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。想先验证模型对话效果可以用 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。最后说个实用技巧NLAH 文档里的 Failure Taxonomy 不要一次写全先覆盖你实际遇到的两三类失败跑一段时间后再补。我一开始写了七八种失败类型结果运行时频繁在分类上纠结反而拖慢了流程。先窄后宽比一上来就追求完备更实用。
返回列表