1. 项目概述这不是“学个框架”而是重新理解“智能体如何真正工作”“学习 Agent Harness 笔记”这个标题乍看平平无奇像极了某位开发者随手记下的学习备忘录。但如果你在最近半年里持续关注大模型落地实践、智能体工程化或AI应用架构演进就会立刻意识到——这五个字背后站着一个正在快速成型的行业共识Agent 不再是 Demo 展示里的炫技脚本而是一套需要被系统性编排、可观测、可调试、可灰度发布的工程基础设施。Agent Harness 正是为解决这一核心矛盾而生的轻量级执行底座。它不替代 LangChain 或 LlamaIndex 这类功能丰富的 SDK也不对标 AutoGen 那种面向多智能体协作的复杂范式它的定位非常清晰给单个 Agent 提供最小可行的“运行沙盒”与“诊断接口”。你可以把它理解成智能体世界的“Postman DevTools 单元测试框架”三合一工具——没有花哨的 UI没有预设的 workflow 模板只有一组干净的 Python 接口、一套可插拔的观测钩子hook以及一个能让开发者在 5 分钟内跑通“输入 → 思考 → 工具调用 → 输出”全链路的最小闭环。我第一次在某开源项目 issue 区看到有人提 “Can we use Agent Harness for debugging tool calling latency?” 时就意识到这个项目已经悄然越过“玩具阶段”。它解决的不是“怎么让 Agent 动起来”而是“当 Agent 动得不对、动得太慢、动得不可信时我该看哪里、改什么、验证是否生效”。这种问题在真实业务中每天都在发生比如某电商客服 Agent 在调用库存查询 API 时偶发超时但日志只显示 “tool call failed”你根本不知道是网络抖动、参数拼错还是工具函数内部抛了未捕获异常又比如某数据分析 Agent 在处理用户模糊提问时反复生成无效的 SQL你无法判断是 prompt 设计缺陷、还是 LLM 对 schema 理解偏差、抑或是工具返回结果格式不一致导致解析失败。Agent Harness 的价值就体现在它把所有这些“黑箱时刻”强行拉到白光下它强制你在定义 Agent 时声明输入/输出 Schema自动记录每一次 LLM 调用的完整 prompt、响应、耗时、token 数精确捕获工具调用的入参、出参、执行时长、异常堆栈并允许你用标准 pytest 语法编写断言验证 Agent 行为是否符合预期。它不承诺让你写出完美的 Agent但它保证任何一次失败都有迹可循任何一次优化都有据可依。这份笔记就是我在两周内从零开始搭建、调试、压测并最终将一个金融问答 Agent 集成进生产环境监控体系的全过程复盘。它不讲抽象理论只记录每一个pip install命令背后的权衡每一行assert断言想验证的真实业务逻辑以及那些官方文档里绝不会写的、踩坑后才懂的硬核细节。2. 核心设计思路拆解为什么是 Harness而不是 Framework 或 SDK2.1 “Harness”一词的精准隐喻约束力与可见性并存在软件工程语境中“harness” 从来不是一个泛泛而谈的“框架”framework或“开发包”SDK。它的本意是“挽具”——一种套在马身上、用于控制方向、分配力量、同时让驭手能清晰感知马匹状态的物理装置。把这个概念迁移到智能体开发中其设计哲学就呼之欲出了Agent Harness 的核心使命不是赋予 Agent 更多能力而是为 Agent 的每一次“发力”提供可测量的约束与可观察的反馈。这直接决定了它与主流方案的根本差异。LangChain 是一个典型的“能力增强型” SDK。它提供了海量的工具链Tool、记忆模块Memory、链式调用Chain和代理模板AgentExecutor。开发者可以像搭积木一样快速组合出功能丰富的 Agent。但代价是当链条断裂时你很难快速定位是哪一块积木松动了。它的调试模式如verboseTrue输出的是高度抽象的日志流缺乏结构化字段难以做自动化分析它的测试机制依赖于手动构造输入、比对输出字符串无法验证中间步骤如 LLM 是否真的按预期生成了 tool name 和 args它对工具调用的错误处理是“尽力而为”的异常信息常被层层包装原始堆栈丢失。而 Agent Harness 则反其道而行之它主动“削足适履”要求你必须为每个 Agent 显式定义InputSchema和OutputSchemaPydantic 模型这意味着你无法回避对输入数据边界的思考它强制所有工具函数必须接受**kwargs并返回dict且规定了status、data、error三个顶层键这抹平了不同工具实现的差异让统一观测成为可能它甚至不提供现成的 LLM 封装而是要求你传入一个符合Callable[[str], str]签名的函数——这看似增加了初始成本实则彻底解耦了“智能体逻辑”与“大模型服务”让你可以轻松切换本地 Ollama 模型、云端 API甚至用 mock 函数进行纯逻辑测试。2.2 架构极简主义三层结构拒绝过度设计Agent Harness 的代码仓库结构异常清爽只有三个核心模块core/、utils/、test/。这种极简并非偷懒而是对“智能体调试”这一垂直场景的深度聚焦。core/agent.py这是唯一的核心类AgentHarness。它不继承任何基类不实现任何抽象方法就是一个纯粹的、职责单一的“执行协调器”。它的run()方法接收一个input_data: dict然后严格按四步执行1) 用InputSchema验证并标准化输入2) 调用用户传入的llm_call函数传入由prompt_template渲染出的完整 prompt3) 解析 LLM 返回的 JSON 字符串提取tool_name和tool_args4) 调用对应工具函数捕获其返回值或异常并用OutputSchema进行最终校验。整个过程没有魔法没有隐式状态所有中间变量prompt、llm_response、tool_input、tool_output都作为RunResult对象的属性被完整保留。这种“线性流水线”设计让任何一步的失败都能被精准捕获和归因。core/hook.py这是 Harness 的“神经末梢”。它定义了一个Hook抽象基类仅包含on_start、on_llm_call、on_tool_call、on_finish四个生命周期方法。用户可以继承它实现自己的日志记录、性能打点、异常告警等逻辑并通过AgentHarness(hooks[MyLoggingHook()])注册。关键在于所有 hook 方法都接收一个context: dict参数其中包含了当前执行步骤的所有上下文信息如context[prompt]、context[llm_response]、context[tool_name]。这避免了传统 AOP 方案中需要全局状态或复杂上下文管理的麻烦让可观测性变得极其轻量。utils/test_utils.py这里封装了run_agent_test辅助函数它接受一个AgentHarness实例、一组测试用例每个用例是(input_dict, expected_output_dict)元组和一个可选的assert_func。它会自动执行agent.run(input)并将结果与expected_output进行深度比对支持忽略某些字段、校验特定字段类型。更重要的是它会在测试失败时打印出完整的RunResult对象包括llm_response的原始字符串、tool_args的解析结果、tool_output的具体内容——这比任何AssertionError都更直观地告诉你“哪里出了问题”。这种三层结构没有 Service 层没有 Repository 层没有 Config 层。它不试图构建一个“智能体操作系统”而是做一个称职的“智能体手术台”提供无菌环境标准化输入/输出、精密器械结构化日志与钩子、高清显微镜详尽的测试报告。当你需要一个能快速验证想法、稳定交付质量、方便团队协作的 Agent 开发底座时这种克制的设计反而成了最大的优势。2.3 与主流方案的对比不是替代而是补位理解 Agent Harness 的定位必须将其放在当前智能体技术栈的坐标系中审视。下表列出了它与几个典型方案的关键差异维度Agent HarnessLangChain (AgentExecutor)AutoGen (ConversableAgent)LlamaIndex (QueryEngine)核心目标Agent 可观测性与可测试性快速构建功能丰富的 Agent 应用多智能体协作与对话编排基于文档的知识检索与问答抽象层级最低层执行引擎 观测接口中高层提供 Chain、Tool、Memory 等抽象组件高层定义 Agent 角色、通信协议、群组管理中高层封装索引构建、检索、RAG 流程调试能力结构化日志、全链路上下文、可编程 Hook、原生 pytest 集成verbose日志非结构化、有限的回调CallbackHandler对话历史记录、Agent 内部状态快照需手动导出检索过程可视化response_source_nodes、LLM 调用日志测试友好度内置run_agent_test支持输入/输出 Schema 校验、中间步骤断言需手动构造MockLLM、MockTool测试逻辑分散测试需模拟整个对话流程复杂度高测试聚焦于检索准确率对 LLM 生成环节覆盖弱学习曲线极低只需理解InputSchema/OutputSchema/Hook三个概念陡峭需掌握大量组件概念、配置项、生命周期陡峭需理解角色定义、消息协议、群组调度中等需理解索引类型、嵌入模型、检索器参数这张表清晰地表明Agent Harness 不是一个“大而全”的解决方案而是一个“小而精”的专业工具。它不和 LangChain 比谁的工具库更丰富也不和 AutoGen 比谁的多智能体编排更强大。它的战场在更底层当你的 Agent 已经用 LangChain 搭建完成但上线后频繁出现不可预测的行为时Agent Harness 就是你第一时间要接入的“诊断仪”当你用 AutoGen 设计了一个复杂的多 Agent 协作流程但某个 Agent 总是在特定环节掉链子时你可以单独拎出那个 Agent用 Harness 进行隔离测试。它的价值恰恰在于它的“不完整”——它只做一件事并把它做到极致让 Agent 的每一次呼吸、每一次心跳都清晰可见。3. 核心细节解析与实操要点从安装到第一个可调试 Agent3.1 环境准备与依赖管理为什么推荐 Poetry 而非 Pipenv安装 Agent Harness 本身只有一行命令pip install agent-harness。但真正的挑战始于环境隔离。我见过太多团队因为在一个共享的venv中混装了langchain0.1.0和langchain0.2.0导致 Harness 的InputSchema验证逻辑与 LangChain 的BaseTool类型冲突最终调试数小时才发现是版本问题。因此强烈建议使用 Poetry 进行依赖管理而非更常见的 Pipenv 或纯 pip。原因有三锁定文件poetry.lock的确定性更强Poetry 的锁文件不仅记录包名和版本还精确记录了每个包的哈希值sha256。这意味着无论你在 macOS、Linux 还是 Windows 上运行poetry install只要poetry.lock文件相同安装出的依赖树就 100% 一致。Pipenv 的Pipfile.lock虽然也做类似事情但在处理 C 扩展包如numpy、torch的二进制分发时偶尔会出现平台兼容性问题。而 Agent Harness 的调试场景最怕的就是“在我机器上好好的到 CI 上就挂了”。依赖冲突提示更友好当你的项目同时依赖agent-harness和langchain-core时Poetry 会在poetry add阶段就明确报错“Because agent-harness (0.3.1) depends on langchain-core (^0.1.0) and your project depends on langchain-core (0.2.0), version solving failed.” 这种提示直指要害远胜于 pip 在安装后运行时报出的ImportError: cannot import name BaseTool from langchain_core.tools这类晦涩错误。虚拟环境管理更透明Poetry 默认为每个项目创建独立的、路径清晰的虚拟环境通常在~/.cache/pypoetry/virtualenvs/下并通过poetry shell或poetry run python来激活。这避免了source venv/bin/activate后忘记 deactivate 导致的全局污染。对于需要频繁切换多个 Agent 项目的开发者这点尤为重要。我的标准初始化流程如下# 1. 创建项目目录 mkdir my-financial-agent cd my-financial-agent # 2. 初始化 Poetry会自动生成 pyproject.toml poetry init # 3. 添加核心依赖注意指定 langchain-core 版本以匹配 Harness poetry add agent-harness langchain-core0.1.14 # 4. 添加开发依赖pytest 用于测试black 用于代码格式化 poetry add --group dev pytest black # 5. 进入 Poetry shell此时已激活虚拟环境 poetry shell执行完以上步骤你的pyproject.toml文件中会包含类似这样的依赖块[tool.poetry.dependencies] python ^3.9 agent-harness ^0.3.1 langchain-core 0.1.14 [tool.poetry.group.dev.dependencies] pytest ^7.4.0 black ^23.10.0提示langchain-core0.1.14是经过充分测试的稳定版本。虽然 Harness 的setup.py声明了langchain-core0.1.0但0.2.x系列引入了重大 API 变更如BaseTool类的重构会导致 Harness 的工具调用逻辑失效。务必在pyproject.toml中显式锁定此版本。3.2 定义你的第一个 AgentInputSchema 与 OutputSchema 的实战意义Agent Harness 的灵魂在于它强制你用 Pydantic 模型来定义InputSchema和OutputSchema。这看起来像是一个繁琐的仪式但正是这个仪式帮你规避了 80% 的线上故障。让我们以一个真实的金融问答 Agent 为例逐步拆解。需求用户输入一个自然语言问题如“帮我查一下股票 AAPL 过去 30 天的收盘价”Agent 需要识别出股票代码AAPL和时间范围30 days调用get_stock_price工具获取数据并返回一个结构化的 JSON包含success: bool、message: str、data: list[dict]每条数据含date和close_price。第一步定义 InputSchemafrom pydantic import BaseModel, Field from typing import Optional class FinancialQueryInput(BaseModel): 用户查询的输入结构 question: str Field(..., description用户的原始自然语言问题) user_id: Optional[str] Field(None, description可选的用户唯一标识用于审计) # 注意这里我们不定义 stock_code 或 days # 因为它们是 LLM 从 question 中解析出的中间产物不应由用户直接提供。 # InputSchema 只描述用户“能且应该”提供的信息。注意Field(..., description...)中的...是 Pydantic 的“必填”标记。description字段会被自动注入到 LLM 的 system prompt 中指导模型理解每个字段的含义。这是 Harness 的一个隐藏技巧它会将InputSchema的description拼接到 prompt 里让 LLM 的“理解力”有据可依。第二步定义 OutputSchemafrom datetime import date from typing import List, Dict, Any class StockPriceData(BaseModel): date: date close_price: float class FinancialQueryOutput(BaseModel): Agent 返回的输出结构 success: bool Field(..., description操作是否成功) message: str Field(..., description对 success 状态的简要说明) data: List[StockPriceData] Field( default_factorylist, description股票价格数据列表仅在 successTrue 时有效 ) # 这里我们也没有定义 error 字段 # 因为 Harness 的工具调用机制会自动捕获异常并将其映射到 output[error] 字段。 # OutputSchema 只描述“成功路径”下的理想输出。第三步编写 Prompt TemplatePROMPT_TEMPLATE 你是一个专业的金融信息助手。请根据用户的提问严格按以下 JSON 格式输出不要有任何额外的文本、解释或 markdown 格式。 { tool_name: get_stock_price, tool_args: { stock_code: string, 股票代码如 AAPL, days: integer, 查询天数如 30 } } 用户提问{question} 关键点tool_name和tool_args必须与你后续定义的工具函数名完全一致。tool_args中的字段名stock_code,days也必须与工具函数的参数名一致。Harness 会用json.loads(llm_response)解析并用tool_args字典作为**kwargs调用工具。任何不匹配都会导致KeyError。第四步实现工具函数import requests from typing import Dict, Any def get_stock_price(stock_code: str, days: int) - Dict[str, Any]: 模拟调用外部金融 API 获取股票价格。 返回格式必须严格遵循 Harness 的约定{status: success|error, data: ..., error: ...} try: # 这里是真实的 API 调用逻辑 # response requests.get(fhttps://api.example.com/stock/{stock_code}/history?days{days}) # data response.json() # 为演示我们返回模拟数据 mock_data [ {date: 2023-10-01, close_price: 175.43}, {date: 2023-10-02, close_price: 176.21}, ] return { status: success, data: mock_data, error: None } except Exception as e: return { status: error, data: None, error: str(e) }注意工具函数的返回值必须是一个dict且必须包含status、data、error三个键。这是 Harness 进行统一错误处理和日志记录的前提。status为error时error字段的值会被自动提取并放入最终的OutputSchema的message字段中。第五步组装 AgentHarness 实例from agent_harness import AgentHarness # 创建 Harness 实例 agent AgentHarness( input_schemaFinancialQueryInput, output_schemaFinancialQueryOutput, prompt_templatePROMPT_TEMPLATE, llm_calllambda prompt: {tool_name: get_stock_price, tool_args: {stock_code: AAPL, days: 30}}, # Mock LLM tools{get_stock_price: get_stock_price} ) # 运行测试 result agent.run({question: 帮我查一下股票 AAPL 过去 30 天的收盘价}) print(result.output) # 会打印出符合 FinancialQueryOutput 的结构化字典这个看似简单的五步实际上完成了对 Agent 行为的“契约式定义”。InputSchema是你与用户的契约OutputSchema是你与下游服务的契约Prompt Template是你与 LLM 的契约Tool Function是你与外部系统的契约。Harness 的价值就在于它用代码强制你把所有这些契约都白纸黑字地写下来。当契约清晰时问题就不再是“为什么没结果”而是“哪个契约被违反了”。3.3 Hook 机制详解如何用 10 行代码实现生产级可观测性Hook 是 Agent Harness 最强大的扩展点。它不像传统的日志框架那样只能记录“发生了什么”而是能让你在 Agent 执行的每一个关键节点拿到完整的上下文从而做出精准的决策。下面是一个在生产环境中被反复验证过的、实用的LoggingHook示例import logging import time from agent_harness.hook import Hook from typing import Dict, Any logger logging.getLogger(agent_harness) class ProductionLoggingHook(Hook): def __init__(self, service_name: str financial-agent): self.service_name service_name self._start_time None def on_start(self, context: Dict[str, Any]): self._start_time time.time() # 记录请求 ID便于全链路追踪 request_id context.get(request_id, unknown) logger.info( f[{self.service_name}] Request started. ID: {request_id}, fInput: {context.get(input_data, {})} ) def on_llm_call(self, context: Dict[str, Any]): prompt context.get(prompt, ) # 计算 prompt 长度用于容量监控 prompt_tokens len(prompt.split()) logger.debug( f[{self.service_name}] LLM called. Prompt length: {prompt_tokens} tokens, fPrompt preview: {prompt[:100]}... ) def on_tool_call(self, context: Dict[str, Any]): tool_name context.get(tool_name, unknown) tool_args context.get(tool_args, {}) # 记录工具调用前的准备时间LLM 解析耗时 if self._start_time: parse_time time.time() - self._start_time logger.info( f[{self.service_name}] Tool {tool_name} invoked. fParse time: {parse_time:.3f}s, Args: {tool_args} ) def on_finish(self, context: Dict[str, Any]): result context.get(result) if result and hasattr(result, output): output result.output.dict() if hasattr(result.output, dict) else result.output success output.get(success, False) message output.get(message, ) # 根据业务状态打不同等级的日志 if success: logger.info( f[{self.service_name}] Request finished successfully. fMessage: {message} ) else: logger.error( f[{self.service_name}] Request failed. Message: {message} ) # 计算总耗时 if self._start_time: total_time time.time() - self._start_time logger.info( f[{self.service_name}] Request completed. Total time: {total_time:.3f}s )将这个 Hook 注册到你的 Agent 中agent AgentHarness( # ... 其他参数 hooks[ProductionLoggingHook(service_namefinancial-agent)] )这段代码带来的价值是巨大的精准的性能瓶颈定位on_llm_call记录 prompt 长度on_tool_call记录从 LLM 返回到工具调用的时间差即解析耗时on_finish记录总耗时。三者对比你能立刻知道是 LLM 生成慢、还是 JSON 解析慢、还是工具调用慢。安全的敏感信息过滤on_start中只打印input_data的摘要{}而on_finish中只打印message避免了将用户的完整问题或股票数据的明细可能含敏感信息泄露到日志中。业务语义化的日志等级成功时打INFO失败时打ERROR这使得运维人员可以通过grep ERROR app.log快速发现所有失败请求无需在海量日志中大海捞针。实操心得不要试图在一个 Hook 里做所有事。我曾见过一个“全能 Hook”它既发 Slack 告警、又写数据库、又调用 Prometheus Pushgateway。结果一次数据库连接超时导致整个 Agent 执行被阻塞。正确的做法是每个 Hook 只做一件事并且这件事必须是幂等的、快速的、失败不影响主流程的。日志 Hook 只负责写日志告警 Hook 只负责发通知监控 Hook 只负责打点。这样任何一个 Hook 的失败都不会拖垮 Agent 的核心执行。4. 实操过程与核心环节实现从本地调试到 CI/CD 集成4.1 编写第一个单元测试超越字符串比对的深度验证Agent Harness 的run_agent_test函数是其测试能力的集大成者。但很多人只把它当作一个更高级的assertEqual这是极大的浪费。真正的威力在于它支持对RunResult对象的任意字段进行断言。让我们为前面的金融 Agent 编写一个“黄金标准”测试# test_financial_agent.py import pytest from agent_harness.utils.test_utils import run_agent_test from my_agent import agent, FinancialQueryInput, FinancialQueryOutput def test_aapl_30_days_success(): 测试查询 AAPL 30 天股价应成功返回数据 # 定义测试用例(input_dict, expected_output_dict) test_case ( {question: 帮我查一下股票 AAPL 过去 30 天的收盘价}, { success: True, message: 查询成功, # 注意这里我们不校验具体的 data 内容因为那是 mock 数据 # 我们只关心 data 是一个 list且长度 0 } ) # 自定义断言函数对 RunResult 的深层结构进行验证 def custom_assert(result): # 1. 验证 LLM 是否真的生成了正确的 tool_name assert result.llm_response is not None assert get_stock_price in result.llm_response # 2. 验证 tool_args 是否被正确解析 assert result.tool_args is not None assert result.tool_args.get(stock_code) AAPL assert result.tool_args.get(days) 30 # 3. 验证工具调用是否成功 assert result.tool_output is not None assert result.tool_output.get(status) success # 4. 验证最终输出是否符合 Schema assert isinstance(result.output, FinancialQueryOutput) assert result.output.success is True assert len(result.output.data) 0 # 确保有数据返回 # 执行测试 run_agent_test( agentagent, test_cases[test_case], assert_funccustom_assert ) if __name__ __main__: pytest.main([__file__, -v])这个测试的价值远超一个简单的assert output[success] True它验证了 LLM 的“思考过程”通过检查result.llm_response确保模型没有胡乱生成tool_name比如误写成get_stock_info。它验证了“解析环节”的健壮性result.tool_args是 Harness 从 LLM 的 JSON 字符串中解析出的dict。检查它是否包含正确的stock_code和days就是在验证 JSON 解析逻辑是否可靠。它验证了“工具环节”的正确性result.tool_output是工具函数的原始返回值。检查其status就是在确认工具函数本身的逻辑没有 bug。它验证了“最终输出”的合规性result.output是经过OutputSchema校验后的 Pydantic 模型实例。检查其类型和字段就是在确认整个数据流的终点是干净、可信的。实操心得在 CI/CD 流水线中我通常会设置两级测试。第一级是“冒烟测试”smoke test只运行 2-3 个最核心的用例确保 Agent 的基本骨架没有崩溃耗时控制在 10 秒内。第二级是“回归测试”regression test运行全部 50 个用例覆盖各种边界条件如空输入、非法 stock_code、超长问题耗时可能达 2 分钟。两级测试都失败才触发告警。这种分层策略既保证了快速反馈又确保了质量底线。4.2 本地调试技巧如何在 VS Code 中像调试普通 Python 一样调试 AgentVS Code 是目前最流行的 Python IDE而 Agent Harness 的设计使其与 VS Code 的调试器无缝集成。关键在于理解AgentHarness.run()的执行流程并在正确的位置设置断点。步骤一在agent_harness/core/agent.py的run()方法中设置断点打开 VS Code按下CtrlPmacOS 为CmdP输入Python: Select Interpreter选择你项目 Poetry 环境下的 Python 解释器路径类似~/.cache/pypoetry/virtualenvs/my-financial-agent-xxx-py3.9/bin/python。然后在agent_harness/core/agent.py文件的run()方法内部找到以下几行# agent_harness/core/agent.py def run(self, input_data: dict) - RunResult: # Step 1: Validate and normalize input validated_input self.input_schema(**input_data) # -- 在这里设断点 # Step 2: Render prompt prompt self.prompt_template.format(**validated_input.dict()) # -- 在这里设断点 # Step 3: Call LLM llm_response self.llm_call(prompt) # -- 在这里设断点 # Step 4: Parse LLM response parsed json.loads(llm_response) # -- 在这里设断点 # Step 5: Call tool tool_output self.tools[parsed[tool_name]](**parsed[tool_args]) # -- 在这里设断点 # Step 6: Validate and construct output final_output self.output_schema(**tool_output[data]) # -- 在这里设断点在上述 6 个位置都设置断点。然后创建一个debug.py文件# debug.py from my_agent import agent if __name__ __main__: result agent.run({ question: 帮我查一下股票 AAPL 过去 30 天的收盘价 }) print(Final output:, result.output)右键点击debug.py选择Debug Python File。程序将在第一个断点处暂停。此时你可以查看input_data变量确认原始输入是否符合预期。查看validated_input变量确认InputSchema的校验和默认值填充是否正确。查看prompt变量复制其内容粘贴到你常用的 LLM Playground如 OpenAI Chat中手动测试 prompt 的效果。查看llm_response变量确认 LLM 是否返回了有效的 JSON。查看parsed变量确认 JSON 解析是否成功tool_name和tool_args是否正确。查看tool_output变量确认工具函数的执行结果是否符合 Harness 的约定格式。这种“逐帧播放”式的调试让你对 Agent 的每一个内部状态都了如指掌。它比任何日志都更直观是定位复杂问题的终极武器。4.3 CI/CD 集成如何在 GitHub Actions 中自动化 Agent 质量门禁将 Agent Harness 的测试能力融入 CI/CD是保障线上质量的最后防线。以下是一个精简、高效、已在多个项目中验证的 GitHub Actions 工作流# .github/workflows/test-agent.yml name: Test Financial Agent on: push: branches: [main, develop] pull_request: branches: [main, develop] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - name: Set up Python uses: actions/setup-pythonv4 with: python-version: 3.9 - name: Install Poetry uses: snok/install-poetryv1 with: virtualenvs-create: true virtualenvs-in-project: false - name: Install dependencies run: poetry install - name: Run unit tests run: poetry run pytest tests/ -v --tbshort # --tbshort 精简 traceback让失败信息一目了然 - name: Run integration tests (with real LLM) if: github.event_name pull_request # 只在 PR 时运行避免 main 分支的每次 push 都调用付费 API env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} run: | # 使用真实 OpenAI API 替换 mock poetry run
阅读完成 · 觉得有帮助?