solon-ai-harness 的 Agent 每加一个模型就写一份 sk-?TaoToken 这样改 ChatConfig
当 HarnessEngine 里堆满 sk- 开头的硬编码问题就不在模型本身了用 Solon AI 4.0 的solon-ai-harness搭 Agent前几个modelAdd写起来确实顺手setApiUrl(https://api.deepseek.com)、setApiKey(sk-你的Key)、setModel(deepseek-chat)三行搞定一个模型。但当你按第 3.4 节配完多模型、又在第 10 节写代码审查 Agent 时会发现同一把 Key、同一套地址被抄了第三遍。更麻烦的是运行时切换——options().chatModel(engine.getModelOrMain(gpt-4o))想换模型得先回去确认那个ChatConfig里到底写的是哪家的 URL。模型地址和 Key 散落在 Java 代码里加一个模型就多一处硬编码长任务在会话窗口和压缩阈值下持续消耗 Token而配置本身却没有任何集中管理的地方。这篇就针对这个接入配置问题把solon-ai-harness的模型通道统一接到 TaoToken官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 所有setApiKey(sk-***)的那一步改成先注册创建 KeysetApiUrl一律填https://taotoken.net/apisetModel保持你原本要用的模型名。Harness 的工具权限、沙盒、拦截器、子代理、心智记忆全部照原文不动——TaoToken 在这里只提供 Key 和 Base URL不参与工具调用、会话存储或压缩策略。前置拿到一把 Key理解它替换了什么在动手改代码之前先把 TaoToken 在这个架构里的位置说清楚。solon-ai-harness的ChatConfig需要三个东西才能工作一个 API 地址、一个 API Key、一个模型名。原文里这三个值分别指向 DeepSeek、OpenAI 等各家官方端点每个模型一套。TaoToken 做的事情是把「地址」和「Key」这两项收敛成一份Base URLhttps://taotoken.net/api注意不带/v1也不加任何查询参数。ChatConfig.setApiUrl直接填这个值。API Key在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 注册后到控制台创建。多个modelAdd共用这一把 Key。模型名setModel保持你原本modelAdd中要用的模型名不变比如deepseek-chat、gpt-4o等。也就是说改动只发生在ChatConfig().then(slf - {...})这个 lambda 内部的两行setApiUrl和setApiKey。setModel不动HarnessEngine的其余构建链不动。如果你还没创建 Key先走这一步打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 完成注册。进入控制台在 API Keys 页面创建一个新 Key复制保存。这个 Key 就是后面所有setApiKey要填的值。控制台入口在这里https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite API Keys 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。接入相关的文档说明在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。可复制配置把每个 modelAdd 的地址和 Key 换掉下面按原文的结构给出改完之后的代码。核心原则只有一条凡是原文写setApiKey(sk-***)的地方都换成你从 TaoToken 创建的那把 Key凡是setApiUrl的地方都填https://taotoken.net/api。Hello World 的 engine 构建原文第 2 节的 Hello World改完后是这样import org.noear.solon.ai.agent.AgentSession; import org.noear.solon.ai.agent.session.InMemoryAgentSession; import org.noear.solon.ai.agent.session.AgentSessionProvider; import org.noear.solon.ai.chat.ChatConfig; import org.noear.solon.ai.harness.HarnessEngine; import org.noear.solon.ai.harness.permission.ToolPermission; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class DemoApp { public static void main(String[] arg) throws Throwable { AgentSessionProvider sessionProvider new AgentSessionProvider() { private final MapString, AgentSession sessionMap new ConcurrentHashMap(); Override public AgentSession getSession(String instanceId) { return sessionMap.computeIfAbsent( instanceId, k - InMemoryAgentSession.of(k) ); } }; HarnessEngine engine HarnessEngine.of(/data/work/, .tmp) .systemPrompt(你是一个 AI 助手请根据用户指令完成任务。) .sessionProvider(sessionProvider) .toolsAdd(ToolPermission.TOOL_PI) .modelAdd(new ChatConfig().then(slf - { slf.setApiUrl(https://taotoken.net/api); slf.setApiKey(YOUR_API_KEY); slf.setModel(deepseek-chat); })) .build(); engine.prompt(在当前目录下创建一个 README.md内容为 # Hello Harness) .call(); } }和原文唯一的差别就是setApiUrl和setApiKey两行。HarnessEngine.of的两个参数、sessionProvider、toolsAdd(ToolPermission.TOOL_PI)全部保持原样。多模型配置共用一把 Key原文第 3.4 节的多模型配置改完后.modelAdd(new ChatConfig().then(slf - { slf.setApiUrl(https://taotoken.net/api); slf.setApiKey(YOUR_API_KEY); slf.setModel(deepseek-chat); })) .modelAdd(new ChatConfig().then(slf - { slf.setApiUrl(https://taotoken.net/api); slf.setApiKey(YOUR_API_KEY); slf.setModel(gpt-4o); }))注意这里两个modelAdd用的是同一把 Key地址也是同一个。第一个添加的模型仍然是主模型运行时通过options()切换的逻辑不变engine.prompt(帮我重构 UserService 类的逻辑) .session(session) .options(o - { o.chatModel(engine.getModelOrMain(gpt-4o)); o.toolContextPut(HarnessEngine.ATTR_CWD, /data/projects/myapp); }) .call();engine.getModelOrMain(gpt-4o)拿到的仍然是你在第二个modelAdd里注册的那个模型只是它的地址和 Key 现在指向 TaoToken。代码审查 Agent 的完整配置原文第 10 节的代码审查 Agent改完后HarnessEngine engine HarnessEngine.of(/data/projects/myapp, .soloncode/) .systemPrompt(你是一个资深代码审查专家负责分析代码质量。) .sessionProvider(sessionProvider) .sessionWindowSize(12) .compressionThreshold(50, 40_000) .maxTurns(30) .autoRethink(true) .toolsAdd(ToolPermission.TOOL_PI) .modelAdd(new ChatConfig().then(slf - { slf.setApiUrl(https://taotoken.net/api); slf.setApiKey(YOUR_API_KEY); slf.setModel(deepseek-chat); })) .sandboxEnabled(true) .build();sessionWindowSize、compressionThreshold、maxTurns、autoRethink、sandboxEnabled这些全部照原文不动。TaoToken 不介入会话窗口管理也不影响压缩阈值的触发逻辑——它只是模型请求的出口。如果你用 CLI 方式接入如果你的场景涉及命令行工具可以这样装和跑npm i -g taotoken/taotoken taotoken cc -k YOUR_API_KEY -u https://taotoken.net/api -m deepseek-chat这里的-u同样填https://taotoken.net/api不带/v1。验证请求跑通 call() 和 stream()配置改完之后先验证最基本的同步调用能通。同步调用验证用 Hello World 的代码把engine.prompt(...).call()跑起来。如果控制台没有抛异常并且工作目录下出现了README.md说明模型通道已经通了。这一步验证的是ChatConfig里的地址和 Key 被正确使用。流式响应验证原文第 4.2 节的流式调用同样可以直接验证engine.prompt(分析当前项目的代码结构并生成文档).stream();流式模式下Agent 的推理过程会逐步输出。如果能看到内容持续吐出说明 TaoToken 的 Base URL 在流式场景下也工作正常。多模型切换验证在同一份HarnessEngine上先跑一次主模型再通过options()切到第二个模型AgentSession session engine.getSession(default); engine.prompt(用一句话说明当前项目用了什么构建工具) .session(session) .call(); engine.prompt(换一个模型重新回答上一个问题) .session(session) .options(o - o.chatModel(engine.getModelOrMain(gpt-4o))) .call();两次调用都能返回结果说明多个modelAdd共用一把 Key 的配置是有效的。在模型对话页做一次独立验证如果你想把「Key 是否有效」和「Harness 代码是否正确」分开排查可以先去模型对话页面单独发一条消息https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 。在对话页里选一个模型、发一句话如果能正常回复说明 Key 和地址没问题剩下的就是 Java 代码里的配置问题。本篇常见错排查改配置的过程中下面这几个错误最容易碰到。错误一setApiUrl 多写了 /v1https://taotoken.net/api是完整的 Base URL不要再拼/v1。如果你写成https://taotoken.net/api/v1请求路径会变成/api/v1/chat/completions这类形式和实际端点不匹配通常会返回 404 或路径错误。检查方法直接看你代码里setApiUrl的字符串确认结尾是/api后面没有任何东西。错误二Key 填成了别家的 sk-原文里每个setApiKey(sk-***)都要换成 TaoToken 创建的 Key。如果你只改了setApiUrl但忘了改setApiKey请求会带着旧 Key 发到新地址结果是 401 未授权。检查方法搜一遍代码里所有的setApiKey确认每一处都是同一把 TaoToken Key。错误三多个 modelAdd 用了不同的 Key虽然技术上可以每个modelAdd填不同的 Key但既然地址已经统一到 TaoTokenKey 也应该统一。混用会导致排查困难——你不知道是哪个模型的配置出了问题。检查方法把所有modelAdd里的setApiKey值对比一遍确保一致。错误四setModel 写成了 TaoToken 不支持的模型名setModel保持你原本要用的模型名。如果你在原文里写的是deepseek-chat改完后还是deepseek-chat。不要因为换了地址就改模型名。如果模型名本身写错了请求会返回模型不存在的错误。检查方法对照你原本modelAdd里的setModel值确认没有被改动。错误五运行时切换时 getModelOrMain 的参数对不上engine.getModelOrMain(gpt-4o)里的字符串必须和某个modelAdd中setModel的值完全一致。如果你在modelAdd里写的是gpt-4o切换时写gpt4o就找不到对应模型会回退到主模型或者报错。检查方法把getModelOrMain的参数和所有setModel的值列出来对比。错误六把 TaoToken 当成了工具调用的中间层需要明确TaoToken 只提供 Key 和 Base URL。Harness 的工具权限toolsAdd、disallowedToolsAdd、沙盒sandboxEnabled、拦截器压缩、停止循环、HITL、子代理、心智记忆这些全部由solon-ai-harness自己管理和 TaoToken 无关。如果你发现工具调用行为异常排查方向应该在 Harness 的配置上而不是 TaoToken。错误七会话窗口和压缩阈值导致的 Token 消耗误判原文里sessionWindowSize(8)和compressionThreshold(30, 30_000)控制的是会话历史窗口和压缩触发条件。长任务下这些参数会导致持续的模型调用从而消耗 Token。这是 Harness 的正常行为不是配置错误。如果你觉得消耗过快应该调整的是sessionWindowSize和compressionThreshold而不是怀疑 Key 或地址有问题。接入之后把配置集中到一处回到最初的问题每加一个模型就写一份sk-根源在于模型地址和 Key 散落在 Java 代码里。把setApiUrl统一成https://taotoken.net/api、setApiKey统一成一把 TaoToken Key 之后加新模型时你只需要在modelAdd里写setModel(新模型名)地址和 Key 两行可以复制粘贴不需要再去各家官方文档找端点。如果你后续要做长期的编码任务或者 Agent 开发可以考虑 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。它适合需要持续调用模型、又不想每次手动管理多把 Key 的场景。接入文档在这里https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite API Keys 管理页在这里https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。如果你在改ChatConfig的过程中遇到报错先去 API Keys 页面确认 Key 状态再对照上面的排查清单逐项检查。

相关新闻

从初三数学圆PDF到结构化题库:Python抽取与公式识别实战

从初三数学圆PDF到结构化题库:Python抽取与公式识别实战

简介:一份面向初三学生的圆专题数学练习资料,围绕中考常考的“圆”相关知识编排,适合课后巩固、考前强化及教师布置分层作业使用。整体以单个PDF文件打包,总大小仅147KB,内容紧凑、便于下载后按题目顺序逐题训练。其中…

2026/9/20 1:17:19 阅读更多 →
ZeroClaw SOP 外设信号触发器(Peripheral Fan-In)完全指南:board/signal 精确匹配、条件语法与未接线状态的实战处理

ZeroClaw SOP 外设信号触发器(Peripheral Fan-In)完全指南:board/signal 精确匹配、条件语法与未接线状态的实战处理

ZeroClaw SOP 外设信号触发器(Peripheral Fan-In)完全指南:board/signal 精确匹配、条件语法与未接线状态的实战处理 【免费下载链接】zeroclaw Fast, small, and fully autonomous AI personal assistant infrastructure, any OS, any platf…

2026/9/20 1:16:19 阅读更多 →
Chrome DevTools 深度实战:从入门到性能优化排查

Chrome DevTools 深度实战:从入门到性能优化排查

你要是问一个前端,Chrome 开发者工具(DevTools)对他意味着什么,有人会说是“审查元素”,有人会说是“看接口请求”,还有人只会打开 Console 看 console.log。回答到这个层面,基本就暴露了他的段…

2026/9/20 1:16:19 阅读更多 →

最新新闻

QQ空间历史说说导出:用GetQzonehistory三步把说说、配图、评论存成本地表

QQ空间历史说说导出:用GetQzonehistory三步把说说、配图、评论存成本地表

QQ空间历史说说导出:用GetQzonehistory三步把说说、配图、评论存成本地表 【免费下载链接】GetQzonehistory 获取QQ空间发布的历史说说 项目地址: https://gitcode.com/GitHub_Trending/ge/GetQzonehistory 准备换手机重装QQ前,我意识到QQ空间从没…

2026/9/20 5:27:32 阅读更多 →
攀爬机器人文献复现:从PDF综述到可验证模块的工程落地

攀爬机器人文献复现:从PDF综述到可验证模块的工程落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 5:27:32 阅读更多 →
AI论文写作工具全攻略:从文献管理到格式规范

AI论文写作工具全攻略:从文献管理到格式规范

1. 论文写作工具革命:当传统参考文献管理遇上AI去年指导学弟修改毕业论文时,他的参考文献部分突然全部变成乱码,距离查重只剩3天。这种崩溃场景每个写过论文的人都经历过——从格式调整到文献排序,手工操作不仅耗时耗力&#xff0…

2026/9/20 5:27:32 阅读更多 →
Java生产级日期与并发工具设计实战

Java生产级日期与并发工具设计实战

1. 这不是“工具类合集”,而是一套Java工程师的日常生存装备包你有没有过这种经历:凌晨两点改完线上Bug,发现又要写一个格式化日期的工具方法——明明三个月前在另一个项目里写过几乎一模一样的代码;又或者,在做订单超…

2026/9/20 5:27:32 阅读更多 →
免费窗口布局工具 FancyZones:3 分钟让窗口自动归位

免费窗口布局工具 FancyZones:3 分钟让窗口自动归位

免费窗口布局工具 FancyZones:3 分钟让窗口自动归位 【免费下载链接】PowerToys Microsoft PowerToys is a collection of utilities that supercharge productivity and customization on Windows 项目地址: https://gitcode.com/GitHub_Trending/po/PowerToys …

2026/9/20 5:27:32 阅读更多 →
文学创作中的环境描写与心理刻画技法

文学创作中的环境描写与心理刻画技法

1. 文学创作中的环境描写技法解析雨夜独行者的场景描写堪称环境描写的经典范例。这种通过外部环境映射人物内心的创作手法,在文学创作中被称为"客观对应物"理论——即用具体可感的物象来表现抽象的情感状态。路灯在湿漉漉的街道上摇曳的描写,不…

2026/9/20 5:26:32 阅读更多 →

日新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →