点击蓝字
关注我们
第一期和第二期我们详细地了解了AI Agent CLI的整体架构、项目初始化、核心模块设计与完整代码。今天我们将继续探讨它的运行测试、进阶拓展与常见问题。
六、运行与测试
6.1 启动交互模式
# Windows PowerShell — Key 已在 .env 中时可省略$env:OPENAI_API_KEY="your-key"python agent_cli.py -v
预期交互:


在 Windows 上,模型应倾向使用 dir *.py 而非 ls(System Prompt 第 5 条 + GBK 解码共同保证可用性)。
6.2 单次提问模式
适合脚本调用或 CI 集成:
python agent_cli.py "读取 README.md 的前 3 段并总结"python agent_cli.py --max-steps 25"分析 tests 目录结构并给出测试建议"
单次模式下回答同样经 Markdown() 渲染;若管道重定向到文件,Rich 会输出 ANSI 码,可用 python agent_cli.py "..." > out.txt 或后续加 --no-markdown 开关(进阶扩展)。
6.3 建议的手动验收用例

6.4 单元测试
当前仓库 tests/test_agent.py:
from agent.tools.registry import ToolRegistryfrom agent.tools.shell_tools import register_shell_tools, run_shelldef test_run_shell():reg = ToolRegistry()register_shell_tools(reg)out = run_shell("echo hello")assert "hello" in out
运行:
pytest tests/ -v工具 handler 是纯函数,最适合单测。测完整 Agent 循环需要 mock LLM,MVP 阶段手动验收即可。
建议补充的测试(尚未入库,可自行添加):
def test_run_shell_timeout():out = run_shell("sleep 99", timeout=1)assert "超时" in out
在 Windows 上可把 sleep 99 换成 timeout /t 99 /nobreak 或 ping -n 99 127.0.0.1 > nul。
6.5 调试技巧
●开 -v:Rich 彩色看清每一步调了什么工具、返回什么。
●打印 messages:在 core.py 的循环里临时 import json; print(json.dumps(self.messages, ensure_ascii=False, indent=2)),对照 API 文档检查消息格式。
●API 报错 tool_call_id not found:几乎一定是 assistant 消息的 tool_calls 没正确写回 messages。
●模型从不调工具:检查 tools 是否传入、tool_choice 是否为 "auto"、system prompt 是否足够强调「必须用工具」。
●Windows 乱码:确认 shell_tools.py 使用 _decode_output,不要用固定 UTF-8 的 text=True。
●Markdown 显示异常:模型若返回非 Markdown 纯文本,Rich 也会正常显示;若代码块未闭合,渲染可能略丑,可 prompt 要求「代码用 markdown 代码块包裹」。
七、进阶扩展
按优先级排列,每一步都不破坏核心架构,只是在现有模块上「加一层」。
7.1 增加工具
新增工具的标准流程:
1、在 agent/tools/ 下写 handler 函数
2、写 register_xxx_tools(registry) 注册 schema
3、在 Agent.__init__ 里调用 register
示例 - 代码库搜索:
# agent/tools/search_tools.pyimport subprocessdef grep_repo(pattern: str, path: str = ".") -> str:proc = subprocess.run(["rg", "-n", pattern, path],capture_output=True, text=True, timeout=30,)return proc.stdoutor proc.stderror"(无匹配)"def register_search_tools(registry):registry.register(name="grep_repo",description="在代码库中按正则搜索文本",parameters={"type": "object","properties": {"pattern": {"type": "string", "description": "正则表达式"},"path": {"type": "string", "description": "搜索目录,默认当前目录"},},"required": ["pattern"],},handler=grep_repo,)
用 Python 实现的工具(glob、pathlib)比让模型写 shell 更跨平台,推荐优先封装。
7.2 工作目录沙箱
Agent 能跑 shell、能写文件,默认等于给了模型本机权限。最小防护是限制路径:
import osfrom pathlib import PathALLOWED_ROOT = Path(os.getenv("AGENT_WORKSPACE", ".")).resolve()def safe_path(path: str) -> Path:p = Path(path).expanduser().resolve()ifnot str(p).startswith(str(ALLOWED_ROOT)):raise PermissionError(f"路径越界: {p},允许范围: {ALLOWED_ROOT}")return p
在 read_file / write_file 开头调用 safe_path(path)。Shell 侧维护命令黑名单:rm -rf /、format、shutdown、mkfs 等一律拒绝。
7.3 危险操作人工确认
写入和执行类工具执行前询问用户:
⚠️ 即将执行 write_file(path="config.py", content="...")是否继续?[y/n]:
实现方式:给 ToolRegistry.register 加 permission 字段(READ / WRITE / EXECUTE),execute 里对 WRITE/EXECUTE 调 input() 或 Confirm.ask()(Rich)确认。拒绝时返回 "用户拒绝执行" 字符串,模型会收到并调整策略。
7.4 流式输出
最终回答用 stream=True 逐 token 打印,体验更接近 ChatGPT:
stream = client.chat.completions.create(..., stream=True)for chunk in stream:if chunk.choices[0].delta.content:print(chunk.choices[0].delta.content, end="", flush=True)
注意:流式模式下 tool_calls 是分块到达的,需要累积 name 和 arguments 字符串后再 parse。工具调用阶段建议仍用非流式,或参考 OpenAI 文档拼装 delta。流式与 Markdown() 冲突时,可仅对最终一轮非 tool 回复流式打印纯文本。
7.5 对话持久化与上下文裁剪
REPL 多轮对话会让 messages 无限增长。两个策略:
●Sliding window:保留 system + 最近 N 轮 user/assistant。
●Tool 结果压缩:久远的 role: tool 消息只留前 200 字符。
def trim_messages(messages, max_turns=10):system = messages[0]rest = messages[1:]return [system] + rest[-(max_turns * 4):]
7.6 多 Agent 协作
单个 Agent 类足够复用,换 system prompt 和工具集即可扮演不同角色:
●Planner Agent → 只输出步骤计划,不给工具
●Worker Agent → 完整工具集,执行子任务
●Critic Agent → 只读工具,审查 Worker 产出
在 CLI 层写 Orchestrator 调度:Planner 输出 plan → 拆成子任务 → Worker 逐个执行 → Critic 检查。每个 Agent 仍是同一个类,不需要新框架。
7.7 接入 MCP(Model Context Protocol)
MCP 是标准化的外部工具协议,生态里有 filesystem、git、database 等 Server。接入思路:
●用 mcp Python SDK 以 stdio 连接 MCP Server
●拉取 Server 暴露的工具列表
●动态转成 OpenAI function schema,注册进 ToolRegistry
●调用时转发给 MCP Server,结果字符串化后返回
这样你的 Agent CLI 可以复用 Cursor、Claude Desktop 同款工具生态,而不必每个集成自己写。
7.8 LLM 容错
生产环境建议给 LLMClient 加重试:
for attempt in range(3):try:return self.client.chat.completions.create(**kwargs)except RateLimitError:time.sleep(2 ** attempt)
429、5xx、网络抖动都应重试;401/404 不应重试。还可配置 OPENAI_FALLBACK_MODELS,主模型挂掉时依次尝试备用模型。
7.9 Rich 进阶
当前 MVP 已用 Rich 做基础美化,还可按需扩展:

Rich 与核心 Agent 逻辑解耦:只改 agent_cli.py 和 verbose 打印即可,不必动 ReAct 循环。
7.10 跨平台 list_dir 工具
即便有 OS 提示,模型仍可能误用 ls。可新增纯 Python 工具,彻底避免 shell 差异:
def list_dir(path: str = ".") -> str:p = Path(path).expanduser().resolve()ifnot p.is_dir():return f"不是目录: {p}"entries = sorted(p.iterdir(), key=lambda x: (not x.is_dir(), x.name.lower()))lines = [f"{'[DIR]'if e.is_dir() else'[FILE]'}{e.name}"for e in entries[:200]]return"\n".join(lines) or"(空目录)"
在 System Prompt 中加一条:「列目录优先用 list_dir,不要 run_shell」。
八、常见问题
Q1: 模型不调用工具,只瞎编答案?
原因:模型认为凭「知识」就能答,或 prompt 未强调必须用工具。
排查:
●确认 tools=self.registry.schemas 确实传入了 API
●System prompt 写「需要查看文件时必须 read_file,不要猜测」
●换更强的模型(gpt-4o、deepseek-chat / deepseek-v4 对 tool calling 支持更好)
●用户问题要具体:「分析 core.py」比「这个项目怎么样」更容易触发工具
Q2: 工具调用死循环?
现象:同一命令反复失败,模型不停止。
对策:
●max_steps 默认 15,硬性截断
●Prompt 写:「同一操作失败两次则停止并说明原因」
●进阶:在 registry 里记录已执行命令 hash,重复则直接返回「请勿重复调用」
Q3: Context 超长 / Token 爆掉?
●read_file 截断大文件(默认 8000 字符)
●run_shell 截断输出(默认 12000 字符)
●REPL 多轮后做 sliding window 或压缩旧 tool 结果
●选用 context 更大的模型,或把「读全文件再总结」拆成「分段读取」
Q4: Windows 与 Linux 命令差异?
模型训练数据偏 Linux,在 Windows 上可能写 ls、find 而失败。
解法(当前 MVP 已部分实现):
●System prompt 通过 sys.platform 自动注明 OS 和 shell 类型(见 prompts.py)
●run_shell 对 Windows 输出做 GBK/cp936 解码(见 shell_tools._decode_output)
●封装跨平台工具:用 Python glob.glob、pathlib.iterdir 代替 shell 列目录(见 7.10)
●提供 list_dir、grep 等纯 Python 工具,减少对 shell 的依赖
Q5: API 报错 Invalid parameter: messages?
多半是 messages 格式不对。常见错误:
●assistant 有 tool_calls 但后续缺少对应 tool 消息
●tool 消息的 tool_call_id 与 assistant 里的 id 不匹配
●把 OpenAI 对象直接 append 进 list 而非 dict
用 -v + 打印 messages 对照 OpenAI 文档排查。
Q6: 和 LangChain / AutoGPT 比,什么时候该换框架?

核心建议:先按本文跑通 300 行 MVP,理解消息流和 ReAct 环;真遇到框架能省大量时间的场景再引入,避免一开始就被抽象层淹没。
Q7: Windows 上 run_shell 输出乱码?
现象:dir、中文文件名等返回 `` 或不可读字符。
原因:cmd 默认代码页多为 GBK,旧版用 encoding="utf-8" 解 subprocess 会失败。
解决:使用当前 shell_tools.py 的 bytes + _decode_output 实现;勿改回 text=True, encoding="utf-8"。
Q8: Rich Markdown 在终端里显示不对?
●终端需支持 Unicode;Windows Terminal、新版 PowerShell 一般没问题。
●代码块需模型输出标准 ``` 围栏;否则按普通段落渲染。
●CI/日志收集可暂时不用 Markdown,直接 print(answer)。
●需要纯文本管道输出时,增加 --plain 开关(见 7.9)。
E n d
声明:本文为51Testing软件测试网 blues_C 用户投稿内容,该用户投稿时已经承诺独立承担涉及知识产权的相关法律责任,并且已经向51Testing承诺此文并无抄袭内容。发布本文的用途仅仅为学习交流,不做任何商用,未经授权请勿转载,否则作者和51Testing有权追究责任。如果您发现本公众号中有涉嫌抄袭的内容,欢迎发送邮件至:editor@51testing.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

夜雨聆风