☰
构建AI工作流引擎:从提示词工程到自动化代码审查实战
2026/10/23 10:16:15 网站建设 项目流程

1. 项目概述:从被动使用到主动编排

最近半年,我几乎每天都要和Claude、GPT这类大模型打交道。从最初的简单问答,到后来让它帮我写代码片段、分析日志,再到设计系统架构,我发现了一个问题:每次对话都像是一次性的“手工作坊”。我需要反复描述上下文、粘贴代码、解释业务逻辑,甚至为了一个复杂的多步骤任务,我得在同一个聊天窗口里不断地“推着”AI往前走,一旦对话历史过长或者需要回溯修改,体验就变得非常糟糕。

这让我开始思考,能不能像管理基础设施一样,用代码来“驯服”AI,让它成为我工作流中一个稳定、可靠、可重复调用的组件?而不是一个需要我不断手动喂养提示词的聊天机器人。于是,就有了这个“Claude Code Harness”项目。本质上,它是一个本地化的AI工作流编排与执行引擎,核心目标是将我与Claude的交互从临时的、基于网页的聊天,转变为结构化的、版本可控的、可批量执行的自动化脚本。

简单来说,我构建了一套系统,让我可以用写Python脚本的方式,定义复杂的、多步骤的AI任务。比如:“分析这个Git仓库最近一周的提交,找出可能引入bug的代码模式,并生成重构建议报告”。这样一个任务,涉及到获取数据、分块处理、多轮对话、结果汇总等多个环节。通过这个Harness,我只需要定义好任务流程和每个步骤的指令,剩下的就交给系统自动执行。它帮我管理API密钥、处理速率限制、维护对话上下文、格式化输出,最终将结构化的结果保存下来。这不仅仅是省去了复制粘贴的麻烦,更是将AI的能力真正“工程化”地集成到了我的开发工具链中。

2. 核心设计思路:像调用函数一样调用AI

构建这样一个系统,首先要摒弃“聊天”的思维定式,转而用软件工程的视角来看待与AI的协作。我的核心设计原则有以下几点:

2.1 声明式任务定义,而非命令式对话

在网页聊天中,我们是通过一句接一句的指令(命令式)来驱动AI。而在Harness中,我采用声明式的方法。我定义一个“任务”(Task),它由多个“步骤”(Step)组成。每个步骤声明了它的输入是什么(如上一步的输出、一个本地文件、一段静态文本),要对这个输入执行什么操作(例如“总结”、“翻译”、“代码审查”),以及期望的输出格式(例如JSON、Markdown、纯文本)。

这种声明式的好处是任务变得可描述、可复用、可测试。我可以把一次成功的代码审查流程保存为一个任务模板,下次只需要替换目标代码文件,就能一键运行整个审查流程。任务的逻辑清晰可见,而不是淹没在冗长的聊天历史里。

2.2 上下文管理的工程化

大模型有令牌(Token)数限制,Claude也不例外。处理长文档或复杂任务时,如何有效利用有限的上下文窗口是最大挑战之一。网页聊天时,我们只能凭感觉截取或总结历史消息。在Harness中,我实现了系统化的上下文管理策略:

  1. 自动分块与摘要链:对于超长的输入文本(如一份50页的设计文档),系统会自动将其分割成语义连贯的块。处理时,可以采用“Map-Reduce”模式:先让AI对每个块进行初步分析(Map),再让AI基于所有块的分析结果生成一份总摘要或报告(Reduce)。这样,无论多长的文档,都能在有限的上下文窗口内被处理。
  2. 关键信息提取与持久化:在任务执行过程中,某些中间结论或关键数据需要被提取出来,作为后续步骤的“事实依据”,而不是每次都重新从原始对话中推断。Harness会按照我的定义,将AI输出中的特定部分(如解析出的JSON字段、识别出的关键问题列表)提取并结构化存储,注入到后续步骤的提示词中。
  3. 对话状态的序列化:整个任务执行过程中的所有请求和响应,连同元数据(如使用的模型、令牌消耗、时间戳)都会被完整地序列化保存到本地。这相当于拥有了每一次AI交互的“数据库”。我可以随时回放、调试任何一次任务执行,分析令牌消耗的成本,或者基于某次成功的运行结果进行微调和优化。

2.3 提示词(Prompt)的模板化与版本控制

提示词是驱动AI的“代码”。在聊天界面里改提示词,就像在记事本里写代码,没有高亮、没有版本管理、难以复用。在我的Harness里,提示词被提升为一等公民:

  • 模板化:提示词被写成模板文件(例如.jinja2或.txt文件),其中包含变量占位符。执行任务时,系统会将具体的输入数据(如文件内容、上一步的结果)注入到模板中,生成最终的提示词。这确保了提示词结构的稳定性和可复用性。
  • 版本控制:所有的提示词模板和任务定义文件(通常是YAML或JSON)都存放在Git仓库中。我可以清晰地看到提示词的迭代历史:“哦,上周我修改了代码审查提示词,加强了对安全漏洞的检查。” 这实现了AI工作流的真正“基础设施即代码”(IaC)。
  • A/B测试:我可以轻松创建同一个任务的两个版本,仅修改提示词模板,然后并行运行,对比两者的输出效果和质量,从而科学地优化提示词。

2.4 韧性(Resilience)与错误处理

API服务不是100%可靠的,可能会遇到网络超时、速率限制(Rate Limit)或模型内部错误。在手动聊天时,遇到错误我们只能重试。在自动化系统中,必须内置健壮的错误处理机制。

我的Harness实现了:

  • 自动重试与退避:对于可重试的错误(如网络抖动、速率限制),系统会自动进行指数退避重试。
  • 检查点(Checkpoint):对于多步骤任务,每成功完成一步,状态都会保存。如果任务在第三步失败,修复问题后可以从第三步开始重启,而不是从头再来,节省了时间和API费用。
  • Fallback策略:对于关键步骤,可以定义备选模型或备选提示词。当主策略失败时,自动尝试备用方案。

3. 技术栈与架构拆解

我的Harness不是一个庞大的单体应用,而是一组松散耦合的Python模块和配置文件。核心架构可以分为四层:

3.1 配置与定义层

这是系统的“蓝图”,全部由配置文件定义。

  • 任务定义文件(task_definition.yaml):这是核心。它定义了一个任务的骨架。
    name: "daily_code_review" description: "自动审查指定Git目录下当日变更的代码" steps: - name: "get_git_diff" type: "command" # 类型可以是 command, llm, script 等 command: "git diff --name-only HEAD~1 HEAD" output_to: "changed_files" - name: "review_single_file" type: "llm" for_each: "{{ changed_files }}" # 遍历上一步输出的文件列表 template: "templates/code_review.jinja2" input_vars: file_path: "{{ item }}" file_content: "{{ read_file(item) }}" model: "claude-3-opus-20240229" output_to: "review_results" - name: "generate_summary_report" type: "llm" template: "templates/summary_report.jinja2" input_vars: reviews: "{{ review_results }}" model: "claude-3-sonnet-20240229" output_to: "final_report" - name: "save_report" type: "script" script: "scripts/save_report.py" input_vars: report: "{{ final_report }}"
    这个YAML定义了一个四步任务:1. 执行Git命令获取变动的文件列表;2. 对每个文件调用Claude进行代码审查;3. 汇总所有审查结果生成报告;4. 调用Python脚本保存报告。
  • 提示词模板(.jinja2文件):定义了与AI对话的具体内容。
  • 环境配置(.env文件):安全地存储API密钥、模型默认参数、代理设置等。

3.2 核心执行引擎层

这是用Python编写的“大脑”,负责解析任务定义、协调步骤执行、管理状态。

  • 任务解析器:读取YAML文件,解析出步骤列表、依赖关系(通过output_to和input_vars定义)。
  • 步骤执行器:这是一个多态的设计。有一个基础的StepExecutor接口,然后有CommandStepExecutor(执行shell命令)、LLMStepExecutor(调用大模型)、ScriptStepExecutor(执行Python脚本)等具体实现。新增一种步骤类型,只需要实现新的执行器即可。
  • 上下文管理器:维护一个全局的上下文字典(Context Dict)。每个步骤的输入从这个字典中获取,输出也写回这个字典。它负责变量的替换(如将{{ changed_files }}替换为实际的值)和数据的传递。
  • 状态持久化器:将每次任务运行的完整上下文、每一步的输入输出、元数据序列化为JSON文件,保存到runs/目录下,按任务名和时间戳组织。

3.3 模型交互层

这是与Claude API直接对话的封装层,关键在于抽象。

  • 统一的客户端封装:我并没有直接使用Anthropic官方的SDK,而是自己封装了一个LLMClient类。这个类内部处理了:
    • 请求构造:根据不同的模型和参数,构造符合API规范的请求体。
    • 响应解析:统一提取响应中的文本内容、思考过程(如果模型支持)和令牌使用量。
    • 错误处理:捕获API异常,并根据错误类型决定是重试、降级还是彻底失败。
    • 日志记录:详细记录每一次请求和响应,便于调试和审计。
  • 为什么要抽象?这为未来接入其他模型(如GPT、Gemini、本地部署的Llama)留下了通道。我只需要实现一个新的AnthropicClient或OpenAIClient,继承自LLMClient基类,上层执行引擎的代码完全不需要改动。这符合“依赖倒置”原则。

3.4 工具与集成层

这是Harness与外部世界交互的“手和脚”。

  • 文件系统操作:读取文件内容、写入结果、遍历目录。
  • Git集成:通过封装git命令或使用GitPython库,获取代码变更、提交信息等。
  • 命令行工具(CLI):我使用click库构建了一个命令行界面。核心命令很简单:
    # 运行一个任务 ai-harness run --task daily_code_review --param branch=main # 列出所有历史运行记录 ai-harness list-runs # 重放某个特定运行,用于调试 ai-harness replay run_20240520_143022
  • 结果导出:可以将AI生成的结构化报告(如JSON格式的代码审查问题列表)导出为Markdown、HTML,甚至自动创建Jira Ticket或GitHub Issue。

4. 实战:构建一个自动化代码审查工作流

理论说了这么多,我们来看一个最常用、也最能体现价值的实战案例:自动化代码审查。我将拆解如何用Harness实现它。

4.1 第一步:定义任务蓝图

首先,在tasks/目录下创建code_review.yaml。这个任务的目标是:对比main分支和当前特性分支的差异,对所有变动的.py文件进行审查,并生成一份包含严重程度分级的报告。

任务步骤设计如下:

  1. 收集变更:使用Git命令获取两个分支间有差异的Python文件列表。
  2. 过滤与分块:过滤掉测试文件,如果文件太大,则进行智能分块。
  3. 并行审查:对每个文件(或文件块)调用Claude进行审查。这一步可以并行执行以提升速度。
  4. 汇总分析:将所有文件的审查结果汇总,让Claude进行整体评估,识别出跨文件的系统性风险。
  5. 生成报告:将最终结果格式化为漂亮的Markdown报告,并保存。

4.2 第二步:雕琢提示词模板

提示词的质量直接决定审查效果。我的templates/code_review.jinja2模板如下:

你是一个资深Python代码审查专家。请严格审查以下代码片段。 文件路径:{{ file_path }} 代码内容: ```python {{ code_content }}

请从以下维度进行分析,并按照指定JSON格式输出:

  1. 潜在缺陷(Bugs):指出可能导致程序崩溃、逻辑错误或未预期行为的代码。
  2. 安全漏洞(Security):检查是否存在注入、硬编码密钥、不安全反序列化等问题。
  3. 性能问题(Performance):识别低效的算法、重复计算、不必要的IO等。
  4. 代码风格与可读性(Style):是否符合PEP 8?命名是否清晰?函数是否过长?
  5. 设计问题(Design):模块耦合度是否过高?职责是否单一?是否有更好的设计模式可以应用?

输出要求:

  • 对每个发现的问题,必须提供:category(类别)、severity(严重程度:High/Medium/Low)、line_number(行号,如适用)、description(描述)、suggestion(改进建议)。
  • 如果某个维度没有问题,则输出空列表。
  • 最终输出必须是一个合法的JSON对象,包含以下键:bugs,security,performance,style,design。

请开始你的分析。

这个提示词有几个关键点: * **角色设定明确**:“资深Python代码审查专家”给了AI一个清晰的上下文。 * **指令结构化**:明确列出了五个审查维度,引导AI进行系统性思考,而不是泛泛而谈。 * **输出格式锁定**:强制要求JSON格式,并且规定了具体的键名。这使得后续步骤可以**程序化地解析**结果,而不是去理解一段自由文本。这是工程化的关键一步。 * **提供了示例结构**:在描述中暗示了每个问题项应包含的字段。 ### 4.3 第三步:配置执行与并发 在任务定义中,`review_single_file`步骤的`for_each`循环是串行的。为了加速,我修改了执行引擎,为`LLMStepExecutor`增加了并发支持。 ```python # 在LLMStepExecutor中 async def execute_for_each(self, items, context, template): semaphore = asyncio.Semaphore(5) # 控制最大并发数,避免触发API速率限制 async def process_one(item): async with semaphore: # 构建单个请求的上下文 step_context = self._build_step_context(item, context) prompt = self._render_template(template, step_context) # 异步调用LLM客户端 response = await self.llm_client.acall(prompt) return self._parse_response(response) # 使用asyncio.gather并发执行 results = await asyncio.gather(*[process_one(item) for item in items]) return results

这里使用了Python的asyncio实现异步并发。同时,通过Semaphore限制并发数,这是必须的,因为Claude API有严格的每分钟请求数(RPM)限制。盲目高并发会导致大量429错误,任务失败。

实操心得:API限制是“甜蜜的负担”刚开始我忽略了速率限制,设置了并发数为10,任务瞬间失败。后来我仔细阅读了Anthropic的文档,并为不同的模型设置了不同的Semaphore值(Opus模型更严格,Sonnet稍宽松)。更好的做法是从环境变量读取这些限制,或者实现一个更智能的、能动态调整的限流器。

4.4 第四步:结果汇总与报告生成

每个文件审查后,会得到一个JSON对象。汇总步骤的提示词模板templates/summary.jinja2需要处理这个列表。

你是一个技术负责人。以下是AI助手对本次代码提交中多个文件的审查结果汇总: {{ all_reviews_json }} 请完成以下工作: 1. **问题归类与去重**:将相同或类似的问题合并,避免重复。 2. **风险评估**:从项目整体角度,识别出最高风险的3个问题(综合考虑严重程度和影响范围)。 3. **给出行动建议**:针对不同严重程度的问题,给出具体的修复优先级和建议(例如:必须立即修复、应在合并前修复、可以放在技术债务中后续优化)。 4. **生成报告摘要**:用一段话总结本次审查的整体代码质量。 请以Markdown格式输出报告,包含“总体评估”、“高风险问题”、“详细问题列表”、“行动建议”等章节。

这个步骤的输入是所有JSON结果的列表。我在这里选择使用claude-3-sonnet模型,因为它更便宜、更快,且对于总结归纳类任务足够出色,没必要每次都使用最顶级的Opus模型。这是成本与效果的权衡。

4.5 第五步:运行与输出

在命令行中执行:

ai-harness run --task code_review --param base_branch=main --param feature_branch=feat/new-ai-integration

系统会开始执行。我可以在终端看到实时日志:

[INFO] 开始任务: code_review [INFO] 步骤1/get_changed_files: 成功。找到5个.py文件。 [INFO] 步骤2/review_single_file: 开始并发审查5个文件(并发数:3)... [INFO] 文件 module_a.py 审查完成,发现2个问题。 [INFO] 文件 module_b.py 审查完成,发现0个问题。 ... [INFO] 步骤3/generate_summary: 调用Claude-3-Sonnet生成汇总报告... [INFO] 步骤4/save_report: 报告已保存至 reports/code_review_20240520_150123.md [INFO] 任务执行成功!总耗时 42.3 秒,总Token消耗:~12,500。

最终,在reports/目录下会生成一个Markdown文件,内容结构清晰,问题列表一目了然,并且附带了具体的行号和修复建议。我可以直接将这个报告链接到Pull Request中,作为自动化审查的评论。

5. 避坑指南与效能优化

在开发和日常使用这个Harness的过程中,我踩过不少坑,也总结出一些能极大提升体验和效率的技巧。

5.1 成本控制:Token是真金白银

使用Opus模型处理大量文本,费用不容小觑。我的优化策略是:

  • 分层使用模型:像前面例子所示,在需要最高创造力和推理能力的“核心分析”步骤(如单文件深度审查)使用Opus。在“总结归纳”、“格式转换”、“简单分类”等步骤,使用更便宜的Sonnet甚至Haiku模型。这通常能节省30%-50%的成本,而对最终结果质量影响甚微。
  • 缓存机制:对于内容不变或变化频率低的输入(如公司代码规范文档、API接口说明),其AI分析结果是可以缓存的。我实现了一个基于文件内容MD5哈希的简单缓存层。在调用LLM前,先检查缓存中是否有该输入的历史分析结果,如果有且未过期,则直接返回缓存结果。这尤其适用于CI/CD流水线中,针对未修改的代码文件,可以避免重复审查。
  • 设置预算与告警:在Harness的配置中,我为每个任务设置了预估的Token上限。执行时,系统会实时累加消耗,如果接近上限,会发出警告或自动终止。同时,我将每日的API消耗情况通过脚本发送到团队聊天工具中,让成本可视化。

5.2 稳定性保障:应对API的“不可靠性”

  • 退避重试策略:这是必须实现的。我的重试逻辑不是简单的time.sleep,而是指数退避。例如,第一次重试等1秒,第二次等2秒,第三次等4秒,并在每次重试时加入随机抖动(Jitter),避免多个任务同时重试造成“惊群效应”。
    def exponential_backoff_with_jitter(retry_count): base_delay = 1 max_delay = 32 delay = min(max_delay, base_delay * (2 ** retry_count)) jitter = random.uniform(0, delay * 0.1) # 增加10%以内的随机抖动 return delay + jitter
  • 请求与响应完整性校验:网络传输可能中断。我会校验每次请求是否成功发送,响应是否完整接收。对于流式响应(如果需要),要处理中途断开的情况,并记录断点以便续传。
  • 依赖外部命令的稳定性:对于git diff这类外部命令,要做好异常捕获。比如,指定的分支不存在时,任务应该优雅失败并给出明确错误信息,而不是抛出难懂的Python异常。

5.3 提示词工程:从“有效”到“高效”

  • 结构化输出是王道:尽可能让AI输出JSON、XML或带明确标记的文本。这比让AI写一段自由文本,然后自己再用复杂的正则表达式去解析要可靠一万倍。Claude对结构化输出的支持很好,在提示词中明确要求,它几乎每次都能遵守。
  • 提供少量示例(Few-Shot):对于非常复杂的输出格式,或者需要AI模仿特定风格时,在提示词中提供1-2个清晰的输入输出示例,效果比千言万语的描述要好得多。
  • 温度(Temperature)参数的选择:对于需要确定性、可重复结果的审查、总结、提取类任务,我将温度设置为0.1或0.2。对于需要创造力的头脑风暴、起名、生成多种方案等任务,可以调到0.7或0.8。这个参数在任务定义文件中就可以指定。
  • 系统提示词(System Prompt)的妙用:Anthropic的API支持system参数。我会把一些全局的、角色性的指令放在system中(如“你是一个严谨的软件工程师”),把具体的任务指令放在user消息中。这有助于模型更好地维持角色一致性。

5.4 维护与迭代:像对待产品一样对待Harness

  • 版本化一切:任务定义、提示词模板、工具脚本全部进Git。每次对提示词的优化,都是一个提交。这让我们可以清晰地追踪是什么改动让审查结果变得更准确了。
  • 建立评估体系:如何知道新的提示词比旧的好?我建立了一个简单的评估流程:准备一组“黄金标准”代码案例(包含已知的bug、坏味道等),用不同的提示词版本运行审查任务,对比AI发现问题的召回率(Recall)和准确率(Precision)。虽然不完美,但提供了数据驱动的优化方向。
  • 文档化任务库:随着任务越来越多,一个README.md是远远不够的。我建立了一个简单的任务目录网站(用MkDocs生成),每个任务都有详细的描述、输入输出说明、使用示例和作者信息。这让团队其他成员也能轻松复用我构建好的工作流。

构建这个Claude Code Harness的过程,是一个将前沿AI能力“拉下神坛”,融入朴实无华的工程实践的过程。它没有炫酷的界面,有的只是配置文件、命令行和日志。但正是这种工程化的朴素,让我和我的团队能够稳定、高效、规模化地利用AI的能力,让它从偶尔灵光一现的“魔法”,变成了日常开发中值得信赖的“副驾驶”。如果你也厌倦了在聊天窗口里重复劳动,不妨从自动化一个最简单的代码审查或周报生成任务开始,亲手搭建属于你自己的AI工作流引擎。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询