1. 拆开 AI Agent 的引擎盖Harness 到底在管什么很多人第一次听到 Harness 这个词脑子里浮现的是线束、马具、安全带这类物理概念。放到 AI Agent 的语境里这个比喻其实相当贴切——如果把大语言模型比作一台马力强劲但只会空转的发动机那 Harness 就是把这台发动机接到轮子上、接上油门刹车和仪表盘的那一整套传动与控制系统。没有它模型再强也只是在聊天框里输出文字有了它模型才能真正下地干活去读写文件、调用接口、执行命令、记住上下文、从错误里爬起来继续跑。我接触过不少自己动手搭 Agent 的朋友最常见的误区就是一上来就盯着 Prompt 调优觉得只要提示词写得够好Agent 就能自己跑起来。结果往往是单轮对话看着挺聪明一旦让它连续完成一个多步骤任务就开始胡言乱语、重复劳动、忘记目标甚至陷入死循环。问题几乎从来不在模型本身而在于外面那层 Harness 没搭好。Harness 的本质是围绕 LLM 构建的一整套运行时基础设施它负责把一次模型调用升级成一个能持续完成任务的进程。那 Harness 究竟由哪些部分组成结合我自己的搭建经验和社区里反复出现的讨论一套能真正干活的 Harness基本可以拆成七个子系统Agent Loop主循环、LLM Integration模型接入层、Context Management上下文管理、Tool / Skill System工具与技能系统、Memory记忆系统、State Persistence状态与持久化、Guardrails Observability护栏与可观测性。这七个部分各司其职缺一个都会在某个环节掉链子。这篇文章适合三类人看一是刚入门、想从零搭一个能跑通多步任务的 Agent 的开发者二是已经搭了个能跑的 Demo、但一上真实任务就翻车的实践者三是想搞清楚市面上那些 Agent 产品底层到底在做什么的技术爱好者。我会尽量把每个子系统的为什么讲透配上可以直接抄的参数和伪代码也会把我踩过的坑摊开来说。读完你应该能对着自己的项目逐个检查这七块有没有做到位。2. 七个子系统逐个拆解每个都在解决什么真问题2.1 Agent Loop整个 Harness 的心脏Agent Loop 是 Harness 里最核心也最容易被低估的部分。它的工作听起来简单调用模型、拿到输出、判断要不要执行工具、执行完把结果塞回去、再调用模型如此循环直到任务完成。但真正难的地方在于什么时候停和怎么防止跑飞。一个最朴素的循环长这样while not done: response llm.chat(messages, toolstool_schemas) if response.has_tool_call: result execute_tool(response.tool_call) messages.append(tool_result_message(result)) else: done True这段代码能跑但生产环境里会出各种问题。我见过最多的三种翻车场景模型反复调用同一个工具、参数一模一样陷入死循环模型在任务其实没完成时就返回了纯文本提前交卷模型一次返回多个工具调用但执行顺序有依赖关系乱序执行导致结果错误。针对死循环我的做法是加一个重复检测器记录最近 N 次工具调用的 (工具名, 参数哈希)如果连续三次完全相同就强制中断并在下一轮提示里注入你刚才重复了同样的操作请换一种思路或说明为什么卡住。这个 N 一般取 3 就够太小会误伤正常的重试太大又拦不住。针对提前交卷关键是任务完成度校验。纯靠模型自己判断我做完了非常不可靠。更稳的方式是在循环退出前跑一个轻量的检查如果任务涉及文件产出就检查文件是否存在且非空如果涉及数据查询就检查是否拿到了非空结果。校验不过就把失败原因塞回上下文让模型继续。针对多工具调用的顺序问题我倾向于串行执行 依赖声明。虽然并行能省时间但 Agent 场景下工具之间经常有隐式依赖比如先创建文件再写入内容并行带来的收益远小于出错后的排查成本。如果确实要并行至少要把无依赖的工具分组组内并行、组间串行。提示Agent Loop 一定要设一个硬性的最大轮次上限比如 25 轮或 50 轮。我见过没有上限的循环跑了几百轮烧掉大量 token 还没停下来。上限触发时不要静默退出要把当前状态和未完成原因记录下来方便人工介入。2.2 LLM Integration别把模型接入想得太简单LLM Integration 这层新手往往觉得就是调个 API 的事。但真正做起来你会发现这里藏着大量工程细节不同模型的工具调用格式不一样、流式输出和工具调用经常打架、超时和重试策略要精细设计、token 计费要实时监控。先说工具调用格式的差异。有的模型用标准的 function calling 字段有的模型需要你在 Prompt 里用特定标记描述工具还有的模型对工具参数的类型要求特别严格比如数字不能传字符串。我的经验是在接入层做一层适配器Adapter把各家模型的输出统一成内部标准格式上层 Agent Loop 只认这一种格式。这样换模型时只需要改适配器不用动主循环。再说流式与工具调用的冲突。流式输出对用户体验很重要但工具调用需要拿到完整的参数 JSON 才能执行。常见的坑是开了流式模型边输出边调用工具结果参数还没输出完就被截断了。解决办法是分阶段处理——文本内容走流式工具调用走非流式缓冲等完整的 tool_call 块收齐后再执行。超时和重试这块我的参数配置供参考单次请求超时设 60 秒复杂推理任务可以放宽到 120 秒重试最多 3 次采用指数退避1s、2s、4s。但要注意工具调用类的请求不要盲目重试因为如果第一次其实已经执行成功了、只是响应丢了重试会导致重复执行。这种情况要么用幂等工具要么在重试前先查询状态。# 适配器伪代码 class LLMAdapter: def normalize_tool_call(self, raw_response): # 把不同厂商的格式统一成 {name, arguments, id} ... def chat(self, messages, tools, streamFalse): # 统一处理超时、重试、流式 ...2.3 Context Management上下文是稀缺资源上下文管理是 Harness 里最考验功力的部分。模型的上下文窗口是有限的而 Agent 跑多步任务时消息会越堆越多很快就会撑爆窗口或者让模型注意力涣散。我见过太多 Agent 在任务进行到一半时开始答非所问根源就是上下文里塞了太多无关的历史。核心策略是分层管理。我把上下文分成三层系统层角色设定、工具说明、全局约束基本不变、任务层当前任务目标、关键中间结果、已完成的里程碑、临时层最近几轮的原始对话和工具输出。当上下文接近窗口上限时优先压缩临时层——把早期的工具输出摘要成一句话只保留关键结论。具体压缩怎么做我的做法是按重要性打分。每条消息打三个维度的分是否包含任务目标高权重、是否包含未解决的错误高权重、时间新旧程度越新越高。分数低的先被摘要或丢弃。摘要不是简单截断而是让模型自己总结这段历史里对当前任务有用的信息是什么把总结结果作为一条新消息保留。还有一个容易被忽略的点工具输出的体积控制。有些工具比如读取大文件、查询数据库会返回巨量内容直接塞进上下文会瞬间吃掉几千 token。我的处理是给工具输出设一个上限比如 4000 字符超出部分截断并附上内容已截断如需完整内容请用分页参数重新查询的提示。更好的做法是让工具本身支持分页或摘要模式。注意不要为了省 token 把上下文压得太狠。我踩过的坑是压缩过度导致模型丢失了关键的任务约束结果做出来的东西完全跑偏。压缩后一定要保留任务目标和所有未解决的错误信息这两类内容优先级最高。2.4 Tool / Skill SystemAgent 的手和脚工具系统决定了 Agent 能干哪些活。这块的设计直接影响到 Agent 的能力边界和稳定性。我把它分成两个层次原子工具和技能Skill。原子工具是最小执行单元比如读文件、写文件、执行命令、发 HTTP 请求、查询数据库。每个工具需要定义清楚名称、描述、参数 schema、返回值格式、错误类型。描述写得越清楚模型用错的概率越低。我见过很多工具调用失败不是模型笨而是工具描述含糊——比如一个叫process的工具模型根本不知道它是处理文本还是处理图片。技能则是原子工具的组合封装对应一类完整的能力。比如生成一份周报这个技能内部可能包含读取数据、汇总、格式化、写文件四个原子工具。技能的价值在于降低模型的决策负担——与其让模型自己组合五个工具不如直接给它一个高层技能。这也是为什么社区里用 Skill 扩展 Agent的讨论越来越热。工具设计有几个硬性原则。第一幂等优先。读操作天然幂等写操作尽量设计成幂等比如用唯一 ID 去重。第二错误信息要可读。工具失败时返回的错误不能是堆栈而应该是文件不存在路径是 X请检查路径是否正确这种模型能理解并据此调整的提示。第三参数校验前置。在真正执行前先校验参数类型和范围避免执行到一半才报错。工具类型典型例子幂等性风险等级读操作读文件、查数据库天然幂等低写操作写文件、发请求需设计中高执行操作跑命令、跑脚本通常不幂等高查询操作搜索、检索天然幂等低高风险工具尤其是执行命令类一定要加白名单或沙箱。我自己的做法是命令执行工具只允许特定前缀的命令且禁止管道和重定向到系统目录。这不是不信任模型而是工程上必须有的兜底。2.5 Memory让 Agent 记住该记的Memory 和 Context Management 容易混淆但它们是两回事。Context 管的是当前这次任务里模型能看到什么Memory 管的是跨任务、跨会话要记住什么。前者是工作台后者是档案柜。Memory 通常分三类短期记忆当前会话内的关键信息其实和 Context 有重叠、长期记忆用户偏好、历史决策、领域知识、实体记忆关于特定对象的结构化信息比如某个项目的配置、某个客户的习惯。长期记忆的实现方式简单的是存成向量库做语义检索复杂的是结构化存储加检索。我的经验是不要什么都往长期记忆里塞。判断标准很简单这条信息在未来的任务里会不会被用到会才存。否则就是噪音。我见过把每一轮对话都存进向量库的做法结果检索出来的全是无关内容反而干扰模型。实体记忆我强烈建议用结构化存储比如 JSON 或关系表而不是向量。因为实体信息往往是精确查询项目 X 的配置是什么向量检索的模糊性在这里是缺点不是优点。把实体信息存成结构化数据需要时直接按 key 取又快又准。提示Memory 写入要有遗忘机制。长期记忆无限增长会拖慢检索、增加噪音。可以给每条记忆加一个最后使用时间和使用次数长期不用且次数低的定期清理。这个策略和缓存淘汰很像LRU 的思路在这里同样适用。2.6 State Persistence断了能续上Agent 跑长任务时进程可能因为各种原因中断——超时、崩溃、人工暂停。如果没有状态持久化一切从头再来之前烧的 token 和时间全白费。State Persistence 这层就是解决断点续跑的问题。状态要存什么至少包括当前任务目标、已完成步骤、当前上下文快照、待执行的工具调用、已产生的中间产物。存储介质可以是文件、数据库或对象存储取决于任务规模和并发量。小规模用本地 JSON 文件就够大规模上数据库。关键设计是状态的可序列化。Agent 运行时内存里的对象往往包含不可序列化的东西比如连接、句柄持久化时要提取出纯数据部分。我的做法是定义一个AgentState数据类只包含可序列化字段运行时对象和持久化对象之间做显式转换。恢复时要注意幂等性。如果中断发生在工具执行到一半恢复后不能盲目重跑要先检查工具的实际执行结果比如文件是否已写入。这就是前面强调工具幂等的原因——它让恢复变得简单可靠。2.7 Guardrails Observability看不见的刹车和仪表盘最后这层最容易被跳过但恰恰是区分玩具和能用的工具的关键。Guardrails 是护栏负责拦住危险操作Observability 是可观测性负责让你看清 Agent 到底在干什么。护栏包括输入过滤拦住明显恶意的指令、输出校验检查模型输出是否符合格式要求、操作审批高风险操作需要人工确认、资源限制限制 token 消耗、执行时间、工具调用次数。我特别推荐操作审批这一条——对于删除文件、发送外部请求这类不可逆操作让 Agent 先输出计划、人工确认后再执行能避免绝大多数灾难。可观测性包括完整日志每一轮的消息、工具调用、结果、耗时、指标监控token 消耗、轮次、成功率、平均耗时、链路追踪一个任务从开始到结束的完整调用链。没有这些Agent 出问题时你只能靠猜。我自己的项目里日志是结构化的 JSON每条记录带 trace_id方便按任务聚合查看。{ trace_id: task-20260115-001, round: 3, tool: read_file, args: {path: /data/report.csv}, result_summary: 读取成功1200 行, duration_ms: 45, tokens_used: 320 }有了这样的日志排查问题时可以快速定位到是哪一轮、哪个工具出的问题而不是对着几百行对话发呆。3. 从零搭一个最小可用 Harness完整实操流程3.1 环境准备与技术选型动手之前先把技术栈定下来。我的建议是语言选 Python生态最成熟LangChain、LangGraph 这类框架能省掉大量胶水代码模型接入用统一适配层不要直接绑死某一家状态存储先用本地文件跑通了再考虑上数据库。依赖清单大致如下pip install langchain langgraph openai pydanticLangGraph 特别值得说一下它把 Agent Loop 抽象成了图结构节点是处理步骤、边是流转条件天然支持循环、分支、中断恢复。相比自己手写 while 循环用图来描述流程更清晰也更容易加护栏和持久化。当然如果你想把每个细节都攥在手里手写循环也完全可行只是要自己实现状态管理。目录结构我习惯这样组织agent_harness/ ├── core/ │ ├── loop.py # Agent Loop │ ├── llm_adapter.py # 模型接入 │ ├── context.py # 上下文管理 │ └── state.py # 状态定义 ├── tools/ │ ├── registry.py # 工具注册 │ └── builtin.py # 内置工具 ├── memory/ │ └── store.py # 记忆存储 ├── guardrails/ │ └── checks.py # 护栏检查 └── main.py这个结构的好处是每个子系统独立成模块替换或升级某一块时不影响其他部分。比如你想把本地文件存储换成数据库只改state.py和memory/store.py就行。3.2 核心循环的落地实现先定义状态对象这是整个 Harness 的数据核心from dataclasses import dataclass, field from typing import Any dataclass class AgentState: task: str messages: list field(default_factorylist) step: int 0 max_steps: int 25 done: bool False artifacts: dict field(default_factorydict) last_tool_calls: list field(default_factorylist)主循环的逻辑我把关键判断都标出来def run_agent(state: AgentState, llm, tools): while not state.done and state.step state.max_steps: state.step 1 # 1. 上下文压缩检查 state.messages compress_if_needed(state.messages) # 2. 调用模型 response llm.chat(state.messages, toolstools.schemas()) # 3. 处理工具调用 if response.tool_calls: # 重复检测 if is_repeating(state.last_tool_calls, response.tool_calls): state.messages.append(hint_message(检测到重复操作请换思路)) continue for call in response.tool_calls: result tools.execute(call) state.messages.append(tool_result(call, result)) state.last_tool_calls response.tool_calls else: # 4. 完成度校验 if verify_completion(state): state.done True else: state.messages.append(hint_message(任务似乎未完成请继续)) return state这段代码里有几个设计决策值得展开。为什么先压缩再调用模型因为压缩本身可能消耗 token放在调用前能确保模型看到的是压缩后的版本避免压缩了但这一轮没用上的浪费。为什么重复检测放在执行前因为一旦执行了重复操作副作用已经产生检测就晚了。为什么完成度校验不交给模型前面说过模型自评不可靠用客观检查文件存在、结果非空更稳。3.3 工具注册与执行的安全边界工具注册我用装饰器模式写起来清爽class ToolRegistry: def __init__(self): self.tools {} def register(self, name, description, schema): def decorator(func): self.tools[name] { func: func, description: description, schema: schema } return func return decorator def execute(self, call): tool self.tools.get(call.name) if not tool: return {error: f未知工具 {call.name}} try: validate_args(call.arguments, tool[schema]) return tool[func](**call.arguments) except Exception as e: return {error: f执行失败{str(e)}}安全边界主要靠三招。第一招是参数校验用 Pydantic 定义 schema类型不对直接拦下。第二招是路径白名单文件操作只允许在指定工作目录内用os.path.realpath解析后检查前缀防止../穿越。第三招是命令白名单执行类工具只放行预定义的命令前缀。ALLOWED_CMD_PREFIXES [ls, cat, grep, python script.py] def safe_exec(cmd): if not any(cmd.startswith(p) for p in ALLOWED_CMD_PREFIXES): return {error: 命令不在白名单内} if any(ch in cmd for ch in [|, , , ;]): return {error: 禁止使用管道和重定向} return subprocess.run(cmd, shellTrue, capture_outputTrue, timeout30)注意shellTrue本身有风险白名单是第一道防线超时是第二道。生产环境更稳妥的是用shellFalse加参数列表彻底杜绝命令注入。我这里为了演示简洁用了 shellTrue实际项目请务必收紧。3.4 上下文压缩与记忆写入的时机上下文压缩的触发条件我用的是token 占比而不是固定条数。因为不同消息长度差异巨大按条数压缩容易误判。具体做法是估算当前消息的总 token可以用 tiktoken 精确算也可以按字符数除以 3 粗略估当超过窗口的 70% 时触发压缩。压缩时保留哪些我的优先级是系统消息永远保留、任务目标永远保留、未解决的错误永远保留、最近 5 轮原始消息保留、其余按重要性摘要。摘要用一次独立的模型调用完成提示词大意是把以下对话历史压缩成对完成当前任务有用的要点保留关键结论和未解决问题。记忆写入的时机我选在任务完成后而不是过程中。原因是任务完成时才有完整的结论可以沉淀过程中写入容易把中间态的错误信息也存进去。写入前做一次筛选只存结论性和偏好性的信息过程性的细节丢弃。def write_memory(state): summary llm.summarize(state.messages, focus结论和偏好) if is_worth_remembering(summary): memory_store.save(summary, tagsextract_tags(state.task))is_worth_remembering的判断可以简单点摘要长度超过阈值、包含明确的结论词最终确定决定、或者涉及用户偏好我喜欢我习惯。这些规则不完美但比无脑全存强得多。4. 踩坑实录那些让我熬夜的典型问题4.1 工具调用格式不兼容的排查换模型时最常遇到的问题就是工具调用格式对不上。表现是模型明明该调用工具却输出了一段描述工具调用的文本或者调用了但参数解析失败。排查思路是先看原始响应把模型返回的原始 JSON 打出来对比适配器期望的格式。我遇到过一次某模型把工具参数放在function.arguments里而适配器读的是tool_call.arguments字段路径差了一层导致所有工具调用都拿不到参数。这种问题看原始响应一眼就能定位但如果只看适配器处理后的结果会以为是模型不会调用工具方向就错了。速查表如下现象可能原因排查动作模型输出文本而非工具调用工具 schema 描述不清检查工具描述是否明确参数解析失败字段路径不匹配打印原始响应对比工具调用被截断流式与工具调用冲突工具调用改非流式调用不存在的工具工具列表未同步检查 schema 与注册表一致4.2 上下文爆炸导致模型失智这个坑我踩得最深。有一次让 Agent 处理一个数据分析任务它读了几个大文件上下文瞬间涨到十几万 token然后模型开始胡言乱语把之前读过的数据张冠李戴。当时我以为是模型能力问题换了个更强的模型结果一样。后来才意识到是上下文太长导致注意力涣散。解决办法就是前面说的分层压缩加工具输出限流。改完之后同样的任务上下文稳定在窗口的 50% 左右模型表现立刻正常。这件事让我明白一个道理Agent 的稳定性很大程度上取决于你喂给模型的上下文质量而不是数量。4.3 死循环与提前终止的识别死循环的识别前面提过用重复检测。但还有一种更隐蔽的情况模型不是完全重复而是每次微调参数看起来在努力实际在原地打转。比如反复调整一个查询条件每次改一点点但结果始终不满足。这种情况重复检测抓不到需要进展检测。我的做法是记录每一步的目标达成度比如查询返回的行数、文件的大小如果连续 5 步这个指标没有实质变化就判定为停滞注入提示让模型反思策略。这个阈值 5 是经验值任务简单可以调到 3复杂任务可以放宽到 8。提前终止的识别靠的是完成度校验。我列了一个校验清单不同任务类型用不同检查项文件产出类文件存在且大小 0数据查询类结果非空代码生成类代码能通过语法检查多步任务类所有子目标都有对应的完成标记4.4 状态恢复时的幂等陷阱有一次 Agent 跑到第 18 步崩溃了我从第 17 步的状态恢复结果发现第 17 步的工具其实已经执行成功了只是状态没来得及保存。恢复后重跑导致文件被写了两遍数据重复。这个坑的教训是状态保存要在工具执行前和执行后各做一次。执行前保存即将执行的标记执行后保存已完成的结果。恢复时先检查标记如果发现即将执行但没有已完成说明中断发生在执行过程中需要先查询实际执行结果再决定是否重跑。def execute_with_checkpoint(call, state): state.pending_call call save_state(state) # 执行前 result tools.execute(call) state.pending_call None state.completed_calls.append(call.id) save_state(state) # 执行后 return result配合幂等工具这套机制能保证恢复后不会重复产生副作用。虽然多了一次状态写入的开销但相比数据错乱的代价这点开销完全值得。5. 让 Harness 真正扛住并发与长任务5.1 并发场景下的状态隔离单任务跑通之后下一步就是并发。多个任务同时跑最大的风险是状态串台——A 任务的消息混进了 B 任务的上下文。解决办法是每个任务一个独立的 State 实例用 task_id 隔离所有存储操作都带 task_id 前缀。class TaskManager: def __init__(self): self.tasks {} def create_task(self, task_desc): task_id generate_id() self.tasks[task_id] AgentState(tasktask_desc) return task_id def get_state(self, task_id): return self.tasks.get(task_id)如果任务量大内存放不下所有状态就要把状态落到外部存储用 task_id 作为 key。这时候要注意并发读写的问题——两个进程同时改同一个任务的状态会冲突。简单的办法是加锁复杂一点用乐观锁版本号更新时检查版本号是否变化。5.2 长任务的断点续跑设计长任务比如跑几个小时的数据处理必须支持断点续跑。设计要点有三个状态定期快照、快照可序列化、恢复时校验一致性。快照频率我一般设成每完成一个子步骤存一次而不是按时间。因为按时间存可能存到一半的状态恢复时不好处理。按步骤存每个快照都是一个完整的、可继续的状态。恢复时的校验主要是检查快照里的待执行和已完成是否自洽。如果发现某个工具既在待执行又在已完成里说明快照本身有问题需要回退到更早的快照。5.3 资源限制与成本控制Agent 跑起来最怕的就是成本失控。我给自己定的规矩是每个任务设 token 预算和轮次预算任一超限就暂停并通知。token 预算根据任务复杂度定简单任务 5 万复杂任务 50 万超了先暂停看是不是哪里出了问题。成本控制还有一个技巧是模型分级。简单判断用便宜的小模型复杂推理用贵的大模型。比如重复检测、完成度校验这类轻量判断完全可以用小模型甚至规则实现没必要动用大模型。任务类型推荐模型档位预算参考简单判断小模型/规则1 万 token常规任务中档模型10 万 token复杂推理大模型50 万 token5.4 可观测性面板的搭建最后说说可观测性。我给自己搭了一个简单的面板实时显示运行中的任务数、每个任务的当前轮次、token 消耗、最近一次工具调用、是否有错误。数据来源就是前面说的结构化日志。面板不用做得多花哨一个终端里的实时刷新表格就够用。关键是能一眼看出哪个任务卡住了、哪个任务在烧钱。有了这个排查问题的效率能提升好几倍。我甚至设了告警某个任务连续 10 轮没有进展或者 token 消耗超过预算的 80%就发通知提醒。def render_dashboard(tasks): for tid, state in tasks.items(): print(f{tid} | 轮次 {state.step} | ftokens {state.tokens_used} | f状态 {运行中 if not state.done else 完成})这套东西搭起来不复杂但带来的掌控感是质的飞跃。从不知道 Agent 在干嘛到随时能看到它在哪一步、花了多少这个转变对调试和优化太重要了。6. 关于 Harness 工程的一些个人体会搭了几套 Harness 之后我最大的体会是Agent 的能力上限由模型决定但稳定性下限由 Harness 决定。同一个模型Harness 搭得好能稳定完成多步任务搭得差三步就翻车。所以与其纠结用哪个模型不如先把这七个子系统检查一遍看看哪块是短板。另一个体会是不要过度设计。我一开始想给每个子系统都做得很完善结果复杂度爆炸调试起来痛苦不堪。后来学乖了先搭最小可用版本——一个简单循环、几个基础工具、文件存储状态跑通之后再按需增强。哪块出问题就加强哪块而不是一开始就追求大而全。还有一点护栏和可观测性要尽早加不要等出事再加。我吃过亏早期为了快速验证跳过了护栏结果 Agent 误删了一个重要文件。从那以后任何 Agent 项目我都先把操作审批和日志加上哪怕功能还没做全。这两块的成本很低但能避免的损失很大。最后分享一个小技巧给 Agent 加一个解释模式。在关键决策点比如选择哪个工具、为什么认为任务完成让模型输出一句简短的理由。这些理由不参与执行只写进日志。排查问题时看这些理由往往比看工具调用本身更能理解 Agent 的思路也更容易发现它在哪一步想歪了。这个模式对调试的帮助比我用过的任何工具都大。
企业数字化 ERP 产品动态
相关推荐
微软Copilot重构超级应用:Home、Code、Autopilot三件套全解析 今早刷到微软正式通告:Microsoft Copilot 重构成超级应用,Home、Code、Autopilot 三件套同步上线。说实话,这比我预想的动作要快。以前 Copilot 给人的印象是聊天框里的全能助手,你跟它说一句,它回一段,问得… · 2026/11/2 12:55:51
多模态语言理解中的细粒度对齐技术解析 1. 项目背景与核心挑战 2025年NIPS会议上这篇关于多模态语言理解的研究论文,直指当前跨模态学习领域最关键的瓶颈问题——细粒度对齐。想象一下,当人类看到"一只橘猫趴在键盘上"这句话时,大脑能瞬间关联到具体的视觉特征࿱… · 2026/11/2 12:55:51
《读懂 Token》README 越详细,AI 越看不懂:1000 Token 才是甜蜜点 README 越详细,AI 越看不懂:1000 Token 才是甜蜜点系列第 4 篇 实操层你花了一下午写给人类看的那份详细 README,AI 每次进你项目都得从头读一遍。
这句话听起来有点反直觉——README 不是越详细越好吗?对人类读者来说是的。但 A… · 2026/11/3 2:50:28
最小操作次数使数组元素相等【力扣LeetCode 每日一题】 453. 最小操作次数使数组元素相等
网页链接
力扣LeetCode
力扣LeetCode & 每日一题,完成每日打卡,即可获得力扣积分。获得相应数量的积分,能在【力扣商店】,换取相应奖品!助力每日有题做,丰盈积分日… · 2026/11/3 2:50:28
备份问题:覆盖保存前怎样留一份可回退副本?新手一步步做 大家好,我是 SiKi老师。改完存档或导出配置一点保存,文件立刻变成新内容,原来那份却找不到了。很多工具直接 write_text 覆盖原路径,中间没有副本。新手需要的不是复杂版本库,而是覆盖前先留一份带时间戳、能手动拷回去… · 2026/11/3 2:50:28
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 4:42:45
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 5:17:18