ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

LLM Agent Harness架构详解:从核心组件到工程实践

2026/8/30 7:17:32 拓冰建站 浏览量
LLM Agent Harness架构详解:从核心组件到工程实践 2026年了AI 应用开发已经从前两年的“调 API 跑 demo”进入到“把模型真正嵌进业务系统”的阶段。很多同学在 B 站刷到了 Harness 相关视频看完觉得每个点都懂但真要自己动手实现一套可控的 Agent 应用还是会卡在工具编排、上下文管理、安全拦截这些细节上。网上关于 Harness 的讲解比较零散有讲 CI/CD 的有讲测试脚手架也有讲大模型 Agent 运行时的混在一起很容易看晕。这篇文章会把 Harness 架构重新梳理成一套完整的学习路径先搞清楚它到底解决什么问题再拆解核心组件然后从零实现一个轻量级 LLM Agent Harness最后补充高频面试题和工程最佳实践。无论你是在准备大模型岗位面试还是想把 DeepSeek、Codex 这类模型工具落地到实际项目都可以直接参考这套思路。1. 背景与核心概念1.1 Harness 在不同技术语境下的含义“Harness”这个词本身有“捆绑、控制、驾驶”的意思在不同技术领域里有不同指向刚接触时容易混淆。在 CI/CD 领域Harness 是一个持续交付平台产品解决部署流水线、灰度发布、变更审批等问题。在软件测试领域Test Harness 通常指自动化测试的脚手架负责启动被测系统、加载数据、执行用例并汇总结果。在大模型应用开发领域Harness 通常指围绕 LLM 和 Agent 打造的“运行时支撑层”它把模型调用、工具注册、上下文管理、安全策略、日志观测等横切逻辑收拢在一起让开发者不用每次从零搭一套轮子。本文讨论的是第三种也就是大模型应用与 Agent 开发中的 Harness 架构。你可能还听过 DeepSeek Harness、Codex Harness 这类社区项目它们的命名逻辑也类似在某个具体模型或 CLI 工具之上再封装一层可编排、可扩展、可监控的运行框架。1.2 为什么大模型应用开发需要 Harness先看一个常见场景你要做一个能查天气、能算数、能查数据库的智能助手。如果用最原始的方式写通常要处理下面几类问题每次调用模型前都要手动拼系统提示词、历史上下文、用户问题。模型返回了工具调用指令你要自己解析 JSON 参数再写一堆 if-else 分发到不同函数。工具执行结果要重新拼回对话让模型继续推理这个过程很容易出现字段格式错误。用户连续对话几十轮后上下文越来越长Token 成本越来越高需要想办法裁剪或压缩。工具权限一旦配置不当模型可能被诱导执行危险操作比如删文件、改数据。这些问题看起来不大但每接入一个新业务场景就重复一遍代码会迅速腐化。Harness 的价值就是把这层能力做成标准化的运行时组件对上层业务提供统一入口。对下层模型提供兼容适配。对工具函数提供注册和调度机制。对安全和观测提供统一策略。这也是为什么现在很多团队在招聘大模型应用开发工程师时特别喜欢问 Harness、Agent 架构、工具调用循环相关的问题。因为面试官想确认的不只是你会不会调 API而是你有没有把工程问题系统化的能力。1.3 本文会讲清楚哪些内容读完本文你会掌握以下内容Harness 架构在 LLM Agent 开发中的定位和边界。六大核心组件的职责与最小实现。一个可运行的轻量级 Agent Harness 项目包含模型接入、工具注册、上下文管理、安全拦截和主循环。常见报错的排查思路例如 tool_calls 解析失败、上下文超限、安全策略误伤。大模型 Agent 方向的高频面试题与答题思路。生产环境落地的安全、性能、成本建议。2. 环境准备与版本说明2.1 运行环境本文示例使用 Python 编写建议环境如下操作系统Windows / macOS / Linux 均可命令略有差异。Python 版本3.10 或更高版本。模型接口需要有一个 OpenAI 兼容的模型服务接口例如你使用的模型平台提供的 API。SDK建议安装openai库版本以 1.x 为主。需要说明的是模型平台和 SDK 版本迭代比较快不同版本的参数名和返回结构可能不同。如果后续官方接口有变化请优先以你使用的模型平台文档和已安装 SDK 的实际定义为准不要死记硬背下面的参数名。2.2 项目结构规划为了让代码更清晰我们按模块拆分最终目录结构如下my_harness/ ├── main.py ├── requirements.txt ├── harness/ │ ├── __init__.py │ ├── adapter.py │ ├── registry.py │ ├── memory.py │ ├── guardrails.py │ └── agent.py └── tools/ ├── __init__.py └── example_tools.pyadapter.py模型接入层负责封装模型 API 调用。registry.py工具注册层负责收集函数、生成 JSON Schema、按名称调用工具。memory.py上下文管理层负责保存用户与模型的对话记录。guardrails.py安全策略层负责在工具调用前做参数校验。agent.pyAgent 主循环把所有组件串起来。2.3 安装依赖在项目根目录执行pip install openai python-dotenv如果网络环境特殊需要配国内镜像源可以用pip install openai python-dotenv -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后建议在项目根目录创建.env文件用来保存模型 API Key 和接口地址不要把密钥写死在代码里。LLM_API_KEY你的_API_Key LLM_BASE_URLhttps://你的模型服务地址 LLM_MODELdeepseek-chat注意.env文件要加入.gitignore防止密钥被提交到 Git 仓库。3. Harness 架构的核心组件拆解一个相对完整的 LLM Agent Harness核心组件可以拆成六层。下面逐层说明职责和最小实现思路。3.1 模型接入层把模型差异挡在外面模型接入层Model Adapter是所有功能的地基。它的主要作用是把不同模型服务商的 API 差异封装起来让上层代码只依赖一个统一的chat()方法。实际开发中你可能会遇到这样的问题今天用的是 DeepSeek明天要切换到其他兼容模型。同一个模型服务商又可能发布多个模型版本。不同模型的请求参数、返回字段结构不完全一致。如果业务代码里到处都是直接调用 SDK 的语句切换模型时会非常痛苦。封装成 Adapter 之后上层只需要传messages和可选的tools不需要关心底层是哪个平台。最小示例思路如下from openai import OpenAI class ModelAdapter: def __init__(self, api_key: str, base_url: str, model: str): self.client OpenAI(api_keyapi_key, base_urlbase_url) self.model model def chat(self, messages, toolsNone): params { model: self.model, messages: messages, } if tools: params[tools] tools params[tool_choice] auto response self.client.chat.completions.create(**params) return response.choices[0].message3.2 工具注册层把业务能力变成模型可调用的函数大模型本身不能执行任意操作它只能“提出要调用某个工具”。真正执行的仍然是业务代码。工具注册层Tool Registry负责两件事把 Python 函数转换成模型需要的函数描述也就是 JSON Schema。根据模型返回的工具名称和参数找到对应函数并执行。为什么不写死 if-else因为工具一多if-else 分发的代码会非常冗长而且新增工具时容易漏改。Registry 的直观优势是注册一个函数自动生成 schema自动按名称调度。最小示例思路如下import inspect import json class ToolRegistry: def __init__(self): self._tools {} def register(self, func): self._tools[func.__name__] func return func def call(self, name: str, arguments_text: str): if name not in self._tools: raise ValueError(f未知工具: {name}) args json.loads(arguments_text) return self._tools[name](**args)3.3 上下文管理层让模型记住关键信息又不超限无状态模型本身没有记忆多轮对话依赖我们把历史消息重新传给它。上下文管理层Conversation Memory负责历史消息的保存、拼装和裁剪。在实际项目中内存列表只是一种最简单的方案。更复杂的实现会有滑动窗口只保留最近 N 轮消息。摘要压缩把超过窗口的历史信息用模型总结成摘要。向量检索从长历史中只取与当前问题相关的消息片段。数据库持久化把会话保存到 Redis 或 MySQL支持用户跨会话恢复。设计上下文管理层时要特别关注“裁剪后不能破坏对话结构”。比如系统消息必须始终在消息列表最前面工具调用和工具结果要成对出现否则模型可能产生幻觉。3.4 执行循环Agent 的“大脑转动机制”Agent 的执行循环是整个 Harness 的调度核心它决定了模型和工具之间如何互动。标准循环通常是把当前消息列表发给模型。判断模型返回值中是否存在tool_calls字段。如果没有工具调用说明模型给出了最终答案循环结束。如果有工具调用依次执行工具并把工具结果以roletool的消息追加回对话。带着工具结果再次请求模型继续步骤 2。这个循环一般需要设置最大步数防止模型陷入“反复调用工具”的死循环。生产环境中最大步数通常控制在 5 到 10 步同时配合超时和重试机制。3.5 安全策略层给工具调用加一道门禁模型生成的工具调用不一定都是合理、安全的。比如用户通过提示词注入让 Agent 去执行DROP TABLE或者删除生产环境关键文件。安全策略层Guardrails的作用就是在执行工具前做参数校验、权限校验和风险拦截。常见做法包括黑名单关键词匹配例如rm -rf、DROP TABLE。强制工具参数只能来自结构化 JSON不让模型直接拼字符串命令。高权限操作必须经过人工审批接口。工具执行环境使用沙箱或容器隔离。全链路审计日志记录谁在什么时间调用了什么工具。安全策略是容易被新手忽略但在面试和生产中极其重要的部分。3.6 观测与日志层让 Agent 行为可复现、可追踪Agent 应用比普通接口更难排查问题因为同一个用户问题模型可能每次输出不同的工具调用路径。如果没有日志和链路追踪出问题很难复现。生产级 Harness 至少需要记录每次请求的消息列表。模型返回的原始响应。工具调用名称、参数、结果。每轮循环的耗时和 Token 消耗。安全拦截命中的策略。有了这些数据才能做回归测试、成本分析和故障复盘。4. 完整实战案例从零实现一个轻量级 Agent Harness下面我们把上面的组件串起来实现一个可以在本地运行的最小 Harness。示例中会注册两个工具获取当前时间、两个整数相加。同时演示安全策略如何拦截高风险工具调用。4.1 创建项目结构和依赖文件先创建目录和依赖文件mkdir my_harness cd my_harness mkdir harness tools touch harness/__init__.py tools/__init__.pyrequirements.txt内容openai1.0 python-dotenv4.2 模型接入层实现文件路径my_harness/harness/adapter.pyimport os from openai import OpenAI class ModelAdapter: 模型接入层封装 OpenAI 兼容接口的调用。 def __init__(self, api_key: str None, base_url: str None, model: str None): self.client OpenAI( api_keyapi_key or os.getenv(LLM_API_KEY), base_urlbase_url or os.getenv(LLM_BASE_URL), ) self.model model or os.getenv(LLM_MODEL, deepseek-chat) def chat(self, messages, toolsNone): params { model: self.model, messages: messages, } if tools: params[tools] tools params[tool_choice] auto response self.client.chat.completions.create(**params) return response.choices[0].message这里要注意api_key和base_url支持从构造参数传入也支持从环境变量读取。环境变量方式更适合生产环境。4.3 工具注册层实现文件路径my_harness/harness/registry.pyimport inspect import json class ToolRegistry: 工具注册层根据函数签名自动生成 schema并支持按名称调用。 def __init__(self): self._tools {} def register(self, func): self._tools[func.__name__] func return func def get_schemas(self): schemas [] for name, func in self._tools.items(): schema { type: function, function: { name: name, description: (func.__doc__ or ).strip(), parameters: { type: object, properties: {}, required: [], }, }, } params schema[function][parameters] sig inspect.signature(func) for param_name, param in sig.parameters.items(): if param.annotation is int: params[properties][param_name] {type: integer} else: params[properties][param_name] {type: string} if param.default is inspect.Parameter.empty: params[required].append(param_name) schemas.append(schema) return schemas def call(self, name: str, arguments_text: str): if name not in self._tools: raise ValueError(f未知工具: {name}) args json.loads(arguments_text) if arguments_text else {} return self._tools[name](**args)这个实现简化为只支持int和str类型实际项目中你可以引入pydantic或手写更完整的类型映射支持嵌套对象、数组、枚举等。4.4 上下文管理与安全策略实现文件路径my_harness/harness/memory.pyclass ConversationMemory: 上下文管理层维护对话消息列表并做简单的滑动窗口裁剪。 def __init__(self, max_turns: int 10): self.messages [] self.max_turns max_turns def reset(self): self.messages [] def add_system(self, content: str): self.messages.append({role: system, content: content}) def add_user(self, content: str): self.messages.append({role: user, content: content}) self._trim() def add_assistant(self, content: str None, tool_callsNone): msg {role: assistant} if content: msg[content] content if tool_calls: msg[tool_calls] tool_calls self.messages.append(msg) self._trim() def add_tool_result(self, tool_call_id: str, content: str): self.messages.append({ role: tool, tool_call_id: tool_call_id, content: content, }) self._trim() def get_messages(self): return self.messages def _trim(self): system_msgs [m for m in self.messages if m[role] system] other_msgs [m for m in self.messages if m[role] ! system] if len(other_msgs) self.max_turns * 2: other_msgs other_msgs[-(self.max_turns * 2):] self.messages system_msgs other_msgs文件路径my_harness/harness/guardrails.pySENSITIVE_WORDS [ rm -rf, drop table, truncate table, delete from, ] def validate_tool_call(tool_name: str, arguments: dict) - bool: 安全策略层在工具执行前做参数风险校验。 if tool_name in {execute_shell, execute_sql, restart_service}: raw .join(str(value).lower() for value in arguments.values()) for word in SENSITIVE_WORDS: if word in raw: return False return True这里必须强调一下上面的SENSITIVE_WORDS只是演示实际项目的安全策略必须更完整。你还需要考虑用户身份权限、IP 白名单、敏感接口白名单、人工审批流程等因素而不是只做关键词匹配。4.5 Agent 主循环实现文件路径my_harness/harness/agent.pyimport json from .adapter import ModelAdapter from .registry import ToolRegistry from .memory import ConversationMemory from .guardrails import validate_tool_call class Agent: Agent 主循环串联模型接入、工具调用、上下文管理和安全策略。 def __init__( self, model_adapter: ModelAdapter, tool_registry: ToolRegistry, system_prompt: str None, max_steps: int 5, ): self.adapter model_adapter self.tools tool_registry self.memory ConversationMemory() self.system_prompt system_prompt or 你是一个有用的助手可以调用工具完成任务。 self.memory.add_system(self.system_prompt) self.max_steps max_steps def run(self, user_input: str): self.memory.add_user(user_input) for _ in range(self.max_steps): message self.adapter.chat( self.memory.get_messages(), toolsself.tools.get_schemas(), ) # 情况一模型没有要求调用工具说明可以输出最终答案 if not message.tool_calls: self.memory.add_assistant(contentmessage.content) return message.content # 情况二模型要求调用工具先把 assistant 消息保存进历史 self.memory.add_assistant( tool_calls[ { id: tc.id, type: function, function: { name: tc.function.name, arguments: tc.function.arguments, }, } for tc in message.tool_calls ] ) # 逐个执行工具调用 for tc in message.tool_calls: try: arguments json.loads(tc.function.arguments) if tc.function.arguments else {} except json.JSONDecodeError: arguments {} if not validate_tool_call(tc.function.name, arguments): self.memory.add_tool_result( tc.id, 该工具调用已被安全策略拦截请换一种方式完成用户请求。, ) continue try: result self.tools.call(tc.function.name, tc.function.arguments) self.memory.add_tool_result(tc.id, str(result)) except Exception as e: self.memory.add_tool_result(tc.id, f工具执行失败: {e}) return 已达到最大执行步数请简化问题或检查工具配置。这个循环比较完整地展现了 Agent 的核心逻辑。在真实项目中你可能还会加入“调用模型前先检查记忆是否需要压缩”“大模型返回内容过长时截断”“工具执行结果过大时只保留摘要”等处理。4.6 工具函数与主程序入口文件路径my_harness/tools/example_tools.pyfrom datetime import datetime def get_current_time(): 返回当前服务器时间格式为 YYYY-MM-DD HH:MM:SS。 return datetime.now().strftime(%Y-%m-%d %H:%M:%S) def add(a: int, b: int): 对两个整数做加法运算。 return a b文件路径my_harness/main.pyimport os from dotenv import load_dotenv from harness.adapter import ModelAdapter from harness.registry import ToolRegistry from harness.agent import Agent from tools.example_tools import get_current_time, add def main(): load_dotenv() registry ToolRegistry() registry.register(get_current_time) registry.register(add) adapter ModelAdapter( api_keyos.getenv(LLM_API_KEY), base_urlos.getenv(LLM_BASE_URL), modelos.getenv(LLM_MODEL), ) agent Agent( model_adapteradapter, tool_registryregistry, system_prompt你是一个会调用工具的助手。 如果需要获取当前时间请调用 get_current_time 如果需要计算两个整数之和请调用 add。, ) print(Harness Agent 已启动输入 exit 退出。) while True: user_input input(你) if user_input.strip().lower() in {exit, quit}: break answer agent.run(user_input) print(助手, answer) if __name__ __main__: main()4.7 运行与验证在项目根目录执行python main.py如果你配置好了.env中的接口地址和 Key并且模型支持函数调用控制台会进入交互模式。比如输入你现在几点了模型很可能返回一个tool_calls要求调用get_current_time然后 Harness 执行工具并把时间返回给模型最终模型把结果整理成自然语言返回助手当前时间是 2026-01-15 10:24:33。如果输入你计算 12 30模型会调用add(12, 30)最终输出42。这里需要说明由于不同模型和不同版本的 API 行为可能存在差异如果你发现模型始终不调用工具建议先检查system_prompt是否明确描述了工具的使用场景再检查工具 schema 是否生成正确。5. 常见问题与排查思路5.1 常见问题速查表问题现象常见原因解决思路模型不调用工具system prompt 没有说明工具用途或模型本身不支持函数调用优化提示词确认所选模型支持 tool calling解析tool_calls报错SDK 版本不同message 对象结构有差异打印原始响应以实际 SDK 返回结构为准工具参数 JSON 解析失败模型返回的 arguments 不是严格 JSON可能被截断增加异常捕获尝试二次修复或提示模型重试上下文越来越长费用涨得很快没有做历史消息裁剪或摘要压缩使用滑动窗口、摘要压缩、向量检索工具执行结果很大模型反而回答不好工具结果塞入上下文太多干扰模型注意力对工具结果做截断、摘要或转成结构化数据安全策略误伤正常请求黑名单匹配太粗糙改为白名单校验完善参数结构约束和权限模型5.2 模型返回异常时的打印调试法遇到任何tool_calls解析问题第一步不是猜原因而是把模型的原始返回结构打印出来。例如在adapter.chat()方法中临时加一行print(response.choices[0].message)然后对比你当前使用的 SDK 版本返回的字段结构确认tool_calls是列表还是对象、arguments是字符串还是字典。版本差异导致的字段变化是这类问题最常见的来源。5.3 工具调用成功但最终回答不理想这种情况通常不是 Harness 循环的问题而是工具返回结果的表达方式不对。比如工具返回的是一个很长的 Python dict直接str(result)塞回对话模型可能难以理解关键信息。更推荐的做法是让工具返回简洁的摘要性文本。把 JSON 数据整理成表格或 key-value 形式。特别重要的指标放在最前面。5.4 安全拦截导致 Agent 无法完成任务如果你在validate_tool_call中拦截了某个工具调用Agent 会把拦截结果回传给模型模型通常会自动调整策略。但要注意过于严格的策略可能导致 Agent 频繁“绕路”影响体验。建议在开发阶段开启详细日志把每次拦截命中的策略名称、参数内容、触发原因都记录下来方便调整规则。6. 面试技巧与高频面试题6.1 面试官问 Harness 时到底在考察什么大模型应用开发岗位的面试中Harness 类问题通常不是背概念而是考察三件事你有没有真正写过 Agent 应用对模型交互循环是否熟悉。你能不能把工程化问题拆解成可设计的组件。你有没有安全意识能不能应对提示词注入、权限滥用这些真实风险。所以回答问题的时候不要只背定义最好结合项目经历讲。比如“我在项目里负责了工具注册层遇到某个参数类型映射问题最终通过扩展 schema 生成器解决”这种表达远胜于“工具注册层就是注册函数的”。6.2 高频面试题与参考作答面试题 1什么是 Harness 架构它解决什么问题参考回答Harness 是围绕大模型应用的运行时支撑层把模型接入、工具编排、上下文管理、安全策略和观测日志等能力收拢成统一框架。它解决的核心问题是让开发者更关注业务逻辑而不是每次都重复处理模型调用和工具调用的细节。面试题 2请描述一次完整的 Agent 工具调用循环。参考回答用户问题进入后先写入上下文管理器然后模型接入层携带消息和工具 schema 发起请求模型返回结果后判断是否存在tool_calls如果存在把 assistant 消息保存到历史再逐个执行工具并回填tool消息然后带着新消息再次请求模型直到模型返回最终文本或无工具调用为止。整个过程需要设置最大步数防止无限循环。面试题 3上下文超出模型 Token 限制时你会怎么处理参考回答优先做消息裁剪只保留最近 N 轮更早但重要的历史可以生成摘要放回系统提示词如果业务涉及大量知识库内容则用向量检索只取与当前问题相关的片段。另外对工具返回结果也要做截断因为工具结果过大同样是 Token 消耗的大头。面试题 4模型返回的 tool_calls 参数不是合法 JSON你会怎么处理参考回答第一步是异常捕获避免整个 Agent 崩溃第二步是尝试从原始文本中提取 JSON 片段例如用正则截取第一个{到最后一个}如果仍失败可以让模型重新生成参数或者把错误信息回传给模型提示其修正同时记录日志用于后续分析是哪类问题导致生成的参数不完整。面试题 5如何防止 Agent 被提示词注入后执行危险操作参考回答核心原则是最小权限。第一可执行的工具必须提前注册不允许模型动态生成任意命令第二工具参数必须结构化避免让模型直接拼接 shell 命令或 SQL第三对高危操作设置人工审批第四执行环境使用沙箱隔离第五全链路审计日志确保任何可疑操作可追溯。安全是系统工程不能只靠关键词黑名单。面试题 6Harness 如何支持多模型切换参考回答通过模型接入层抽象统一接口内部封装不同模型服务商的 API 差异。业务代码只依赖统一的chat()/embed()方法切换模型时只需修改配置或调整 Adapter 实现。生产环境中还可以做模型降级策略当主模型超时或不可用时自动切换到备用模型。面试题 7如何评估一个 Agent Harness 的好坏参考回答可以从功能、性能、成本、稳定性四个维度评估。功能上考察工具调用成功率、复杂任务完成率性能上关注端到端延迟和工具执行耗时成本上关注 Token 消耗和 API 调用次数稳定性上关注错误恢复率、人工干预率、重复调用率。另外还需要有回归测试集避免模型版本升级后行为退化。6.3 面试中展示深度的技巧面试时如果想在 Harness 话题上拿到加分不要停留在“我会用 LangChain”这个层面。可以主动聊下面这些细节你如何处理工具调用的错误重试。你怎么保证工具返回结果和模型历史消息的配对关系。你在生产环境中怎么控制并发和限流。你在日志中记录了哪些字段方便事后复盘。你有没有遇到过模型版本升级导致工具调用行为变化的情况。这些内容不需要每个都精通但只要你能讲出自己在真实项目里踩过的坑和解决方案面试官对工程能力的判断会明显提高。7. 最佳实践与工程建议7.1 安全边界设计要前置Harness 一旦接入真实业务安全就不是可选项。这里给出几条容易落地的建议工具权限要按用户维度隔离不能所有登录用户都能调用所有工具。工具注册时给每个工具标记风险等级例如只读、可写、高风险。高危工具调用必须走审批接口或者需要二级确认。生产环境禁止把完整 API Key 放入前端代码、日志或 Git 历史。定期检查审计日志发现异常请求要及时复盘。在进行任何删除、更新、重启类操作前先在测试环境验证并做好备份。7.2 配置管理要规范不要把所有配置散落在代码里。建议把模型地址、模型名称、超时时间、重试次数、会话窗口大小、安全策略开关都放到统一配置中心或.env文件中。不同环境开发、测试、生产使用不同的配置项并确保生产环境的敏感配置有严格的访问控制。7.3 成本和性能优化大模型应用的资源消耗比传统接口更高所以在 Harness 设计中要提前考虑成本控制设置单用户单会话的最大轮数。对长文本工具结果做截断而不是原样回传。使用缓存减少重复请求例如相同问题在短时间内可以命中缓存。合理设置temperature避免模型在成本无关的问题上过度发散。对模型调用做聚合统计每天关注 Token 消耗和失败率变化。7.4 测试、可观测性和持续迭代Harness 的核心是模型驱动的动态行为比传统代码更难测试但也更需要测试。建议维护一个 Golden Set也就是一批带预期结果的测试问题每次调整提示词、升级模型或修改工具逻辑后都跑一遍回归。可观测性方面线上环境建议对每个 Agent 请求生成一个 Trace ID从用户输入到模型响应、工具调用、安全策略命中结果全链路串起来。这样即使某个问题只在特定上下文下出现也能通过日志复现。7.5 学习路线建议如果你想往大模型应用开发方向深入可以参考下面的路线第一阶段掌握基础 HTTP 调用和 OpenAI 兼容接口理解消息结构。第二阶段动手实现函数调用工具理解 tool_calls 的交互循环。第三阶段把工具注册、上下文管理、安全策略拆成组件形成自己的 Harness。第四阶段研究消息队列、向量数据库、任务队列等外部依赖把 Harness 扩展成多 Agent 协作系统。第五阶段关注模型评估、成本管理、线上监控和压测把 Harness 做成可运营的工程产品。学习 Harness 架构关键不是收藏多少资料而是亲自动手把一个小循环跑通。只要你理解了模型与工具之间的那几轮交互再去看各种 Agent 框架源码会轻松很多。建议你直接拿本文的示例项目改一改加上一个自己的业务工具比如查询订单、查天气、操作数据库跑一遍完整的工具调用链路比看十篇架构分析更有用。