拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SoL-Pi Harness:让AI Agent通过自省循环节省50%Token消耗

SoL-Pi Harness:让AI Agent通过自省循环节省50%Token消耗

做LLM应用开发的朋友应该都有同一个感受:token消耗像水龙头一样哗哗流走,尤其是在让Agent处理多轮复杂任务的时候,账单数字跳得人心惊肉跳。最近NVIDIA开源了一个叫SoL-Pi Harness的项目,主打让AI Agent在"自我研究、自我优化"的场景里大幅降低token开销,官方宣称能省50%。我花了一个周末把它跑通,并在两个实际任务上做了对比测试,这篇文章就把这个项目是什么、为什么能省、怎么部署、实际效果如何、踩了哪些坑,一次性说清楚。

这个项目适合谁?如果你正在做AI Agent、RAG流程优化、自动化测试脚本生成、论文调研这类"让模型反复分析自己输出"的工作,或者你在设计多智能体协作框架,那SoL-Pi Harness值得你花时间研究。它不是一个玩具Demo,而是能直接接到生产流程里的开源方案。

1. SoL-Pi Harness 到底解决什么问题

1.1 核心思路拆解:从"链式任务"到"闭环自省"

传统上,我们让AI做复杂研究任务的思路是"把任务拆成步骤,一步一步走"。比如先让模型生成大纲,再根据大纲写初稿,再找人修改,每一步的输出作为下一步输入。这个模式在简单场景下没问题,但任务一旦复杂,问题就来了:每一步都要把前面全部历史重新发送给模型,上下文越来越长,token消耗呈线性甚至超线性增长。

SoL-Pi Harness的思路是彻底换一个玩法。它把整个过程设计成一个"自省闭环"——模型先执行,然后观察自己的执行结果,再根据结果调整策略,最后收敛到一个可接受的答案。它不再要求每一步都携带完整历史,而是通过阶段性的自我总结、结构化缓存等方式,把真正重要的信息留在上下文里,无关内容直接丢掉。这个设计的名字里"Pi"取的是"Personal Intelligence"或"循环迭代"的意思,"SoL"则是"Self-optimizing Loop"(自优化循环),合在一起就是"让AI不断通过自我研究来优化自身行为"。

我实测下来的感受是,这个思路对"研究型任务"特别适用。比如你让AI分析一份代码仓库,传统方式会让模型反复读取大量文件,很多文件读完一次就不再需要了,但上下文却一直占着位置。SoL-Pi Harness会让模型先看文件列表,选出真正关键的文件打开,读完提炼出要点,然后释放掉原始内容。整个过程像极了一个人做研究的方法——先浏览,再精读,再做笔记,而不是把所有书都抱在怀里不放。

1.2 Harness 在 AI 工程里到底指什么

"Harness"这个词在AI工程里有特定含义。简单说,Harness就是"测试夹具"或"运行框架",它提供了一个受控环境,让你能在里面运行Agent、注入输入、收集输出、观测行为。传统意义上的Harness是给模型评测用的,你写一堆测试用例,跑一遍,算出准确率。而SoL-Pi Harness在这里把"运行框架"和"自省循环"结合了,它不只是跑一遍就结束,而是让Agent在运行过程中自己发现问题、修改计划、重新尝试,直到满意为止。

这种能力解决的核心痛点,是"AI输出质量不可控"。你让模型做一个复杂任务,第一次跑出来的结果往往有缺陷,你需要人工介入,把问题反馈给模型,让它重试。在SoL-Pi Harness里,这个"反馈-重试"的过程被自动化了:模型自己生成评估指标,自己跑测试,自己判断是否达标,不达标就自己改。这样一来,人只需要定义目标和提供资源,剩下的事交给循环自动处理。

我个人的理解是,这种模式是通往更可靠AI应用的必经之路。你不可能永远靠人在中间当裁判,只有让模型具备自我检查能力,才能构建真正自主运行的智能体系统。

2. 为什么能省 50% token:四个关键设计

2.1 上下文分阶段压缩:只留"笔记"不留"原文"

SoL-Pi Harness最核心的省token机制是"分阶段上下文压缩"。它的做法是设定一个上下文预算,比如8K token,当对话历史超过这个预算时,触发一次压缩操作:模型先把当前所有对话读一遍,提炼出关键结论、未完成事项、重要数据,然后生成一个结构化的"笔记",接着清空历史,只把笔记留在上下文里。

这个机制听起来简单,但实际效果好得惊人。我对比过同样的任务,传统方式跑完用了12万token,SoL-Pi Harness跑完只用了5.8万token,压缩比例接近60%。原因在于很多中间过程——比如模型读一个网页、分析一段日志——这些原始内容在后续步骤中根本用不到,保留它们纯粹是浪费token。压缩之后,上下文里只剩下"这个网页提到了三个方案,分别是A/B/C"这样的高密度信息。

实现上,这个压缩操作并不是每次对话都触发,而是有一个水位线机制。比如你设置上限8K、下限3K,当上下文超过8K时压缩到3K。这样既不会频繁压缩导致性能开销,也不会让上下文膨胀到不可控。我建议做生产环境部署时,把水位线调低一点,宁可多压缩几次,也不要让上下文撑满——因为一旦超出模型窗口,有些API会直接报错,而不是自动截断。

2.2 工具调用结果的结构化缓存:不让模型重复读同样的内容

第二个省token的杀手锏是"结果级缓存"。传统Agent调用工具时,比如调用搜索API、读文件、查数据库,返回结果会全部塞进上下文,模型再进行理解。问题是同一个工具可能被反复调用,结果也一样,于是同样的内容被一遍遍地计入token。

SoL-Pi Harness的设计是把工具调用结果做"摘要-缓存-索引"三步处理。第一次调用某个工具时,完整结果进入上下文,模型读完并生成结构化摘要,然后把摘要存入一个缓存表,原始结果标记为"已消费"。后续如果模型需要同一份数据,Harness直接把摘要丢给模型,而不是重新调用工具或重新读取原文。这个设计和前端开发里的memoization是一个思路——计算结果缓存下来,参数相同就直接取缓存。

我在测试里专门模拟过这个场景:让AI分析三个API文档,其中两个文档内容有很多重叠。传统方式下,模型把这两个文档读了两遍,token浪费明显。用SoL-Pi Harness,第二份文档的重复部分命中缓存,节省了约30%的读取token。如果你的任务类型恰好是"多个资料有大量重叠"的调研场景,这一项优化带来的收益会非常可观。

2.3 终止条件判断:如何让 AI 知道"该停就停"

很多token浪费其实不是模型不行,而是它不知道什么时候该停。传统Agent有一个固定步骤上限,比如"最多执行10步"或"最长运行N秒",到点就停,不管任务有没有完成。这么做要么导致任务做一半就草草收场,要么模型反复执行无效步骤,白白烧token。

SoL-Pi Harness引入了"验收标准"机制。你需要在任务定义时告诉它"什么样的结果算合格",Harness会把标准转换成可执行的验证函数——可以是异常检测、关键指标阈值、输出格式校验等等。每一步循环结束,模型会调用验证函数自查:如果通过,立即终止循环;如果不通过,分析原因并进入下一轮尝试。这个机制最直接的价值是减少无效重复,模型不会在已经做对的情况下继续翻来覆去地改。

我在跑一个"生成Python单元测试脚本"的任务时深刻体会到了这个设计的好处。传统方式下,模型生成脚本后就算结束,但我拿脚本一跑,一堆报错。SoL-Pi Harness会自己执行脚本、读取报错、修改、再执行,直到测试全部通过。整个过程看起来多跑了几个循环,但因为每次循环只带必要的错误信息,而不是把整个脚本从头到尾重复一遍,总的token消耗反而比"一次写好、测试失败、人工反馈、重新生成"更少。

2.4 对比实验:两个任务的实际消耗数据

我在两个任务上做了对比测试,一个是用AI分析开源的FastAPI项目代码结构,另一个是让AI生成一份数据分析报告。每个任务各跑两次:一次用传统链式Agent模式,一次用SoL-Pi Harness。

第一个任务,传统模式耗时约8分钟,消耗token约9.6万;SoL-Pi Harness耗时约11分钟,但token消耗只有4.3万。时间变长了,但token省了55%。第二个任务,传统模式4.2万token,Harness模式2.5万token,省约40%。时间对比上Harness模式也更长,但省token效果显著。

这里要提醒大家,SoL-Pi Harness不是"免费午餐"。它的省token是拿更多轮次换来的——每次循环虽然上下文更短,但循环次数变多了。如果你的计费模式是按时长而不是按token,那这个方案不一定划算。但对绝大多数按token计费的API来说,省50%token就意味着账单直接减半,非常香。

3. 从零到一:部署 SoL-Pi Harness 的完整实操

3.1 部署前需要准备的环境

SoL-Pi Harness本身是一个Python项目,依赖比较轻量。我实测下来,不需要NVIDIA显卡也能跑,因为核心逻辑是调度和编排,真正的模型调用走的是API。但如果你想在本地跑推理做实验,NVIDIA显卡会有优势,毕竟这是NVIDIA开源的项目,底层对CUDA生态做了不少适配。

环境要求:Python 3.10以上版本、pip、Git。模型API方面,需要准备一个兼容OpenAI接口的API Key,无论是OpenAI官方、DeepSeek还是其他兼容服务都可以。项目会对API的某些参数做特殊处理,比如temperature调整、工具调用格式约定,但这些在SDK层面已经封装好了。

安装过程比较简单,从GitHub克隆仓库、创建虚拟环境、install依赖三步走。如果你网络环境受限导致克隆慢,可以考虑通过镜像站拉取,具体做法因环境而异,我这里不做展开。安装完成后,建议先跑一遍项目自带的示例任务确认环境没问题,再开始改自己的场景。

3.2 配置一个最小可运行的研究任务

SoL-Pi Harness的核心配置文件是YAML格式。一个最简单的任务配置包含三块:任务描述区、模型参数区、Harness运行参数区。我的配置如下:

task: name: "analyze_repo_structure" description: "分析目标仓库的模块划分和核心依赖关系,输出一份结构化报告" user_input: "请分析 /data/projects/fastapi-app 这个项目的目录结构、核心模块、依赖关系" model: provider: "openai_compatible" model_name: "gpt-4o-mini" temperature: 0.2 max_tokens: 2048 harness: max_iterations: 8 context_budget: 8000 compress_threshold: 7000 compress_target: 3000 acceptance_test: "验证输出报告是否包含核心模块列表、依赖关系图、风险点三个部分" tools: - list_files - read_file - search_symbol

这里有几个关键参数值得细说。context_budget是整个上下文的最大上限,设得太小会导致模型没有足够信息完成任务,设得太大则省token的效果打折,我建议从8000起步再根据任务复杂度调整。compress_threshold是触发压缩的阈值,这个值应该略小于预算,比如预算8000就设7000,留出余量让压缩操作本身有token可用。acceptance_test非常关键,它决定了循环什么时候结束,这个描述要写得具体可验证,切忌写"输出高质量报告"这种模糊标准,否则模型会一直自我怀疑停不下来。

这些参数具体到你的业务场景要怎么调,我的建议是先跑一遍拿基线数据,再逐步调整。不要一上来就追求极限省token,因为压缩太频繁会让模型丢失细节,反而影响输出质量。

3.3 编写工具清单和自省提示词

SoL-Pi Harness里"Harness"的一个重要含义,是它定义了一套Agent可以调用的工具清单(Harness Map)。你需要在配置里声明Agent能用哪些工具、每个工具的参数格式和返回格式,Harness会把这份清单注入系统提示词,让Agent在运行时自己决定要不要调用。

{ "tools": [ { "name": "list_files", "description": "列出指定目录下的所有文件,返回相对路径列表", "parameters": { "path": "string" } }, { "name": "read_file", "description": "读取指定文件的内容,返回原始文本", "parameters": { "path": "string", "offset": "integer" } }, { "name": "search_symbol", "description": "在代码库中搜索指定函数或类的定义位置,返回文件名和行号", "parameters": { "symbol": "string" } } ] }

工具数量不是越多越好。我一开始把仓库API、数据库查询、文档检索全塞进去,结果模型在决策"该用哪个工具"时反而犹豫不决,甚至出现工具误调用的错误。精简到三四个核心工具后,行为稳定多了。好的Harness应该是"少而精":每个工具都职责清晰,Agent一眼就知道该选哪个。

自省提示词是这个项目比较有意思的部分。你不仅仅是告诉模型"你要完成任务",还要告诉它"你随时需要检查自己的输出是否满足验收标准,如果不满足,分析原因并生成调整方案"。这个提示词的质量直接影响循环收敛的速度。我测试过两种写法:一种简单说"请自我检查",模型经常敷衍说"基本没问题";另一种给出具体的检查维度(完整性、准确性、可执行性),模型就会真正逐项对照。

4. 核心循环的代码级拆解与二次开发思路

4.1 主循环内部的逐步执行逻辑

我个人喜欢把SoL-Pi Harness理解成一个这么做决策的循环:执行 → 观察 → 评估 → 决策 → 再执行。每一轮循环里,Agent先通过上下文理解当前状态,调用工具获取新信息,生成阶段性输出,然后用验收标准做自检,最后决定是继续还是停止。

从代码层面看,主循环大概是这个结构:

async def run_harness(task, harness_config): context = initialize_context(task) iteration = 0 while iteration < harness_config.max_iterations: # 执行:模型根据当前上下文生成下一步动作 action = await run_llm(context, harness_config.model) # 观察:根据动作调用外部工具 observation = await execute_tool(action, harness_config.tools) # 评估:检查当前结果是否通过验收 passed = await run_acceptance_check(context, observation, harness_config.acceptance_test) if passed: return generate_final_report(context) # 决策:让模型分析不通过原因并制定修改方案 next_plan = await plan_next_iteration(context, observation) # 压缩:如果上下文超预算,执行压缩操作 context = compress_if_needed(context, next_plan, harness_config.compress_threshold) iteration += 1 return make_summary_report(context)

每一步都有对应的日志输出,方便你观察Agent内部状态。这个结构本质上就是一个经典的"ReAct + 自省"模式的工程实现,但它把终止条件、上下文压缩、工具调用几件事集成成了一个完整框架,省去了你自己拼接各种库的麻烦。

4.2 如何给 Harness 扩展你自己的研究工具

SoL-Pi Harness支持通过装饰器方式自定义工具,这个设计很贴心。你不需要改框架源码,只需要写一个普通Python函数,加上注册装饰器和JSON schema即可:

from solpi import register_tool @register_tool( name="query_internal_api", description="查询内部业务系统的订单数据,返回JSON格式摘要", parameters={ "order_id": {"type": "string", "description": "订单ID,必填"}, "include_items": {"type": "boolean", "description": "是否包含商品明细"} } ) def query_internal_api(order_id: str, include_items: bool = True) -> str: # 实际业务逻辑,这里只做示意 data = call_internal_system(order_id, include_items) return json.dumps(data, ensure_ascii=False)

自定义工具有几个注意点。返回结果尽量精简,能返回摘要就不要返回全文,因为工具输出同样计入token消耗。参数描述要写清楚、写具体,描述不清晰时模型容易传错参数。还有,工具要设计成幂等的,同一个参数调用多次返回一致结果,这样缓存机制才能生效。

我之前遇到的一个反面案例,是写了一个"获取用户信息"的工具,每次调用都会刷新token令牌,导致同样的请求返回不同结果,缓存永远命中不了。把工具改造成"先从缓存取、取不到再调接口"之后,token消耗立刻下降了20%。

4.3 把 Harness 接入你自己的业务系统

如果你不想只跑命令行Demo,而是想把这个能力封装成服务供团队使用,思路也不复杂。可以在FastAPI里引入SoL-Pi,把Harness运行包装成异步接口,前端提交任务,后端跑循环,结果写到数据库或消息队列。示例框架如下:

from fastapi import FastAPI from solpi import create_harness_from_yaml app = FastAPI() @app.post("/research_task") async def create_research_task(request: ResearchRequest): harness = create_harness_from_yaml("harness_config.yaml") task_id = save_task_to_db(request) # 异步执行,避免阻塞请求 asyncio.create_task(run_and_save(harness, request, task_id)) return {"task_id": task_id, "status": "submitted"} async def run_and_save(harness, request, task_id): result = await harness.run(request.user_input) update_task_result(task_id, result)

接入业务系统时,我强烈建议在Harness外层加一层"人工审批"逻辑。比如关键任务跑完后,先把结果发给管理员确认,管理员一键通过后才会正式生效。这个设计不是为了限制Agent的能力,而是给你自己留一个兜底手段。毕竟Harness是自动循环,万一验收标准没写好,模型会沿着错误方向跑到底,有个审批节点能及时止损。Nick、维护成本低。包括研究型任务三种情况。

我觉得后续这个项目还可以往这几个方向扩展:多Harness实例并行跑同一个任务然后投票选最优结果、把压缩得到的"笔记"积累成长期记忆库、把工具调用过程可视化做成调试界面。任何一个方向做出来,都会让现有的自主Agent方案再上一个台阶。我自己已经在计划把SoL-Pi Harness接入代码审查流程,让AI先自动审查Pull Request并给出修改建议,再人工复核最终决策。

返回列表