写点粗浅的harness相关内容(1)

哇,刚上来一看,上篇文章都是三年前写的了。。。

反正近期也没什么事,记录总结一下近期学到的东西

1. harness是什么?

其实也没什么高谈阔论,我们直接从主旨说起吧:

harness 是什么?

我第一次琢磨的时候想的很简单:

LLM为核心,通过代码或者提前写好的提示词、校验规则,实现一个具有特定功能的系统。

这个理解对吗?只能说方向上没什么问题但说不上准确。实际上harness应该是"以LLM为核心决策组件,通过代码、提示词、工具、状态管理以及各种运行规则,把模型组织成一个能够持续完成任务的系统。"

很多人第一次接触harness,都会把它理解成提示词工程(正是在下= =)。

实际上提示词只是其中的一部分,思考是模型的事情,harness本身不负责思考。

harness真正负责的是:LLM的思考能够变成实际行动。


2. 关于use tool(重点)

那,那我问你,这个行动怎么实现的?

如果模型想查个天气,它总不能真的执行代码吧?

那当然是不行的,毕竟我们用的LLM就一生成模型,它能做的事情只有一件:唠嗑,根据上下文生成内容。它不会执行函数,也不知道什么是调用。真正执行工具的一直都是harness

那问题又来了,harness又是怎么知道模型想调用哪个工具的?

其实也就是在请求模型的时候,我们会把所有允许它用的工具一起发过去。

举个例子:

json 复制代码
{
  "name": "search_weather",
  "description": "查天气",
  "parameters": {
    "type": "object",
    "properties": {
      "city": {
        "type": "string",
        "description": "城市名"
      }
    },
    "required": ["city"]
  }
}

这串JSON通常被叫做 Tool Schema

可以理解成:我现在手头有的,模型可以用的工具。 模型看到这些Tool Schema之后,如果认为当前任务需要用到某个工具,则会返回一个结构化的数据,比如:

json 复制代码
{
  "tool_call": {
    "name": "search_weather",
    "arguments": "{\"city\":\"A市\"}"
  }
}

解析后就是:

json 复制代码
{
  "city": "A市"
}

这个数据很关键。它就是在告诉系统:"我觉得应该调用search_weather"。

那么问题又来了。

模型怎么知道返回这样的数据呢?我需要提前约束吗?其实是不用的,现在主流的大模型 API 基本都原生支。所以也不需要自己在提示词里先写一堆要求,比如 "返回什么什么格式的JSON"

而是通过 API 把 tools 一起传给模型。

模型如果决定调用工具,API 返回的就是专门的 tool_call/function_call 字段,就像上面写的那个一样。


3. harness具体怎么工作的?

收到这个格式的响应消息之后,harness才会开始工作。

它会先检查:

  • 这个工具在我们的tool schema中是否存在?
  • 参数是否合法?
  • 当前用户权限够不够?(如果有权限的设计)
  • 这个操作是不是危险操作?
  • 需要用户二次确认吗?

全部通过以后,才会跑去执行你的search_weather()

然而,得到执行结果之后,这个流程并不一定就结束了。


假设用户说:

帮我查看当前目录有哪些py格式的文件。

第一轮,模型不知道目录里有什么。于是它觉得该调用file_list方法。

scss 复制代码
file_list(".")

harness执行之后,得到:

css 复制代码
main.py
agent.py
README.md
test.py

显然任务到这里时还没有结束。

所以harness会把这次执行返回的结果也结果追加上下文中,于是下一轮发送给模型的内容,就变成了:

css 复制代码
User:
帮我查看当前目录有哪些py格式的文件。

Assistant:
调用了 list_files。

Tool:
main.py
agent.py
README.md
test.py

模型再次收到请求的时候,并不是接着上一轮继续思考,而是重新阅读整个上下文,那么看到这里它就知道当前目录里都有点什么文件。接下来它可以继续调用新的工具(比如find_py),也可以直接给出最终答案。

这也是agent最核心的运行循环:

  1. 模型根据当前上下文判断是不是需要工具。
  2. 如果需要工具,就返回tool call格式的数据。
  3. harness收到tool call的数据,做校验并执行工具。
  4. 将执行结果重新拼进上下文。
  5. 再给上下文整个丢给模型。
  6. 重复以上过程,直到模型认为任务已经完成,此时将结果作为最终输出。
markdown 复制代码
模型做决策
    ↓
harness调用工具
    ↓
工具返回结果
    ↓
harness更新上下文
    ↓
模型基于新的上下文重新做决策

因为模型实际每次请求时它都会重新读取当前提供给它的上下文,然后重新开始推理。所以整个过程中,真正持续存在的其实不是模型,而是harness持续更新的上下文。

它不一定就是保存聊天记录,还可以包括:

  • 工具调用历史
  • 当前任务状态
  • 中间变量
  • 记忆
  • 计划(如果有的话)
  • 已经生成的文件
  • 运行日志
  • ...

这些共同组成了agent当前的运行状态。但很多时候并不会把所有运行状态全部塞给模型。

因为因为上下文窗口是有限的,聊天来来回回十次百次千次,兴许上下文就爆了。

所以harness往往还需要一个上下文构建器,负责从你对话中积攒的大量上下文中挑出这一轮真正有价值的信息,再交给模型。

也就是说tool calling只是harness的基础。

真正决定一个agent好不好用的,往往是:

  • 状态怎么维护;
  • 上下文怎么提炼、语言怎么组织;
  • 哪些信息该给模型;
  • 哪些信息应该被丢掉(此处应有:"正在压缩上下文...")。

4. 简单总结

反正就一句话:模型负责思考,harness让模型思考转化为实际行动。

那么这篇文章内容就这些,当然了,本意还是为了归纳总结,自己能强化记忆已经不算白写,如果能帮到对harness有兴趣的人,那更是赚到了口牙

相关推荐
星栈7 小时前
oh-my-pi工程级AI编码工使用体验
人工智能·后端·agent
周末程序猿7 小时前
LLM智能路由实践:通过 Harness 工程节约模型成本
人工智能·agent
玉鸯11 小时前
多 Agent 系统通信的实现原理与最佳实践
llm·agent·mcp
Tsonglew11 小时前
OpenWorker 代码解剖:一个 AI 同事"敢让它干活"的工程学
agent·ai编程
测试开发技术13 小时前
AI 测试提效 | 告别手工写脚本,分享我的 Playwright + Skill 批量生成 UI 自动化脚本方案
自动化测试·人工智能·ui·自动化·agent·skill·ai测试
喜欢的名字被抢了13 小时前
langgraph教程系列-06-让流程可暂停 - 持久化与 checkpoint
agent·langgraph
喜欢的名字被抢了14 小时前
langgraph教程系列-05-给 agent 装上手脚 - 工具调用
agent·教程·langgraph
leeyi14 小时前
Embedder 接口 + 缓存层源码:一个把 key 撑大 3 倍的实现(第71篇-E57)
aigc·agent·ai编程
JaydenAI14 小时前
[Agent的评估-07]整合MEAI针对自然语言处理相关的评估器
ai·nlp·agent·evaluation·maf