资讯动态

港大开源 OpenHarness 深度拆解:用 Python 把 Agent 白盒化,TaoToken 统一 Key 打通 MCP 调用链

发布时间:2026/10/15 20:14:19 来源:尧图企业网站定制
1. 为什么要把 Agent 拆成「模型 Harness」两层OpenHarness 是香港大学数据科学研究所开源的一个 Agent Harness 项目用约 1.1 万行 Python 重新实现了 Claude Code 的核心骨架。它不是一个新模型也不是一个开箱即用的聊天工具而是一层「马甲」模型负责推理和决策Harness 负责给模型装上手、眼睛、记忆和安全边界。适合谁适合想搞清楚 Agent 内部到底怎么跑、想自己改工具调用逻辑、想把 MCP 服务接进一个可观测执行链的 Python 开发者。传统 Agent 框架的问题在于「黑盒感」太重。你给它一个任务它调了一堆工具最后返回结果中间发生了什么、哪一步触发了哪个工具、参数是什么、返回了什么、有没有被权限拦截全靠日志猜。OpenHarness 的设计理念是「The model is the agent. The code is the harness.」——把模型层和框架层彻底拆开框架层用纯 Python 写每个工具调用、每次权限检查、每条消息追加都是显式代码你可以打断点、可以改、可以替换。我试过把一个本地文件整理任务丢给默认配置的 Agent结果它在第三步就卡住了因为 Bash 工具被权限规则拦了。换成 OpenHarness 之后我能直接在execute_tool里打印tool_call的完整结构看到模型传的command参数里带了一个没转义的空格问题一目了然。这种「白盒化」不是口号是实实在在的调试效率提升。它的核心循环非常朴素while True: response await api.stream(messages, tools) if response.stop_reason ! tool_use: break for tool_call in response.tool_uses: result await harness.execute_tool(tool_call) messages.append(tool_results)模型决定「做什么」Harness 负责「怎么做」——包括参数校验、权限检查、执行、结果格式化、再塞回消息列表。这个循环里每一个箭头都是你可以插桩的地方。OpenHarness 围绕这个循环搭了 10 个子系统Engine、Tools43 个内置工具、Skills、Plugins、Permissions、Hooks、Commands、MCP、Memory、Coordinator。其中 MCP 子系统和 Permissions 子系统是本文重点因为前者决定你能不能接外部工具后者决定你敢不敢让 Agent 碰真实文件。如果你之前用过 Claude Code 或者 Cline会发现 OpenHarness 的插件格式、Skills 格式、甚至plugin.json的结构都高度兼容。这意味着你已有的生态积累可以直接迁移过来不用从零写工具描述。接下来我会从环境准备开始一步步把 OpenHarness 跑起来接上 TaoToken 的统一 Key再注册一个 MCP 服务最后验证整条调用链是否打通。2. TaoToken 统一 Key 的前置准备与 MCP 调用链设计在动手改 OpenHarness 配置之前先把「模型通道」这件事理清楚。OpenHarness 默认走 Anthropic 风格的 API 接口环境变量是ANTHROPIC_BASE_URL、ANTHROPIC_API_KEY、ANTHROPIC_MODEL三件套。如果你手头有多个模型供应商的 Key每换一个模型就要改一次环境变量、重启一次进程调试多工具编排时非常烦。TaoToken 在这里的角色是提供一个统一的 API 通道你只需要维护一个 Key就能在同一个 Base URL 下切换不同模型省掉反复改配置的麻烦。先明确三个东西的对应关系这是后面所有配置的基础配置项作用在 OpenHarness 中的位置Base URLAPI 请求的入口地址ANTHROPIC_BASE_URL环境变量API Key身份凭证ANTHROPIC_API_KEY环境变量Model ID指定调用的模型ANTHROPIC_MODEL环境变量TaoToken 的 API 入口是https://taotoken.net/api注意这个地址不带任何查询参数直接作为 Base URL 使用。Key 的获取在控制台的 API Keys 页面登录后创建一个新 Key复制出来保存好后面配置里要用。模型 ID 则根据你实际想调用的模型填写比如claude-sonnet-4-20250514这类标准 ID具体以模型对话页面或接入文档里列出的为准。为什么要在 OpenHarness 场景下强调统一 Key因为 MCP 调用链天然是多工具的。一个任务可能先调文件读取工具再调 MCP 提供的数据库查询工具再调 Web 搜索工具每一步都是一次独立的模型请求。如果每次请求都因为 Key 或 Base URL 不一致而失败排查成本会成倍上升。统一 Key 之后你只需要确认一个通道是通的剩下的问题就集中在 Harness 层和 MCP 服务本身。这里给一个最小化的环境变量配置你可以直接写进~/.zshrc或~/.bashrcexport ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEYsk-你的TaoTokenKey export ANTHROPIC_MODELclaude-sonnet-4-20250514写完之后执行source ~/.zshrc让配置生效。验证环境变量是否生效可以用echo $ANTHROPIC_BASE_URL确认输出是https://taotoken.net/api而不是空字符串。这一步看起来简单但后面 401 报错十有八九是这里没配对。关于 MCP 调用链的设计OpenHarness 的 MCP 子系统支持标准 Model Context Protocol 客户端可以接入外部 MCP 服务器。调用链大致是模型输出tool_use块 → Harness 识别这是 MCP 工具 → 转发给对应的 MCP 服务器 → 服务器执行并返回结果 → Harness 把结果格式化后追加到消息列表 → 模型继续推理。整条链路里Harness 是中枢MCP 服务器是外挂的手。你要做的就是把 MCP 服务器的注册信息写进 OpenHarness 的配置文件然后确认 Harness 能发现这些工具。如果你还没有 Key先去控制台创建一个如果已经有 Key 但不确定模型 ID 怎么写可以去模型对话页面发一条测试消息看看返回里用的模型标识是什么。接入文档里有完整的 Base URL 和参数说明遇到不确定的字段优先查文档不要靠猜。3. 可复制的 OpenHarness 配置片段与 MCP 服务注册这一节给可直接复制粘贴的配置。OpenHarness 的配置目录默认在~/.openharness/插件和 MCP 相关配置放在项目根目录的.openharness/下。先克隆项目并安装依赖git clone https://github.com/HKUDS/OpenHarness.git cd OpenHarness uv sync --extra dev安装完成后先确认oh命令可用。如果你激活了虚拟环境直接运行oh如果没激活用uv run oh。第一次运行会提示你配置模型但我们可以直接通过环境变量覆盖跳过交互式配置。接下来是权限配置。OpenHarness 的权限模式有三档Default写入/执行前询问、Auto全部允许适合沙箱、Plan阻止所有写入适合代码审查。调试阶段建议用 Default既能跑通流程又不会让 Agent 乱改文件。权限配置写在~/.openharness/settings.json里格式如下{ permission: { mode: default, path_rules: [ { pattern: /etc/*, allow: false }, { pattern: ./workspace/*, allow: true } ], denied_commands: [rm -rf /, DROP TABLE, shutdown] } }这个 JSON 里mode控制全局策略path_rules做路径级白名单和黑名单denied_commands是命令级硬拦截。注意path_rules的匹配是从左到右生效的所以把更具体的规则放在前面。我踩过的坑是把./workspace/*写成了workspace/*结果相对路径匹配不上Agent 一直提示权限不足。然后是 MCP 服务注册。OpenHarness 的 MCP 配置放在项目根目录的.openharness/mcp.json格式兼容主流 MCP 客户端{ mcpServers: { filesystem: { command: npx, args: [ -y, modelcontextprotocol/server-filesystem, /Users/yourname/workspace ] }, sqlite: { command: uvx, args: [ mcp-server-sqlite, --db-path, /Users/yourname/workspace/demo.db ] } } }这里注册了两个 MCP 服务filesystem 提供文件读写能力sqlite 提供数据库查询能力。command是启动命令args是参数数组。注意 filesystem 服务的最后一个参数是允许访问的根目录一定要写绝对路径写相对路径会导致服务启动后找不到目录。sqlite 服务用uvx启动前提是你本地装了 uv如果没有可以用npx替代但包名要换成对应的 npm 包。如果你用的是 Cline 或 Claude Code 的 MCP 配置可以直接把mcpServers这一段复制过来OpenHarness 的字段名和它们一致。这也是它兼容生态的一个体现。注册完成后运行oh plugin list可以看到已加载的插件运行oh mcp list如果版本支持可以看到已注册的 MCP 服务。如果命令不存在说明你的版本还没暴露这个子命令可以直接启动oh后在交互模式里用/mcp查看。最后补一个 Skills 的配置示例。Skills 是按需加载的领域知识放在~/.openharness/skills/下用 Markdown 文件定义--- name: db-query description: 安全地查询 SQLite 数据库并格式化结果 --- # DB Query Skill ## When to use 当用户要求查询本地 SQLite 数据库时使用。 ## Workflow 1. 先调用 sqlite MCP 的 list_tables 确认表结构 2. 根据用户问题生成 SELECT 语句禁止使用 DELETE/UPDATE 3. 执行查询并把结果整理成表格返回这个文件保存为~/.openharness/skills/db-query.md下次启动时 Harness 会根据任务描述自动决定是否加载。Skills 的好处是不用把领域知识硬编码进工具描述里模型只在需要时才看到这些指导。4. 验证请求从单次提示到 MCP 工具调用的完整链路配置写完之后先做最小连通性验证。用非交互模式发一条最简单的提示oh -p 用一句话解释什么是 Agent Harness如果返回了正常的文本回答说明 Base URL、Key、Model ID 三件套是通的。如果报 401先检查ANTHROPIC_API_KEY有没有多余空格如果报连接超时检查ANTHROPIC_BASE_URL是不是写成了带路径的形式正确写法就是https://taotoken.net/api不要在后面加/v1或/messages。连通之后测试 JSON 输出模式这个模式在脚本化调用时很有用oh -p 列出当前目录下的 Python 文件 --output-format json返回的 JSON 里会包含messages数组和tool_uses字段你可以清楚看到模型决定调用哪个工具、传了什么参数。这就是白盒化的第一个体现不用猜直接看结构化输出。接下来验证 MCP 工具是否被正确加载。发一条会触发 filesystem MCP 的提示oh -p 读取 workspace 目录下的 README.md 文件总结它的内容如果 MCP 注册成功你会看到执行过程中出现了mcp__filesystem__read_file这类工具调用。如果模型直接说「我无法访问文件系统」说明 MCP 服务没被 Harness 发现。这时候按顺序排查先确认.openharness/mcp.json的路径对不对必须在项目根目录再确认npx或uvx命令在 PATH 里可用最后手动跑一遍 MCP 服务的启动命令看它能不能独立启动。再测一个多工具编排的场景把文件读取和数据库查询串起来oh -p 读取 workspace 下的 schema.sql然后在 demo.db 里执行建表语句最后列出所有表这条提示会触发 filesystem 读取、sqlite 执行、sqlite 列表三个工具调用。执行过程中你可以观察消息列表是怎么一步步增长的模型先输出读取文件的 tool_useHarness 执行后把文件内容追加为 tool_result模型再输出执行 SQL 的 tool_use以此类推。如果中间某一步被权限拦截你会看到明确的拒绝信息而不是静默失败。流式模式适合观察实时事件oh -p 分析 workspace 下的代码结构 --output-format stream-json这个模式会逐行输出 JSON 事件包括message_start、content_block_delta、tool_use、tool_result等。你可以用jq过滤出工具调用事件oh -p 分析 workspace 下的代码结构 --output-format stream-json | jq select(.type tool_use)这样就能实时看到 Agent 每一步在调什么工具。实测下来这个组合是排查「Agent 为什么卡住」最快的方式——你直接看最后一个 tool_use 是什么就知道它卡在哪个工具上了。如果一切顺利你应该能看到完整的调用链模型推理 → 工具调用 → 结果回填 → 继续推理 → 最终回答。整条链路里TaoToken 负责模型通道OpenHarness 负责 Harness 层MCP 服务负责外部工具三者各司其职。5. 本篇常见报错排查401、local proxy failed 与 reading choices这一节按真实报错来。第一个高频错误是 401Error: 401 Unauthorized {error: {message: Invalid API key, type: authentication_error}}原因通常是三个Key 没设置、Key 有误、Key 前后有空格。排查顺序是先echo $ANTHROPIC_API_KEY确认非空再确认没有引号包裹有些 shell 会把引号也当成值的一部分最后去控制台重新生成一个 Key 替换。注意环境变量修改后要重新source或者开新终端旧终端里的进程不会自动读取新值。第二个错误是 local proxy failedError: local proxy failed: dial tcp 127.0.0.1:8080: connect: connection refused这个报错说明你的请求被转发到了一个本地端口但那个端口上没有服务在监听。常见原因是之前配置过某个本地代理工具环境变量里残留了HTTP_PROXY或HTTPS_PROXY。检查方式env | grep -i proxy如果有输出用unset HTTP_PROXY HTTPS_PROXY ALL_PROXY清掉然后重新运行。OpenHarness 本身不需要任何本地代理直连https://taotoken.net/api即可。第三个错误是 reading choicesError: reading choices: unexpected end of JSON input这个报错通常出现在流式响应解析阶段说明 Harness 收到的响应体不是合法的 JSON。可能原因有两个一是 Base URL 写错了请求打到了一个返回 HTML 的地址上二是模型 ID 不存在服务端返回了错误页而不是标准 JSON。排查方法是先用curl直接打一次 APIcurl -s https://taotoken.net/api/v1/messages \ -H x-api-key: $ANTHROPIC_API_KEY \ -H anthropic-version: 2023-06-01 \ -H content-type: application/json \ -d {model:$ANTHROPIC_MODEL,max_tokens:64,messages:[{role:user,content:hi}]}如果 curl 返回的是标准 JSON说明通道没问题问题在 OpenHarness 的解析逻辑或版本兼容性上如果 curl 也报错把返回体完整打印出来看错误信息。注意anthropic-version头是必须的缺了会返回 400。第四个错误是 OAuth 相关Error: OAuth token expired, please re-authenticateOpenHarness 兼容 Claude Code 的 OAuth 流程但如果你用的是 API Key 模式不应该触发 OAuth。出现这个报错说明配置里混入了 OAuth 凭证或者某个插件强制走了 OAuth 路径。检查~/.openharness/下有没有credentials.json之类的文件有的话临时移走强制走环境变量里的 API Key。第五个错误是 MCP 服务启动失败Error: MCP server filesystem failed to start: spawn npx ENOENT这是npx不在 PATH 里导致的。解决方法是用绝对路径或者先which npx确认位置把command字段改成绝对路径。Windows 上则是npx.cmd。同理uvx找不到就换成uv的绝对路径。排查这类问题的通用思路是分层验证先验证模型通道curl 打 API再验证 Harness 层oh -p单次提示再验证 MCP 层手动启动 MCP 服务最后验证组合链路多工具编排提示。哪一层断了就集中修那一层不要一上来就改配置。6. 把白盒 Agent 工作流固定下来的几个实用做法跑通之后建议把配置固化成可复用的模板。第一件事是把环境变量写进项目级的.env文件而不是全局 shell 配置这样不同项目可以用不同的 Key 和模型。OpenHarness 启动时会读取项目根目录的.env格式就是标准的KEYVALUE。第二件事是把常用的 MCP 服务注册和权限规则做成模板文件放在版本控制里。团队协作时每个人 clone 下来只需要填自己的 Key其余配置直接复用。权限规则尤其重要denied_commands里至少要有rm -rf /、DROP TABLE、shutdown这几条防止 Agent 在 Auto 模式下误操作。第三件事是用 Skills 沉淀领域知识。每次你发现 Agent 在某个任务上反复犯错就把正确的做法写成一个.md文件丢进~/.openharness/skills/。比如「生成 SQL 前必须先 list_tables」「改代码前必须先跑测试」这类约束写成 Skill 比写在提示词里更稳定因为 Skill 是按需加载的不会占用每次请求的上下文。第四件事是善用 Hooks。OpenHarness 支持 PreToolUse 和 PostToolUse 两个生命周期钩子你可以在工具执行前后插入自定义逻辑。比如在 PreToolUse 里记录每次工具调用的参数到日志文件在 PostToolUse 里检查返回结果是否包含敏感信息。Hooks 的配置写在.openharness/hooks/hooks.json格式和 Claude Code 兼容。最后如果你要把这套工作流用到长期编码或 Agent 编排场景可以考虑用 Coding Plan 来管理模型调用配额避免调试过程中频繁切换 Key。模型对话页面适合快速验证单个模型是否可用接入文档则是配置字段的权威参考。整条链路跑通之后你会发现 OpenHarness 的价值不在于它内置了多少工具而在于它把 Agent 的每一步都摊开在你面前——模型是模型代码是代码中间没有魔法。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑