公司动态
ArchAgent v2分阶段搜索:架构设计超越人工冠军的工程实践
在实际架构设计评测中经常会遇到一类被称作“人工冠军”的基线由一位或多位专家在限定时间内手工完成的架构方案通常被认为代表了当前人类设计能力的较高水平。ArchAgent v2 采用的分阶段搜索并不是让大模型一句话生成整份架构而是把设计过程拆成多个可评估、可回溯、可修正的阶段每个阶段只做一件相对明确的事。最终在可量化的评测指标上ArchAgent v2 的方案得分超过了人工冠军。这个结果并不神秘搜索方式的改变比模型本身能力的提升更能带来稳定的收益。这篇文章会围绕 ArchAgent v2 的分阶段搜索方法展开先说明它解决的问题再给出整体流程和核心模块然后提供一个用 Python 实现的最小可运行骨架最后讨论评测设计、常见坑和工程化建议。如果你想在智能体架构设计、自动方案生成或基于搜索的 Agent 任务中引入类似机制这篇文章可以作为落地参考。1. 为什么架构设计要从“一次性生成”走向分阶段搜索1.1 从人工架构设计到智能体架构设计人工架构设计的过程不是一蹴而就的。一个合格的人类架构师拿到需求后会先澄清目标再拆分模块然后设计数据流和接口最后做约束校验。遇到冲突时会回到前面某一步重新选择方案。这个过程本质上是“搜索 评估 回溯”的循环而不是简单的线性输出。智能体架构设计是让大模型或 Agent 替代部分架构设计工作。早期的常见做法是让模型一次性输出完整架构给它一段需求文本它返回一个包含模块、接口、技术选型和部署结构的方案。这种方式在简单场景下可用但复杂场景下问题很多模块之间不一致、约束冲突、遗漏非功能性需求、同一问题多次生成结果不稳定。ArchAgent v2 的出发点是把人工设计过程中最关键的“分阶段推进 可回溯”机制搬进 Agent 的搜索流程。它不再追求一次生成完美答案而是通过多轮分阶段搜索逼近最优方案。1.2 分阶段搜索要解决什么问题分阶段搜索解决的核心问题是长链路任务里的错误累积。一次生成完整架构时模型需要同时处理需求理解、模块拆分、接口设计、约束校验、资源评估等多个子任务。任何一个子任务出错都可能让最终方案不可用。更麻烦的是由于没有中间评估错误只能到最后才能被发现修正成本很高。分阶段搜索先把任务切成若干阶段每个阶段有明确的输入、输出和评估信号。模型在每一阶段只需要做相对小的决策决策完成后先评估再决定继续、修正还是回溯。这样做了之后错误在早期阶段就可能被拦截不会一路传导到最终方案。这个思路和传统启发式搜索类似只不过 ArchAgent v2 用大模型作为状态生成器和状态评估器因此具备对自然语言需求的理解能力也有更强的方案生成能力。1.3 与一次性生成相比分阶段搜索改变了什么可以用一张对比表来理解两类方式的不同维度一次性生成分阶段搜索输出方式单次得到完整方案分多轮生成每轮覆盖部分设计错误发现时机最终评估时才能发现每个阶段结束后可评估回溯能力基本没有根据局部或全局分数决定是否回溯模型调用次数少多对评估器的依赖低高结果稳定性随提示词波动大通过搜索过程收敛适合场景简单、低风险需求多约束、高复杂度架构任务这里要注意分阶段搜索并不是无条件优于一次性生成。它增加了模型调用次数、搜索时间和对评估器质量的要求。如果任务本身很简单一次性生成反而更快。ArchAgent v2 的价值是在复杂架构设计任务上通过搜索换稳定性和上限。2. ArchAgent v2 分阶段搜索的整体流程和模块设计2.1 五个核心阶段解析、生成、局部优化、全局校验、回溯扩展ArchAgent v2 的搜索流程可以拆成五个阶段。下面用一套通用命名来说明实际项目里可以调整阶段名称和顺序。阶段输入主要操作输出需求解析原始需求文本抽取目标、约束、优先级、冲突点结构化需求清单候选生成结构化需求生成多个候选架构草图候选集合局部优化单个候选架构针对局部约束做修正优化后的候选全局校验优化后的候选跨模块检查接口、数据流、冲突完整方案或冲突报告回溯扩展当前最好方案对未覆盖部分做新的搜索分支新候选或终止信号这五个阶段不是严格的线性流水线。整体是一个循环从需求解析开始进入候选生成然后局部优化再全局校验。校验通过后更新当前最优方案未通过或发现可扩展空间时回到生成或优化阶段继续搜索。2.2 搜索状态如何表示分阶段搜索能不能稳定工作取决于状态表示是否清晰。每个阶段都要能把自己的输出变成下一个阶段可读的状态同时还要记录来源方便回溯。在 ArchAgent v2 的设计里搜索状态可以抽象为一个树节点。节点包含阶段标识、内容、来源父节点、评估分数和额外元信息。树形结构既允许记录回溯路径也方便做并行扩展。from dataclasses import dataclass, field from typing import Any, Optional dataclass class SearchNode: node_id: str parent_id: Optional[str] stage: str # parse / generate / improve / validate / expand content: dict # 当前阶段的设计内容 score: float 0.0 # 最近一次评估分数 meta: dict field(default_factorydict) # 额外信息如时间、模型、策略参数每个节点保存了stage和content。stage表示这个节点处于哪个阶段content保存结构化内容。例如在generate阶段的节点content可能是一个包含模块列表的字典在validate阶段的节点content可能是完整的架构方案。2.3 阶段之间如何传递信息阶段间的信息传递主要包括三种结构化数据需求清单、模块列表、接口定义、约束列表。评估信号每个候选方案的局部分数、全局分数、冲突列表。搜索元信息当前搜索深度、已消耗预算、父节点来源。如果某一阶段输出的结构化数据字段不统一后续阶段无法稳定读取搜索就会退化成多个互不相干的模型调用。这也是为什么分阶段搜索必须最先设计好数据协议。一个可靠的传递方式是把约束统一表示为带优先级的列表{ requirement_id: req-001, constraints: [ {type: latency, value: p95 200ms, priority: 1}, {type: cost, value: single vm, priority: 2}, {type: data_residency, value: cn-east, priority: 1} ] }结构化约束可以让后续阶段直接判断某个设计是否满足条件而不是靠模型从原始文本中反复回忆。2.4 预算如何分配与终止分阶段搜索意味着模型调用次数远高于一次性生成。所以要为搜索设定预算。常见预算维度有三种预算维度默认建议说明模型调用次数20 到 50 次防止失控调用单阶段最大搜索宽度3 到 8 个候选控制每次生成的候选数最大搜索深度3 到 10 层控制回溯路径长度搜索终止条件通常是以下条件的组合预算耗尽。全局校验连续 N 次未发现新的改进。当前方案满足所有高优先级约束。候选池为空且无可回溯分支。在工程实现里终止条件必须有明确日志否则难以判断搜索是正常收敛还是因为异常退出。3. 用 Python 搭一个可运行的 ArchAgent v2 搜索骨架3.1 环境准备下面给出一个最小骨架用于演示分阶段搜索的流程。它不依赖任何外部 LLM 服务使用确定性伪随机函数模拟模型生成和评估因此可以直接运行。推荐环境# Python 3.10 pip install pydanticpydantic不是必须的只是为了让数据结构校验更清晰。你也可以只用标准库里的dataclass。3.2 定义需求、约束和搜索节点先用dataclass定义需求约束和搜索节点。这里的关键是字段不能太复杂否则后续阶段很难复用。from dataclasses import dataclass, field from typing import Optional dataclass class Requirement: id: str text: str constraints: list[dict] field(default_factorylist) dataclass class ArchNode: node_id: str parent_id: Optional[str] stage: str content: dict score: float 0.0 meta: dict field(default_factorydict)ArchNode的stage字段会在搜索器内部反复变化。每进入一个新阶段就创建一个新的子节点而不是修改当前节点。这样便于回溯。3.3 实现阶段处理函数为了演示下面用一个PhasedSearchAgent类来包住各阶段。每个阶段都接收当前节点和搜索上下文返回新节点列表。这里用random模拟 LLM 的多样生成实际项目中可以替换成大模型调用。import random import uuid class PhasedSearchAgent: def __init__(self, budget: int 20, max_candidates: int 3): self.budget budget self.max_candidates max_candidates self.used 0 def _mock_llm(self, prompt: str): # 模拟单次 LLM 调用实际替换为 model.generate(prompt) self.used 1 return random.choice( [ {modules: [auth, order, payment], score_hint: random.uniform(0.3, 0.9)}, {modules: [gateway, user, billing], score_hint: random.uniform(0.3, 0.9)}, {modules: [api, worker, store], score_hint: random.uniform(0.3, 0.9)}, ] ) def parse_requirements(self, reqs: list[Requirement]) - ArchNode: content {parsed_reqs: [r.text for r in reqs]} return ArchNode( node_idstr(uuid.uuid4()), parent_idNone, stageparsed, contentcontent, ) def generate_candidates(self, parent: ArchNode) - list[ArchNode]: nodes [] for _ in range(self.max_candidates): raw self._mock_llm(generate architecture sketches) nodes.append( ArchNode( node_idstr(uuid.uuid4()), parent_idparent.node_id, stagegenerated, content{modules: raw[modules]}, meta{raw_hint: raw[score_hint]}, ) ) if self.used self.budget: break return nodes def local_improve(self, parent: ArchNode) - ArchNode: raw self._mock_llm(improve module splitting) improved_modules parent.content[modules] [f{raw[modules][0]}_improved] return ArchNode( node_idstr(uuid.uuid4()), parent_idparent.node_id, stageimproved, content{modules: improved_modules}, ) def global_validate(self, parent: ArchNode) - ArchNode: # 模拟全局校验检查模块数量是否达标 raw self._mock_llm(validate global architecture) ok len(parent.content[modules]) 3 return ArchNode( node_idstr(uuid.uuid4()), parent_idparent.node_id, stagevalidated, content{modules: parent.content[modules], valid: ok}, )这段代码里的_mock_llm很关键。它把所有可能调用大模型的位置抽象成单一方法后续替换成真实模型时只需要改这一个方法而不用改动搜索流程。3.4 评估器和模拟打分每个候选方案在全局校验后都要打分。这里实现一个非常简单的评估器满足约束项越多、模块数越合理分数越高。def evaluate_node(node: ArchNode, reqs: list[Requirement]) - float: modules node.content.get(modules, []) score 0.0 score min(len(modules), 5) * 0.2 # 模块数合理性5 个模块为上限 for req in reqs: for constraint in req.constraints: if 网关 in constraint.get(value, ) and gateway in modules: score 0.1 if auth in constraint.get(value, ) and auth in modules: score 0.1 node.score score return score这个评估器明显是模拟的。真实项目的评估器应该基于可量化的规则或者调用独立的评测服务。注意不要把评估器实现为搜索器内部的一个隐藏函数否则后续很难单独替换。3.5 组装分阶段搜索主循环主循环负责把各阶段串起来并按预算控制是否继续。def run_search(self, reqs: list[Requirement]) - ArchNode: root self.parse_requirements(reqs) best: Optional[ArchNode] None frontier: list[ArchNode] [] frontier.extend(self.generate_candidates(root)) while frontier and self.used self.budget: node frontier.pop() if node.stage generated: improved self.local_improve(node) validated self.global_validate(improved) score evaluate_node(validated, reqs) validated.score score if best is None or score best.score: best validated frontier.extend(self.generate_candidates(node)) elif node.stage validated: continue return best需要把这段run_search加到PhasedSearchAgent类中并补全缩进。运行时可以看到最终会返回一个validated节点里面带有模块列表和分数。运行入口if __name__ __main__: reqs [ Requirement( idr1, text需要一个带认证和支付的电商系统, constraints[ {type: module, value: auth}, {type: module, value: payment}, ], ) ] agent PhasedSearchAgent(budget15, max_candidates3) best agent.run_search(reqs) print(best.content) print(score:, best.score)这个骨架把分阶段搜索的流程完整串起来了。学习时可以先运行再观察self.used是否在预算内增长。生产环境替换_mock_llm和evaluate_node后可以接入真实模型和真实评估策略。4. 为什么分阶段搜索能在评测中超过人工冠军4.1 复杂任务被拆成小决策错误更容易暴露人工架构设计最大的问题不是经验不足而是注意力预算有限。当需求包含大量约束时人类专家很难在短时间内同时记住所有约束并检查方案是否每个都满足。模型虽然也有 token 上限和上下文丢失问题但分阶段搜索把“检查约束”这个动作拆成独立阶段每次只针对一小部分内容做检查。在 ArchAgent v2 的流程里需求解析阶段会先把所有约束结构化后续每个阶段都能显式读取这些约束。相当于给搜索过程加了一张“约束清单”模型不需要靠记忆只需要在每一阶段对着清单比对。错误因此更早被暴露。4.2 搜索可以回溯人工冠军靠经验覆盖分支有限人工专家在受限时间内通常只会在少数几个候选方向之间选择一旦选定方向就很少返回重建。这是因为回溯需要额外时间而且会打乱已经完成的设计。分阶段搜索天然支持回溯。任何一个候选节点都可以作为新的搜索分支起点。如果某个方向在全局校验阶段分数不高可以回到生成阶段重新生成一批候选。由于搜索过程保留完整路径回溯不需要重新解释需求只需要从某个中间节点继续扩展。这种系统性覆盖能力是人工冠军难以完全复制的。4.3 评估信号更密集模型能快速修正一次性生成方案时模型通常只有在最终阶段才能收到评估信号而且信号很粗只有“这个方案行不行”没有“哪一步出了问题”。分阶段搜索在每个阶段之后都有局部评估模型能根据局部反馈修正下一步动作。例如候选生成阶段发现生成的模块列表缺少auth模块下一轮生成时就可以把这个约束加入提示词。这种反馈循环让搜索过程不断逼近严格满足约束的方案。人工专家同样具备修改能力但修改频率和覆盖范围很难在一个小时内达到机器搜索的密度。4.4 但要注意“击败”只是测评语境下的结果在讨论 ArchAgent v2 超过人工冠军时要区分“测评得分”和“实际生产可用性”。测评通常只覆盖若干指标例如模块覆盖率、约束满足率、评估得分。人工冠军可能在实际可维护性、工程经验、风险判断、团队协商等维度上更强而这些维度很难量化进标准评测集。所以更准确的表述是在特定评测集和量化指标下ArchAgent v2 的分阶段搜索取得了超过人工冠军的成绩。这个结果说明搜索方法在可量化维度上有优势但不能简单断言机器架构设计已经完全取代人类架构师。5. 评测设计如何判断分阶段搜索确实有效5.1 评测集构造不能只追求覆盖面还要构造冲突如果评测集中的需求都比较简单一次性生成也能取得不错分数分阶段搜索的优势就不明显。评测集至少要包含以下几类任务任务类型示例考察点多模块任务电商系统、客服系统模块拆分完整度强约束任务必须满足合规、延迟、成本要求约束满足率约束冲突任务低成本与高可用冲突冲突处理能力增量修改任务在旧架构上增加新功能回溯和局部修改能力开放式设计任务从零设计一套内部平台完整性和全局一致性冲突任务尤其重要。因为一次性生成最怕冲突而分阶段搜索可以通过回溯重新选择方案。若评测集没有冲突体现不出方法优势。5.2 指标定义要覆盖方案质量和过程质量方案质量指标包括约束满足率满足的约束数 / 总约束数。模块覆盖率需求点覆盖到的模块数 / 需求点总数。冲突数量模块之间接口或数据流冲突的次数。资源估算偏差模块资源预估与期望资源的偏差。过程质量指标包括搜索调用次数。达到最优方案时的轮次。回溯次数。稳定率同一需求重复运行得到分数的标准差。没有过程质量指标很难判断搜索是否是在高效工作还是靠大量随机试错撞出来的结果。5.3 对照实验设计v1、v2 与人工冠军为了验证 ArchAgent v2 的收益至少要做三组对照组别方案说明A一次性生成v1 风格单次调用模型生成完整架构B分阶段搜索v2 风格使用本文的搜索流程C人工冠军由指定专家在限定时间内完成三组用同一批评测集统一打分逻辑。人工冠军通常需要多人独立设计取最优成绩避免个人偏好影响。运行多次后统计平均分、最高分、最低分和标准差。若 B 组的平均分和稳定性都高于 A说明分阶段搜索是有效机制若 B 组能超过 C 组的最优结果才能说“击败人工冠军”在本次评测语境下成立。5.4 结果记录要保留完整搜索轨迹记录至少需要包含每次搜索树节点的父节点关系。每个候选方案的评分明细。每个阶段的输入输出摘要。模型调用次数和预算消耗。最终方案的完整内容。只要有这些记录后续才能复现分数定位失败样本。否则评测结果很难被审计。6. 落地分阶段搜索时最容易踩的坑和排查路径6.1 阶段过早剪枝导致遗漏最优解现象搜索跑完最终分数不高而且最优解出现在较早阶段被剪掉的分支上。原因在全局校验之前就根据局部分数丢弃了一些候选。局部分数低不代表全局方案差可能只是某个模块没有优化好。排查方式检查日志中每个被剪枝节点的评分。对比被剪枝节点和最终最优节点的评分。观察是否在 generate 或 improve 阶段就调用了评估器并做了阈值过滤。处理建议剪枝必须基于全局校验结果而不是局部阶段分数。也可以延迟剪枝保留 top-K 局部分数较低的候选留给后续阶段修正。6.2 评估器顺序偏差导致评分倒挂现象同一份方案在不同阶段评估分数不同明明内容没有变化分数却因为约束读取顺序不同而改变。原因评估器在执行约束判断时如果一旦命中某个约束就提前返回或对约束权重处理不一致就会产生顺序偏差。排查方式固定输入顺序多次调用评估器观察分数波动。打印每条约束是否满足找到不一致项。处理建议评估器先收集所有约束结果再统一计算加权分数。评估器设计成纯函数相同输入必须相同输出。6.3 阶段间信息断裂导致模型反复出错现象后续阶段不知道前面阶段已经确定的模块列表又生成了重复或冲突的模块。原因阶段之间传递的是自然语言段落而不是结构化数据。模型每次调用都要从文本中重新提取关键信息容易丢失。排查方式检查每个阶段的实际输入内容。统计重复模块出现的频率。确认节点 content 中是否存在必要字段。处理建议阶段之间只传递结构化 JSON 或 dataclass不传递纯文本摘要。每次调用模型前把关键约束格式化进提示词并确保字段名一致。6.4 搜索预算大量浪费在无效探索现象预算很高但大部分调用都用于生成相似候选没有产生新的信息。原因生成候选时缺少多样性控制每次调用模型都得到几乎相同的结果。排查方式统计候选内容相似度。查看是否存在明显重复的模块组合。处理建议在提示词中要求不同候选关注不同约束例如候选 A 优先满足成本候选 B 优先满足高可用。使用温度参数调整多样性并在生成阶段引入去重逻辑。6.5 日志和回放机制缺失导致无法定位上线问题现象线上运行一次搜索后结果异常但日志只有最终节点中间过程完全不可查。原因没有记录搜索树也没有把阶段间输入输出持久化。处理建议为每个节点生成唯一 ID记录 parent_id。每次阶段调用都写入结构化日志保存输入摘要、输出摘要、耗时和模型参数。定期用一条固定需求做回放对比两次搜索过程的差异。7. 从演示代码到生产环境的工程化建议7.1 搜索策略参数化不要写死在流程里搜索宽度、深度、预算、温度参数都要配置化。不要为了更好地在某一个案例上跑通把max_candidates和budget写死在代码里。推荐配置项search: max_calls: 30 max_candidates: 5 max_depth: 8 enable_backtrack: true backtrack_policy: highest_score_first llm: model: gpt-4o-mini temperature: 0.7 max_tokens: 2048这类配置放到 YAML 或 JSON 文件里方便不同需求切换。7.2 评估器和搜索器解耦不要在搜索器内部直接做评估。搜索器负责选择节点、调用阶段、控制预算评估器负责打分。两者接口分开后可以单独验证搜索器是否在按照策略运行也可以单独测试评估器是否稳定。一个合理接口如下class BaseEvaluator: def evaluate(self, node: ArchNode, reqs: list[Requirement]) - float: raise NotImplementedError搜索器只依赖BaseEvaluator具体评估逻辑由外部传入。7.3 多智能体协作或并行搜索单 Agent 串行搜索的瓶颈是时间。生产环境可以用并行搜索多个搜索器并行运行每个搜索器使用不同的初始候选策略最终汇总分数最高的方案。并行时要特别注意预算管理。共享预算和独立预算的选择会影响结果稳定性预算方式优点缺点独立预算容易控制每个分支总调用次数可能翻倍共享预算总成本可控竞态条件需要处理如果使用共享预算建议用一个计数器统一控制所有并行 Agent 的调用次数。7.4 知识库与经验沉淀搜索器每次生成方案时都会积累大量有效或无效的设计片段。可以把这些片段存入知识库下次生成候选时作为参考。例如历史某个需求要求“低成本 高可用”最终搜索发现用双节点主从比三节点集群更合适这个经验可以沉淀为候选生成阶段的提示词素材。但知识库需要过滤否则会引入噪音。建议只收录经过全局校验且分数高于阈值的方案片段。7.5 可复用的上线前检查清单在把 ArchAgent v2 从实验代码部署到生产环境前建议按下表逐项检查检查项通过标准数据结构完整每个节点都有 parent_id、stage、score 和 content评估器确定性相同输入重复调用分数一致阶段信息传递所有阶段只依赖结构化字段不依赖自然语言记忆预算控制搜索总调用次数不超过配置上限日志回放可从一条日志时间线重建搜索树冲突处理评测集包含至少一个需求冲突案例人工复核最终方案有复核入口标注生成依据降级方案搜索失败时返回最近一次满足基本约束的方案这个清单不是一次性检查建议在每次修改搜索策略或替换模型后重新执行。ArchAgent v2 的分阶段搜索本质上是把“一次想不清楚就多想几步”的思路工程化。它不要求模型每一步都完美只要求每一步都有状态、有评估、能回溯。放在架构设计场景中这种机制比单纯依赖模型能力更可控。实际落地时最值得花时间设计的不是提示词而是阶段划分和评估器。只要状态清晰、评估稳定、预算合理分阶段搜索就有机会在量化评测中超过人工冠军。后续再往前推进可以尝试自动生成阶段策略、让搜索根据任务难度动态调整阶段数量以及把人类专家的评分反馈持续融入评估器。