哇,刚上来一看,上篇文章都是三年前写的了。。。
反正近期也没什么事,记录总结一下近期学到的东西
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最核心的运行循环:
- 模型根据当前上下文判断是不是需要工具。
- 如果需要工具,就返回
tool call格式的数据。 harness收到tool call的数据,做校验并执行工具。- 将执行结果重新拼进上下文。
- 再给上下文整个丢给模型。
- 重复以上过程,直到模型认为任务已经完成,此时将结果作为最终输出。
markdown
模型做决策
↓
harness调用工具
↓
工具返回结果
↓
harness更新上下文
↓
模型基于新的上下文重新做决策
因为模型实际每次请求时它都会重新读取当前提供给它的上下文,然后重新开始推理。所以整个过程中,真正持续存在的其实不是模型,而是harness持续更新的上下文。
它不一定就是保存聊天记录,还可以包括:
- 工具调用历史
- 当前任务状态
- 中间变量
- 记忆
- 计划(如果有的话)
- 已经生成的文件
- 运行日志
- ...
这些共同组成了agent当前的运行状态。但很多时候并不会把所有运行状态全部塞给模型。
因为因为上下文窗口是有限的,聊天来来回回十次百次千次,兴许上下文就爆了。
所以harness往往还需要一个上下文构建器,负责从你对话中积攒的大量上下文中挑出这一轮真正有价值的信息,再交给模型。
也就是说tool calling只是harness的基础。
真正决定一个agent好不好用的,往往是:
- 状态怎么维护;
- 上下文怎么提炼、语言怎么组织;
- 哪些信息该给模型;
- 哪些信息应该被丢掉(此处应有:"正在压缩上下文...")。
4. 简单总结
反正就一句话:模型负责思考,harness让模型思考转化为实际行动。
那么这篇文章内容就这些,当然了,本意还是为了归纳总结,自己能强化记忆已经不算白写,如果能帮到对harness有兴趣的人,那更是赚到了口牙