首页/新闻资讯/正文详情

零基础复现Claude Code(五):终端篇——用TaoToken统一Key打通run_cmd执行命令链路

发布时间:2026/9/25 18:47:44 来源:云帆数科 栏目:资讯中心
零基础复现Claude Code(五):终端篇——用TaoToken统一Key打通run_cmd执行命令链路
1. 从“能改”到“能验证”终端执行到底解决了什么上一篇我们让 Agent 学会了读写文件它能真正动手改代码了。但改完代码之后呢它不知道改对了没有。就像一个实习生你让他修 Bug他埋头改完说“我改好了”你问“你跑过测试吗”他愣住“我只会改代码不会跑测试。”这一篇要补上的就是这条验证链路。核心是给 Agent 装一个run_cmd工具让它能执行终端命令——跑测试、看日志、列目录、查 Git 状态从而形成“读文件 → 改文件 → 跑测试 → 看结果 → 再调整”的完整闭环。这也是 Claude Code 终端执行能力最关键的跃升从盲改到验证式修改。命令执行是 Agent 所有工具里风险最高的一个。read_file最多泄露信息write_file改坏了还能靠备份恢复而run_cmd一旦执行了删除类命令可能造成不可逆的破坏。所以这一篇不只是教你怎么调subprocess更重要的是把安全边界设计清楚白名单 黑名单双重过滤、超时控制、输出截断一个都不能少。适合谁看已经跟完前四篇、手里有一个能读写文件的 ReAct Agent现在想让它具备终端执行能力的读者。如果你还没搭好前面的骨架建议先回看第 3、4 篇否则这一篇的代码会缺少落点。另外说明一下模型调用通道的问题。本地跑 Agent 时模型请求需要走一个统一的 API 入口。我这边用的是 TaoToken 的统一 Key 通道把模型调用和命令执行串在同一个循环里配置集中、切换模型方便。下面会给出可复制的配置骨架你照着填自己的 Key 就能跑。2. TaoToken 前置统一 Key 与 API 通道配置在写run_cmd之前先把模型调用这条线理顺。Agent 的每一轮循环都要请求模型如果 Key 和 Base URL 散落在代码各处后面调试会很痛苦。我的做法是集中到一个配置文件里代码只读配置不硬编码。2.1 获取统一 Key到 TaoToken 控制台创建一个 API Key。这个 Key 同时用于模型对话和后续的 Coding Plan 场景不用为每个模型单独申请。创建后复制保存后面填进配置文件。2.2 config.toml 骨架在项目根目录建一个config.toml把模型通道参数集中管理[llm] # TaoToken 统一 Key 通道 api_key sk-your-taoToken-key base_url https://api.taotoken.example/v1 model claude-3-5-sonnet max_tokens 4096 temperature 0.2 [agent] max_iterations 15 command_timeout 30 max_output_length 2000 workspace ./test_workspace这里几个参数和本篇强相关command_timeout控制单条命令最长执行时间防止cat /dev/random这类命令卡死max_output_length控制返回给模型的输出长度避免 Token 预算被一条ls -R /撑爆。2.3 settings.json 骨架如果你更习惯 JSON 配置或者要和已有的工具链对齐可以用settings.json{ llm: { api_key: sk-your-taoToken-key, base_url: https://api.taotoken.example/v1, model: claude-3-5-sonnet }, agent: { max_iterations: 15, command_timeout: 30, max_output_length: 2000, safe_commands: [ls, cat, grep, find, pytest, git], dangerous_commands: [rm, sudo, chmod, curl, wget] } }注意api_key不要提交到 Git。建议用环境变量覆盖或者把配置文件加进.gitignore。生产环境里更推荐从环境变量读取配置文件只留占位符。配置就绪后模型调用这条线就通了。接下来进入本篇的核心run_cmd工具的定义与落地。3. 可复制配置run_cmd 工具定义与 subprocess 落地这一节给出完整可跑的代码。目标是一个安全的run_cmd它接收命令字符串经过双重过滤后交给subprocess.run执行最后把截断后的输出返回给模型。3.1 安全策略定义先定义黑白名单和长度限制。原则是默认拒绝、显式允许——你没法穷举所有危险命令但可以穷举所有安全命令。import subprocess import shlex import os # 危险命令黑名单出现即拒绝 DANGEROUS_COMMANDS [ rm, rmdir, del, format, mkfs, dd, sudo, su, chmod, chown, curl, wget, , , |, ] # 安全命令白名单只允许这些 SAFE_COMMANDS [ ls, dir, pwd, cd, cat, head, tail, less, grep, find, wc, git, python, node, npm, pytest, jest, cargo, ] MAX_OUTPUT_LENGTH 2000 COMMAND_TIMEOUT 30黑名单里特意放了、、|这些重定向和管道符号因为它们可能覆盖文件或把危险命令串起来。curl、wget也禁掉避免 Agent 下载并执行外部代码。3.2 run_cmd 核心实现def run_cmd(command: str) - str: 执行 Shell 命令只读操作 command: 命令字符串如 ls -la 返回命令输出或错误信息 try: # 安全检查 1黑名单过滤 for dangerous in DANGEROUS_COMMANDS: if dangerous in command.lower(): return f拒绝执行命令包含危险操作 {dangerous} # 安全检查 2白名单验证 cmd_parts shlex.split(command) if not cmd_parts: return 错误空命令 base_cmd cmd_parts[0] if base_cmd not in SAFE_COMMANDS: return f拒绝执行{base_cmd} 不在安全命令列表中 # 执行命令 result subprocess.run( cmd_parts, capture_outputTrue, textTrue, timeoutCOMMAND_TIMEOUT, cwdos.getcwd(), ) # 合并 stdout 和 stderr output result.stdout if result.stderr: output f\n[stderr]: {result.stderr} # 截断过长输出 if len(output) MAX_OUTPUT_LENGTH: return f{output[:MAX_OUTPUT_LENGTH]}\n\n... (输出已截断共 {len(output)} 字符) return output if output else (命令执行成功无输出) except subprocess.TimeoutExpired: return 错误命令执行超时30 秒 except Exception as e: return f错误{str(e)}这段代码有几个关键点值得展开。第一用shlex.split把命令拆成列表而不是shellTrue直接丢字符串这样能避免命令注入。第二capture_outputTrue和textTrue配合直接拿到字符串形式的输出不用手动 decode。第三timeout是必须的没有它一条卡死的命令会让整个 Agent 停摆。3.3 集成到工具分发器把run_cmd挂到已有的execute_tool分发逻辑里def execute_tool(action: str) - str: tool_name, args parse_action(action) if tool_name is None: return f错误无法解析 Action - {action} if tool_name read_file: return read_file(args[0]) elif tool_name write_file: return write_file(args[0], args[1]) elif tool_name run_cmd: if len(args) ! 1: return 错误run_cmd 需要 1 个参数命令字符串 return run_cmd(args[0]) else: return f错误未知工具 - {tool_name}3.4 更新 System Prompt工具定义好了还要告诉模型它能用这个工具以及边界在哪self.system_prompt 你是一个 Python 工程师 Agent。 可用工具 - read_file(path): 读取文件内容 - write_file(path, content): 写入文件 - run_cmd(command): 执行 Shell 命令只读操作如 ls、cat、pytest 命令执行限制 - 只能执行安全的只读命令ls、cat、grep、pytest 等 - 禁止删除、修改权限、网络请求等危险操作 - 命令输出会被截断到 2000 字符 输出格式 Thought: [你的思考] Action: [工具调用] 到这里run_cmd的定义和落地就完成了。下一节做一次端到端验证看 Agent 能不能真的跑通“改代码 → 跑测试 → 验证”的闭环。4. 验证动作一次端到端命令执行闭环光看代码不够得让它跑起来。这一节用一个带 Bug 的计算器文件做验证观察 Agent 是否能在修改后主动执行pytest并读取结果。4.1 准备测试环境import os from react_agent import ReActAgent os.makedirs(test_workspace, exist_okTrue) with open(test_workspace/calculator.py, w) as f: f.write(def add(a, b): return a - b # Bug: 应该是加法 def test_add(): assert add(2, 3) 5 ) agent ReActAgent(max_iterations15) result agent.run( 请帮我修复 test_workspace/calculator.py 中的 Bug。 步骤 1. 读取文件找出 Bug 2. 修复 Bug 3. 运行 pytest 验证修复是否成功 ) print(f最终结果{result})4.2 预期执行过程运行后你应该看到类似下面的循环输出[第 1 轮] Thought: 我需要先读取文件看看代码有什么问题 Action: read_file(test_workspace/calculator.py) Observation: def add(a, b): return a - b ... [第 2 轮] Thought: 我看到了 Bugadd 函数应该返回 ab Action: write_file(test_workspace/calculator.py, ...) Observation: 成功文件已保存 [第 3 轮] Thought: 我应该运行 pytest 验证修复是否正确 Action: run_cmd(pytest test_workspace/calculator.py) Observation: 1 passed in 0.01s [第 4 轮] Thought: 测试通过了Bug 已成功修复 Answer: Bug 已修复pytest 测试通过。4.3 成功结果说明关键看第 3 轮Agent 主动调用了run_cmd(pytest ...)并且从 Observation 里读到了1 passed。这说明命令执行闭环打通了——模型不再只是“说改好了”而是能自己验证改对了没有。如果第 3 轮返回的是“拒绝执行”或“超时”说明安全策略或超时配置需要调整。如果返回的是截断提示说明输出确实太长截断策略生效了这是预期行为。提示验证时建议在专门的test_workspace目录里跑不要在主项目目录直接执行。命令执行的cwd是当前工作目录隔离环境能避免误操作。5. 本篇常见错排查命令执行这块坑不少下面几个是我实际调试时踩过的按出现频率排序。5.1 用 shellTrue 导致注入风险错误写法subprocess.run(command, shellTrue)这种写法会把整个字符串交给 shell 解析;、、|都能拼接额外命令等于把安全过滤绕过了。正确做法是用shlex.split拆成列表再传subprocess.run(shlex.split(command))5.2 忘记设置 timeout 导致卡死cat /dev/random或者一个等待输入的交互式命令会让subprocess.run永远不返回。表现是 Agent 停在那里不动日志也不再输出。排查时先看是不是某条命令没有超时保护。修复就是始终传timeout30并在except subprocess.TimeoutExpired里返回明确错误。5.3 白名单太宽松如果白名单里放了python模型可能生成python -c import os; os.system(rm -rf /)。虽然黑名单会拦rm但这类拼接方式很容易绕过。更稳的做法是只允许pytest这类特定测试命令或者对python -c、node -e单独禁用。5.4 没有截断输出导致 Token 爆炸ls -R /能输出几 MB 文本按 Token 换算成本很高还会直接超出模型上下文窗口。表现是模型请求报上下文超限或者响应变得极慢。修复就是加MAX_OUTPUT_LENGTH截断并在返回里带上“已截断”提示让模型知道输出不完整。5.5 命令执行目录不对subprocess.run默认继承当前进程的工作目录。如果 Agent 在项目根目录跑而测试文件在子目录pytest可能找不到文件。排查时先确认cwd参数或者让命令里带完整相对路径。我在验证时统一用test_workspace作为工作目录避免路径混乱。5.6 错误信息没有返回给模型如果except里只写pass模型拿不到失败原因就会反复重试同一个错误命令。正确做法是把异常信息拼成字符串返回模型看到“超时”或“拒绝执行”后能调整策略比如换一条命令或换参数。6. 语义一致 CTA把终端能力接进你的工作流到这里run_cmd的定义、安全策略、subprocess 落地和端到端验证都跑通了。你的 Agent 现在能完成“改代码 → 跑测试 → 看结果 → 再调整”的闭环这是从教学原型走向可用工具的关键一步。接下来按你的实际场景选下一步动作如果你在排障或接入阶段重点是先把 Key 和通道配通建议看 API Keys 与接入文档把config.toml里的base_url、api_key、model三个字段对齐再回来调run_cmd的超时和截断参数。如果你想先验证模型在终端场景下的对话表现比如让它解释一条命令的输出、判断测试失败原因可以直接用模型对话做几轮交互确认模型能正确理解stdout和stderr的区别。如果你打算长期做编码类 Agent或者要把这套循环接到更复杂的任务流里建议了解 Coding Plan它更适合多轮编码、工具调用密集的场景能减少每次手动配 Key 的重复工作。下一篇我们会把llm_client.py、tools.py、react_agent.py三个文件组装成统一的命令行入口加上配置加载和错误重试让它从“散装脚本”变成一个真正能用的 Mini Claude Code。终端篇的这块拼图先在这里落地。

相关推荐

从粒子探测器到云数据库:三个“Atlas”背后的核心技术全景
从粒子探测器到云数据库:三个“Atlas”背后的核心技术全景

如果你最近经常刷到“atlas”这个词,你的第一反应可能和我一样:到底是哪家的产品?是那个会后空翻的机器人,还是某个大型云数据库,或者是粒子物理实验里的巨型探测器?答案是:都有可能。这也是“a… · 2026/9/25 18:46:55

如何写好 Skills:用 TaoToken 统一 Key 打通 Agent 与 CC 的配置骨架
如何写好 Skills:用 TaoToken 统一 Key 打通 Agent 与 CC 的配置骨架

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

Docker 常见仓库与镜像使用指南(2026 实战版)
Docker 常见仓库与镜像使用指南(2026 实战版)

前阵子带一个新人,让他用 Docker 起个 MySQL,他从某篇博客抄了条命令:docker run --name some-mysql --link some-app:app -d mysql跑不通,来问我。我一看就知道这教程是七八年前的——--link 这个参数 Docker 官方早就标记废弃了… · 2026/9/25 18:46:43

工地人员管理还在 “靠喊“?建享云新品预告|AI 智能定位工牌即将上线,轻量化落地工地管理
工地人员管理还在 “靠喊“?建享云新品预告|AI 智能定位工牌即将上线,轻量化落地工地管理

导语:建筑工地属于人员流动性大、作业面分散、环境复杂的特殊场景,传统人工管理模式长期存在效率低、管控弱、数据缺的问题。多数项目至今依赖现场巡查、人工点名、口头调度、纸质台账管理,直接导致三大管理顽疾:看不见&#xff0… · 2026/9/25 19:11:35

想随时听自己的环境音?用 Moodist + 群晖搭一个可远程打开的白噪音页面!
想随时听自己的环境音?用 Moodist + 群晖搭一个可远程打开的白噪音页面!

文章目录前言1. Moodist 更像一个“环境音调音台”2. 先 SSH 登录群晖 NAS3. 给 Moodist 单独准备目录4. 拉取 Moodist 镜像5. 启动 Moodist 容器6. 先确认局域网页面能打开7. 为什么还要给 Moodist 加公网入口8. 在群晖上安装 cpolar 套件9. 在套件中心手动安装10. 先给 Moodi… · 2026/9/25 19:11:35

车辆管理系统网站源码
车辆管理系统网站源码

源码下载:download.csdn.net/download/m0_66047725/93483866 简介: 车辆管理系统网站源码 测试环境:Nginx PHP8.2 MySQL5.7 |模块|说明| |多租户(SaaS)|一套程序服务多家企业,数据按企业完全隔离&am… · 2026/9/25 19:11:29

Step 5 Preview 免费白嫖攻略:6000 亿参数旗舰模型,新用户最高 75 天免费用
Step 5 Preview 免费白嫖攻略:6000 亿参数旗舰模型,新用户最高 75 天免费用

Step 5 Preview 免费白嫖攻略:6000 亿参数旗舰模型,新用户最高 75 天免费用一句话速览:阶跃星辰 9 月 20 日发布旗舰基座模型 Step 5 Preview——600B 参数 MoE 架构、27B 激活、1M 上下文、AA 智能指数 44 分(开源前三&#xff0… · 2026/9/25 19:11:23

长假自驾跑长途,除碳这事可以提前排期!
长假自驾跑长途,除碳这事可以提前排期!

每次长假自驾前,总能见到这么一类车友:头天晚上收拾行李到半夜,临了往油箱里怼一瓶除碳剂,拍着油箱说“兄弟,路上辛苦你了”。结果上了高速跑两百公里进服务区,才后知后觉:这玩意儿刚要起效&… · 2026/9/25 19:11:05

闲鱼超级管家系统源码下载
闲鱼超级管家系统源码下载

源码下载:download.csdn.net/download/m0_66047725/93483853 简介: 闲鱼超级管家全面升级新版本,自动滑块、发货、评价、要花、擦亮通通稳定支持,时刻维护!时刻更新!坚决保证使用世界上最强 AI模型(5.6 s… · 2026/9/25 19:10:59

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

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

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

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

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

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

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码