拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Agent Harness 跑单元测试中的 LLM 调用:Key 用 TaoToken

1. Agent Harness 单元测试跑通了为什么真实 LLM 调用还是翻车Agent Harness 是一类把 Agent 拆成 Agent Core、Tool Registry、Memory Store、Planner、Executor、Observer 等模块的开发框架适合用 Python pytest 做单元测试的团队。它的单元测试有个天然矛盾LLM 输出随机、外部 API 依赖不稳定所以大家都会用 Mock 把 LLM Client 和工具调用全部替换掉。Mock 让测试快、稳、可重复但也带来一个盲区——所有用例都绿了真实链路却可能因为 Base URL 写错、Key 没生效、请求格式不对而直接失败。我试过在 Agent Harness 项目里只跑 Mock 用例覆盖率报告很漂亮结果把 LLM Client 切到真实通道时返回体解析直接抛异常因为 Mock 里我手写的 JSON 结构和真实响应字段对不上。这类问题单元测试永远发现不了必须额外做一次真实调用验证。这篇就按这个思路写先按常规方式把 pytest Mock 用例写好保证 Agent Core、Tool Registry、Memory Store 的逻辑被锁定然后单独加一个“验证用量”的步骤把 LLM Client 的 Base URL 指向 TaoToken用同一个 Key 跑通一次真实请求确认返回结果和 Token 消耗记录都正常。这样既不干扰单元测试里的 Mock 逻辑又能补上“Mock 全过、真实调用却失败”的盲区。2. 前置准备TaoToken Key 与 LLM Client 配置TaoToken 在这里的角色是验证用的模型通道。你不需要改单元测试里的任何 Mock只需要在验证脚本或集成测试里把 LLM Client 的请求地址和 Key 换成 TaoToken 的配置。打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建账号并生成 Key。创建完成后在控制台复制 Key后面配置里会用到。Base URL 填https://taotoken.net/api注意这里不加/v1也不带任何 UTM 参数。很多 OpenAI 兼容客户端默认会在 Base URL 后面拼/v1/chat/completions如果你填了带/v1的地址最终路径就会变成/v1/v1/chat/completions直接 404。Key 的管理入口在 API Keys 页面接入文档在 doc 页面模型对话验证在模型对话页面。如果你后面要做长期编码或 Agent 任务可以看 Coding Plan如果只是验证链路用按量 Key 就够了。配置时建议把 Key 放在环境变量里不要硬编码进测试文件export TAOTOKEN_API_KEY你的Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api这样单元测试和验证脚本可以共用同一套环境变量Mock 用例不会去读它只有真实调用验证时才读取。3. 可复制配置LLM Client 指向 TaoToken假设你的 Agent Harness 里有一个llm_client.py原本指向外部 API。我们把它改成可配置的 Base URL默认走 Mock验证时走 TaoToken。# src/agent_harness/llm_client.py import os import json import requests from typing import Optional class LLMClient: def __init__(self, api_key: Optional[str] None, base_url: Optional[str] None): self.api_key api_key or os.getenv(TAOTOKEN_API_KEY) self.base_url base_url or os.getenv(TAOTOKEN_BASE_URL, https://taotoken.net/api) self.model gpt-4o-mini def generate(self, prompt: str, temperature: float 0.0) - str: url f{self.base_url}/chat/completions headers { Authorization: fBearer {self.api_key}, Content-Type: application/json, } payload { model: self.model, messages: [{role: user, content: prompt}], temperature: temperature, } resp requests.post(url, headersheaders, jsonpayload, timeout30) resp.raise_for_status() data resp.json() return data[choices][0][message][content]注意url的拼接方式base_url是https://taotoken.net/api后面直接接/chat/completions最终请求地址是https://taotoken.net/api/chat/completions。如果你用的 SDK 会自动补/v1那就把 Base URL 保持为https://taotoken.net/api让 SDK 去拼。单元测试里继续用 Mock不受影响# tests/unit/test_agent_core.py from unittest.mock import MagicMock from src.agent_harness.agent_core import AgentCore from src.agent_harness.llm_client import LLMClient def test_process_direct_response(): mock_llm MagicMock(specLLMClient) mock_llm.generate.return_value {response: 你好我是智能客服} mock_memory MagicMock() mock_memory.search.return_value [] agent AgentCore(llm_clientmock_llm, memory_storemock_memory) result agent.process(你好) assert result[response] 你好我是智能客服 mock_llm.generate.assert_called_once()这段用例不碰网络跑起来毫秒级完成。验证脚本单独写不放进tests/unit/避免污染单元测试的隔离性。4. 验证请求真实调用与 Token 消耗确认验证脚本放在scripts/verify_llm.py它复用同一个LLMClient但走真实网络# scripts/verify_llm.py import os import json from src.agent_harness.llm_client import LLMClient def main(): client LLMClient() prompt 请只返回 JSON{response: 验证成功} raw client.generate(prompt, temperature0.0) print(原始返回, raw) cleaned raw.strip().removeprefix(json).removesuffix().strip() data json.loads(cleaned) assert response in data, 返回体缺少 response 字段 print(解析结果, data) print(Base URL, client.base_url) print(Key 前缀, client.api_key[:8] ... if client.api_key else 未设置) if __name__ __main__: main()运行python scripts/verify_llm.py预期输出类似原始返回 {response: 验证成功} 解析结果 {response: 验证成功} Base URL https://taotoken.net/api Key 前缀 sk-xxxxx...如果返回体里带了 Markdown 代码块标记脚本里的removeprefix/removesuffix会处理掉。这一步验证了三件事Key 有效、Base URL 正确、返回结构能被 Agent Core 的解析逻辑消费。接着去控制台看用量记录确认这次请求的 Token 消耗被正常统计。如果用量页面没有新增记录说明请求可能没真正打到通道上或者 Key 被用在了别的地址。验证通过后你可以把这次真实返回的 JSON 结构复制回单元测试的 Mock 返回值里让 Mock 数据和真实响应保持一致。这是 Mock 测试和真实验证之间最实用的联动方式。5. 本篇常见错排查5.1 404 或路径重复最常见的原因是 Base URL 填成了https://taotoken.net/api/v1而客户端又自动拼了/v1/chat/completions。解决方法是 Base URL 只填https://taotoken.net/api让客户端或 SDK 去补版本路径。如果你用的是 OpenAI Python SDK可以这样初始化from openai import OpenAI client OpenAI( api_keyos.getenv(TAOTOKEN_API_KEY), base_urlhttps://taotoken.net/api )5.2 401 未授权Key 没读到、Key 复制时带了空格、或者环境变量没生效。先在终端确认echo $TAOTOKEN_API_KEY如果输出为空说明环境变量没导出成功。Windows 下用set TAOTOKEN_API_KEY...Mac/Linux 用export。另外注意不要把 Key 写进pytest.ini或提交到仓库。5.3 Mock 用例被真实调用污染如果你在conftest.py里定义了全局的llm_clientfixture并且它直接实例化了真实LLMClient那么单元测试可能会意外发起网络请求。正确做法是单元测试里始终用MagicMock(specLLMClient)真实LLMClient只在验证脚本或集成测试里实例化。可以在pytest.ini里加标记区分[pytest] markers integration: 需要真实网络和 Key 的测试然后集成测试用pytest.mark.integration日常跑pytest -m not integration只跑 Mock 用例。5.4 返回体解析失败真实 LLM 返回的 JSON 可能被包在 Markdown 代码块里也可能前后有换行。Agent Core 的_parse_llm_response要做好清理去掉json和再strip()最后json.loads。如果解析仍然失败打印原始返回体对比 Mock 里的结构差异。5.5 用量记录对不上验证请求成功后去控制台看用量。如果记录延迟等几秒刷新。如果一直没有检查请求是否真的走了 TaoToken 的 Base URL而不是被本地代理或缓存拦截。可以在验证脚本里打印client.base_url确认。6. 拿到 Key 后怎么继续验证链路跑通后你的 Agent Harness 就有了两层保障单元测试用 Mock 锁定组件逻辑真实调用验证用 TaoToken 确认端到端可用。接下来可以按需分流排障和接入细节看 API Keys 页面和接入文档里面有针对不同客户端的 Base URL 配置说明。想快速验证模型返回效果用模型对话页面直接发请求不用写代码。如果你要做长期编码任务或 Agent 自动化Coding Plan 更适合持续调用场景。把验证脚本里的返回结构同步回 Mock 用例是保持测试和真实环境一致的关键动作。每次改 Prompt 或换模型后先跑一遍验证脚本再跑单元测试顺序不要反。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门