ARTICLE DETAIL

资讯详情

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

Agent 加了检查:TypeScript 项目里用 TaoToken 统一 Key 的验证闭环

Agent 加了检查:TypeScript 项目里用 TaoToken 统一 Key 的验证闭环 1. 为什么 Agent 说“搞定了”却总翻车如果你正在用 TypeScript 写 Agent 项目大概率遇到过这种场景Agent 改完代码回你一句“任务完成”你满心欢喜去跑npm run build结果满屏红色类型错误。问题不在模型能力而在流程——它把“文件写进去了”当成了“任务做对了”。我试过在几个小 Agent 项目里复现这个坑发现根因很一致Agent 的完成信号是自证的。它写完文件、列一下目录、读一眼内容就认为验证通过。系统没有强制它跑真正的检查命令也没有在检查失败时把错误反馈回去让它继续修。于是“假完成”成了默认行为。这篇要解决的就是这件事在 TypeScript Agent 项目里用 npm scripts 搭一道检查门禁让 Agent 在声称完成之前必须先过类型检查和验证脚本不通过就阻断完成信号。同时把模型调用统一走 TaoToken 的 Key避免每个脚本里散落不同的 API 配置。适合正在做 Agent 工具链、想让“完成”这个词变得可信的开发者。核心检索词先摆出来Agent 检查、TypeScript 验证、npm 脚本门禁、TaoToken 统一 Key。下面从环境准备到可复制配置再到验证请求和排错一步步落地。2. TaoToken 前置统一 Key 与环境变量在讲门禁之前先把 Key 的事情理清楚。Agent 项目里通常有多个入口会调模型主循环、验证脚本、可能还有单独的修复脚本。如果每个地方都硬编码 Key 或者读不同的环境变量排查问题时会很痛苦。统一走 TaoToken 的 API用一个环境变量管住所有调用点是后面验证闭环能稳定跑的前提。TaoToken 的 API 地址是https://taotoken.net/api兼容常见的 OpenAI 风格调用方式。你需要在项目根目录建一个.env文件记得加进.gitignore里面放统一 Key# .env TAOTOKEN_API_KEYsk-你的实际Key TAOTOKEN_BASE_URLhttps://taotoken.net/api然后在 TypeScript 代码里统一读取。建议封装一个src/llm/client.ts所有模型调用都从这里走// src/llm/client.ts import OpenAI from openai; const apiKey process.env.TAOTOKEN_API_KEY; const baseURL process.env.TAOTOKEN_BASE_URL ?? https://taotoken.net/api; if (!apiKey) { throw new Error(缺少 TAOTOKEN_API_KEY请检查 .env 配置); } export const llm new OpenAI({ apiKey, baseURL });这样验证脚本、修复脚本、主循环用的都是同一个 clientKey 只在一处配置。如果你还没有 Key可以去 TaoToken 的 API Keys 页面创建一个https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentapikeys 。创建后直接填进.env即可。注意不要把.env提交到仓库也不要在日志里打印完整 Key。验证脚本输出时只打印 Key 是否存在不打印内容。3. 可复制配置package.json scripts 骨架门禁的核心在 npm scripts。思路是把“检查”拆成几个可组合的命令Agent 完成信号触发时跑verifyverify内部先跑类型检查再跑自定义验证脚本。任何一步非零退出整个verify就失败完成信号被阻断。下面是我在项目里实际用的package.jsonscripts 骨架你可以直接复制{ name: agent-verify-demo, version: 1.0.0, type: module, scripts: { typecheck: tsc --noEmit, lint: eslint \src/**/*.ts\, verify:agent: tsx scripts/verify-agent.ts, verify: npm run typecheck npm run lint npm run verify:agent, agent: tsx src/main.ts }, devDependencies: { typescript: ^5.4.0, tsx: ^4.7.0, eslint: ^8.57.0, typescript-eslint/parser: ^7.0.0, typescript-eslint/eslint-plugin: ^7.0.0 }, dependencies: { openai: ^4.40.0, dotenv: ^16.4.0 } }几个关键点说明一下。typecheck用tsc --noEmit只做类型检查不产出文件速度快适合门禁。verify:agent是自定义验证脚本用来检查 Agent 产出的文件是否符合预期比如某个导出是否存在、某个函数签名是否正确。verify把三者串起来用保证前一步失败就中断。tsconfig.json也要配好确保tsc --noEmit能覆盖到 Agent 生成的文件{ compilerOptions: { target: ES2022, module: ESNext, moduleResolution: Bundler, strict: true, noEmit: true, skipLibCheck: true, esModuleInterop: true, resolveJsonModule: true, include: [src/**/*.ts, scripts/**/*.ts, exports/**/*.ts] } }注意include里加了exports/**/*.ts因为 Agent 经常把生成的文件写到exports/目录。如果漏了这个路径类型检查根本扫不到 Agent 的产出门禁就是摆设。自定义验证脚本scripts/verify-agent.ts可以这样写// scripts/verify-agent.ts import { existsSync, readFileSync } from node:fs; import { resolve } from node:path; const target resolve(process.cwd(), exports/blog_verify_bad.ts); if (!existsSync(target)) { console.error([verify] 目标文件不存在:, target); process.exit(1); } const content readFileSync(target, utf-8); // 检查是否包含明显的类型错误写法示例规则 if (content.includes(not-a-number)) { console.error([verify] 检测到类型不匹配的赋值检查未通过); process.exit(2); } console.log([verify] 自定义验证通过);这个脚本故意留了一条规则如果文件里出现not-a-number这种明显类型不匹配的赋值直接退出码 2。这样即使tsc因为某些配置没扫到自定义脚本也能兜底。4. 验证请求跑一次 npm run verify 看结果配置好了来实际跑一次。先制造一个“坏文件”模拟 Agent 声称完成但代码有问题的场景mkdir -p exports cat exports/blog_verify_bad.ts EOF export const x: number not-a-number; EOF然后执行门禁npm run verify预期输出会是这样typecheck先报类型错误 agent-verify-demo1.0.0 typecheck tsc --noEmit exports/blog_verify_bad.ts:1:7 - error TS2322: Type string is not assignable to type number. 1 export const x: number not-a-number; ~ Found 1 error in the same file.因为tsc返回非零退出码后面的lint和verify:agent不会执行整个npm run verify失败。这就是门禁生效的表现检查不过完成信号被阻断。现在把文件改对cat exports/blog_verify_bad.ts EOF export const x: number 42; EOF npm run verify这次输出会一路绿到底 tsc --noEmit eslint src/**/*.ts tsx scripts/verify-agent.ts [verify] 自定义验证通过看到[verify] 自定义验证通过并且退出码为 0才允许 Agent 对外说“完成”。如果你在 Agent 主循环里接入这个逻辑可以在它准备输出完成信号前调用npm run verify捕获退出码非零就把 stderr 摘要塞回给模型让它继续修。关于模型调用如果你想在验证脚本里用模型做语义级检查可以走 TaoToken 的模型对话接口统一用前面配好的 client。需要调试模型行为时模型对话页面在https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentmodels 。长期跑编码类 Agent 任务的话Coding Plan 更适合持续调用https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentcodingplan 。5. 本篇常见错排查门禁跑不起来通常卡在几个固定位置。下面按我踩过的坑列一下。错误一tsc报 “Cannot find module” 但文件明明存在。多半是tsconfig.json的include没覆盖到 Agent 的输出目录。检查include数组里有没有exports/**/*.ts或你实际用的目录。另一个可能是moduleResolution设成了Node而项目用了 ESM改成Bundler或NodeNext试试。错误二npm run verify里没生效前一步失败后面还在跑。检查是不是在 Windows 的 cmd 里跑cmd 对的支持和 bash 不同。建议统一在 Git Bash 或 WSL 里执行或者用npm-run-all这类工具替代。错误三环境变量读不到client 初始化就抛错。确认.env在项目根目录并且入口文件顶部有import dotenv/config;。如果用的是tsx直接跑脚本dotenv 不会自动加载必须显式引入。另外确认TAOTOKEN_BASE_URL没有多余空格。错误四自定义验证脚本退出码不对明明失败了却返回 0。Node 里process.exit(1)才是失败console.error不会改变退出码。检查每个失败分支是否都调用了process.exit并传了非零值。另外tsx执行时如果脚本抛未捕获异常退出码也是非零但错误信息可能不直观建议用 try/catch 包住主逻辑。错误五Agent 用花活命令绕过检查。比如它不跑npm run verify而是自己拼一个echo pass。解决办法是把验证逻辑收进 Agent 的工具层只暴露一个run_verify工具内部固定执行npm run verify不让模型自由拼命令。这样它没有绕过空间。提示排障时先把npm run typecheck单独跑通再跑npm run verify。分层定位比一上来跑全量快得多。6. 把门禁接进 Agent 主循环配置和验证都跑通后最后一步是把它接进 Agent 的完成信号逻辑。核心原则只有一条模型不能自己宣布完成必须由外部检查命令的退出码来裁决。在src/main.ts里可以这样处理// src/main.ts import { execSync } from node:child_process; function runVerify(): { ok: boolean; output: string } { try { const output execSync(npm run verify, { encoding: utf-8, stdio: pipe, }); return { ok: true, output }; } catch (err: any) { const output (err.stdout ?? ) (err.stderr ?? ); return { ok: false, output }; } } // 当模型输出包含完成意图时 const result runVerify(); if (!result.ok) { // 把错误摘要塞回对话让模型继续修 const feedback 检查未通过请根据以下错误继续修改\n${result.output.slice(0, 2000)}; // 将 feedback 作为下一条用户消息发回模型 } else { // 只有这里才允许输出“任务完成” }这段逻辑的关键在于runVerify的返回值决定后续走向模型没有投票权。检查失败时把 stderr 截断后回传模型看到具体错误再改改完再跑直到退出码为 0。如果来回多轮仍然失败就如实输出“检查未通过”而不是假装成功。如果你想让 Agent 在修复阶段调用模型统一走前面配好的 TaoToken client接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentdoc 。需要看完整 API 能力时API 入口是 https://taotoken.net/api 。Claude Code 相关的接入方式可以参考https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentclaudecode 。整套闭环跑下来你会发现“完成”这个词终于有了依据。检查不过就不许说完成——这不是给 Agent 加负担而是让它的输出变得可信任。
返回列表