✨ 复制成功!

以文会友,打造好学人设!

📋 已复制到剪贴板:

《Agent Harness入门教程》


1 AI Agent与Harness概述
    1.1  什么是AI Agent

    1.2  什么是Agent Harness

    1.3  为什么需要Harness

2 核心概念与架构模式
    2.1  Agent的核心循环

    2.2  Harness的典型架构

    2.3  单Agent vs 多Agent

    2.4  Agent生命周期

    2.5  核心术语表

3 环境搭建与基础组件
    3.1  选择LLM Provider

    3.2  搭建最小Harness

    3.3  实现工具调用机制

    3.4  结构化输出与解析

    3.5  日志与调试基础

4 工具系统设计
    4.1  工具的定义与注册

    4.2  工具Schema设计

    4.3  安全沙箱

5 记忆与会话管理
6 Agent推理与规划
7 商业项目实战练习

快速体验:10分钟跑通第一个Agent

创建时间:2026-08-31 更新时间:2026-09-04 阅读次数:1913 次

本节目标

在开始深入Harness的架构和原理之前,先亲手跑一个最小可用的Agent。这个Agent虽然简单,但它具备了完整的“感知-思考-行动”循环:接收一个目标,自主决定调用哪个工具,并基于工具结果给出最终回答。

你需要准备:

  • 一台能联网的电脑
  • Python 3.10+
  • 一个OpenAI API Key(或兼容的模型服务)
  • 10分钟

lets go,让我们开始这段奇妙旅程吧。

第一步:安装依赖

创建项目目录,安装两个库:

mkdir my-first-agent
cd my-first-agent
pip install openai rich

openai 用于调用LLM,rich 只是为了打印更美观的运行日志,不装也不影响核心逻辑。

第二步:配置API Key

将你的API Key设置为环境变量:

export OPENAI_API_KEY="sk-..."

第三步:编写Agent

创建一个文件 agent.py,输入以下代码:

import json
from openai import OpenAI

client = OpenAI()

# ---------- 1. 定义工具 ----------

def get_weather(city: str) -> str:
    """查询指定城市的天气(模拟数据)。"""
    mock_data = {
        "北京": "晴,26°C,湿度40%",
        "上海": "多云,29°C,湿度65%",
        "深圳": "雷阵雨,31°C,湿度80%",
    }
    return mock_data.get(city, f"暂无{city}的天气数据,请确认城市名称")

def calculate(expression: str) -> str:
    """计算数学表达式。"""
    try:
        result = eval(expression, {"__builtins__": {}}, {})
        return f"计算结果:{result}"
    except Exception as e:
        return f"计算出错:{e}"

# 工具的JSON Schema,告诉LLM如何调用它们
TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "查询指定城市的天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名称"}
                },
                "required": ["city"]
            }
        }
    },
    {
        "type": "function",
        "function": {
            "name": "calculate",
            "description": "计算数学表达式,支持加减乘除和括号",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {"type": "string", "description": "数学表达式,如 '(3+5)*2'"}
                },
                "required": ["expression"]
            }
        }
    }
]

# 工具名到函数的映射
TOOL_MAP = {
    "get_weather": get_weather,
    "calculate": calculate,
}

# ---------- 2. Agent核心循环 ----------

def run_agent(user_input: str, max_iterations: int = 5):
    messages = [{"role": "user", "content": user_input}]

    for turn in range(max_iterations):
        # 调用LLM
        response = client.chat.completions.create(
            model="gpt-4o-mini",  # 用便宜快速的模型即可
            messages=messages,
            tools=TOOLS,
        )
        message = response.choices[0].message

        # 如果LLM要调用工具
        if message.tool_calls:
            # 把LLM的决策加入对话历史
            messages.append(message)

            for tool_call in message.tool_calls:
                name = tool_call.function.name
                args = json.loads(tool_call.function.arguments)

                print(f"[Agent调用工具] {name}({args})")

                # 执行工具
                result = TOOL_MAP[name](**args)
                print(f"[工具返回] {result}")

                # 将工具结果加入对话历史
                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.id,
                    "content": result
                })
        else:
            # LLM直接给出了最终回答
            return message.content

    return "达到最大迭代次数,Agent未能完成任务"

# ---------- 3. 运行 ----------

if __name__ == "__main__":
    print("=" * 50)
    print("你的第一个AI Agent")
    print("试试:北京和上海哪个更热?答案乘2是多少?")
    print("=" * 50)

    while True:
        user_input = input("\n你> ").strip()
        if user_input.lower() in ("exit", "quit"):
            break
        if not user_input:
            continue

        answer = run_agent(user_input)
        print(f"\nAgent> {answer}")

第四步:运行并观察

python agent.py

输入一个需要多步推理和工具调用的问题:

你> 北京今天多少度?这个数字乘以3再加5等于多少?

你会看到类似这样的输出:

[Agent调用工具] get_weather({'city': '北京'})
[工具返回] 晴,26°C,湿度40%
[Agent调用工具] calculate({'expression': '26 * 3 + 5'})
[工具返回] 计算结果:83

Agent> 北京今天26°C。26 × 3 + 5 = 83。

代码背后到底发生了什么?

让我们拆解这段代码背后的核心机制:

第一,工具定义是Agent的“能力边界”。

TOOLS 列表中的JSON Schema告诉LLM:“你有两个工具可用,一个查天气,一个算数学。查天气需要一个city参数,计算需要一个expression参数。”没有这些定义,LLM不知道它能做什么。

第二,Agent循环是“感知-思考-行动”的不断重复。

用户输入 → LLM判断是否需要工具 → 需要 → 执行工具 → 结果反馈给LLM
                                      ↑              │
                                      └──────────────┘
                                    循环,直到LLM认为可以回答

每一轮循环中,LLM看到的是完整的对话历史(包括之前的工具调用和结果),这让它能够基于新信息做出下一步决策。

第三,LLM自主决定了调用什么、以什么顺序调用。

用户只说了“北京今天多少度?这个数字乘以3再加5等于多少?”——没有说“先查天气,然后算数学”。Agent自己知道:

  • 需要先查天气获取温度
  • 温度是26,需要计算26×3+5
  • 两个工具都完成了,可以给出最终答案

这就是Agent与普通程序最本质的区别:你定义工具,它决定如何使用。

你还可以试着这样玩

运行起来之后,你可以尝试不同的输入,观察Agent的行为:

场景A:Agent不知道答案,会主动调用工具

你> 深圳现在下雨吗?
[Agent调用工具] get_weather({'city': '深圳'})
[工具返回] 雷阵雨,31°C,湿度80%

Agent> 是的,深圳现在有雷阵雨,气温31°C。

场景B:不需要工具时,Agent直接回答

你> 你好,介绍一下你自己
Agent> 你好!我是一个AI助手,可以帮你查询天气和计算数学表达式...

场景C:信息不足时,Agent会尝试弥补

你> 帮我查一下天气
[Agent调用工具] get_weather({'city': '北京'})  # 可能默认查北京

场景D:工具没帮上忙时,Agent会老实说明

你> 广州今天天气如何?
[Agent调用工具] get_weather({'city': '广州'})
[工具返回] 暂无广州的天气数据,请确认城市名称

Agent> 抱歉,我暂时查不到广州的天气数据。

这个Agent“缺”了什么?

跑通了这个Agent,你就有了一个最小可用的Harness雏形。但它距离“可靠”还有很长的路:

缺失的能力可能导致的问题
记忆管理每个问题都是全新对话,Agent不记得你上一轮说过什么
错误重试工具调用失败时,Agent不会自动重试或换策略
执行日志关掉终端就丢了全部运行记录,出问题无法回溯
评估体系你不知道这个Agent回答得对不对,更不知道改了Prompt后是变好还是变坏
安全边界eval() 执行任意表达式,如果用户输入恶意代码怎么办?
成本控制没有token计数,不知道每次运行花了多少钱

这些问题,正是本书后面各章节要逐一解决的。现在,你只需要记住:你已经亲手写了一个Agent,它能在没有你逐步指导的情况下,自主选择工具并完成任务。

常见问题排查

Q: 运行报错 AuthenticationError?

确认环境变量设置正确:echo $OPENAI_API_KEY 应该能看到你的key。

Q: Agent反复调用同一个工具,陷入循环?

这是LLM推理不稳定的表现。可以尝试换一个模型(如 gpt-4o),或者简化问题。本书后面第6章会讨论如何用Harness来缓解这类问题。

Q: 想用国产模型或本地模型?

将 client = OpenAI() 改为指向兼容的API端点:

client = OpenAI(
    base_url="https://your-model-endpoint.com/v1",
    api_key="your-key"
)

只要模型支持Function Calling,代码逻辑完全一样。

留给读者的扩展思考

在你进入下一章之前,留三个问题给自己:

  • 如果工具执行耗时10秒,这个Agent会怎样?用户会看到什么?
  • 如果同时有100个用户在问问题,这段代码能直接部署吗?为什么?
  • 如果你把 get_weather 的模拟数据删掉,换成真实的天气API,Agent的行为会有什么变化?

带着这些问题继续读下去,你会更清楚Harness要解决的究竟是什么。

本教程共32节,当前为第5节!
本教程最新修订时间为:2026-09-30 09:02:04

📌 面试天下网:一款服务于上班族的口袋书,让大家在地铁里/公交上可以学习大模型技术!
📌 网站公告:【悬赏 200 元/篇】寻找“大模型面试战场”的一手回忆录
📌 网站公告:【大模型/Agent面试陪练1V1指导】正式启动......

评论专区

评论加载中...